diff --git a/FUNDING.yml b/FUNDING.yml
deleted file mode 100644
index 12d807f..0000000
--- a/FUNDING.yml
+++ /dev/null
@@ -1 +0,0 @@
-ko_fi: evaisa
\ No newline at end of file
diff --git a/GUIDs.txt b/GUIDs.txt
deleted file mode 100644
index a96b3d5..0000000
--- a/GUIDs.txt
+++ /dev/null
@@ -1,30 +0,0 @@
-{d3d376b6-af21-4ae3-917c-3e8fb781b724} bank:/Master Bank
-{4bce5662-de5a-06a1-1735-b4714672b1bc} bank:/Master Bank.strings
-{91582d81-bc04-4e28-971c-5f71aeefedd7} bank:/online
-{fd1ec6a6-24b7-4a2e-9988-9733b99dc81e} bus:/
-{ab2beddd-fa07-445b-a933-d5cca76adb6e} bus:/UNASSIGNED 2
-{1a5d4dc3-8fc9-4261-a499-f3f6b0202e17} bus:/UNASSIGNED 3
-{0b728e09-75ca-402a-994c-60d2966e6400} bus:/UNASSIGNED 4
-{c77e6e4c-f45c-48ef-911b-7981915e0fd8} bus:/ambience+reverb
-{f34de4a2-1c20-4c14-99a0-eeb17d2f30a1} bus:/ambient
-{2cbf3aea-7bb4-4ea3-a5d4-bf22bf26f0d0} bus:/distant_reverb
-{af5b14c7-ccc0-43a9-aa70-65cd8f5344a4} bus:/game_sfx
-{8f8e9fd3-8a5c-4873-8776-2d3f3be234a5} bus:/lowpass
-{4686115c-5062-400a-b903-d03d5c45527e} bus:/music
-{5499ef15-f83e-4e92-9144-d53eab549f87} bus:/music_intro_etc
-{9e5f6674-ecca-4cb3-9e39-050604be24e9} bus:/music_reverb
-{8340afee-1bfb-481c-8b65-a1721703356c} bus:/reverb
-{40bdfd79-5dfd-4303-8a71-0792c637c380} bus:/ui
-{c7d655d8-ec85-4d25-bc91-cf2cca64fbb7} event:/message/received
-{2f99f806-4b51-4b0a-a879-566644591f29} parameter:/Migration Name Conflict (3)/lowpass
-{6864bf18-2f50-4b34-aecc-63c1bdf7fdf4} parameter:/Migration Name Conflict (4)/Distance
-{ddf75d16-bdbe-4460-908b-0a29bd483835} parameter:/lowpass
-{dadeda7a-c13b-484b-929e-d3c513e7173b} snapshot:/cave
-{bc5e80f9-a380-47c9-8799-3e02eea94feb} snapshot:/drugged
-{310cecea-3674-4ea8-a6ac-2a8facd05638} snapshot:/hills
-{2aa42396-4f12-4e40-9319-c51683cc06d1} snapshot:/music_duck
-{53a7180c-9635-4a37-a2b8-fb8001ac66ff} snapshot:/music_reverb
-{fcb63c0a-331d-44e6-bf64-cfa8c5b6e6e7} snapshot:/snowcave
-{8c3abc6b-141a-42fe-9d0f-eefcf03cd52f} snapshot:/teleport_nearby
-{c9b0b78b-9869-4058-91fb-73188f7b9103} snapshot:/underwater
-{a0219622-35b0-4a2d-8de4-650884606931} snapshot:/vault
diff --git a/README.md b/README.md
index 01dafb4..810ad7c 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1 @@
-# noita-online
-**A multiplayer gamemode framework for Noita using SteamAPI**
-What it does is implement several of Steam's networking / matchmaking APIs and provides a user interface for lobbies, chat, etc.
-Essentially it makes it easy for mod developers to create online multiplayer gamemodes for Noita, which can even be uploaded to since they do not need to be unsafe.
-
-*List of mods using this framework:*
-- [Noita Arena](https://github.com/EvaisaDev/noita-arena) - A party game style online PvP arena mode.
-- [Bomberminä](https://github.com/EvaisaDev/noita-bombergame) - A online PvP bomberman clone.
-
-
-You can support my work @[https://ko-fi.com/evaisa](https://ko-fi.com/evaisa)
-
-Credits:
-- [Dextercd](https://github.com/dextercd) - for helping me implement lots of Noita Online stuff.
-- [Noita Community](https://discord.gg/noita) - for being fucking awesome
-
-*If I missed anyone in the credits please hit me up.*
+下载之后覆盖原文件
diff --git a/bin/NoitaPatcher/load.lua b/bin/NoitaPatcher/load.lua
deleted file mode 100644
index b41f660..0000000
--- a/bin/NoitaPatcher/load.lua
+++ /dev/null
@@ -1,24 +0,0 @@
-
--- You're supposed to `dofile_once("path/to/load.lua")` this file.
-
-
-local orig_do_mod_appends = do_mod_appends
-
-do_mod_appends = function(filename, ...)
- do_mod_appends = orig_do_mod_appends
- do_mod_appends(filename, ...)
-
- local noitapatcher_path = string.match(filename, "(.*)/load.lua")
- if not noitapatcher_path then
- print("Couldn't detect NoitaPatcher path")
- end
-
- __nsew_path = noitapatcher_path .. "/noitapatcher/nsew/"
-
- package.cpath = package.cpath .. ";./" .. noitapatcher_path .. "/?.dll"
- package.path = package.path .. ";./" .. noitapatcher_path .. "/?.lua"
-
- -- Lua's loader should now be setup properly:
- -- local np = require("noitapatcher")
- -- local nsew = require("noitapatcher.nsew")
-end
diff --git a/bin/NoitaPatcher/noitapatcher.dll b/bin/NoitaPatcher/noitapatcher.dll
deleted file mode 100644
index 8bf9c4c..0000000
Binary files a/bin/NoitaPatcher/noitapatcher.dll and /dev/null differ
diff --git a/bin/NoitaPatcher/noitapatcher.pdb b/bin/NoitaPatcher/noitapatcher.pdb
deleted file mode 100644
index 7ab4462..0000000
Binary files a/bin/NoitaPatcher/noitapatcher.pdb and /dev/null differ
diff --git a/bin/NoitaPatcher/noitapatcher/nsew/native_dll.lua b/bin/NoitaPatcher/noitapatcher/nsew/native_dll.lua
deleted file mode 100644
index 07a86e6..0000000
--- a/bin/NoitaPatcher/noitapatcher/nsew/native_dll.lua
+++ /dev/null
@@ -1,11 +0,0 @@
----Native library. Primarily for internal use.
----@module 'noitapatcher.nsew.native_dll'
-
-local ffi = require("ffi")
-
-native_dll = {}
-
----The NSEW support dll loaded in with `ffi.load`.
-native_dll.lib = ffi.load(__nsew_path .. "nsew_native.dll")
-
-return native_dll
diff --git a/bin/NoitaPatcher/noitapatcher/nsew/nsew_native.dll b/bin/NoitaPatcher/noitapatcher/nsew/nsew_native.dll
deleted file mode 100644
index acffc35..0000000
Binary files a/bin/NoitaPatcher/noitapatcher/nsew/nsew_native.dll and /dev/null differ
diff --git a/bin/NoitaPatcher/noitapatcher/nsew/rect.lua b/bin/NoitaPatcher/noitapatcher/nsew/rect.lua
deleted file mode 100644
index 31c7c31..0000000
--- a/bin/NoitaPatcher/noitapatcher/nsew/rect.lua
+++ /dev/null
@@ -1,167 +0,0 @@
----Rectangle utilities.
----@module 'noitapatcher.nsew.rect'
-
----@class Rect
-local rect = {}
-
-local ffi = require("ffi")
-local native_dll = require("noitapatcher.nsew.native_dll")
-
-ffi.cdef([[
-
-struct nsew_rectangle {
- int32_t left;
- int32_t top;
- int32_t right;
- int32_t bottom;
-};
-
-
-struct nsew_rectangle_optimiser;
-
-struct nsew_rectangle_optimiser* rectangle_optimiser_new();
-void rectangle_optimiser_delete(struct nsew_rectangle_optimiser* rectangle_optimiser);
-void rectangle_optimiser_reset(struct nsew_rectangle_optimiser* rectangle_optimiser);
-void rectangle_optimiser_submit(struct nsew_rectangle_optimiser* rectangle_optimiser, struct nsew_rectangle* rectangle);
-void rectangle_optimiser_scan(struct nsew_rectangle_optimiser* rectangle_optimiser);
-int32_t rectangle_optimiser_size(const struct nsew_rectangle_optimiser* rectangle_optimiser);
-const struct nsew_rectangle* rectangle_optimiser_get(const struct nsew_rectangle_optimiser* rectangle_optimiser, int32_t index);
-
-
-struct lua_nsew_rectangle_optimiser {
- struct nsew_rectangle_optimiser* impl;
-};
-
-]])
-
----@class Rectangle_fields
----@field top integer
----@field bottom integer
----@field right integer
----@field left integer
-
----@alias Rectangle Rectangle_mt | Rectangle_fields
-
----@class Optimiser_fields
----@field top integer
----@field bottom integer
----@field right integer
----@field left integer
-
----@alias Optimiser Optimiser_fields | Optimiser_mt
-
----@class Rectangle_mt
-local Rectangle_mt_index = {
- ---@param r Rectangle
- ---@return integer
- area = function(r)
- return (r.right - r.left) * (r.bottom - r.top)
- end,
- ---@param r Rectangle
- ---@return integer
- height = function(r)
- return r.bottom - r.top
- end,
- ---@param r Rectangle
- ---@return integer
- width = function(r)
- return r.right - r.left
- end,
-}
-local Rectangle_mt = {
- __index = Rectangle_mt_index,
-}
-
----@type fun(left, top, right, bottom): Rectangle
----@diagnostic disable-next-line: assign-type-mismatch
-rect.Rectangle = ffi.metatype("struct nsew_rectangle", Rectangle_mt)
-
----Given an iterator that returns rectangles, return an iterator where the
----rectangle extents never exceed `size`.
----@param iterator fun(): Rectangle? returning rectangles
----@param size integer maximum width and height
----@return fun(): Rectangle? rectangles where the extents never exceed `size`
-function rect.parts(iterator, size)
- local region
- local posx
- local posy
- return function()
- if region == nil then
- region = iterator()
- if region == nil then
- return nil
- end
- posx = region.left
- posy = region.top
- end
-
- local endx = math.min(posx + size, region.right)
- local endy = math.min(posy + size, region.bottom)
-
- local ret = rect.Rectangle(posx, posy, endx, endy)
-
- -- Setup for next iteration: place to the right, wraparound, or
- -- we're done with this region.
- if endx ~= region.right then
- posx = endx
- elseif endy ~= region.bottom then
- posx = region.left
- posy = endy
- else
- region = nil
- end
-
- return ret
- end
-end
-
----@class Optimiser_mt
-local Optimiser_mt_index = {
- submit = function(opt, rectangle)
- native_dll.lib.rectangle_optimiser_submit(opt.impl, rectangle)
- end,
- scan = function(opt)
- native_dll.lib.rectangle_optimiser_scan(opt.impl)
- end,
- reset = function(opt)
- native_dll.lib.rectangle_optimiser_reset(opt.impl)
- end,
- size = function(opt)
- return native_dll.lib.rectangle_optimiser_size(opt.impl)
- end,
- get = function(opt, index)
- return native_dll.lib.rectangle_optimiser_get(opt.impl, index)
- end,
- iterate = function(opt)
- local size = native_dll.lib.rectangle_optimiser_size(opt.impl)
- local index = 0
- return function()
- if index >= size then
- return nil
- end
-
- local ret = native_dll.lib.rectangle_optimiser_get(opt.impl, index)
- index = index + 1
- return ret
- end
- end,
-}
-
-local Optimiser_mt = {
- __gc = function(opt)
- native_dll.lib.rectangle_optimiser_delete(opt.impl)
- end,
- __index = Optimiser_mt_index,
-}
-
----@type fun(unknown): Optimiser
----@diagnostic disable-next-line: assign-type-mismatch
-rect.Optimiser = ffi.metatype("struct lua_nsew_rectangle_optimiser", Optimiser_mt)
-
----Create a new rectangle Optimiser
----@return Optimiser optimiser
-function rect.Optimiser_new()
- return rect.Optimiser(native_dll.lib.rectangle_optimiser_new())
-end
-
-return rect
diff --git a/bin/NoitaPatcher/noitapatcher/nsew/world.lua b/bin/NoitaPatcher/noitapatcher/nsew/world.lua
deleted file mode 100644
index 6bf27c3..0000000
--- a/bin/NoitaPatcher/noitapatcher/nsew/world.lua
+++ /dev/null
@@ -1,326 +0,0 @@
----@diagnostic disable: cast-local-type
----World read / write functionality.
----@module 'noitapatcher.nsew.world'
----@class World
-local world = {}
-
-local ffi = require("ffi")
-local world_ffi = require("noitapatcher.nsew.world_ffi")
-
-local C = ffi.C
-
-ffi.cdef([[
-
-enum ENCODE_CONST {
- PIXEL_RUN_MAX = 8192,
-
- LIQUID_FLAG_STATIC = 1,
-};
-
-struct __attribute__ ((__packed__)) EncodedAreaHeader {
- int32_t x;
- int32_t y;
- uint8_t width;
- uint8_t height;
-
- uint16_t pixel_run_count;
-};
-
-struct __attribute__ ((__packed__)) PixelRun {
- uint16_t length;
- int16_t material;
- uint8_t flags;
-};
-
-struct __attribute__ ((__packed__)) EncodedArea {
- struct EncodedAreaHeader header;
- struct PixelRun pixel_runs[PIXEL_RUN_MAX];
-};
-
-]])
-
----@class PixelRun
----@field flags integer
----@field material integer
----@field length integer
-
----@class EncodedAreaHeader
----@field x integer
----@field y integer
----@field width integer
----@field height integer
----@field pixel_run_count integer
-
----@class EncodedArea
----@field header EncodedAreaHeader
----@field pixel_runs PixelRun[] a pointer
-
-world.EncodedAreaHeader = ffi.typeof("struct EncodedAreaHeader")
-world.PixelRun = ffi.typeof("struct PixelRun")
----@type fun(): EncodedArea
----@diagnostic disable-next-line: assign-type-mismatch
-world.EncodedArea = ffi.typeof("struct EncodedArea")
-
-local pliquid_cell = ffi.typeof("struct CLiquidCell*")
-
----Total bytes taken up by the encoded area
----@param encoded_area EncodedArea
----@return integer total number of bytes that encodes the area
----```lua
----local data = ffi.string(area, world.encoded_size(area))
----peer:send(data)
----```
-function world.encoded_size(encoded_area)
- return ffi.sizeof(world.EncodedAreaHeader) + encoded_area.header.pixel_run_count * ffi.sizeof(world.PixelRun)
-end
-
----Encode the given rectangle of the world
----The rectangle defined by {`start_x`, `start_y`, `end_x`, `end_y`} must not exceed 256 in width or height.
----@param chunk_map unknown
----@param start_x integer coordinate
----@param start_y integer coordinate
----@param end_x integer coordinate
----@param end_y integer coordinate
----@param encoded_area EncodedArea? memory to use, if nil this function allocates its own memory
----@return EncodedArea? encoded_area returns an EncodedArea or nil if the area could not be encoded
----@see decode
-function world.encode_area(chunk_map, start_x, start_y, end_x, end_y, encoded_area)
- start_x = ffi.cast('int32_t', start_x)
- start_y = ffi.cast('int32_t', start_y)
- end_x = ffi.cast('int32_t', end_x)
- end_y = ffi.cast('int32_t', end_y)
- ---@cast start_x integer
- ---@cast start_y integer
- ---@cast end_x integer
- ---@cast end_x integer
-
- encoded_area = encoded_area or world.EncodedArea()
-
- local width = end_x - start_x
- local height = end_y - start_y
-
- if width <= 0 or height <= 0 then
- print("Invalid world part, negative dimension")
- return nil
- end
-
- if width > 256 or height > 256 then
- print("Invalid world part, dimension greater than 256")
- return nil
- end
-
- encoded_area.header.x = start_x
- encoded_area.header.y = start_y
- encoded_area.header.width = width - 1
- encoded_area.header.height = height - 1
-
- local run_count = 1
-
- local current_run = encoded_area.pixel_runs[0]
- local run_length = 0
- local current_material = 0
- local current_flags = 0
-
- local y = start_y
- while y < end_y do
- local x = start_x
- while x < end_x do
- local material_number = 0
- local flags = 0
-
- local ppixel = world_ffi.get_cell(chunk_map, x, y)
- local pixel = ppixel[0]
-
- if pixel ~= nil then
- local cell_type = pixel.vtable.get_cell_type(pixel)
-
- --if cell_type ~= C.CELL_TYPE_SOLID then
- local material_ptr = pixel.vtable.get_material(pixel)
- material_number = world_ffi.get_material_id(material_ptr)
- --end
-
- if cell_type == C.CELL_TYPE_LIQUID then
- local liquid_cell = ffi.cast(pliquid_cell, pixel)
- if liquid_cell.is_static then
- flags = bit.bor(flags, C.LIQUID_FLAG_STATIC)
- end
- end
-
- if cell_type == C.CELL_TYPE_GAS or cell_type == C.CELL_TYPE_FIRE then
- material_number = -1
- end
- end
-
- if x == start_x and y == start_y then
- -- Initial run
- current_material = material_number
- current_flags = flags
- elseif current_material ~= material_number or current_flags ~= flags then
- -- Next run
- current_run.length = run_length - 1
- current_run.material = current_material
- current_run.flags = current_flags
-
- if run_count == C.PIXEL_RUN_MAX then
- print("Area too complicated to encode")
- return nil
- end
-
- current_run = encoded_area.pixel_runs[run_count]
- run_count = run_count + 1
-
- run_length = 0
- current_material = material_number
- current_flags = flags
- end
-
- run_length = run_length + 1
-
- x = x + 1
- end
- y = y + 1
- end
-
- current_run.length = run_length - 1
- current_run.material = current_material
- current_run.flags = current_flags
-
- encoded_area.header.pixel_run_count = run_count
-
- return encoded_area
-end
-
-local PixelRun_const_ptr = ffi.typeof("struct PixelRun const*")
-
----Load an encoded area back into the world.
----@param grid_world unknown
----@param header EncodedAreaHeader header of the encoded area
----@param pixel_runs PixelRun[] or ffi array of PixelRun from the encoded area
----@see encode_area
-function world.decode(grid_world, header, pixel_runs)
- local chunk_map = grid_world.vtable.get_chunk_map(grid_world)
-
- local top_left_x = header.x
- local top_left_y = header.y
- local width = header.width + 1
- local height = header.height + 1
- local bottom_right_x = top_left_x + width
- local bottom_right_y = top_left_y + height
-
- local current_run_ix = 0
- local current_run = pixel_runs[current_run_ix]
- local new_material = current_run.material
- local flags = current_run.flags
- local left = current_run.length + 1
-
- local new_name = CellFactory_GetName(new_material)
-
- if(new_name == "concrete_collapsed")then
- new_material = CellFactory_GetType("templebrick_static")
- flags = bit.bor(flags, C.LIQUID_FLAG_STATIC)
- end
-
-
- local y = top_left_y
- while y < bottom_right_y do
- local x = top_left_x
- while x < bottom_right_x do
- if world_ffi.chunk_loaded(chunk_map, x, y) then
- local ppixel = world_ffi.get_cell(chunk_map, x, y)
- local current_material = 0
-
- if ppixel[0] ~= nil then
- local pixel = ppixel[0]
- local cell_type = pixel.vtable.get_cell_type(pixel)
- if cell_type == C.CELL_TYPE_SOLID then
- local bodies = PhysicsBodyIDQueryBodies( x, y, x, y, false, false )
-
- local entities_nearby = EntityGetInRadius( x, y, 50 )
-
- local entity_found = false
- for k, v in ipairs(entities_nearby)do
- local body_ids = PhysicsBodyIDGetFromEntity(v)
- if(body_ids ~= nil and #body_ids >= 0)then
- for i, body_id in ipairs(body_ids)do
- if(body_id == bodies[1])then
- entity_found = true
- end
- end
- end
- end
-
- if entity_found then
- goto next_pixel
- end
- end
-
-
-
- current_material = world_ffi.get_material_id(pixel.vtable.get_material(pixel))
-
- if(((cell_type == C.CELL_TYPE_GAS or cell_type == C.CELL_TYPE_FIRE) or current_material == 0) and new_material == -1)then
- goto next_pixel
- elseif(new_material == -1)then
- new_material = 0
- end
-
- if new_material ~= current_material then
- world_ffi.remove_cell(grid_world, pixel, x, y, false)
- end
- end
-
- if current_material ~= new_material and new_material ~= 0 and new_material ~= -1 then
- local mat_ptr = world_ffi.get_material_ptr(new_material)
- if mat_ptr == nil then
- GamePrint("NULL mat_ptr encountered")
- goto next_pixel
- end
- local pixel = world_ffi.construct_cell(grid_world, x, y, mat_ptr, nil)
- if pixel == nil then
- -- TODO: This can happen when the material texture has a
- -- transparent pixel at the given coordinate. There's
- -- probably a better way to deal with this, but for now
- -- we skip positions like this.
- goto next_pixel
- end
- local cell_type = pixel.vtable.get_cell_type(pixel)
-
- if cell_type == C.CELL_TYPE_LIQUID then
- local liquid_cell = ffi.cast(pliquid_cell, pixel)
- liquid_cell.is_static = bit.band(flags, C.CELL_TYPE_LIQUID) == C.LIQUID_FLAG_STATIC
- end
-
- ppixel[0] = pixel
- end
- end
-
- ::next_pixel::
-
- left = left - 1
- if left <= 0 then
- current_run_ix = current_run_ix + 1
- if current_run_ix >= header.pixel_run_count then
- -- No more runs, done
- assert(x == bottom_right_x - 1)
- assert(y == bottom_right_y - 1)
- return
- end
-
- current_run = pixel_runs[current_run_ix]
- new_material = current_run.material
- flags = current_run.flags
- local new_name = CellFactory_GetName(new_material)
- if(new_name == "concrete_collapsed")then
- new_material = CellFactory_GetType("templebrick_static")
- flags = bit.bor(flags, C.LIQUID_FLAG_STATIC)
- end
- left = current_run.length + 1
- end
-
- x = x + 1
- end
- y = y + 1
- end
-end
-
-return world
diff --git a/bin/NoitaPatcher/noitapatcher/nsew/world_ffi.lua b/bin/NoitaPatcher/noitapatcher/nsew/world_ffi.lua
deleted file mode 100644
index 298c445..0000000
--- a/bin/NoitaPatcher/noitapatcher/nsew/world_ffi.lua
+++ /dev/null
@@ -1,423 +0,0 @@
----@diagnostic disable: assign-type-mismatch
----Noita world functionality exposed.
----@module 'noitapatcher.nsew.world_ffi'
-
----@class WorldFFI
-local world_ffi = {}
-
-local ffi = require("ffi")
-
-local np = require("noitapatcher")
-local world_info = np.GetWorldInfo()
-
-if not world_info then
- error("Couldn't get world info from NoitaPatcher.")
-end
-
-local gg_ptr = world_info.game_global
-
-ffi.cdef([[
-
-typedef void* __thiscall placeholder_memfn(void*);
-
-struct Position {
- int x;
- int y;
-};
-
-struct Colour {
- uint8_t r;
- uint8_t g;
- uint8_t b;
- uint8_t a;
-};
-
-struct AABB {
- struct Position top_left;
- struct Position bottom_right;
-};
-
-struct std_string { /* VC++ std::string */
- char *buffer;
- char sso_buffer[12];
- size_t size;
- size_t capacity;
-};
-
-typedef enum cell_type {
- none=0,
- liquid=1,
- gas=2,
- solid=3,
- fire=4,
- invalid=4294967295
-} cell_type;
-
-struct CellData {
- struct std_string name;
- struct std_string ui_name;
- int material_type;
- int id_2;
- enum cell_type cell_type;
- int platform_type;
- unsigned int wang_color;
- int gfx_glow;
- unsigned int gfx_glow_color;
- char unknown1[24];
- unsigned int default_primary_colour;
- char unknown2[36];
- bool cell_holes_in_texture;
- bool stainable;
- bool burnable;
- bool on_fire; /* Created by retype action */
- int fire_hp;
- int autoignition_temperature; /* Created by retype action */
- int _100_minus_autoignition_temp; /* Created by retype action */
- int temperature_of_fire;
- int generates_smoke;
- int generates_flames;
- bool requires_oxygen;
- char padding1[3];
- struct std_string on_fire_convert_to_material;
- char unknown3[4];
- struct std_string on_fire_flame_material;
- char unknown4[4];
- struct std_string on_fire_smoke_material;
- char unknown5[4];
- struct ConfigExplosion *explosion_config;
- int durability;
- int crackability;
- bool electrical_conductivity;
- bool slippery;
- char padding2[2];
- float stickyness; /* Created by retype action */
- struct std_string cold_freezes_to_material;
- struct std_string warmth_melts_to_material;
- char unknown6[8];
- int16_t cold_freezes_chance_rev;
- int16_t warmth_melts_chance_rev;
- bool cold_freezes_to_dont_do_reverse_reaction;
- char padding3[3];
- int lifetime;
- int hp;
- float density;
- bool liquid_sand;
- bool liquid_slime;
- bool liquid_static;
- bool liquid_stains_self;
- int liquid_sticks_to_ceiling;
- float liquid_gravity;
- int liquid_viscosity;
- int liquid_stains;
- unsigned int liquid_stains_custom_color;
- float liquid_sprite_stain_shaken_drop_chance;
- float liquid_sprite_stain_ignited_drop_chance;
- int8_t liquid_sprite_stains_check_offset;
- char padding4[3];
- float liquid_sprite_stains_status_threshold;
- float liquid_damping;
- float liquid_flow_speed;
- bool liquid_sand_never_box2d;
- char unknown7[3];
- int8_t gas_speed;
- int8_t gas_upwards_speed;
- int8_t gas_horizontal_speed;
- int8_t gas_downwards_speed;
- float solid_friction;
- float solid_restitution;
- float solid_gravity_scale;
- int solid_static_type;
- float solid_on_collision_splash_power;
- bool solid_on_collision_explode;
- bool solid_on_sleep_convert; /* Created by retype action */
- bool solid_on_collision_convert;
- bool solid_on_break_explode;
- bool solid_go_through_sand;
- bool solid_collide_with_self;
- char padding5[2];
- struct std_string solid_on_collision_material;
- char unknown8[4];
- struct std_string solid_break_to_type;
- char unknown9[4];
- struct std_string convert_to_box2d_material;
- char unknown10[4];
- int vegetation_full_lifetime_growth;
- struct std_string vegetation_sprite;
- bool vegetation_random_flip_x_scale;
- char padding6[3];
- char unknown11[12];
- float wang_noise_percent;
- float wang_curvature;
- int wang_noise_type;
- char unknown12[12];
- bool danger_fire;
- bool danger_radioactive;
- bool danger_poison;
- bool danger_water;
- char unknown13[24];
- bool always_ignites_damagemodel;
- bool ignore_self_reaction_warning;
- char padding7[2];
- char unknown14[12];
- float audio_size_multiplier;
- bool audio_is_soft;
- char padding8[3];
- char unknown15[8];
- bool show_in_creative_mode;
- bool is_just_particle_fx;
- char padding9[2];
- // struct grid_CosmeticParticleConfig *ParticleEffect;
-};
-
-enum CellType {
- CELL_TYPE_NONE = 0,
- CELL_TYPE_LIQUID = 1,
- CELL_TYPE_GAS = 2,
- CELL_TYPE_SOLID = 3,
- CELL_TYPE_FIRE = 4,
-};
-
-struct Cell_vtable {
- void (__thiscall *destroy)(struct Cell*, char dealloc);
- enum CellType (__thiscall *get_cell_type)(struct Cell*);
- void* field2_0x8;
- void* field3_0xc;
- void* field4_0x10;
- struct Colour (__thiscall *get_colour)(struct Cell*);
- void* field6_0x18;
- void (__thiscall *set_colour)(struct Cell*, struct Colour);
- void* field8_0x20;
- void* field9_0x24;
- void* field10_0x28;
- void* field11_0x2c;
- struct CellData* (__thiscall *get_material)(void *);
- void* field13_0x34;
- void* field14_0x38;
- void* field15_0x3c;
- void* field16_0x40;
- void* field17_0x44;
- void* field18_0x48;
- void* field19_0x4c;
- struct Position * (__thiscall *get_position)(void *, struct Position *);
- void* field21_0x54;
- void* field22_0x58;
- void* field23_0x5c;
- void* field24_0x60;
- void* field25_0x64;
- void* field26_0x68;
- void* field27_0x6c;
- void* field28_0x70;
- bool (__thiscall *is_burning)(struct Cell*);
- void* field30_0x78;
- void* field31_0x7c;
- void* field32_0x80;
- void (__thiscall *stop_burning)(struct Cell*);
- void* field34_0x88;
- void* field35_0x8c;
- void* field36_0x90;
- void* field37_0x94;
- void* field38_0x98;
- void (__thiscall *remove)(struct Cell*);
- void* field40_0xa0;
-};
-
-// In the Noita code this would be the ICellBurnable class
-struct Cell {
- struct Cell_vtable* vtable;
-
- int hp;
- char unknown1[8];
- bool is_burning;
- char unknown2[3];
- uintptr_t material_ptr;
-};
-
-struct CLiquidCell {
- struct Cell cell;
- int x;
- int y;
- char unknown1;
- char unknown2;
- bool is_static;
- char unknown3;
- int unknown4[3];
- struct Colour colour;
- unsigned not_colour;
-};
-
-typedef struct Cell (*cell_array)[0x40000];
-
-struct ChunkMap {
- int unknown[2];
- cell_array* (*cells)[0x40000];
- int unknown2[8];
-};
-
-struct GridWorld_vtable {
- placeholder_memfn* unknown[3];
- struct ChunkMap* (__thiscall *get_chunk_map)(struct GridWorld* this);
- placeholder_memfn* unknown2[30];
-};
-
-struct GridWorld {
- struct GridWorld_vtable* vtable;
- int unknown[318];
- int world_update_count;
- struct ChunkMap chunk_map;
- int unknown2[41];
- struct GridWorldThreadImpl* mThreadImpl;
-};
-
-struct GridWorldThreaded_vtable;
-
-struct GridWorldThreaded {
- struct GridWorldThreaded_vtable* vtable;
- int unknown[287];
- struct AABB update_region;
-};
-
-struct vec_pGridWorldThreaded {
- struct GridWorldThreaded** begin;
- struct GridWorldThreaded** end_;
- struct GridWorldThreaded** capacity_end;
-};
-
-struct WorldUpdateParams {
- struct AABB update_region;
- int unknown;
- struct GridWorldThreaded* grid_world_threaded;
-};
-
-struct vec_WorldUpdateParams {
- struct WorldUpdateParams* begin;
- struct WorldUpdateParams* end_;
- struct WorldUpdateParams* capacity_end;
-};
-
-struct GridWorldThreadImpl {
- int chunk_update_count;
- struct vec_pGridWorldThreaded updated_grid_worlds;
-
- int world_update_params_count;
- struct vec_WorldUpdateParams world_update_params;
-
- int grid_with_area_count;
- struct vec_pGridWorldThreaded with_area_grid_worlds;
-
- int another_count;
- int another_vec[3];
-
- int some_kind_of_ptr;
- int some_kind_of_counter;
-
- int last_vec[3];
-};
-
-typedef struct Cell** __thiscall get_cell_f(struct ChunkMap*, int x, int y);
-typedef bool __thiscall chunk_loaded_f(struct ChunkMap*, int x, int y);
-
-typedef void __thiscall remove_cell_f(struct GridWorld*, void* cell, int x, int y, bool);
-typedef struct Cell* __thiscall construct_cell_f(struct GridWorld*, int x, int y, void* material_ptr, void* memory);
-
-]])
-
---local function check_celldata_field(f, o)
--- local offset = ffi.offsetof("struct CellData", f)
--- assert(offset == o, "Expected field " .. f .. " to be at offset " .. o)
---end
---
---check_celldata_field("wang_color", 0x40)
---check_celldata_field("generates_flames", 0xa4)
---check_celldata_field("durability", 0x104)
---check_celldata_field("cold_freezes_to_material", 0x114)
---check_celldata_field("liquid_sand", 0x160)
---check_celldata_field("liquid_sprite_stain_ignited_drop_chance", 0x17c)
---check_celldata_field("gas_horizontal_speed", 0x196)
---check_celldata_field("solid_on_sleep_convert", 0x1ad)
---check_celldata_field("solid_break_to_type", 0x1d0)
---check_celldata_field("vegetation_sprite", 0x20c)
---check_celldata_field("wang_noise_type", 0x23c)
---check_celldata_field("ignore_self_reaction_warning", 0x269)
---check_celldata_field("is_just_particle_fx", 0x289)
-
----@class ChunkMap pointer type
----@class GridWorld pointer type
----@class Material pointer type
----@class Cell pointer type
-
----Access a pixel in the world.
----You can write a cell created from world_ffi.construct_cell to this pointer to add a cell into the world.
----If there's already a cell at this position, make sure to call world_ffi.remove_cell first.
----@type fun(chunk_map: ChunkMap, x: integer, y: integer): Cell
-world_ffi.get_cell = ffi.cast("get_cell_f*", world_info.get_cell)
-
----Remove a cell from the world. bool return has unknown meaning.
----@type fun(grid_world: GridWorld, cell: Cell, x: integer, y: integer): boolean
-world_ffi.remove_cell = ffi.cast("remove_cell_f*", world_info.remove_cell)
-
----Create a new cell. If memory is null pointer it will allocate its own memory.
----@type fun(grid_world: GridWorld, x: integer, y: integer, material: Material, memory: ffi.cdata*)
-world_ffi.construct_cell = ffi.cast("construct_cell_f*", world_info.construct_cell)
-
----Check if a chunk is loaded. x and y are world coordinates.
----```lua
----if world_ffi.chunk_loaded(chunk_map, x, y) then
---- local cell = world_ffi.get_cell(chunk_map, x, y)
---- ..
----```
----@type fun(chunk_map: ChunkMap, x: integer, y: integer): boolean
-world_ffi.chunk_loaded = ffi.cast("chunk_loaded_f*", world_info.chunk_loaded)
-
-world_ffi.Position = ffi.typeof("struct Position")
-world_ffi.Colour = ffi.typeof("struct Colour")
-world_ffi.AABB = ffi.typeof("struct AABB")
-world_ffi.CellType = ffi.typeof("enum CellType")
-world_ffi.Cell = ffi.typeof("struct Cell")
-world_ffi.CLiquidCell = ffi.typeof("struct CLiquidCell")
-world_ffi.ChunkMap = ffi.typeof("struct ChunkMap")
-world_ffi.GridWorld = ffi.typeof("struct GridWorld")
-world_ffi.GridWorldThreaded = ffi.typeof("struct GridWorldThreaded")
-world_ffi.WorldUpdateParams = ffi.typeof("struct WorldUpdateParams")
-world_ffi.GridWorldThreadImpl = ffi.typeof("struct GridWorldThreadImpl")
-
----Get the grid world.
----@return GridWorld
-function world_ffi.get_grid_world()
- local game_global = ffi.cast("void*", gg_ptr)
- local world_data = ffi.cast("void**", ffi.cast("char*", game_global) + 0xc)[0]
- local grid_world = ffi.cast("struct GridWorld**", ffi.cast("char*", world_data) + 0x44)[0]
- return grid_world
-end
-
-local celldata_size = 0x290
-
----Turn a standard material id into a material pointer.
----@param id integer material id that is used in the standard Noita functions
----@return Material material to internal material data (aka cell data).
----```lua
----local gold_ptr = world_ffi.get_material_ptr(CellFactory_GetType("gold"))
----```
-function world_ffi.get_material_ptr(id)
- local game_global = ffi.cast("char*", gg_ptr)
- local cell_factory = ffi.cast('char**', (game_global + 0x18))[0]
- local begin = ffi.cast('char**', cell_factory + 0x18)[0]
- local ptr = begin + celldata_size * id
- return ptr
-end
-
----Turn a material pointer into a standard material id.
----@param material Material to a material (aka cell data)
----@return integer material id that is accepted by standard Noita functions such as `CellFactory_GetUIName` and `ConvertMaterialOnAreaInstantly`.
----```lua
----local mat_id = world_ffi.get_material_id(cell.vtable.get_material(cell))
----```
----See: `world_ffi.get_material_ptr`
-function world_ffi.get_material_id(material)
- local game_global = ffi.cast("char*", gg_ptr)
- local cell_factory = ffi.cast('char**', (game_global + 0x18))[0]
- local begin = ffi.cast('char**', cell_factory + 0x18)[0]
- local offset = ffi.cast('char*', material) - begin
- return offset / celldata_size
-end
-
-return world_ffi
diff --git a/bin/lfs.dll b/bin/lfs.dll
deleted file mode 100644
index b489fbd..0000000
Binary files a/bin/lfs.dll and /dev/null differ
diff --git a/bin/libz.a b/bin/libz.a
deleted file mode 100644
index 0e5f403..0000000
Binary files a/bin/libz.a and /dev/null differ
diff --git a/bin/libzstd.dll b/bin/libzstd.dll
deleted file mode 100644
index 7400e08..0000000
Binary files a/bin/libzstd.dll and /dev/null differ
diff --git a/bin/lua-utf8.dll b/bin/lua-utf8.dll
deleted file mode 100644
index 4a1e1d6..0000000
Binary files a/bin/lua-utf8.dll and /dev/null differ
diff --git a/bin/luajit_minhook.dll b/bin/luajit_minhook.dll
deleted file mode 100644
index e99c15e..0000000
Binary files a/bin/luajit_minhook.dll and /dev/null differ
diff --git a/bin/luasteam.dll b/bin/luasteam.dll
deleted file mode 100644
index e2686b3..0000000
Binary files a/bin/luasteam.dll and /dev/null differ
diff --git a/bin/luasteam.pdb b/bin/luasteam.pdb
deleted file mode 100644
index 18d6e56..0000000
Binary files a/bin/luasteam.pdb and /dev/null differ
diff --git a/bin/spng.a b/bin/spng.a
deleted file mode 100644
index 241e322..0000000
Binary files a/bin/spng.a and /dev/null differ
diff --git a/bin/spng.dll b/bin/spng.dll
deleted file mode 100644
index 077d6d5..0000000
Binary files a/bin/spng.dll and /dev/null differ
diff --git a/data/gamemode_data/coop_test/biome_map.lua b/data/gamemode_data/coop_test/biome_map.lua
deleted file mode 100644
index fe854e7..0000000
--- a/data/gamemode_data/coop_test/biome_map.lua
+++ /dev/null
@@ -1,3 +0,0 @@
--- constants (color format is ARGB)
-dofile_once("data/scripts/lib/utilities.lua")
-BiomeMapSetSize( 70, 48 )
diff --git a/data/gamemodes.lua b/data/gamemodes.lua
deleted file mode 100644
index f0c97f3..0000000
--- a/data/gamemodes.lua
+++ /dev/null
@@ -1,49 +0,0 @@
-gamemodes = {
- --[[
- {
- id = "cooptest",
- name = "CoopTest",
- version = 1,
- settings = { -- lobby settings
- },
- default_data = { -- lobby data which is set when a lobby is created
- key = "value",
- },
- refresh = function(lobby) -- runs when lobby settings are changed.
-
- end,
- enter = function(lobby) -- Runs when the player enters a lobby
- local seed = tonumber(steam.matchmaking.getLobbyData(lobby, "seed") or 1)
- end,
- start = function(lobby) -- Runs when the gamemode starts for non spectators (start button pressed or running game entered)
-
- end,
- spectate = function(lobby) -- Runs when the gamemode starts for spectators (start button pressed or running game entered)
-
- end,
- update = function(lobby) -- Runs every frame while the game is in progress.
-
- end,
- late_update = function(lobby) -- runs at the end of every frame while the game is in progress.
-
- end,
- leave = function(lobby) -- runs when the local player leaves the lobby
-
- end,
- disconnected = function(lobby, user) -- runs when a player disconnects
-
- end,
- received = function(lobby, event, message, user)
-
- end,
- on_projectile_fired = function(lobby, shooter_id, projectile_id, rng, position_x, position_y, target_x, target_y, send_message, unknown1, multicast_index, unknown3)
-
- end,
- on_projectile_fired_post = function(lobby, shooter_id, projectile_id, rng, position_x, position_y, target_x, target_y, send_message, unknown1, multicast_index, unknown3)
-
- end,
- }
- ]]
-}
-
-return gamemodes
\ No newline at end of file
diff --git a/files/entities/input_manager.xml b/files/entities/input_manager.xml
deleted file mode 100644
index 33ae37c..0000000
--- a/files/entities/input_manager.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/files/gfx/ui/1pixel.png b/files/gfx/ui/1pixel.png
deleted file mode 100644
index d9db2f1..0000000
Binary files a/files/gfx/ui/1pixel.png and /dev/null differ
diff --git a/files/gfx/ui/9piece_invis.png b/files/gfx/ui/9piece_invis.png
deleted file mode 100644
index 55d8157..0000000
Binary files a/files/gfx/ui/9piece_invis.png and /dev/null differ
diff --git a/files/gfx/ui/9piece_white.png b/files/gfx/ui/9piece_white.png
deleted file mode 100644
index d3ef18c..0000000
Binary files a/files/gfx/ui/9piece_white.png and /dev/null differ
diff --git a/files/gfx/ui/9piece_white.xml b/files/gfx/ui/9piece_white.xml
deleted file mode 100644
index 2adf18e..0000000
--- a/files/gfx/ui/9piece_white.xml
+++ /dev/null
@@ -1,137 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/files/gfx/ui/9piece_window_bar.png b/files/gfx/ui/9piece_window_bar.png
deleted file mode 100644
index 0cb6e01..0000000
Binary files a/files/gfx/ui/9piece_window_bar.png and /dev/null differ
diff --git a/files/gfx/ui/chat.png b/files/gfx/ui/chat.png
deleted file mode 100644
index cfff8c8..0000000
Binary files a/files/gfx/ui/chat.png and /dev/null differ
diff --git a/files/gfx/ui/copy.png b/files/gfx/ui/copy.png
deleted file mode 100644
index 62a28b7..0000000
Binary files a/files/gfx/ui/copy.png and /dev/null differ
diff --git a/files/gfx/ui/crown.png b/files/gfx/ui/crown.png
deleted file mode 100644
index 631ef1a..0000000
Binary files a/files/gfx/ui/crown.png and /dev/null differ
diff --git a/files/gfx/ui/hide.png b/files/gfx/ui/hide.png
deleted file mode 100644
index 5badf84..0000000
Binary files a/files/gfx/ui/hide.png and /dev/null differ
diff --git a/files/gfx/ui/input_cursor.png b/files/gfx/ui/input_cursor.png
deleted file mode 100644
index 337deec..0000000
Binary files a/files/gfx/ui/input_cursor.png and /dev/null differ
diff --git a/files/gfx/ui/input_cursor_invisible.png b/files/gfx/ui/input_cursor_invisible.png
deleted file mode 100644
index 5fd25a2..0000000
Binary files a/files/gfx/ui/input_cursor_invisible.png and /dev/null differ
diff --git a/files/gfx/ui/invis.png b/files/gfx/ui/invis.png
deleted file mode 100644
index 4d4b5a4..0000000
Binary files a/files/gfx/ui/invis.png and /dev/null differ
diff --git a/files/gfx/ui/marker/bottom.png b/files/gfx/ui/marker/bottom.png
deleted file mode 100644
index 35608e0..0000000
Binary files a/files/gfx/ui/marker/bottom.png and /dev/null differ
diff --git a/files/gfx/ui/marker/bottomleft.png b/files/gfx/ui/marker/bottomleft.png
deleted file mode 100644
index 7dc396b..0000000
Binary files a/files/gfx/ui/marker/bottomleft.png and /dev/null differ
diff --git a/files/gfx/ui/marker/bottomright.png b/files/gfx/ui/marker/bottomright.png
deleted file mode 100644
index 3ba8cf4..0000000
Binary files a/files/gfx/ui/marker/bottomright.png and /dev/null differ
diff --git a/files/gfx/ui/marker/left.png b/files/gfx/ui/marker/left.png
deleted file mode 100644
index 4609323..0000000
Binary files a/files/gfx/ui/marker/left.png and /dev/null differ
diff --git a/files/gfx/ui/marker/right.png b/files/gfx/ui/marker/right.png
deleted file mode 100644
index d0415dc..0000000
Binary files a/files/gfx/ui/marker/right.png and /dev/null differ
diff --git a/files/gfx/ui/marker/top.png b/files/gfx/ui/marker/top.png
deleted file mode 100644
index cdba64e..0000000
Binary files a/files/gfx/ui/marker/top.png and /dev/null differ
diff --git a/files/gfx/ui/marker/topleft.png b/files/gfx/ui/marker/topleft.png
deleted file mode 100644
index 65ac096..0000000
Binary files a/files/gfx/ui/marker/topleft.png and /dev/null differ
diff --git a/files/gfx/ui/marker/topright.png b/files/gfx/ui/marker/topright.png
deleted file mode 100644
index e6fe43c..0000000
Binary files a/files/gfx/ui/marker/topright.png and /dev/null differ
diff --git a/files/gfx/ui/menu.png b/files/gfx/ui/menu.png
deleted file mode 100644
index ae7ef04..0000000
Binary files a/files/gfx/ui/menu.png and /dev/null differ
diff --git a/files/gfx/ui/minimize.png b/files/gfx/ui/minimize.png
deleted file mode 100644
index 3247758..0000000
Binary files a/files/gfx/ui/minimize.png and /dev/null differ
diff --git a/files/gfx/ui/no_avatar.png b/files/gfx/ui/no_avatar.png
deleted file mode 100644
index 59cff2d..0000000
Binary files a/files/gfx/ui/no_avatar.png and /dev/null differ
diff --git a/files/gfx/ui/notification.png b/files/gfx/ui/notification.png
deleted file mode 100644
index a2b959f..0000000
Binary files a/files/gfx/ui/notification.png and /dev/null differ
diff --git a/files/gfx/ui/red.png b/files/gfx/ui/red.png
deleted file mode 100644
index 428a191..0000000
Binary files a/files/gfx/ui/red.png and /dev/null differ
diff --git a/files/gfx/ui/send.png b/files/gfx/ui/send.png
deleted file mode 100644
index bd283e3..0000000
Binary files a/files/gfx/ui/send.png and /dev/null differ
diff --git a/files/gfx/ui/send2.png b/files/gfx/ui/send2.png
deleted file mode 100644
index 8cae924..0000000
Binary files a/files/gfx/ui/send2.png and /dev/null differ
diff --git a/files/gfx/ui/show.png b/files/gfx/ui/show.png
deleted file mode 100644
index e7d888a..0000000
Binary files a/files/gfx/ui/show.png and /dev/null differ
diff --git a/files/gfx/ui/spectator.png b/files/gfx/ui/spectator.png
deleted file mode 100644
index 472935d..0000000
Binary files a/files/gfx/ui/spectator.png and /dev/null differ
diff --git a/files/gfx/ui/spectator2.png b/files/gfx/ui/spectator2.png
deleted file mode 100644
index 8dbfd57..0000000
Binary files a/files/gfx/ui/spectator2.png and /dev/null differ
diff --git a/files/scripts/chat_ui.lua b/files/scripts/chat_ui.lua
deleted file mode 100644
index 9b5637b..0000000
--- a/files/scripts/chat_ui.lua
+++ /dev/null
@@ -1,459 +0,0 @@
-dofile_once("data/scripts/lib/utilities.lua")
-local text_input = dofile("mods/evaisa.mp/files/scripts/text_input.lua")
-
-pretty = require("pretty_print")
-
-chat_gui = chat_gui or GuiCreate()
-
-GuiStartFrame(chat_gui)
-
-if (IsPaused()) then
- return
-end
-
-
-
-GuiOptionsAdd(chat_gui, GUI_OPTION.NoPositionTween)
-
-local screen_width, screen_height = GuiGetScreenDimensions(chat_gui);
-
-chat_open = chat_open or false
-
-
-initial_chat_log = {}
-local reverse_chat_direction = ModSettingGet("evaisa.mp.flip_chat_direction")
-
-for i = 1, 20 do
- table.insert(initial_chat_log, " ")
-end
-
-
-chat_log = chat_log or initial_chat_log
-
-new_chat_message = new_chat_message or false
-was_new_chat_message = was_new_chat_message or false
-was_input_hovered = was_input_hovered or false
-
-
-if (#chat_log > 50) then
- -- remove first item
- if (not reverse_chat_direction) then
- table.remove(chat_log, 1)
- else
- table.remove(chat_log, #chat_log)
- end
-end
-
-
-local reverse_chat_direction = ModSettingGet("evaisa.mp.flip_chat_direction")
-
-
-local function split_message(msg)
- local words = {}
- local index = 1
- for word in string.gmatch(msg, "%S+") do
-
- -- split word into chunks of 200 pixels or less
-
- local width, height = GuiGetTextDimensions(chat_gui, word)
-
- if (width > 200) then
- local chunks = {}
- local chunk = ""
- for i = 1, #word do
- local char = word:sub(i, i)
- local char_width, char_height = GuiGetTextDimensions(chat_gui, chunk .. char)
- if (char_width <= 200) then
- chunk = chunk .. char
- else
- table.insert(chunks, chunk)
- chunk = char
- end
- end
- table.insert(chunks, chunk)
-
- for i, chunk in ipairs(chunks) do
- table.insert(words, chunk)
- end
- else
- table.insert(words, word)
- end
-
-
- index = index + 1
- end
-
- local chunks = {}
- local chunk = ""
- for i, word in ipairs(words) do
- local width, height = GuiGetTextDimensions(chat_gui, chunk .. " " .. word)
-
- --print("width: " .. tostring(width))
-
- if width <= 200 then
- if chunk == "" then
- chunk = word
- else
- chunk = chunk .. " " .. word
- end
- else
- table.insert(chunks, chunk)
- chunk = word
- end
- end
- table.insert(chunks, chunk)
-
- return chunks
-end
-
-function handleChatMessage(data)
- --[[
- example data:
-
- {
- lobbyID = 9223372036854775807,
- userID = 76361198523269435,
- type = 1,
- chatID = 1,
- fromOwner = true,
- message = "chat;evaisa: hello there how are you today?; I am great!; Yeah!"
- }
- ]]
-
- local message = data.message
- local split_data = {}
- for token in string.gmatch(message, "[^;]+") do
- table.insert(split_data, token)
- end
-
- if (#split_data > 1 and split_data[1] == "chat") then
- local buffer = {}
- for i = 1, #split_data do
- if (i ~= 1) then
-
- local msg = steam_utils.getTranslatedPersonaName(data.userID, data.userID == steam_utils.getSteamID()) .. ": " .. split_data[i]
-
- local chunks = split_message(msg)
-
- for h = 1, #chunks do
- if (not reverse_chat_direction) then
- local was_found = false
- for j = 1, #chat_log do
- if (chat_log[j] == " ") then
- chat_log[j] = chunks[h]
- new_chat_message = true
- was_found = true
- break
- end
- end
- if (not was_found) then
- table.insert(chat_log, chunks[h])
- new_chat_message = true
- end
- else
- local empty_index = nil
- for j = 1, #chat_log do
- if (chat_log[j] == " ") then
- empty_index = j
- break
- end
- end
- if (empty_index ~= nil) then
- table.remove(chat_log, empty_index)
- end
-
- table.insert(buffer, chunks[h])
- new_chat_message = true
- end
- end
-
- end
- end
- if(reverse_chat_direction)then
- for i = #buffer, 1, -1 do
- print("inserting "..buffer[i].." at 1")
- table.insert(chat_log, 1, buffer[i])
- end
- end
- end
-end
-
-function ChatPrint(text)
-
- local buffer = {}
- local chunks = split_message(text)
-
- for h = 1, #chunks do
- if (not reverse_chat_direction) then
- local was_found = false
- for j = 1, #chat_log do
- if (chat_log[j] == " ") then
- chat_log[j] = chunks[h]
- new_chat_message = true
- was_found = true
- break
- end
- end
- if (not was_found) then
- table.insert(chat_log, chunks[h])
- new_chat_message = true
- end
- else
- local empty_index = nil
- for j = 1, #chat_log do
- if (chat_log[j] == " ") then
- empty_index = j
- break
- end
- end
- if (empty_index ~= nil) then
- table.remove(chat_log, empty_index)
- end
-
- table.insert(buffer, chunks[h])
- new_chat_message = true
- end
- end
-
- if(reverse_chat_direction)then
- for i = #buffer, 1, -1 do
- print("inserting "..buffer[i].." at 1")
- table.insert(chat_log, 1, buffer[i])
- end
- end
-end
-
-local GetPlayer = function()
- local player = EntityGetWithTag("player_unit")
-
- if (player == nil) then
- return
- end
-
- return player[1]
-end
-
-local LockPlayer = function()
- local player = GetPlayer()
- if (player == nil) then
- return
- end
- local controls = EntityGetFirstComponentIncludingDisabled(player, "ControlsComponent")
- if (controls ~= nil) then
- GameAddFlagRun("player_locked_chat")
- ComponentSetValue2(controls, "enabled", false)
- end
-end
-
-local UnlockPlayer = function()
- if(not GameHasFlagRun("player_locked_chat"))then
- return
- end
-
- local player = GetPlayer()
- if (player == nil) then
- return
- end
-
- if (not GameHasFlagRun("player_locked")) then
- local controls = EntityGetFirstComponentIncludingDisabled(player, "ControlsComponent")
- if (controls ~= nil) then
- GameRemoveFlagRun("player_locked_chat")
- ComponentSetValue2(controls, "enabled", true)
- end
- end
-end
-
-chat_opened_with_bind = chat_opened_with_bind or false
-
-if (lobby_code ~= nil) then
- --local pressed, shift_held = hack_update_keys()
-
- local hit_enter = false
-
- local toggled_chat = false
- --for _, key in ipairs(pressed) do
- if bindings:IsJustDown("chat_submit") or bindings:IsJustDown("chat_submit2") then
- hit_enter = true
- toggled_chat = true
- end
-
-
- if (bindings:IsJustDown("chat_open_kb") and not GameHasFlagRun("chat_bind_disabled")) then
- if (chat_open == false) then
- chat_open = true
- chat_opened_with_bind = true
- toggled_chat = true
- elseif (chat_input ~= nil and not chat_input.focus) then
- chat_open = false
- chat_opened_with_bind = false
- toggled_chat = true
- end
- end
-
- --end
-
- --[[if (not chat_open) then
- GuiOptionsAdd(chat_gui, GUI_OPTION.NonInteractive)
- end]]
-
-
- if (chat_open) then
- new_chat_message = false
-
- local window_width = 200
- local window_height = 100
-
- local window_text = GameTextGetTranslatedOrNot("$mp_chat")
- --GuiLayoutBeginVertical(gui, 0, 0, true, 0, 0)
- DrawWindow(chat_gui, -7000, 4, screen_height - (window_height + 26), window_width + 8,
- window_height, window_text, false, function()
- GuiLayoutBeginVertical(chat_gui, 0, 0, true, 0, 0)
- for k, v in ipairs(chat_log) do
- GuiText(chat_gui, 2, 0, v)
- end
- GuiLayoutEnd(chat_gui)
- end, function()
- chat_open = false;
- end, "chat_window")
- GuiLayoutBeginHorizontal(chat_gui, 0, 0, true, 0, 0)
-
- chat_input = chat_input or text_input.create(chat_gui, 2, screen_height - 16, window_width + 2, "", 100, nil, ";", 0)
-
- input_text = input_text or ""
-
- chat_input.text = input_text
- chat_input:transform(2, screen_height - 16, window_width + 2)
- if(not toggled_chat)then
- chat_input:update()
- end
- chat_input:draw()
- if(chat_opened_with_bind)then
- chat_opened_with_bind = false
- chat_input.focus = true
- end
-
-
- input_text = chat_input.text
-
-
- --[[local input_text = GuiTextInput(chat_gui, NewID("Chatting"), 2, screen_height - 16, initial_text,
- window_width + 1, 52,
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_=+[]{}\\|:'\",./<>?`~ ")]]
-
- --local _, _, input_hovered = GuiGetPreviousWidgetInfo(chat_gui)
-
- --[[
- if (initial_text ~= input_text) then
- initial_text = input_text
- end
- ]]
-
- --input_text = ""
- input_hovered = chat_input.focus
-
- if (input_hovered) then
- if (not GameHasFlagRun("chat_input_hovered")) then
- GameAddFlagRun("chat_input_hovered")
- end
- else
- if (GameHasFlagRun("chat_input_hovered")) then
- GameRemoveFlagRun("chat_input_hovered")
- end
- end
-
- if (not was_input_hovered and input_hovered) then
- LockPlayer()
- elseif (not input_hovered) then
- UnlockPlayer()
- end
-
- local sendMessage = function()
- chat_input.cursor_pos = 0
- if (utf8.len(input_text) > 0 and not input_text:match("^%s*$")) then
- -- check if message begins with / or !
- local command = input_text:sub(1, 1)
-
- if (command == "/" or command == "!") then
- -- get command name, get arguments as table, remove ! or / from command name
- local command_name, args = input_text:match("([%w_]+)%s*(.*)")
-
- if(command_name == nil)then
- local username = steamutils.getTranslatedPersonaName(steam_utils.getSteamID())
- local message = username .. ": " .. input_text
-
- local message_final = "chat;" .. message
- steam.matchmaking.sendLobbyChatMsg(lobby_code, message_final)
- else
-
- mp_log:print("command received: " .. command_name)
-
- if(lobby_code ~= nil)then
- local active_mode = FindGamemode(steam.matchmaking.getLobbyData(lobby_code, "gamemode"))
- if(active_mode ~= nil and active_mode.commands and active_mode.commands[command_name])then
- active_mode.commands[command_name](command_name, args)
- elseif(active_mode ~= nil )then
- --local username = steamutils.getTranslatedPersonaName(steam_utils.getSteamID())
- local message = input_text
-
- local message_final = "chat;" .. message
- steam.matchmaking.sendLobbyChatMsg(lobby_code, message_final)
-
- end
- end
- end
- else
-
- --local username = steamutils.getTranslatedPersonaName(steam_utils.getSteamID())
- local message = input_text
-
- local message_final = "chat;" .. message
- steam.matchmaking.sendLobbyChatMsg(lobby_code, message_final)
- end
- end
- input_text = ""
- end
-
- if (hit_enter) then
- sendMessage()
- end
-
- if (GuiImageButton(chat_gui, NewID("Chatting"), 3, screen_height - 16, "", "mods/evaisa.mp/files/gfx/ui/send2.png")) then
- sendMessage()
- end
-
- GuiLayoutEnd(chat_gui)
-
- --GuiLayoutEnd(gui)
-
- was_input_hovered = input_hovered
- end
-
- GuiZSetForNextWidget(chat_gui, 0)
-
- if (GameGetIsGamepadConnected()) then
- GuiOptionsAddForNextWidget(chat_gui, GUI_OPTION.NonInteractive)
- end
- if (GuiImageButton(chat_gui, NewID("MenuButton"), screen_width - 40, screen_height - 20, "", "mods/evaisa.mp/files/gfx/ui/chat.png")) then
- chat_open = not chat_open
- chat_opened_with_bind = false
- GamePlaySound("data/audio/Desktop/ui.bank", "ui/button_click", 0, 0)
- end
-
- if (new_chat_message) then
- --GamePrint("whar")
- if (not chat_open) then
- if (not was_new_chat_message) then
- GamePlaySound("mods/evaisa.mp/online.bank", "message/received", 0, 0)
- --GamePrint("Playing notification noise")
- end
-
- GuiZSetForNextWidget(chat_gui, -1)
- GuiImage(chat_gui, NewID("Notification"), screen_width - 42, screen_height - 22, "mods/evaisa.mp/files/gfx/ui/notification.png", 1, 1, 1)
- end
- end
-
- was_new_chat_message = new_chat_message
-else
- chat_log = initial_chat_log
-end
diff --git a/files/scripts/debugging.lua b/files/scripts/debugging.lua
deleted file mode 100644
index f17a45b..0000000
--- a/files/scripts/debugging.lua
+++ /dev/null
@@ -1,46 +0,0 @@
-mp_log:print("debugging.lua loaded.")
-
---[[
-local OldModSettingSet = ModSettingSet
-ModSettingSet = function(a, b)
- local source = debug.getinfo(2).short_src
- local line = debug.getinfo(2).currentline
-
- if(a == nil or b == nil)then
- mp_log:print("ModSettingSet: " .. source .. ":" .. line)
- end
- -- pcall old function
- if(pcall(OldModSettingSet, a, b) == false)then
- mp_log:print("ModSettingSet: " .. source .. ":" .. line .. " failed")
- end
-end
-
-local oldGameKillInventoryItem = GameKillInventoryItem
-
-GameKillInventoryItem = function(a, b)
- local source = debug.getinfo(2).short_src
- local line = debug.getinfo(2).currentline
-
- if(a == nil or not EntityGetIsAlive(a) or b == nil or not EntityGetIsAlive(b))then
- mp_log:print("GameKillInventoryItem: " .. source .. ":" .. line)
- end
-
- -- pcall old function
- if(pcall(oldGameKillInventoryItem, a, b) == false)then
- mp_log:print("GameKillInventoryItem: " .. source .. ":" .. line .. " failed")
- end
-end
-
-local oldGuiImage = GuiImage
-
-GuiImage = function(...)
- local source = debug.getinfo(2).short_src
- local line = debug.getinfo(2).currentline
-
- mp_log:print("GuiImage: " .. source .. ":" .. line)
-
- -- pcall old function
- if(pcall(oldGuiImage, ...) == false)then
- mp_log:print("GuiImage: " .. source .. ":" .. line .. " failed")
- end
-end]]
\ No newline at end of file
diff --git a/files/scripts/game_functions.lua b/files/scripts/game_functions.lua
deleted file mode 100644
index 9c1bc7a..0000000
--- a/files/scripts/game_functions.lua
+++ /dev/null
@@ -1,246 +0,0 @@
-dofile("data/scripts/lib/utilities.lua")
---ffi = require("ffi")
---
---ffi.cdef([[
---typedef struct Entity Entity;
---
---typedef Entity* __thiscall EntityGet_f(int EntityManager, int entity_nr);
---typedef void __fastcall SetActiveHeldEntity_f(Entity* entity, Entity* item_entity, bool unknown, bool make_noise);
---]])
---
---local EntityManager = ffi.cast("int*", 0x00ff55dc)[0]
-----
---local EntityGet_cfunc = ffi.cast("EntityGet_f*", 0x00527660)
---local SetActiveHeldEntity_cfunc = ffi.cast("SetActiveHeldEntity_f*", 0x009ec390)
-
-local parallax_images = {
-
-}
-
-
---function EntityGet(entity_nr)
--- return EntityGet_cfunc(EntityManager, entity_nr)
---end
-local ffi = require("ffi")
-
-game_funcs = {
- GetUnixTimestamp = function()
- return steam.utils.getUnixTimeStamp()
- end,
- GetUnixTimeElapsed = function(time1, time2)
- return steam.utils.getUnixTimeElapsed(time1, time2)
- end,
- UintToString = function(uint)
- return steam.utils.uintToString(uint)
- end,
- StringToUint = function(str)
- return steam.utils.stringToUint(str)
- end,
- --[[LoadRegion = function(start_x, start_y, width, height)
- local region = ffi.new("world_region", {start_x, start_y, width, height})
- --GamePrint("Loading region: "..tostring(start_x)..","..tostring(start_y)..","..tostring(width)..","..tostring(height))
- LoadRegion_cfunc(region)
- end,]]
- SetPlayerEntity = function(entity_id)
- --[[local entity = EntityGet(entity_id)
- local vector = ffi.cast("void****", 0x00ff5604)[0][22]
- vector[0] = entity]]
- np.SetPlayerEntity(entity_id)
- end,
- ExposeImage = function(filename, width, height)
- local id, w, h = ModImageMakeEditable( filename, width or 0, height or 0 )
- return {
- id = id,
- width = w,
- height = h
- }
- end,
- ReplaceImage = function (file1, file2)
- local id, w, h = ModImageIdFromFilename( file1 )
- if id == 0 then
- return false
- end
- local id2, w2, h2 = ModImageIdFromFilename( file2, w, h )
- if id2 == 0 then
- return false
- end
-
- for i = 0, w - 1 do
- for j = 0, h - 1 do
- local color = ModImageGetPixel( id2, i, j )
- ModImageSetPixel( id, i, j, color )
- end
- end
- end,
- RefreshParallax = function(target, new)
-
-
- -- refresh the parallax background
- local load_outdoors = ffi.cast("void (__fastcall*)(void*)", 0x0087c970)
- local ptr = ffi.cast("void**", ffi.cast("char**", 0x0120925c)[0] + 0x4c)[0]
- load_outdoors(ptr)
- end,
- SetActiveHeldEntity = function(entity_id, item_id, unknown, make_noise)
- --SetActiveHeldEntity_cfunc(EntityGet(entity_id), EntityGet(item_id), unknown, make_noise)
- np.SetActiveHeldEntity(entity_id, item_id, unknown, make_noise)
- end,
- ID2Color = function(str)
- str = tostring(str)
- -- get the bytes of each character counted together
- local sum = 0
- for i = 1, str:len() do
- sum = sum + str:byte(i)
- end
- -- seed random number generator with it
- local random = rng.new(sum)
- -- return a random color
-
- --print("sum: "..tostring(sum))
-
- if (sum == 897) then
- return { r = 235, g = 174, b = 186 }
- end
-
- return { r = random.range(130, 255), g = random.range(130, 255), b = random.range(130, 255) }
- end,
- RenderOffScreenMarkers = function(players)
- marker_gui = marker_gui or GuiCreate()
- GuiStartFrame(marker_gui)
-
- GuiOptionsAdd(marker_gui, GUI_OPTION.NonInteractive)
- local id = 2041242
- local function new_id()
- id = id + 1
- return id
- end
-
- local screen_width, screen_height = GuiGetScreenDimensions(marker_gui)
- local screen_center_x, screen_center_y = screen_width / 2, screen_height / 2
- local camera_x, camera_y = GameGetCameraPos()
- local bounds_x, bounds_y, bounds_w, bounds_h = GameGetCameraBounds()
- -- loop through each player
- for id, player in pairs(players) do
- if (player and EntityGetIsAlive(player)) then
- local x, y = EntityGetTransform(player)
- -- direction from camera to player
- local dx, dy = x - camera_x, y - camera_y
-
-
- -- check if player is outside camera bounds
- if (x < bounds_x or y < bounds_y or x > bounds_x + bounds_w or y > bounds_y + bounds_h) then
- -- normalize that shit
- local length = math.sqrt(dx * dx + dy * dy)
- dx, dy = dx / length, dy / length
-
- -- draw a marker on the edge of the screen in the direction of the player
- -- march from screen center in direction until we are off screen
- local marker_x, marker_y = screen_center_x, screen_center_y
- while (marker_x > 0 and marker_x < screen_width and marker_y > 0 and marker_y < screen_height) do
- marker_x = marker_x + dx
- marker_y = marker_y + dy
- end
-
-
- -- subtract 10 so that we are away from the edge a bit
- marker_x = marker_x - 10 * dx
- marker_y = marker_y - 10 * dy
-
-
- local markers = {
- up = "mods/evaisa.mp/files/gfx/ui/marker/top.png",
- down = "mods/evaisa.mp/files/gfx/ui/marker/bottom.png",
- left = "mods/evaisa.mp/files/gfx/ui/marker/left.png",
- right = "mods/evaisa.mp/files/gfx/ui/marker/right.png",
- topleft = "mods/evaisa.mp/files/gfx/ui/marker/topleft.png",
- topright = "mods/evaisa.mp/files/gfx/ui/marker/topright.png",
- bottomleft = "mods/evaisa.mp/files/gfx/ui/marker/bottomleft.png",
- bottomright = "mods/evaisa.mp/files/gfx/ui/marker/bottomright.png",
- }
-
- -- figure out which marker to draw based on the direction
-
- local marker_image = markers.up
- if (marker_x < screen_center_x - (screen_center_x / 2) and marker_y < screen_center_y - (screen_center_y / 2)) then
- marker_image = markers.topleft
- elseif (marker_x > screen_center_x + (screen_center_x / 2) and marker_y < screen_center_y - (screen_center_y / 2)) then
- marker_image = markers.topright
- elseif (marker_x < screen_center_x - (screen_center_x / 2) and marker_y > screen_center_y + (screen_center_y / 2)) then
- marker_image = markers.bottomleft
- elseif (marker_x > screen_center_x + (screen_center_x / 2) and marker_y > screen_center_y + (screen_center_y / 2)) then
- marker_image = markers.bottomright
- elseif (marker_x < screen_center_x - (screen_center_x / 2)) then
- marker_image = markers.left
- elseif (marker_x > screen_center_x + (screen_center_x / 2)) then
- marker_image = markers.right
- elseif (marker_y < screen_center_y - (screen_center_y / 2)) then
- marker_image = markers.up
- elseif (marker_y > screen_center_y + (screen_center_y / 2)) then
- marker_image = markers.down
- end
-
-
-
- --marker_x, marker_y = marker_x / 2, marker_y / 2
-
- marker_x = marker_x - 2.5
- marker_y = marker_y - 2.5
-
- -- somehow convert id to a color
-
-
- local color = game_funcs.ID2Color(id)
- if (color == nil) then
- color = { r = 255, g = 255, b = 255 }
- end
- local r, g, b = color.r, color.g, color.b
- local a = 1
- GuiColorSetForNextWidget(marker_gui, r / 255, g / 255, b / 255, a)
- GuiZSetForNextWidget(marker_gui, -100000)
-
- GuiImage(marker_gui, new_id(), marker_x, marker_y, marker_image, 1, 1, 1)
- --GuiText(gui, marker_x / 2, marker_y / 2, "o")
- end
- end
- end
- end,
- RenderAboveHeadMarkers = function(players, offset_x, offset_y)
- marker_gui2 = marker_gui2 or GuiCreate()
- GuiStartFrame(marker_gui2)
- GuiOptionsAdd(marker_gui2, GUI_OPTION.NonInteractive)
-
- local id = 2041242
- local function new_id()
- id = id + 1
- return id
- end
-
- -- loop through each player
- for id, player in pairs(players) do
- if (player and EntityGetIsAlive(player)) then
- local x, y = EntityGetTransform(player)
- local screen_x, screen_y = WorldToScreenPos(marker_gui2, x, y)
-
- -- draw a marker above their head
- -- "mods/evaisa.mp/files/gfx/ui/marker/bottom.png"
- local marker_image = "mods/evaisa.mp/files/gfx/ui/marker/bottom.png"
- local marker_x = screen_x - 2.5 - offset_x
- local marker_y = screen_y - offset_y
-
- -- somehow convert id to a color
- local color = game_funcs.ID2Color(id)
-
- if (color == nil) then
- color = { r = 255, g = 255, b = 255 }
- end
-
- local r, g, b = color.r, color.g, color.b
- local a = 1
-
- GuiColorSetForNextWidget(marker_gui2, r / 255, g / 255, b / 255, a)
- GuiImage(marker_gui2, new_id(), marker_x, marker_y, marker_image, 1, 1, 1)
- end
- end
- end,
-}
-
-return game_funcs
diff --git a/files/scripts/gui_utils.lua b/files/scripts/gui_utils.lua
deleted file mode 100644
index 3d67073..0000000
--- a/files/scripts/gui_utils.lua
+++ /dev/null
@@ -1,817 +0,0 @@
-dofile_once("data/scripts/lib/utilities.lua")
---[[
-local generated_id = 1000
-function NewID(identifier, force)
- generated_id = generated_id + 1
- if(identifier ~= nil)then
- generated_id = generated_id + tostring(string.byte(identifier))
- if(force)then
- generated_id = 1000 + tonumber(tostring(string.byte(identifier)))
- end
- end
- return generated_id
-end]]
-
-local start_values = {}
-local reserved_id_space = 3000
-local next_start_value = reserved_id_space
-
-local function get_start_value(identifier)
- if not start_values[identifier] then
- start_values[identifier] = next_start_value
- next_start_value = next_start_value + reserved_id_space
- end
-
- return start_values[identifier]
-end
-
-local id_pool = {}
-
-function NewID(identifier, force)
- identifier = identifier or "default"
-
- if not id_pool[identifier] then
- id_pool[identifier] = start_values[identifier] or get_start_value(identifier)
- end
-
- id_pool[identifier] = id_pool[identifier] + 1
-
- if force then
- id_pool[identifier] = start_values[identifier] or get_start_value(identifier)
- end
-
- return id_pool[identifier]
-end
-
-function ResetIDs()
- id_count = 1
- id_pool = {}
-end
-
-local old_window_stack = {}
-local window_stack = {}
-last_hovered_window = last_hovered_window or nil
-function ResetWindowStack()
- --print("ResetWindowStack")
- for k, window in pairs(old_window_stack) do
- if(window_stack[k] == nil)then
- old_window_stack[k] = nil
- end
- end
-
- for k, window in pairs(window_stack) do
- old_window_stack[k] = window
- end
-
- window_stack = {}
-end
-
-
-function WorldToScreenPos(gui_input, x, y)
- local ww, wh = MagicNumbersGetValue("VIRTUAL_RESOLUTION_X"), MagicNumbersGetValue("VIRTUAL_RESOLUTION_Y")
- local sw, sh = GuiGetScreenDimensions(gui_input)
- local _, _, cam_w, cam_h = GameGetCameraBounds()
- local cx, cy = GameGetCameraPos()
- cx = cx - cam_w / 2
- cy = cy - cam_h / 2
- x, y = x - cx, y - cy
- x, y = x / ww, y / wh
- x, y = x * sw, y * sh
- return x, y
-end
-
-temp_gui = temp_gui or GuiCreate()
-
-function GetGuiMousePosition()
- local players = get_players()
- if(players ~= nil)then
- player = players[1]
- if(player ~= nil)then
- local controls_component = EntityGetFirstComponentIncludingDisabled(player, "ControlsComponent")
-
- GuiStartFrame(temp_gui)
- local screen_width, screen_height = GuiGetScreenDimensions(temp_gui)
- local input_x, input_y = 100, 100;
-
- local b_width = tonumber(game_config.get("internal_size_w")) or 1280
- local b_height = tonumber(game_config.get("internal_size_h")) or 720
-
- local mx, my = mouse_raw_x * screen_width / b_width, mouse_raw_y * screen_height / b_height
- --local mx, my = ComponentGetValue2(controls_component, "mMousePositionRaw")
- return mx, my
- end
- end
- return 0, 0
-end
-
-function ParseStringColors(str)
- -- Define pattern: # followed by [digits,digits,digits]
- local pattern = "#%[(%d+),(%d+),(%d+)%]"
-
- -- Initialize the output table
- local output = {}
-
- -- Initialize the last match position and color
- local last_pos, last_color = 1, nil
-
- -- Iterate through the input string, matching the pattern
- for r, g, b, pos in string.gmatch(str, "()" .. pattern .. "()") do
- -- Extract the text before the color marker or between the pre-existing color markers
- local text = string.sub(str, last_pos, pos - #pattern - 1)
-
- -- Add an entry to the output table
- table.insert(output, {text = text, color = last_color})
-
- -- Update the last match position and color
- last_pos = pos
- last_color = {tonumber(r), tonumber(g), tonumber(b)}
- end
-
- -- Add the remaining text after the last color marker
- local remaining_text = string.sub(str, last_pos)
- if remaining_text ~= "" then
- table.insert(output, {text = remaining_text, color = last_color})
- end
-
- return output
-end
-
-
-function GetMouseDown()
- local players = get_players()
- if(players ~= nil)then
- player = players[1]
- if(player ~= nil)then
- local controls_component = EntityGetFirstComponentIncludingDisabled(player, "ControlsComponent")
- local down = ComponentGetValue2(controls_component, "mButtonDownFire")
- return down
- end
- end
- return false
-end
-
-function GetCenterPosition(x, y, w, h)
- return x - (w/2), y - (h/2)
-end
-
-buttonHovers = buttonHovers or {}
-
-function CustomButton(gui, identifier, x, y, z, scale, image, r, g, b, alpha)
-
- local width, height = GuiGetImageDimensions(gui, image, scale)
- GuiZSetForNextWidget(gui, z - 2)
- GuiImage(gui, NewID(identifier), x, y, image, 0.1, scale)
- local clicked, right_clicked, hovered, _x, _y, _width, _height, draw_x, draw_y, draw_width, draw_height = GuiGetPreviousWidgetInfo(gui)
- local button_id = NewID(identifier)
- if hovered then
-
- if(buttonHovers[button_id] == nil)then
- GamePlaySound("data/audio/Desktop/ui.bank", "ui/button_select", 0, 0)
- buttonHovers[button_id] = true
- end
-
-
-
- -- render GuiImage on top
- GuiColorSetForNextWidget(gui, 255/255, 255/255, 178/255, 1)
- GuiImage(gui, NewID(identifier), -width, y, image, 1, scale)
- else
- buttonHovers[button_id] = nil
- -- render GuiImage on top
- GuiColorSetForNextWidget(gui, r, g, b, alpha)
- GuiImage(gui, NewID(identifier), -width, y, image, alpha, scale)
- end
- if(clicked)then
- GamePlaySound("data/audio/Desktop/ui.bank", "ui/button_click", 0, 0)
-
- end
- return clicked
-end
-
---[[
-function DrawWindow(gui, z_index, x, y, w, h, title, centered, callback, close_callback, identifier, margin_x, margin_y, alignment, no_close_button)
-
- margin_x = margin_x or 2
- margin_y = margin_y or 2
-
- w = w + (margin_x * 2)
- h = h + (margin_y * 2)
-
-
-
- local last_render_width = w
- local had_scroll_bar = false
-
- if(old_window_stack[identifier] ~= nil)then
- last_render_width = old_window_stack[identifier].render_w
- had_scroll_bar = old_window_stack[identifier].had_scroll_bar
- end
-
-
- if(centered)then
-
-
- x, y = GetCenterPosition(x, y, w, h)
- end
-
- if(alignment and not had_scroll_bar)then
- x = x + 8
- end
-
-
- local bar_y = y
-
-
- GuiBeginAutoBox( gui )
- GuiZSet( gui, z_index - 1 )
- GuiColorSetForNextWidget( gui, 0, 0, 0, 0.3 )
- if(type(title) == "function")then
- GuiLayoutBeginHorizontal( gui,x, bar_y, true, 0, 0)
- GuiText(gui, 0, 0, " ")
- title()
- GuiLayoutEnd( gui )
-
- else
- GuiText(gui, x, bar_y, " "..title)
- end
-
-
- if(close_callback ~= nil and not no_close_button)then
- GuiLayoutBeginLayer( gui )
- GuiLayoutBeginHorizontal( gui, 0, 0, true, 0, 0)
- if(CustomButton(gui, "sagsadshds", x + (last_render_width - 10), bar_y + 1, z_index - 600, 1, "mods/evaisa.mp/files/gfx/ui/minimize.png", 0, 0, 0, 0.5))then
- close_callback()
- end
- GuiLayoutEnd( gui )
- GuiLayoutEndLayer( gui )
- end
-
- GuiZSetForNextWidget( gui, z_index )
- GuiOptionsAddForNextWidget(gui, GUI_OPTION.IsExtraDraggable)
- GuiEndAutoBoxNinePiece( gui, 0, last_render_width, 8, false, 0, "mods/evaisa.mp/files/gfx/ui/9piece_window_bar.png", "mods/evaisa.mp/files/gfx/ui/9piece_window_bar.png")
-
- local clicked, right_clicked, hovered, bar_x, bar_y, bar_w, bar_h = GuiGetPreviousWidgetInfo( gui )
-
- --GuiOptionsAddForNextWidget(gui, GUI_OPTION.IgnoreContainer)
-
- local mouse_x, mouse_y = input:GetUIMousePos(gui)
-
- local disable_scroll = true
-
- if (input:WasKeyPressed("f1")) then
- global_scroll_toggle = global_scroll_toggle or false
- global_scroll_toggle = not global_scroll_toggle
-
- end
-
-
- -- only do this if we are the upmost window hovered
- -- check old_window_stack for this
-
- local hovered_windows = {}
- local total_windows = 0
- for k, v in pairs(old_window_stack)do
- if(mouse_x > v.x and mouse_x < v.x + v.render_w and mouse_y > v.y and mouse_y < v.y + v.h)then
- table.insert(hovered_windows, v)
- end
- total_windows = total_windows + 1
- end
-
- if(last_hovered_window == identifier)then
- disable_scroll = false
- else
- if(#hovered_windows > 0)then
-
- -- check z index, lower z is higher up
- local highest_z = 9999
- local highest_window = nil
- for k, v in ipairs(hovered_windows)do
- if(v.z_index < highest_z)then
- highest_z = v.z_index
- highest_window = v.identifier
- end
- end
- if(highest_window ~= nil and highest_window == identifier)then
- disable_scroll = false
- end
- end
- end
-
- if(global_scroll_toggle)then
- disable_scroll = true
- end
-
- local id_extra = 0
- if(disable_scroll)then
- id_extra = id_extra + 1
- id_extra = GameGetFrameNum() % 2
- end
-
- local id = NewID(identifier)
- NewID(identifier)
-
- local screen_width, screen_height = GuiGetScreenDimensions( gui )
-
- -- check if render_w is bigger than w
- local had_scroll_bar = false
-
- if(last_render_width > w)then
- had_scroll_bar = true
- end
-
-
- if(had_scroll_bar and not disable_scroll)then
- last_hovered_window = identifier
- end
-
- local draw_w, draw_h = w, h
-
-
- GuiOptionsAddForNextWidget(gui, GUI_OPTION.NoPositionTween)
- GuiOptionsRemove(gui, GUI_OPTION.DrawScaleIn)
-
- GuiZSetForNextWidget( gui, z_index + 1 )
- GuiBeginScrollContainer( gui, id + id_extra, x, y + bar_h + 3, w - (margin_x * 2), h - bar_h - (margin_y * 2), true, margin_x or 2, margin_y or 2 )
- local _, _, _, _, _, _, _, _, _, render_w, render_h = GuiGetPreviousWidgetInfo( gui )
- GuiZSet( gui, z_index )
- GuiOptionsAddForNextWidget(gui, GUI_OPTION.GamepadDefaultWidget)
- callback(x, y, w, h)
- GuiZSet( gui, 0 )
- GuiEndScrollContainer( gui )
-
-
- window_stack[identifier] = {
- identifier = identifier,
- z_index = z_index,
- x = x,
- y = y,
- w = w,
- h = h,
- render_w = render_w,
- render_h = render_h,
- had_scroll_bar = had_scroll_bar
- }
-
-end
-]]
-
---[[
-
- local was_non_interactive = GuiOptionsHas(gui, GUI_OPTION.NonInteractive)
- GuiOptionsAdd(gui, GUI_OPTION.NonInteractive)
-
- GuiZSetForNextWidget( gui, z_index + 1 )
- GuiBeginScrollContainer( gui, id, x, y, w, h, true, 2, 2 )
- local _, _, _, _, _, _, _, _, _, render_w, render_h = GuiGetPreviousWidgetInfo( gui )
- GuiZSet( gui, z_index )
- callback(x, y, w, h)
- GuiZSet( gui, 0 )
- GuiEndScrollContainer( gui )
-
- local has_scroll_bar = false
- if(render_w > w)then
- print(identifier.." has scroll bar")
- print(tostring(render_w).." > "..tostring(w))
- has_scroll_bar = true
- end
-
-
- if(was_non_interactive)then
- GuiOptionsAdd(gui, GUI_OPTION.NonInteractive)
- else
- GuiOptionsRemove(gui, GUI_OPTION.NonInteractive)
- end
-
-
-
- --local _, _, _, _, _, content_width, content_height = GuiGetPreviousWidgetInfo( gui )
-
- --content_height = content_height - 8
-
- if(not has_scroll_bar and not disable_scroll)then
- w = w + 8
- elseif(has_scroll_bar and not disable_scroll)then
- last_hovered_window = identifier
- end
-]]
-
-function DrawWindow(gui, z_index, x, y, w, h, title, centered, callback, close_callback, identifier, margin_x, margin_y, alignment, no_close_button)
-
- margin_x = margin_x or 2
- margin_y = margin_y or 2
-
- w = w + (margin_x * 2)
- h = h + (margin_y * 2)
-
-
- local had_scroll_bar = last_hovered_window == identifier
-
-
-
- if(centered)then
-
-
- x, y = GetCenterPosition(x, y, w, h)
- end
-
- --[[if(alignment and not had_scroll_bar)then
- x = x + 8
- end]]
-
-
- local bar_y = y
-
- --[[if(had_scroll_bar)then
- w = w - 8
- end]]
-
- GuiBeginAutoBox( gui )
- GuiZSet( gui, z_index - 1 )
- GuiColorSetForNextWidget( gui, 0, 0, 0, 0.3 )
- if(type(title) == "function")then
- GuiLayoutBeginHorizontal( gui,x, bar_y, true, 0, 0)
- GuiText(gui, 0, 0, " ")
- title()
- GuiLayoutEnd( gui )
-
- else
- GuiText(gui, x, bar_y, " "..title)
- end
-
-
- if(close_callback ~= nil and not no_close_button)then
- GuiLayoutBeginLayer( gui )
- GuiLayoutBeginHorizontal( gui, 0, 0, true, 0, 0)
- if(CustomButton(gui, "sagsadshds", x + (w - 10), bar_y + 1, z_index - 600, 1, "mods/evaisa.mp/files/gfx/ui/minimize.png", 0, 0, 0, 0.5))then
- close_callback()
- end
- GuiLayoutEnd( gui )
- GuiLayoutEndLayer( gui )
- end
-
- GuiZSetForNextWidget( gui, z_index )
- GuiOptionsAddForNextWidget(gui, GUI_OPTION.IsExtraDraggable)
- GuiEndAutoBoxNinePiece( gui, 0, w, 8, false, 0, "mods/evaisa.mp/files/gfx/ui/9piece_window_bar.png", "mods/evaisa.mp/files/gfx/ui/9piece_window_bar.png")
-
- local clicked, right_clicked, hovered, bar_x, bar_y, bar_w, bar_h = GuiGetPreviousWidgetInfo( gui )
-
- --GuiOptionsAddForNextWidget(gui, GUI_OPTION.IgnoreContainer)
-
- local mouse_x, mouse_y = input:GetUIMousePos(gui)
-
- local disable_scroll = true
-
- if (input:WasKeyPressed("f1")) then
- global_scroll_toggle = global_scroll_toggle or false
- global_scroll_toggle = not global_scroll_toggle
-
- end
-
-
- -- only do this if we are the upmost window hovered
- -- check old_window_stack for this
-
- local hovered_windows = {}
- local total_windows = 0
- for k, v in pairs(old_window_stack)do
- if(mouse_x > v.x and mouse_x < v.x + v.w and mouse_y > v.y and mouse_y < v.y + v.h)then
- table.insert(hovered_windows, v)
- end
- total_windows = total_windows + 1
- end
-
- if(last_hovered_window == identifier)then
- disable_scroll = false
- else
- if(#hovered_windows > 0)then
-
- -- check z index, lower z is higher up
- local highest_z = 9999
- local highest_window = nil
- for k, v in ipairs(hovered_windows)do
- if(v.z_index < highest_z)then
- highest_z = v.z_index
- highest_window = v.identifier
- end
- end
- if(highest_window ~= nil and highest_window == identifier)then
- disable_scroll = false
- end
- end
- end
-
- if(global_scroll_toggle)then
- disable_scroll = true
- end
-
- local id_extra = 0
- if(disable_scroll)then
- id_extra = id_extra + 1
- id_extra = GameGetFrameNum() % 2
- end
-
- local id = NewID(identifier)
- NewID(identifier)
-
- local screen_width, screen_height = GuiGetScreenDimensions( gui )
-
-
- local was_non_interactive = GuiOptionsHas(gui, GUI_OPTION.NonInteractive)
- GuiOptionsAdd(gui, GUI_OPTION.NonInteractive)
-
- local precalc_w = w - (margin_x * 2)
-
- GuiZSetForNextWidget( gui, z_index - 100 )
- GuiBeginScrollContainer( gui, id + 23587, screen_width + margin_x + 2, y + bar_h + 3, precalc_w, h - bar_h - (margin_y * 2), true, margin_x or 2, margin_y or 2 )
- local _, _, _, _, _, _, _, _, _, render_w, render_h = GuiGetPreviousWidgetInfo( gui )
- GuiZSet( gui, z_index - 101 )
- callback(x, y, w, h)
- GuiZSet( gui, 0 )
- GuiEndScrollContainer( gui )
-
- local had_scroll_bar = false
-
- --print(tostring(render_w - 4).." > "..tostring(w))
-
- if(render_w - 4 > w)then
- had_scroll_bar = true
- end
-
-
- if(was_non_interactive)then
- GuiOptionsAdd(gui, GUI_OPTION.NonInteractive)
- else
- GuiOptionsRemove(gui, GUI_OPTION.NonInteractive)
- end
-
-
-
-
- if(had_scroll_bar and not disable_scroll)then
- last_hovered_window = identifier
- end
-
- if(last_hovered_window == identifier)then
- w = w - 8
- end
-
- local draw_w, draw_h = w, h
-
-
- GuiOptionsAddForNextWidget(gui, GUI_OPTION.NoPositionTween)
- GuiOptionsRemove(gui, GUI_OPTION.DrawScaleIn)
-
- GuiZSetForNextWidget( gui, z_index + 1 )
- GuiBeginScrollContainer( gui, id + id_extra, x, y + bar_h + 3, w - (margin_x * 2), h - bar_h - (margin_y * 2), true, margin_x or 2, margin_y or 2 )
- GuiZSet( gui, z_index )
- GuiOptionsAddForNextWidget(gui, GUI_OPTION.GamepadDefaultWidget)
- callback(x, y, w, h)
- GuiZSet( gui, 0 )
- GuiEndScrollContainer( gui )
-
-
- window_stack[identifier] = {
- identifier = identifier,
- z_index = z_index,
- x = x,
- y = y,
- w = w,
- h = h,
- }
-
-end
-
-
-
-function CustomTooltip(gui, callback, z, x_offset, y_offset )
- if z == nil then z = -12; end
- local left_click,right_click,hover,x,y,width,height,draw_x,draw_y,draw_width,draw_height = GuiGetPreviousWidgetInfo( gui );
- local screen_width,screen_height = GuiGetScreenDimensions( gui );
- if x_offset == nil then x_offset = 0; end
- if y_offset == nil then y_offset = 0; end
- if draw_y > screen_height * 0.5 then
- y_offset = y_offset - height;
- end
- if hover then
- local screen_width, screen_height = GuiGetScreenDimensions( gui );
- GuiZSet( gui, z );
- GuiLayoutBeginLayer( gui );
- GuiLayoutBeginVertical( gui, ( x + x_offset + width * 2 ) / screen_width * 100, ( y + y_offset ) / screen_height * 100 );
- GuiOptionsAdd( gui, GUI_OPTION.NoPositionTween )
- GuiBeginAutoBox( gui );
- if callback ~= nil then callback(); end
- GuiZSetForNextWidget( gui, z + 1 );
- GuiEndAutoBoxNinePiece( gui );
- GuiLayoutEnd( gui );
- GuiLayoutEndLayer( gui );
- end
-end
-
-function Gui9Piece(gui, id_func, x, y, width, height, alpha, z_index, image_sprite, piece_size)
- -- top left
- GuiZSetForNextWidget(gui, z_index)
- GuiImage(gui, id_func(), x, y, image_sprite, alpha, 1, 1, 0, 1, "tl")
- -- top right
- GuiZSetForNextWidget(gui, z_index)
- GuiImage(gui, id_func(), x + width - piece_size, y, image_sprite, alpha, 1, 1, 0, 1, "tr")
- -- bottom left
- GuiZSetForNextWidget(gui, z_index)
- GuiImage(gui, id_func(), x, y + height - piece_size, image_sprite, alpha, 1, 1, 0, 1, "bl")
- -- bottom right
- GuiZSetForNextWidget(gui, z_index)
- GuiImage(gui, id_func(), x + width - piece_size, y + height - piece_size, image_sprite, alpha, 1, 1, 0, 1, "br")
- -- top
- GuiZSetForNextWidget(gui, z_index)
- GuiImage(gui, id_func(), x + piece_size, y, image_sprite, alpha, (width - piece_size * 2) / piece_size, 1, 0, 1, "tc")
- -- bottom
- GuiZSetForNextWidget(gui, z_index)
- GuiImage(gui, id_func(), x + piece_size, y + height - piece_size, image_sprite, alpha, (width - piece_size * 2) / piece_size, 1, 0, 1, "bc")
- -- left
- GuiZSetForNextWidget(gui, z_index)
- GuiImage(gui, id_func(), x, y + piece_size, image_sprite, alpha, 1, (height - piece_size * 2) / piece_size, 0, 1, "lc")
- -- right
- GuiZSetForNextWidget(gui, z_index)
- GuiImage(gui, id_func(), x + width - piece_size, y + piece_size, image_sprite, alpha, 1, (height - piece_size * 2) / piece_size, 0, 1, "rc")
- -- center
- GuiZSetForNextWidget(gui, z_index)
- GuiImage(gui, id_func(), x + piece_size, y + piece_size, image_sprite, alpha, (width - piece_size * 2) / piece_size, (height - piece_size * 2) / piece_size, 0, 1, "c")
-end
-
-local button_stack = {}
-function GuiTextButton(gui, id_func, x, y, text, z_index, line_spacing, color_r, color_g, color_b, color_a, max_width, tooltip_func)
- color_r = color_r or 1
- color_g = color_g or 1
- color_b = color_b or 1
- color_a = color_a or 1
- max_width = max_width or 10000
- local was_hovered = false
- local id = id_func()
- if(button_stack[id] == nil)then
- button_stack[id] = {}
- else
- was_hovered = button_stack[id].hovered
- end
- local any_was_hovered = false
- local any_was_clicked = false
- local any_was_right_clicked = false
-
- local index = 0
- local last_x = 0
- if type(text) == "table" then
- for i, txt in ipairs(text)do
- local str = txt.text
- local color = txt.color or nil
-
- local x_offset = last_x or 0
-
- for line in str:gmatch("[^\r\n]+") do
- local text_width, text_height = GuiGetTextDimensions(gui, line)
- if(was_hovered)then
- GuiColorSetForNextWidget(gui, 255 / 255, 255 / 255, 178 / 255, 1)
- else
- if color then
- GuiColorSetForNextWidget(gui, color[1], color[2], color[3], color[4])
- else
- GuiColorSetForNextWidget(gui, color_r, color_g, color_b, color_a)
- end
- end
- GuiZSetForNextWidget(gui, z_index)
- local offset = index * (text_height + (line_spacing or 0))
-
- if(x_offset ~= 0 and x + x_offset > max_width)then
- index = index + 1
- x_offset = 0
- offset = index * (text_height + (line_spacing or 0))
- end
-
- GuiButton(gui, id_func(), x + x_offset, y + offset, line)
- if(tooltip_func)then
- tooltip_func()
- end
-
- last_x = x + text_width
-
- local clicked, right_clicked, hovered = GuiGetPreviousWidgetInfo(gui)
-
- if(clicked)then
- any_was_clicked = true
- end
- if(right_clicked)then
- any_was_right_clicked = true
- end
- if(hovered)then
- any_was_hovered = true
- end
-
- x_offset = 0
-
-
- index = index + 1
- end
- index = index - 1
-
- end
- else
- for line in text:gmatch("[^\r\n]+") do
- local text_width, text_height = GuiGetTextDimensions(gui, line)
- if(was_hovered)then
- GuiColorSetForNextWidget(gui, 255 / 255, 255 / 255, 178 / 255, 1)
- else
- GuiColorSetForNextWidget(gui, color_r, color_g, color_b, color_a)
- end
- GuiZSetForNextWidget(gui, z_index)
- local offset = index * (text_height + (line_spacing or 0))
- GuiButton(gui, id_func(), x, y + offset, line)
- if(tooltip_func)then
- tooltip_func()
- end
- local clicked, right_clicked, hovered = GuiGetPreviousWidgetInfo(gui)
-
- if(clicked)then
- any_was_clicked = true
- end
- if(right_clicked)then
- any_was_right_clicked = true
- end
- if(hovered)then
- any_was_hovered = true
- end
-
- index = index + 1
- end
- end
-
- button_stack[id].hovered = any_was_hovered
- button_stack[id].clicked = any_was_clicked
- button_stack[id].right_clicked = any_was_right_clicked
-
- return any_was_clicked, any_was_clicked, any_was_hovered
-end
-
-function GuiTextMultiline(gui, x, y, text, z_index, line_spacing, color_r, color_g, color_b, color_a, max_width, tooltip_func)
- -- guitext with multiline support
- color_r = color_r or 1
- color_g = color_g or 1
- color_b = color_b or 1
- color_a = color_a or 1
- max_width = max_width or 10000
-
- local index = 0
- local last_x = 0
- if type(text) == "table" then
- for i, txt in ipairs(text)do
- local str = txt.text
- local color = txt.color or nil
-
- local x_offset = last_x or 0
-
- for line in str:gmatch("[^\r\n]+") do
- local text_width, text_height = GuiGetTextDimensions(gui, line)
-
- if color then
- GuiColorSetForNextWidget(gui, color[1], color[2], color[3], color[4])
- else
- GuiColorSetForNextWidget(gui, color_r, color_g, color_b, color_a)
- end
-
- GuiZSetForNextWidget(gui, z_index)
- local offset = index * (text_height + (line_spacing or 0))
-
- if(x_offset ~= 0 and x + x_offset > max_width)then
- index = index + 1
- x_offset = 0
- offset = index * (text_height + (line_spacing or 0))
- end
-
- GuiText(gui, x + x_offset, y + offset, line)
- if(tooltip_func)then
- tooltip_func()
- end
-
- last_x = x + text_width
-
- x_offset = 0
-
-
- index = index + 1
- end
- index = index - 1
-
- end
- else
- for line in text:gmatch("[^\r\n]+") do
- local text_width, text_height = GuiGetTextDimensions(gui, line)
-
- GuiColorSetForNextWidget(gui, color_r, color_g, color_b, color_a)
-
- GuiZSetForNextWidget(gui, z_index)
- local offset = index * (text_height + (line_spacing or 0))
- GuiText(gui, x, y + offset, line)
- if(tooltip_func)then
- tooltip_func()
- end
-
- index = index + 1
- end
- end
-end
\ No newline at end of file
diff --git a/files/scripts/helpers.lua b/files/scripts/helpers.lua
deleted file mode 100644
index e2fc410..0000000
--- a/files/scripts/helpers.lua
+++ /dev/null
@@ -1,61 +0,0 @@
-local helpers = {
- RAGDOLL_FX = {
- NONE = 0x0,
- NORMAL = 0x1,
- BLOOD_EXPLOSION = 0x2,
- BLOOD_SPRAY = 0x3,
- FROZEN = 0x4,
- CONVERT_TO_MATERIAL = 0x5,
- CUSTOM_RAGDOLL_ENTITY = 0x6,
- DISINTEGRATED = 0x7,
- NO_RAGDOLL_FILE = 0x8,
- PLAYER_RAGDOLL_CAMERA = 0x9,
- },
- DAMAGE_TYPES = {
- DAMAGE_MELEE = 0x1,
- DAMAGE_PROJECTILE = 0x2,
- DAMAGE_EXPLOSION = 0x4,
- DAMAGE_BITE = 0x8,
- DAMAGE_FIRE = 0x10,
- DAMAGE_MATERIAL = 0x20,
- DAMAGE_FALL = 0x40,
- DAMAGE_ELECTRICITY = 0x80,
- DAMAGE_DROWNING = 0x100,
- DAMAGE_PHYSICS_BODY_DAMAGED = 0x200,
- DAMAGE_DRILL = 0x400,
- DAMAGE_SLICE = 0x800,
- DAMAGE_ICE = 0x1000,
- DAMAGE_HEALING = 0x2000,
- DAMAGE_PHYSICS_HIT = 0x4000,
- DAMAGE_RADIOACTIVE = 0x8000,
- DAMAGE_POISON = 0x10000,
- DAMAGE_MATERIAL_WITH_FLASH = 0x20000,
- DAMAGE_OVEREATING = 0x40000,
- DAMAGE_CURSE = 0x80000,
- DAMAGE_HOLY = 0x100000
- }
-}
-
-
-helpers.GetDamageTypes = function(bit_flag)
- local damage_types = {}
-
-
- for damage_type_name, damage_type_value in pairs(helpers.DAMAGE_TYPES) do
- if bit.band(bit_flag, damage_type_value) == damage_type_value then
- table.insert(damage_types, damage_type_name)
- end
- end
-
- return damage_types
-end
-
-helpers.GetRagdollFX = function(index)
- for ragdoll_fx_name, ragdoll_fx_value in pairs(helpers.RAGDOLL_FX) do
- if ragdoll_fx_value == index then
- return ragdoll_fx_name
- end
- end
-end
-
-return helpers
\ No newline at end of file
diff --git a/files/scripts/lobby_handler.lua b/files/scripts/lobby_handler.lua
deleted file mode 100644
index 4cfbff3..0000000
--- a/files/scripts/lobby_handler.lua
+++ /dev/null
@@ -1,669 +0,0 @@
-lobby_count = lobby_count or 0
-lobbies = lobbies or { friend = {}, public = {} }
-
-distance = {
- close = "Close",
- default = "Default",
- far = "Far",
- worldwide = "Worldwide"
-}
-
-disconnect_message = disconnect_message or ""
-banned_members = banned_members or {}
-
-local function SplitMessage(message, characters)
- -- split string at first space after X characters
- -- concatenate with \n\t
- local split = {}
- local i = 1
- while i <= #message do
- local j = i + characters
- if j > #message then
- j = #message
- end
- local k = string.find(message, " ", j)
- if k == nil then
- k = #message
- end
- table.insert(split, string.sub(message, i, k))
- i = k + 1
- end
- return table.concat(split, "\n")
-end
-
-function handleDisconnect(data)
- local message = data.message
- local split_data = {}
- for token in string.gmatch(message, "[^;]+") do
- table.insert(split_data, token)
- end
-
- if (#split_data >= 3) then
- if (split_data[1] == "disconnect") then
- if (split_data[2] == tostring(steam_utils.getSteamID())) then
- msg.log("You were disconnected from the lobby.")
- steam_utils.Leave(data.lobbyID)
- invite_menu_open = false
- menu_status = status.disconnected
- disconnect_message = SplitMessage(split_data[3], 30)
- show_lobby_code = false
- lobby_code = nil
- banned_members = {}
- end
- end
- end
-end
-
-function disconnect(data)
- msg.log("You were disconnected from the lobby.")
- steam_utils.Leave(data.lobbyID)
- menu_status = status.disconnected
- disconnect_message = SplitMessage(data.message, 30)
-end
-
-function handleBanCheck(user)
- if(lobby_code == nil)then
- return false
- end
- if (banned_members[tostring(user)] ~= nil or steam_utils.IsPlayerBlacklisted(user)) then
- mp_log:print("Disconnected member: " .. tostring(user))
- banned_members[tostring(user)] = true
- steam.matchmaking.kickUserFromLobby(lobby_code, user, GameTextGetTranslatedOrNot("$mp_banned_warning"))
- return true
- end
- return false
-end
-
-function handleInProgressCheck(user)
- if(lobby_code == nil)then
- return false
- end
- local is_in_progress = steam.matchmaking.getLobbyData(lobby_code, "in_progress") or "false"
- local allow_in_progress_joining = steam.matchmaking.getLobbyData(lobby_code, "allow_in_progress_joining") or "true"
- --print(is_in_progress)
- --print(allow_in_progress_joining)
- if(is_in_progress == "true" and allow_in_progress_joining == "false")then
- mp_log:print("Disconnected member: " .. tostring(user))
- steam.matchmaking.kickUserFromLobby(lobby_code, user, GameTextGetTranslatedOrNot("$mp_in_progress_warning"))
- return true
- end
- return false
-end
-
-function handleVersionCheck()
- local version = steam.matchmaking.getLobbyData(lobby_code, "version")
- if (version > tostring(MP_VERSION)) then
- disconnect({
- lobbyID = lobby_code,
- message = GameTextGetTranslatedOrNot("$mp_client_outdated")
- })
- return false
- elseif (version < tostring(MP_VERSION)) then
- disconnect({
- lobbyID = lobby_code,
- message = GameTextGetTranslatedOrNot("$mp_host_outdated")
- })
- return false
- end
- return true
-end
-
-function handleGamemodeVersionCheck(lobbycode)
- local gamemode_version = steam.matchmaking.getLobbyData(lobbycode, "gamemode_version")
- local game_version_hash = steam.matchmaking.getLobbyData(lobbycode, "game_version_hash")
- local active_mode = FindGamemode(steam.matchmaking.getLobbyData(lobbycode, "gamemode"))
- --local gamemode = steam.matchmaking.getLobbyData(lobbycode, "gamemode")
- mp_log:print("Gamemode: " .. tostring(active_mode.id))
- mp_log:print("Version: " .. tostring(gamemode_version))
- mp_log:print("Game version hash: " .. tostring(game_version_hash))
- if (active_mode ~= nil and gamemode_version ~= nil) then
- if (active_mode ~= nil) then
- if (active_mode.version > tonumber(gamemode_version)) then
- disconnect({
- lobbyID = lobbycode,
- message = string.format(GameTextGetTranslatedOrNot("$mp_host_gamemode_outdated"), GameTextGetTranslatedOrNot(active_mode.name))
- })
- return false
- elseif (active_mode.version < tonumber(gamemode_version)) then
- disconnect({
- lobbyID = lobbycode,
- message = string.format(GameTextGetTranslatedOrNot("$mp_client_gamemode_outdated"), GameTextGetTranslatedOrNot(active_mode.name))
- })
- return false
- elseif (game_version_hash ~= tostring(noita_version_hash))then
- disconnect({
- lobbyID = lobbycode,
- message = GameTextGetTranslatedOrNot("$mp_game_version_mismatch")
- })
- return false
- end
- else
- disconnect({
- lobbyID = lobbycode,
- message = string.format(GameTextGetTranslatedOrNot("$mp_gamemode_missing"), GameTextGetTranslatedOrNot(active_mode.name))
- })
- return false
- end
- end
- return true
-end
-
-function HasRequiredMods(lobby)
- local required_mod_string = steam.matchmaking.getLobbyData(lobby, "required_mods") or ""
-
- --print(required_mod_string)
-
- local required_mods = required_mod_string ~= "" and bitser.loads(required_mod_string) or {}
-
- local player_mods = ModData()
-
- --print(json.stringify(required_mods))
-
-
- for i = #required_mods, 1, -1 do
- local v = required_mods[i]
- for k2, v2 in pairs(player_mods) do
- if (v2.id == v[1]) then
- table.remove(required_mods, i)
- end
- end
- end
-
- if (#required_mods > 0) then
- return false
- end
-
- return true
-end
-
-local cached_correct_lobbies = {}
-function IsCorrectVersion(lobby)
- if (cached_correct_lobbies[lobby] ~= nil) then
- return cached_correct_lobbies[lobby]
- end
- local version = steam.matchmaking.getLobbyData(lobby, "version")
- local gamemode_version = steam.matchmaking.getLobbyData(lobby, "gamemode_version")
- local game_version_hash = steam.matchmaking.getLobbyData(lobby, "game_version_hash")
- --local gamemode = steam.matchmaking.getLobbyData(lobby, "gamemode")
- local active_mode = FindGamemode(steam.matchmaking.getLobbyData(lobby, "gamemode"))
- if (version ~= tostring(MP_VERSION)) then
- cached_correct_lobbies[lobby] = false
- return false
- end
- if (game_version_hash ~= tostring(noita_version_hash))then
- cached_correct_lobbies[lobby] = false
- return false
- end
- if (active_mode ~= nil and gamemode_version ~= nil) then
-
- if (active_mode.version ~= tonumber(gamemode_version)) then
- cached_correct_lobbies[lobby] = false
- return false
- end
- else
- cached_correct_lobbies[lobby] = false
- return false
- end
-
- cached_correct_lobbies[lobby] = true
- return true
-end
-
-function VersionInfo(lobby)
- -- return version info
- local info = {
- mp_version_same = true,
- mp_version_string = GameTextGetTranslatedOrNot("$mp_lobby_info_same_version"),
- mp_version_string_user = "",
- gamemode_version_same = true,
- gamemode_missing = false,
- gamemode_version_string = "",
- gamemode_version_string_user = "",
- game_version_same = true,
- game_version_string = GameTextGetTranslatedOrNot("$mp_lobby_info_game_same_version"),
- game_version_string_user = ""
- }
-
- local version = steam.matchmaking.getLobbyData(lobby, "version")
- local gamemode_version = steam.matchmaking.getLobbyData(lobby, "gamemode_version")
- local game_version_hash = steam.matchmaking.getLobbyData(lobby, "game_version_hash") or "missing"
- local game_version = steam.matchmaking.getLobbyData(lobby, "game_version") or "missing"
-
- if(version < tostring(MP_VERSION))then
- info.mp_version_same = false
- info.mp_version_string = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_host_older"), version)
- info.mp_version_string_user = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_you_using"), MP_VERSION)
- elseif(version > tostring(MP_VERSION))then
- info.mp_version_same = false
- info.mp_version_string = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_host_newer"), version)
- info.mp_version_string_user = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_you_using"), MP_VERSION)
- end
-
- if(game_version_hash ~= tostring(noita_version_hash))then
- info.game_version_same = false
- info.game_version_string = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_game_host_diff"), game_version)
- info.game_version_string_user = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_you_using"), noita_version)
- end
-
- local active_mode = FindGamemode(steam.matchmaking.getLobbyData(lobby, "gamemode"))
-
- if(active_mode == nil)then
- info.gamemode_missing = true
- info.gamemode_version_same = false
- info.gamemode_version_string = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_gm_missing"), steam.matchmaking.getLobbyData(lobby, "gamemode"), gamemode_version)
- else
- if(active_mode.version > tonumber(gamemode_version))then
- info.gamemode_version_same = false
- info.gamemode_version_string = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_gm_host_older"), GameTextGetTranslatedOrNot(active_mode.name), gamemode_version)
- info.gamemode_version_string_user = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_you_using"), active_mode.version)
- elseif(active_mode.version < tonumber(gamemode_version))then
- info.gamemode_version_same = false
- info.gamemode_version_string = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_gm_host_newer"), GameTextGetTranslatedOrNot(active_mode.name), gamemode_version)
- info.gamemode_version_string_user = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_you_using"), active_mode.version)
- else
- info.gamemode_version_same = true
- info.gamemode_version_string = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_gm_same_version"), GameTextGetTranslatedOrNot(active_mode.name))
- info.gamemode_version_string_user = ""
- end
- end
-
-
- return info
-
-end
-
-function ModInfo(lobby)
- local info = {
- missing_mods = {},
- missing_mods_string = ""
- }
-
- local required_mods = (steam.matchmaking.getLobbyData(lobby, "required_mods") ~= nil and steam.matchmaking.getLobbyData(lobby, "required_mods") ~= "") and bitser.loads(steam.matchmaking.getLobbyData(lobby, "required_mods")) or {}
-
- local player_mods = ModData()
-
- --print(json.stringify(required_mods))
-
-
- for i = #required_mods, 1, -1 do
- local v = required_mods[i]
- for k2, v2 in pairs(player_mods) do
- if (v2.id == v[1]) then
- table.remove(required_mods, i)
- end
- end
- end
-
- if (#required_mods > 0) then
- for i, v in ipairs(required_mods) do
- table.insert(info.missing_mods, v[2])
- end
- info.missing_mods_string = string.format(GameTextGetTranslatedOrNot("$mp_lobby_info_missing_mods_list"), table.concat(info.missing_mods, ", "))
- end
-
- -- remove trailing comma
- if (string.sub(info.missing_mods_string, -2) == ", ") then
- info.missing_mods_string = string.sub(info.missing_mods_string, 1, -3)
- end
-
- return info
-
-end
-
-local inspect = dofile("mods/evaisa.mp/lib/inspect.lua")
-
-function string_split(str, sep)
- local ret = {}
-
- local value_start = 1
-
- while true do
- local skip_start, skip_end = utf8.find(str, sep, value_start, true)
- skip_start = skip_start or #str + 1
- skip_end = skip_end or #str + 1
-
- if value_start <= skip_start then
- local value = utf8.sub(str, value_start, skip_start - 1)
- value_start = skip_end + 1
- ret[#ret + 1] = value
- else
- return ret
- end
- end
-end
-
-
-function SerializeModData(data)
- local serialized = ""
- --print(inspect(data))
- for i, v in ipairs(data) do
- local name = (v.name or ""):gsub("\x01", "")
- local description = (v.description or ""):gsub("\x01", "")
- local download_link = (v.download_link or ""):gsub("\x01", "")
- serialized = serialized .. (v.workshop_item_id or "0") .. "\x01" .. (v.id or "") .. "\x01" .. name .. "\x01" .. description .. "\x01" .. download_link
- if (i < #data) then
- serialized = serialized .. "\x01"
- end
- end
- --print(serialized)
- return serialized
-end
-
-function DeserializeModData(data)
- local split_data = string_split(data, "\x01")
- local mod_data = {}
- for i = 1, #split_data, 5 do
- table.insert(mod_data, {
- workshop_item_id = split_data[i],
- id = split_data[i + 1],
- name = split_data[i + 2],
- description = split_data[i + 3],
- download_link = split_data[i + 4]
- })
- end
- --print(inspect(mod_data))
- return mod_data
-end
-
-
-
-function ModData()
- local nxml = dofile("mods/evaisa.mp/lib/nxml.lua")
- local save_folder = os.getenv('APPDATA'):gsub("\\Roaming", "") ..
- "\\LocalLow\\Nolla_Games_Noita\\save00\\mod_config.xml"
-
- local file, err = io.open(save_folder, 'rb')
- if file then
-
- mp_log:print("Reading mod config file")
-
- local content = file:read("*all")
-
- local data = {
- }
-
- local subscribed_items = steam.UGC.getSubscribedItems()
- local item_infos = {}
-
- for _, v in ipairs(subscribed_items) do
-
- local success, size, folder, timestamp = steam.UGC.getItemInstallInfo(v)
- if (success) then
- item_infos[tostring(v)] = {size = size, folder = folder, timestamp = timestamp}
- end
-
- end
-
- if (StreamingGetIsConnected()) then
- table.insert(data,
- {
- workshop_item_id = "0",
- name = GameTextGetTranslatedOrNot("$mp_mod_twitch_integration_name"),
- description = GameTextGetTranslatedOrNot("$mp_mod_twitch_integration_description"),
- })
- end
-
- local parsedModData = nxml.parse(content)
- for elem in parsedModData:each_child() do
- if (elem.name == "Mod") then
- local modID = elem.attr.name
- local steamID = elem.attr.workshop_item_id
-
- if (ModIsEnabled(modID)) then
- local infoFile = "mods/" .. modID .. "/mod.xml"
- if (steamID ~= "0") then
- if(item_infos[steamID])then
- infoFile = item_infos[steamID].folder .. "/mod.xml"
- else
- debug_log:print("Failed to find item info for: " .. steamID)
- infoFile = nil
- end
- end
-
- if(infoFile)then
- local file2, err = io.open(infoFile, 'rb')
- if file2 then
- local content2 = file2:read("*all")
- if(content2 ~= nil and content2 ~= "")then
- local parsedModInfo = nxml.parse(content2)
-
- local download_link = parsedModInfo.attr.download_link
-
- if (elem.attr.enabled == "1") then
- table.insert(data,
- {
- workshop_item_id = steamID,
- id = modID,
- name = parsedModInfo.attr.name,
- description = parsedModInfo.attr.description,
- download_link = download_link,
- })
- end
- end
- end
- end
- end
- end
- end
-
- file:close()
-
- --mp_log:print("Mod data: "..json.stringify(data))
-
- return data
- end
- return nil
-end
-
-function defineLobbyUserData(lobby)
- local mod_data = ModData()
- if (mod_data ~= nil) then
- steam.matchmaking.setLobbyMemberData(lobby, "mod_data", SerializeModData(mod_data))
- end
-end
-
-function handleModCheck()
- local required_mods = (steam.matchmaking.getLobbyData(lobby_code, "required_mods") ~= nil and steam.matchmaking.getLobbyData(lobby_code, "required_mods") ~= "") and bitser.loads(steam.matchmaking.getLobbyData(lobby_code, "required_mods")) or {}
-
- local player_mods = ModData()
-
- --print(json.stringify(required_mods))
-
-
- for i = #required_mods, 1, -1 do
- local v = required_mods[i]
- for k2, v2 in pairs(player_mods) do
- if (v2.id == v[1]) then
- table.remove(required_mods, i)
- end
- end
- end
-
- if (#required_mods > 0) then
-
- local mods_string = ""
- for i, v in ipairs(required_mods) do
- if(i == #required_mods) then
- mods_string = mods_string .. v[2] .. " ("..v[1]..")"
- else
- mods_string = mods_string .. v[2] .. " ("..v[1].."), "
- end
- end
-
- disconnect({
- lobbyID = lobby_code,
- message = string.format(GameTextGetTranslatedOrNot("$mp_client_missing_mods"), mods_string)
- })
- return false
- end
-
- return true
-end
-
-
-
-cached_lobby_user_data = cached_lobby_user_data or {}
-
-function getLobbyUserData(lobby, userid, force)
- if(cached_lobby_user_data[userid] ~= nil and force ~= true)then
- return cached_lobby_user_data[userid]
- end
- if(lobby == nil) then
- return nil
- end
- if(userid == nil)then
- return nil
- end
- local player_mod_data = steam.matchmaking.getLobbyMemberData(lobby, userid, "mod_data")
- if (player_mod_data ~= nil and player_mod_data ~= "") then
- local data_received = DeserializeModData(player_mod_data)
- cached_lobby_user_data[userid] = data_received
- return data_received
- end
- return nil
-end
-
-
-function getFriendLobbies()
- local friend_lobbies = {}
-
- local friends = steamutils.getSteamFriends();
-
- for k, v in pairs(friends) do
- local game_info = steam.friends.getFriendGamePlayed(v.id)
-
- if (game_info and game_info.gameID == game_id and tostring(game_info.lobbyID) ~= "0" and game_info.lobbyID ~= nil) then
- table.insert(friend_lobbies, game_info.lobbyID)
- end
- end
-
- return friend_lobbies
-end
-
-function refreshLobbies()
- lobbies = { friend = {}, public = {} }
- local indexed_lobby = {}
-
- --steam.matchmaking.addRequestLobbyListStringFilter("LobbyType", "Public", "Equal")
- steam.matchmaking.addRequestLobbyListDistanceFilter(distance[lobby_filter_distance] or distance.worldwide)
-
- local activeSystem = "NoitaOnline"
-
- if (dev_mode) then
- activeSystem = "NoitaOnlineDev"
- end
-
- steam.matchmaking.addRequestLobbyListStringFilter("System", activeSystem, "Equal")
-
-
- for _, lobby in ipairs(getFriendLobbies()) do
- if (lobby ~= nil) then
- if (indexed_lobby[lobby] == nil) then
- if (steam.matchmaking.requestLobbyData(lobby)) then
- local lobby_type = steam.matchmaking.getLobbyData(lobby, "LobbyType")
-
- if (steam.matchmaking.getLobbyData(lobby, "System") ~= nil and steam.matchmaking.getLobbyData(lobby, "System") == activeSystem) then
- local banned = steam.matchmaking.getLobbyData(lobby, "banned_" ..tostring(steam_utils.getSteamID()))
- if ((lobby_type == "Public" or lobby_type == "FriendsOnly") and banned ~= "true") then
- table.insert(lobbies.friend, lobby)
- indexed_lobby[lobby] = true
- end
- end
- end
- end
- end
- end
-
- steam.matchmaking.requestLobbyList(function(data)
- lobby_count = data.count
- if (lobby_count > 0) then
- for i = 0, lobby_count - 1 do
- local lobby = steam.matchmaking.getLobbyByIndex(i)
- if (lobby.lobbyID ~= nil) then
- local lobby_type = steam.matchmaking.getLobbyData(lobby.lobbyID, "LobbyType")
-
- if (steam.matchmaking.getLobbyData(lobby.lobbyID, "System") ~= nil and steam.matchmaking.getLobbyData(lobby.lobbyID, "System") == activeSystem) then
- local banned = steam.matchmaking.getLobbyData(lobby.lobbyID,
- "banned_" .. tostring(steam_utils.getSteamID()))
- if ((lobby_type == "Public" or lobby_type == "FriendsOnly") and banned ~= "true") then
- if (indexed_lobby[lobby.lobbyID] == nil) then
- --indexed_lobby[lobby.lobbyID] = true
- table.insert(lobbies.public, lobby.lobbyID)
- end
- end
- end
- end
- end
- end
- end)
-
-
- return lobbies
-end
-
-function StartGame()
- local lobby_gamemode = FindGamemode(steam.matchmaking.getLobbyData(lobby_code, "gamemode"))
-
- if handleVersionCheck() and handleModCheck() then
- if handleGamemodeVersionCheck(lobby_code) then
- if (lobby_gamemode) then
-
- spectating = steamutils.IsSpectator(lobby_code)
-
- --print("Are we spectating? " .. tostring(spectating))
-
- if (spectating) then
- if (lobby_gamemode.spectate ~= nil) then
- lobby_gamemode.spectate(lobby_code)
- elseif (lobby_gamemode.start ~= nil) then
- lobby_gamemode.start(lobby_code)
- end
- else
- if (lobby_gamemode.start ~= nil) then
- lobby_gamemode.start(lobby_code)
- end
- end
-
- steam.matchmaking.setLobbyMemberData(lobby_code, "in_game", "true")
-
- in_game = true
- game_in_progress = true
-
- gui_closed = true
- else
- disconnect({
- lobbyID = lobby_code,
- message = string.format(GameTextGetTranslatedOrNot("$mp_gamemode_missing"), tostring(steam.matchmaking.getLobbyData(lobby_code, "gamemode")))
- })
- end
- end
- end
-end
-
-function StopGame()
- local lobby_gamemode = FindGamemode(steam.matchmaking.getLobbyData(lobby_code, "gamemode"))
-
- if handleVersionCheck() and handleModCheck() then
- if handleGamemodeVersionCheck(lobby_code) then
- if (lobby_gamemode) then
- if (lobby_gamemode.stop ~= nil) then
- lobby_gamemode.stop(lobby_code)
- end
-
- if(steamutils.IsOwner())then
- steam_utils.TrySetLobbyData(lobby_code, "in_progress", "false")
- end
-
- in_game = false
- game_in_progress = false
-
- gui_closed = false
- else
- disconnect({
- lobbyID = lobby_code,
- message = string.format(GameTextGetTranslatedOrNot("$mp_gamemode_missing"), tostring(steam.matchmaking.getLobbyData(lobby_code, "gamemode")))
- })
- end
- end
- end
-end
\ No newline at end of file
diff --git a/files/scripts/lobby_ui.lua b/files/scripts/lobby_ui.lua
deleted file mode 100644
index 4b64bb0..0000000
--- a/files/scripts/lobby_ui.lua
+++ /dev/null
@@ -1,3001 +0,0 @@
-dofile_once("data/scripts/lib/utilities.lua")
-
-pretty = require("pretty_print")
-
-menu_gui = menu_gui or GuiCreate()
-
-GuiStartFrame(menu_gui)
-
-local text_input = dofile("mods/evaisa.mp/files/scripts/text_input.lua")
-
-status = {
- main_menu = 1,
- lobby = 2,
- creating_lobby = 3,
- joining_lobby = 4,
- disconnected = 5,
-}
-
-GuiOptionsAdd( menu_gui, GUI_OPTION.NoPositionTween )
-
-local lobby_types = {
- GameTextGetTranslatedOrNot("$mp_public"),
- GameTextGetTranslatedOrNot("$mp_private"),
- GameTextGetTranslatedOrNot("$mp_friends_only"),
-}
-
-local function split_message(msg, max_width)
- local words = {}
- local index = 1
-
- -- split string by \n
- for line in string.gmatch(msg, "[^\n]+") do
- for word in string.gmatch(line, "%S+") do
-
- -- split word into chunks of 200 pixels or less
-
- local width, height = GuiGetTextDimensions(menu_gui, word)
-
- if (width > max_width) then
- local chunks = {}
- local chunk = ""
- for i = 1, #word do
- local char = word:sub(i, i)
- local char_width, char_height = GuiGetTextDimensions(menu_gui, chunk .. char)
- if (char_width <= max_width) then
- chunk = chunk .. char
- else
- table.insert(chunks, chunk)
- chunk = char
- end
- end
- table.insert(chunks, chunk)
-
- for i, chunk in ipairs(chunks) do
- table.insert(words, chunk)
- end
- else
- table.insert(words, word)
- end
-
-
- index = index + 1
- end
- table.insert(words, "\n")
- end
-
-
-
-
- local chunks = {}
- local chunk = ""
- local last_word
- for i, word in ipairs(words) do
- local width, height = GuiGetTextDimensions(chat_gui, chunk .. " " .. word)
-
- if width <= max_width then
- if chunk == "" then
- chunk = word
- else
- if(last_word ~= "\n")then
- chunk = chunk .. " " .. word
- else
- chunk = chunk .. word
- end
- end
- else
- table.insert(chunks, chunk)
- chunk = word
- end
- last_word = word
- end
- table.insert(chunks, chunk)
-
- return chunks
-end
-
-local function get_split_string(str, max_width)
- local chunks = split_message(str, max_width)
-
- -- combine with \n
- local result = table.concat(chunks, "\n")
-
-
- return result, #chunks
-end
-
-presets = presets or {}
-reserved_preset_names = reserved_preset_names or {}
-
-function get_preset_folder_name()
- presets_folder_name = os.getenv('APPDATA'):gsub("\\Roaming", "") .. "\\LocalLow\\Nolla_Games_Noita\\save00\\evaisa.mp_presets"
- gamemode_preset_folder_name = presets_folder_name .. "\\"..active_mode.id
-
- return presets_folder_name, gamemode_preset_folder_name
-end
-
-
-gui_closed = gui_closed or false
-invite_menu_open = invite_menu_open or false
-mod_list_open = mod_list_open or false
-lobby_settings_open = lobby_settings_open or false
-lobby_presets_open = lobby_presets_open or false
-was_lobby_presets_open = was_lobby_presets_open or false
-settings_changed = settings_changed or false
-
-lobby_filter_show_full = (lobby_filter_show_full == nil) and true or lobby_filter_show_full
-lobby_filter_show_friends = (lobby_filter_show_friends == nil) and true or lobby_filter_show_friends
-lobby_filter_show_public = (lobby_filter_show_public == nil) and true or lobby_filter_show_public
-lobby_filter_distance = lobby_filter_distance or "worldwide"
-lobby_filter_max_players = lobby_filter_max_players or 0
-
-local is_in_lobby = lobby_code ~= nil and true or false
-
-selected_player = selected_player or nil
-
-menu_status = menu_status or status.main_menu
-
-show_lobby_code = show_lobby_code or false
-
-if(is_in_lobby)then
- menu_status = status.lobby
-end
-
-active_lobby_menu_right = active_lobby_menu_right or nil
-active_lobby_menu_left = active_lobby_menu_left or nil
-
-active_mode = active_mode or nil
-
-local screen_width, screen_height = GuiGetScreenDimensions( menu_gui );
-
--- replace each letter in string with *
-function censorString(input)
- return string.rep("X", #input)
-end
-
-
-function CreateLobby(type, max_players, callback)
- --print("yeah?")
- steam.matchmaking.createLobby(type, max_players, function(e)
- --print("did this run?")
- if(tostring(e.result) == "1")then
- callback(e.lobby)
- else
- mp_log:print("CreateLobby failed: " .. tostring(e.result))
- end
- end )
-end
-
-
-local function GenerateDefaultPreset()
- local default_name = GameTextGetTranslatedOrNot("$mp_default_preset_name")
- local preset_data = {version = MP_PRESET_VERSION, settings = {}}
- for k, v in ipairs(active_mode.settings)do
- preset_data.settings[v.id] = v.default
- end
- reserved_preset_names[default_name] = true
- table.insert(presets, 1, {name=default_name, data=preset_data, default=true})
-end
-
-local function AddGamemodePresets()
- if(active_mode.default_presets ~= nil)then
- for name, data in pairs(active_mode.default_presets)do
- reserved_preset_names[name] = true
- table.insert(presets, 1, {name=name, data=data, default=true})
- end
- end
-
- if(active_mode.preset_registry ~= nil)then
- local data_table = active_mode.preset_registry()
- for _, data in ipairs(data_table)do
- data.default = true
- table.insert(presets, 1, data)
- end
- end
-end
-
-local function RefreshPresets()
- -- create folder if doesn't exist
- if not os.rename(presets_folder_name, presets_folder_name) then
- os.execute("mkdir \"" .. presets_folder_name .. "\"")
- end
-
- if not os.rename(gamemode_preset_folder_name, gamemode_preset_folder_name) then
- os.execute("mkdir \"" .. gamemode_preset_folder_name .. "\"")
- end
-
- presets = {}
-
- -- loop through files in folder, without luafilesystem
- local pfile = io.popen([[dir "]] .. gamemode_preset_folder_name .. [[" /b]])
- for filename in pfile:lines() do
-
- -- if filename ends in .mp_preset
- if(filename:sub(-10) == ".mp_preset")then
- local preset_data = {}
- local file = io.open(gamemode_preset_folder_name .. "\\" .. filename, "r")
- if(file ~= nil)then
- local data = file:read("*all")
- file:close()
- filename = filename:gsub(".mp_preset", "")
- local valid, preset_data = pcall(bitser.loads, data)
- if(valid and preset_data ~= nil)then
- table.insert(presets, {name = filename, extension = ".mp_preset", data = preset_data})
- else
- table.insert(presets, {name = filename, extension = ".mp_preset", corrupt = true, data = {
- version = MP_PRESET_VERSION,
- settings = {}
- }})
- end
- end
- elseif(filename:sub(-5) == ".json")then
- local preset_data = {}
- local file = io.open(gamemode_preset_folder_name .. "\\" .. filename, "r")
- if(file ~= nil)then
- local data = file:read("*all")
- file:close()
- filename = filename:gsub(".json", "")
- local valid, preset_data = pcall(json.parse, data)
- if(valid and preset_data ~= nil)then
- table.insert(presets, {name = filename, extension = ".json", data = preset_data})
- else
- table.insert(presets, {name = filename, extension = ".json", corrupt = true, data = {
- version = MP_PRESET_VERSION,
- settings = {}
- }})
- end
- end
- end
- end
-
- AddGamemodePresets()
- GenerateDefaultPreset()
-end
-
-local function SavePreset(name)
- if(not reserved_preset_names[name])then
-
- local settings_data = {version = MP_PRESET_VERSION, settings = gamemode_settings}
-
- if(active_mode.save_preset)then
- settings_data = active_mode.save_preset(lobby_code, settings_data)
- end
-
- local serialized_data = nil
- local extension = ""
- if(ModSettingGet("evaisa.mp.presets_as_json"))then
- serialized_data = json.stringify(settings_data)
- extension = ".json"
- else
- serialized_data = bitser.dumps(settings_data)
- extension = ".mp_preset"
- end
- --print(json.stringify(settings_data))
- local file = io.open(gamemode_preset_folder_name .. "\\" .. name .. extension, "w")
- if(file ~= nil)then
- file:write(serialized_data)
- file:close()
- end
- else
- print("Preset name is reserved")
- GamePrint("Preset name is reserved")
- end
-end
-
-local function RemovePreset(name, extension)
- if(name ~= " " and name ~= "_" and #name > 0)then
- os.remove(gamemode_preset_folder_name .. "\\" .. name .. extension)
- end
-end
-
-
-local function GetMenuSettings(location)
- if(location == "center")then
-
- width = 220
-
-
- local x = screen_width / 2
-
-
- return width, x
- elseif(location == "left")then
- -- 10 pixels to the left of center
- -- if right is closed, but left is open, 300 pixels wide
- local width = 188
-
- local center_width, center_x = GetMenuSettings("center")
- local x = center_x - (center_width / 2) - (width / 2) - 10
- return width, x
- elseif(location == "right")then
- -- 10 pixels to the right of center
- -- if left is closed, but right is open, 300 pixels wide
- local width = 188
-
- local center_width, center_x = GetMenuSettings("center")
- local x = center_x + (center_width / 2) + (width / 2) + 10
- return width, x
- end
-
-end
-
-
-initial_refreshes = initial_refreshes or 10
-
-if(initial_refreshes > 0)then
- initial_refreshes = initial_refreshes - 1
- if(initial_refreshes == 0)then
- refreshLobbies()
- end
-end
-
-local default_lobby_menus = {
- {
- id = "lobby_settings",
- name = "$mp_lobby_settings",
- button_text = "$mp_lobby_settings",
- menu_left = true,
- draw = function(lobby, gui, new_id)
- local owner = steam.matchmaking.getLobbyOwner(lobby_code)
-
- local internal_types = { "Public", "Private", "FriendsOnly"}
- local internal_type_map = { Public = 1, Private = 2, FriendsOnly = 3 }
-
-
- edit_lobby_type = internal_type_map[steam_utils.GetLobbyData("LobbyType")]
-
- local true_max = 250
-
- local default_max_players = 8
-
- edit_lobby_max_players = steam_utils.getSteamID() and (edit_lobby_max_players or steam.matchmaking.getLobbyMemberLimit(lobby_code)) or steam.matchmaking.getLobbyMemberLimit(lobby_code)
-
- edit_lobby_name = owner == steam_utils.getSteamID() and (edit_lobby_name or steam_utils.GetLobbyData("name")) or steam_utils.GetLobbyData("name")
-
- edit_lobby_seed = owner == steam_utils.getSteamID() and (edit_lobby_seed or steam_utils.GetLobbyData("seed")) or steam_utils.GetLobbyData("seed")
-
- local current_y = 0
- local box_w = 180
-
- -- Lobby Type Field
- local lobby_type_string = get_split_string(GameTextGetTranslatedOrNot("$mp_lobby_type")..": "..lobby_types[edit_lobby_type], 150)
-
- local chunks = select(2, lobby_type_string:gsub('\n', '\n'))
-
- local last_w, last_h = GuiGetTextDimensions(menu_gui, lobby_type_string)
- local box_h = last_h + (chunks <= 1 and 2 or 0)
-
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, 0, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
-
- if(GuiTextButton(menu_gui, function() return NewID("EditLobby") end, 4, 2, lobby_type_string, -5600, 1))then
- edit_lobby_type = edit_lobby_type + 1
- if(edit_lobby_type > #lobby_types and owner == steam_utils.getSteamID())then
- edit_lobby_type = 1
- end
- settings_changed = true
- end
-
- current_y = current_y + box_h + 2
-
- -- Lobby name field
- local lobby_name_string = GameTextGetTranslatedOrNot("$mp_lobby_name")..": "
- local last_w, last_h = GuiGetTextDimensions(menu_gui, lobby_name_string)
- local box_h = last_h + 18
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
- GuiText(menu_gui, 4, current_y + 2, lobby_name_string)
- name_change_frame = name_change_frame or nil
- local lobby_name_value = GuiTextInput(menu_gui, NewID("EditLobby"), 4, current_y + last_h + 2, edit_lobby_name, 156, 25, "qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM!@#$%^&*()_' ")
- local _, _, hover = GuiGetPreviousWidgetInfo(menu_gui)
-
- if(hover)then
- GameAddFlagRun("chat_bind_disabled")
- end
- if(lobby_name_value ~= edit_lobby_name and owner == steam_utils.getSteamID())then
- edit_lobby_name = lobby_name_value
- name_change_frame = GameGetFrameNum()
- end
-
- if(name_change_frame and GameGetFrameNum() - name_change_frame > 30)then
- settings_changed = true
- name_change_frame = nil
- end
-
- current_y = current_y + box_h + 2
-
- -- lobby max players field
- local max_player_string = GameTextGetTranslatedOrNot("$mp_max_players")..": "
- local last_w, last_h = GuiGetTextDimensions(menu_gui, max_player_string)
- local box_h = last_h + 16
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
- GuiText(menu_gui, 4, current_y + 2, max_player_string)
- max_player_change_frame = max_player_change_frame or nil
- local slider_value = GuiSlider(menu_gui, NewID("EditLobby"), 2, current_y + last_h + 2, "", edit_lobby_max_players, 2, true_max, default_max_players, 1, " ", 146)
-
- GuiColorSetForNextWidget(menu_gui, 1, 1, 1, 0.7)
- local value_text = tostring(math.floor(slider_value))
- GuiText(menu_gui, 153, current_y + last_h + 1, value_text)
-
- if(slider_value ~= edit_lobby_max_players and owner == steam_utils.getSteamID())then
- edit_lobby_max_players = slider_value
- max_player_change_frame = GameGetFrameNum()
- end
-
- if(max_player_change_frame and GameGetFrameNum() - max_player_change_frame > 30)then
- settings_changed = true
- max_player_change_frame = nil
- end
-
- current_y = current_y + box_h + 2
-
- -- world seed field
- local seed_string = GameTextGetTranslatedOrNot("$mp_world_seed")..": "
- local last_w, last_h = GuiGetTextDimensions(menu_gui, seed_string)
- local box_h = last_h + 18
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
- GuiText(menu_gui, 4, current_y + 2, seed_string)
- seed_change_frame = seed_change_frame or nil
- local edit_lobby_seed_value = GuiTextInput(menu_gui, NewID("EditLobby"), 4, current_y + last_h + 2, edit_lobby_seed, 156, 25, "1234567890")
- local _, _, hover = GuiGetPreviousWidgetInfo(menu_gui)
- if(hover)then
- GameAddFlagRun("chat_bind_disabled")
- end
- if(edit_lobby_seed_value ~= edit_lobby_seed and owner == steam_utils.getSteamID())then
- edit_lobby_seed = edit_lobby_seed_value
- seed_change_frame = GameGetFrameNum()
- end
-
- if(seed_change_frame and GameGetFrameNum() - seed_change_frame > 30)then
- settings_changed = true
- seed_change_frame = nil
- end
-
- current_y = current_y + box_h + 2
-
- for k, setting in ipairs(active_mode.settings or {})do
- if(owner ~= steam_utils.getSteamID())then
- gamemode_settings[setting.id] = steam.matchmaking.getLobbyData(lobby_code, "setting_"..setting.id)
- end
-
- if(gamemode_settings[setting.id] == nil)then
- gamemode_settings[setting.id] = setting.default
- print("Setting "..setting.id.." to default: "..tostring(setting.default))
- --settings_changed = true
- --GlobalsSetValue("setting_next_"..setting.id, tostring(setting.default))
- else
-
- if(setting.type == "bool" and type(gamemode_settings[setting.id]) == "string")then
- if(gamemode_settings[setting.id] == "true")then
- gamemode_settings[setting.id] = true
- else
- gamemode_settings[setting.id] = false
- end
- elseif(setting.type == "slider" and type(gamemode_settings[setting.id]) == "string")then
- gamemode_settings[setting.id] = tonumber(gamemode_settings[setting.id])
- end
- end
-
- if(gamemode_settings[setting.id] ~= nil)then
- local setting_next = GlobalsGetValue("setting_next_"..setting.id)
- if(setting_next ~= nil)then
- if(setting_next ~= tostring(gamemode_settings[setting.id]))then
- GlobalsSetValue("setting_next_"..setting.id, tostring(gamemode_settings[setting.id]))
- end
- end
- end
-
- if(setting.require == nil or setting.require(setting))then
- --print(setting.id.."; "..tostring(setting.require).."; "..(setting.require and tostring(setting.require(setting)) or "nil"))
- if(setting.type == "enum")then
- local selected_name = ""
- local selected_index = nil
-
- local selected_value = gamemode_settings[setting.id]
- --print("Selected value: "..tostring(selected_value))
- if(selected_value == nil)then
- selected_value = setting.default
- gamemode_settings[setting.id] = setting.default
- settings_changed = true
- end
-
- for k, v in ipairs(setting.options)do
- if(v[1] == selected_value)then
- selected_name = v[2]
- selected_index = k
- end
- end
-
- -- if selected index is nil, reset to default
- if(selected_index == nil)then
- for k, v in ipairs(setting.options)do
- if(v[1] == setting.default)then
- selected_name = v[2]
- selected_index = k
- settings_changed = true
- gamemode_settings[setting.id] = setting.default
- end
- end
- end
-
- local enum_string = get_split_string(GameTextGetTranslatedOrNot(setting.name or "")..": "..GameTextGetTranslatedOrNot(selected_name or ""), 150)
- local chunks = select(2, enum_string:gsub('\n', '\n'))
- local last_w, last_h = GuiGetTextDimensions(menu_gui, enum_string)
- local box_h = last_h + (chunks <= 1 and 2 or 0)
-
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
- if(setting.options[selected_index][3] ~= nil)then
- local info = setting.options[selected_index][3]
- local info_name = "???"
- local info_desc = ""
- if(type(info) == "function")then
- info_name, info_desc = info()
- elseif(type(info) == "table")then
- info_name, info_desc = info[1], info[2]
- else
- info_name = info
- end
-
- if(info_name ~= nil)then
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- GuiText(menu_gui, 0, 0, "[?]")
- GuiTooltip(menu_gui, GameTextGetTranslatedOrNot(info_name or ""), GameTextGetTranslatedOrNot(info_desc or ""))
- end
- end
-
- if(GuiTextButton(menu_gui, function() return NewID("EditLobby") end, 4, current_y + 2, enum_string, -5600, 1, nil, nil, nil, nil, nil, function() GuiTooltip(menu_gui, GameTextGetTranslatedOrNot(setting.name or ""), GameTextGetTranslatedOrNot(setting.description or "")) end))then
- selected_index = selected_index + 1
- if(selected_index > #setting.options)then
- selected_index = 1
- end
- gamemode_settings[setting.id] = setting.options[selected_index][1]
- settings_changed = true
- end
-
-
-
- current_y = current_y + box_h + 2
- elseif(setting.type == "bool")then
- local bool_string = get_split_string(GameTextGetTranslatedOrNot(setting.name or "")..":"..(gamemode_settings[setting.id] and GameTextGetTranslatedOrNot("$mp_setting_enabled") or GameTextGetTranslatedOrNot("$mp_setting_disabled")), 170)
- local chunks = select(2, bool_string:gsub('\n', '\n'))
- local last_w, last_h = GuiGetTextDimensions(menu_gui, bool_string)
- local box_h = last_h + (chunks <= 1 and 2 or 0)
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
-
- local r, g, b, a = 1, 1, 1, 1
-
- -- split bool string by :
- local str1, str2 = bool_string:match("([^,]+:)([^,]+)")
-
- if(gamemode_settings[setting.id])then
- r, g, b, a = 0.4, 1, 0.4, 1
- else
- r, g, b, a = 1, 0.4, 0.4, 1
- end
-
-
- if(GuiTextButton(menu_gui, function() return NewID("EditLobby") end, 4, current_y + 2, {
- {
- text = str1,
- color = {1, 1, 1, 1}
- },
- {
- text = str2,
- color = {r, g, b, a}
- }
- }, -5600, 1, r, g, b, a, 170, function() GuiTooltip(menu_gui, GameTextGetTranslatedOrNot(setting.name or ""), GameTextGetTranslatedOrNot(setting.description or "")) end))then
- gamemode_settings[setting.id] = not gamemode_settings[setting.id]
- settings_changed = true
- end
- GuiTooltip(menu_gui, GameTextGetTranslatedOrNot(setting.name or ""), GameTextGetTranslatedOrNot(setting.description or ""))
- current_y = current_y + box_h + 2
- elseif(setting.type == "slider")then
-
- setting.display_multiplier = setting.display_multiplier or 1
- setting.formatting_string = setting.formatting_string or " $0"
- setting.formatting_func = setting.formatting_func or function(value) return value end
- setting.modifier = setting.modifier
-
- if(setting.modifier == nil)then
- setting.modifier = function(value) return value end
- end
-
- setting.display_fractions = setting.display_fractions or false
-
- local slider_string = get_split_string(GameTextGetTranslatedOrNot(setting.name or "")..": ", 150)
-
- local chunks = select(2, slider_string:gsub('\n', '\n'))
-
- local last_w, last_h = GuiGetTextDimensions(menu_gui, slider_string)
- local box_h = last_h + 16
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
- GuiTextMultiline(menu_gui, 4, current_y + 2, slider_string, -5600, 1, 1, 1, 1, 1, 170, function() GuiTooltip(menu_gui, GameTextGetTranslatedOrNot(setting.name), GameTextGetTranslatedOrNot(setting.description)) end)
-
-
- local slider_value = GuiSlider(menu_gui, NewID("EditLobby"), 2, current_y + last_h + 2, "", gamemode_settings[setting.id], setting.min, setting.max, setting.default, setting.display_multiplier, " ", 146)
- slider_value = setting.modifier(slider_value)
- local clicked, _, hovered = GuiGetPreviousWidgetInfo(menu_gui)
- GuiTooltip(menu_gui, GameTextGetTranslatedOrNot(setting.name), GameTextGetTranslatedOrNot(setting.description))
-
- -- take setting.formatting_string, replace $0 with slider_value, take display multiplier into account
- GuiColorSetForNextWidget(menu_gui, 1, 1, 1, 0.7)
- local value_text = string.gsub(setting.formatting_string, "$0", tostring(setting.display_fractions and (slider_value * setting.display_multiplier) or math.floor(slider_value * setting.display_multiplier)))
- value_text = setting.formatting_func(value_text)
- GuiText(menu_gui, 150, current_y + last_h + 1, value_text)
-
- was_slider_changed = was_slider_changed or {}
-
- if(tostring(slider_value) ~= tostring(gamemode_settings[setting.id]))then
-
- gamemode_settings[setting.id] = slider_value
- was_slider_changed[setting.id] = GameGetFrameNum()
- end
-
- if(was_slider_changed[setting.id] and (GameGetFrameNum() - was_slider_changed[setting.id]) > 30)then
-
- settings_changed = true
- was_slider_changed[setting.id] = nil
-
- --GlobalsSetValue("setting_next_"..setting.id, tostring(gamemode_settings[setting.id]))
- end
-
- current_y = current_y + box_h + 2
- end
- end
-
- if(settings_changed and owner == steam_utils.getSteamID())then
- steam.matchmaking.setLobbyMemberLimit(lobby_code, edit_lobby_max_players)
- steam_utils.TrySetLobbyData(code, "max_players", tostring(edit_lobby_max_players))
- steam_utils.TrySetLobbyData(lobby_code, "name", edit_lobby_name)
-
- steam_utils.TrySetLobbyData(lobby_code, "seed", edit_lobby_seed)
- for k, setting in ipairs(active_mode.settings or {})do
- steam_utils.TrySetLobbyData(lobby_code, "setting_"..setting.id, tostring(gamemode_settings[setting.id]))
- mp_log:print("Updated gamemode setting: "..setting.id.." to "..tostring(gamemode_settings[setting.id]))
- end
- print("Updating lobby type: "..internal_types[edit_lobby_type])
- steam.matchmaking.setLobbyType(lobby_code, internal_types[edit_lobby_type])
- steam_utils.send("refresh", {}, steam_utils.messageTypes.AllPlayers, lobby_code, true, true)
- mp_log:print("Updated limit: "..tostring(edit_lobby_max_players))
- mp_log:print("Updated name: "..tostring(edit_lobby_name))
- mp_log:print("Updated type: "..tostring(internal_types[edit_lobby_type]))
- settings_changed = false
- --print("lobby settings changed!")
- end
-
- end
-
- end,
- },
- {
- id = "lobby_presets",
- name = "$mp_lobby_presets",
- button_text = "$mp_lobby_presets",
- draw = function()
-
-
-
- if(active_mode ~= nil)then
-
-
-
- if(not was_lobby_presets_open)then
- RefreshPresets()
- end
-
- GuiLayoutBeginVertical(menu_gui, 0, 0, true, 0, 0)
-
- preset_name = preset_name or ("Preset_"..tostring(Random(1, 1000000)))
- GuiLayoutBeginHorizontal(menu_gui, 0, 0)
- GuiText(menu_gui, 0, 0, GameTextGetTranslatedOrNot("$mp_preset_name"))
- preset_name = GuiTextInput(menu_gui, NewID("save_preset_name"), 0, 0, preset_name, 90, 15)
-
- local illegal_chars = {
- "/",
- "\\",
- ":",
- "*",
- "?",
- "\"",
- "<",
- ">",
- "|",
- }
-
- for i, char in ipairs(illegal_chars)do
- preset_name = preset_name:gsub(char, "")
- end
-
- -- remove control characters
- preset_name = preset_name:gsub("%c", "")
-
-
- local _, _, hover = GuiGetPreviousWidgetInfo(menu_gui)
-
- if(hover)then
- GameAddFlagRun("chat_bind_disabled")
- end
-
-
- GuiLayoutEnd(menu_gui)
-
- if(GuiButton(menu_gui, NewID("save_preset"), 0, 0, GameTextGetTranslatedOrNot("$mp_save_preset")))then
- if(preset_name ~= " " and preset_name ~= "_" and #preset_name > 0)then
- SavePreset(preset_name)
- RefreshPresets()
- end
- end
-
- if(GuiButton(menu_gui, NewID("open_presets_folder"), 0, 10, GameTextGetTranslatedOrNot("$mp_open_preset_folder")))then
- os.execute("explorer \"" .. gamemode_preset_folder_name .. "\"")
- end
-
- if(GuiButton(menu_gui, NewID("refresh_presets"), 0, 0, GameTextGetTranslatedOrNot("$mp_refresh_presets")))then
- RefreshPresets()
- end
-
- GuiText(menu_gui, 0, 0, "--------------------")
-
- for i, preset in ipairs(presets) do
- GuiLayoutBeginHorizontal(menu_gui, 0, 0)
-
- if(preset.default)then
- GuiColorSetForNextWidget( menu_gui, 0.5, 0.5, 0.5, 1.0 )
- if(GuiButton(menu_gui, NewID(), 0, 0, "[?]"))then
- -- nothing here
- end
- GuiTooltip(menu_gui, GameTextGetTranslatedOrNot("$mp_preset_default"), "")
- end
-
- if(preset.corrupt)then
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- if(GuiButton(menu_gui, NewID(), 0, 0, "[!]"))then
- -- nothing here
- end
- GuiTooltip(menu_gui, GameTextGetTranslatedOrNot("$mp_preset_corrupt"), "")
- end
-
- if(preset.data.version == nil or preset.data.version < MP_PRESET_VERSION)then
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- if(GuiButton(menu_gui, NewID(), 0, 0, "[!]"))then
- -- nothing here
- end
- GuiTooltip(menu_gui, GameTextGetTranslatedOrNot("$mp_preset_outdated"), "")
- end
-
- if((not preset.default) and GuiButton(menu_gui, NewID("remove_preset_"..tostring(preset.name)), 0, 0, GameTextGetTranslatedOrNot("$mp_remove_preset")))then
- popup.create("delete_preset_prompt", string.format(GameTextGetTranslatedOrNot("$mp_delete_preset_confirm"), preset.name),{
- {
- text = GameTextGetTranslatedOrNot("$mp_delete_preset_confirm_description"),
- color = {214 / 255, 60 / 255, 60 / 255, 1}
- },
- }, {
- {
- text = GameTextGetTranslatedOrNot("$mp_delete_preset_confirm_delete"),
- callback = function()
- RemovePreset(preset.name, preset.extension)
- RefreshPresets()
- end
- },
- {
- text = GameTextGetTranslatedOrNot("$mp_delete_preset_confirm_cancel"),
- callback = function()
- end
- }
- }, -6000)
-
- --[[
- RemovePreset(preset.name)
- RefreshPresets()
- ]]
- end
-
- if(GuiButton(menu_gui, NewID("load_preset_"..tostring(preset.name)), 0, 0, ((preset.corrupt and "[invalid]") or "") .. preset.name))then
-
- local data_copy_str = bitser.dumps(preset)
- local data_copy = bitser.loads(data_copy_str)
-
- preset = data_copy
-
- local preset_info = preset
-
-
-
- if(preset.data.version == nil or preset.data.version < MP_PRESET_VERSION)then
- preset_info = {
- outdated = true,
- name = preset.name,
- data = {
- version = preset.data.version or 1,
- settings = preset.data
- }
- }
- end
-
-
-
-
- gamemode_settings = preset_info.data.settings
-
- -- loop through
- for k, setting in ipairs(active_mode.settings or {})do
- if(gamemode_settings[setting.id] == nil)then
- gamemode_settings[setting.id] = setting.default
- print("Setting "..setting.id.." to default: "..tostring(setting.default))
- end
- end
-
-
- print("loaded: "..json.stringify(gamemode_settings))
-
-
-
- preset_name = preset_info.name
- --settings_changed = true
-
- for k, setting in ipairs(active_mode.settings or {})do
- steam_utils.TrySetLobbyData(lobby_code, "setting_"..setting.id, tostring(gamemode_settings[setting.id]))
- mp_log:print("Updated gamemode setting: "..setting.id.." to "..tostring(gamemode_settings[setting.id]))
- end
-
- --steam.matchmaking.sendLobbyChatMsg(lobby_code, "refresh")
- steam_utils.send("refresh", {}, steam_utils.messageTypes.AllPlayers, lobby_code, true, true)
-
- if(active_mode.load_preset)then
- active_mode.load_preset(lobby_code, preset_info.data)
- end
- end
-
- GuiLayoutEnd(menu_gui)
- end
-
-
- GuiLayoutEnd(menu_gui)
-
- end
- was_lobby_presets_open = true
-
- end,
- close = function()
- was_lobby_presets_open = false
- end
- },
- {
- id = "voice_volumes",
- name = "Voice Volumes",
- button_text = "Voice",
- draw = function(lobby, gui, new_id)
- local players = steam_utils.getLobbyMembers(lobby, true)
- local my_id = steam_utils.getSteamID()
- local box_w = 180
- local current_y = 0
-
- for _, v in pairs(players) do
- if v.id ~= my_id then
- local name = tostring(v.name)
- local key = "evaisa.mp.player_vol_" .. tostring(v.id)
- local cur_vol = tonumber(ModSettingGet(key)) or 1.0
-
- local label = name
- if #label > 18 then label = label:sub(1, 18) .. ".." end
-
- local lw, lh = GuiGetTextDimensions(gui, label)
- local box_h = lh + 16
- Gui9Piece(gui, function() return new_id("vc_vol_" .. tostring(v.id)) end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
- GuiText(gui, 4, current_y + 2, label)
-
- local new_vol = GuiSlider(gui, new_id("vc_vol_sl_" .. tostring(v.id)), 2, current_y + lh + 2, "", cur_vol, 0.0, 2.0, 1.0, 0.05, " ", 146)
-
- GuiColorSetForNextWidget(gui, 1, 1, 1, 0.7)
- GuiText(gui, 153, current_y + lh + 1, math.floor(new_vol * 100) .. "%")
-
- if math.abs(new_vol - cur_vol) > 0.01 then
- ModSettingSet(key, new_vol)
- end
-
- current_y = current_y + box_h + 2
- end
- end
-
- if current_y == 0 then
- GuiText(gui, 4, 0, "No other players")
- end
- end,
- }
-}
-lobby_menus = lobby_menus or {}
-
-function generate_lobby_menus_list()
- local new_lobby_menus = {}
-
- for i, v in ipairs(default_lobby_menus)do
- table.insert(new_lobby_menus, v)
- end
-
- local active_mode = FindGamemode(steam.matchmaking.getLobbyData(lobby_code, "gamemode"))
- if(active_mode ~= nil and active_mode.lobby_menus ~= nil)then
- for i, lobby_menu in ipairs(active_mode.lobby_menus)do
- table.insert(new_lobby_menus, lobby_menu)
- end
- end
-
- lobby_menus = new_lobby_menus
-end
-
-
-function custom_menu_close_callback_right()
- if(lobby_code ~= nil and active_lobby_menu_right ~= nil)then
- for i, lobby_menu in ipairs(lobby_menus)do
- if(lobby_menu.id == active_lobby_menu_right)then
- if(lobby_menu.close ~= nil)then
- lobby_menu.close()
- end
- end
- end
- end
-end
-
-function custom_menu_close_callback_left()
- if(lobby_code ~= nil and active_lobby_menu_left ~= nil)then
- for i, lobby_menu in ipairs(lobby_menus)do
- if(lobby_menu.id == active_lobby_menu_left)then
- if(lobby_menu.close ~= nil)then
- lobby_menu.close()
- end
- end
- end
- end
-end
-
-local windows = {
- {
- name = "Menu",
- func = function()
-
- local window_width = 200
- local window_height = 180
-
- local window_text = GameTextGetTranslatedOrNot("$mp_lobby_list_header")
-
- DrawWindow(menu_gui, -4000, screen_width / 2, screen_height / 2, window_width, window_height, window_text, true, function()
- GuiLayoutBeginVertical(menu_gui, 0, 0, true, 0, 0)
-
- if(GuiButton(menu_gui, NewID(), 0, 0, GameTextGetTranslatedOrNot("$mp_create_lobby")))then
- menu_status = status.creating_lobby
- end
-
- if(GuiButton(menu_gui, NewID(), 0, 0, GameTextGetTranslatedOrNot("$mp_join_with_code")))then
- menu_status = status.joining_lobby
- end
-
- GuiText(menu_gui, 2, 0, " ")
- if(GuiButton(menu_gui, NewID(), 0, 0, GameTextGetTranslatedOrNot("$mp_refresh_lobby_list")))then
- refreshLobbies()
- end
- GuiText(menu_gui, 2, 0, " ")
- if(lobby_filter_show_friends)then
- GuiText(menu_gui, 2, 0, "----- "..GameTextGetTranslatedOrNot("$mp_friend_lobbies").." -----")
- if(#lobbies.friend > 0)then
- for k, v in ipairs(lobbies.friend)do
- if(steam.matchmaking.requestLobbyData(v))then
- local lobby_mode_id = steam.matchmaking.getLobbyData(v, "gamemode")
- local active_mode = FindGamemode(steam.matchmaking.getLobbyData(v, "gamemode"))
- local lobby_name = steam.matchmaking.getLobbyData(v, "name")
- local custom_lobby_string = (active_mode and active_mode.custom_lobby_string) and active_mode.custom_lobby_string(v) or ""
-
- if(custom_lobby_string ~= "")then
- custom_lobby_string = custom_lobby_string .. " "
- end
-
- local lobby_members = steam.matchmaking.getNumLobbyMembers(v)
- local lobby_max_players = steam.matchmaking.getLobbyMemberLimit(v)
-
- if(lobby_name ~= nil and active_mode ~= nil and lobby_mode_id ~= nil and lobby_members ~= nil and lobby_max_players ~= nil and (lobby_filter_show_full or lobby_members < lobby_max_players) and (lobby_filter_max_players == 0 or lobby_max_players == lobby_filter_max_players))then
- GuiLayoutBeginHorizontal(menu_gui, 0, 0, true, 0, 0)
- if(not IsCorrectVersion(v))then
- --[[
- if(GuiButton(menu_gui, NewID(), 0, 0, GameTextGetTranslatedOrNot("$mp_version_mismatch").." "..lobby_name))then
- steam_utils.Leave(v)
- steam.matchmaking.joinLobby(v, function(e)
- end)
- end
- ]]
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- if(GuiButton(menu_gui, NewID(), 0, 0, "[?]"))then
- -- nothing here
- end
- CustomTooltip(menu_gui, function()
-
- local info = VersionInfo(v)
-
- --GuiZSetForNextWidget(menu_gui, -6110)
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- --GuiText(menu_gui, 0, 0, "Hide Code")
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, GameTextGetTranslatedOrNot("$mp_version_mismatch"))
-
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, info.mp_version_string)
- if(not info.mp_version_same)then
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, info.mp_version_string_user)
- end
-
- GuiText(menu_gui, 0, 0, " ")
-
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, info.gamemode_version_string)
- if(not info.gamemode_missing and not info.gamemode_version_same)then
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, info.gamemode_version_string_user)
- end
-
- -- game version
- GuiText(menu_gui, 0, 0, " ")
-
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, info.game_version_string)
- if(not info.game_version_same)then
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, info.game_version_string_user)
- end
-
-
- end, -6200, 0, 0)
-
- GuiZSetForNextWidget(menu_gui, -6000)
- GuiColorSetForNextWidget( menu_gui, 0.5, 0.5, 0.5, 1 )
- GuiText(menu_gui, 0, 0, "("..tostring(lobby_members).."/"..tostring(lobby_max_players)..") "..custom_lobby_string..lobby_name)
-
- else
- if(active_mode ~= nil)then
-
- if(HasRequiredMods(v))then
- GuiZSetForNextWidget(menu_gui, -6000)
- if(GuiButton(menu_gui, NewID(), 0, 0, "("..tostring(lobby_members).."/"..tostring(lobby_max_players)..") "..custom_lobby_string..lobby_name))then
- steam_utils.Leave(v)
- steam.matchmaking.joinLobby(v, function(e)
- end)
- end
- else
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- if(GuiButton(menu_gui, NewID(), 0, 0, "[?]"))then
-
- end
- CustomTooltip(menu_gui, function()
- local info = ModInfo(v)
-
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- --GuiText(menu_gui, 0, 0, "Hide Code")
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, GameTextGetTranslatedOrNot("$mp_lobby_info_missing_mods"))
-
- local strings = split_message(info.missing_mods_string, 200) or {}
-
- for k, v in ipairs(strings)do
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, v)
- end
-
- end, -6200, 0, 0)
-
- GuiZSetForNextWidget(menu_gui, -6000)
- GuiColorSetForNextWidget( menu_gui, 0.5, 0.5, 0.5, 1 )
- GuiText(menu_gui, 0, 0, "("..tostring(lobby_members).."/"..tostring(lobby_max_players)..") "..custom_lobby_string..lobby_name)
- end
- else
- --[[if(GuiButton(menu_gui, NewID(), 0, 0, "("..lobby_mode_id..""..GameTextGetTranslatedOrNot("$mp_missing")..")("..tostring(lobby_members).."/"..tostring(lobby_max_players)..") "..lobby_name))then
- steam_utils.Leave(v)
- steam.matchmaking.joinLobby(v, function(e)
- end)
- end]]
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- if(GuiButton(menu_gui, NewID(), 0, 0, "[?]"))then
-
- end
- CustomTooltip(menu_gui, function()
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- --GuiText(menu_gui, 0, 0, "Hide Code")
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, GameTextGetTranslatedOrNot("$mp_missing"))
-
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, string.format(GameTextGetTranslatedOrNot("mp_lobby_info_gm_missing"), lobby_mode_id, steam.matchmaking.getLobbyData(VersionInfo, "version")))
-
- end, -6200, 0, 0)
-
- GuiZSetForNextWidget(menu_gui, -6000)
- GuiColorSetForNextWidget( menu_gui, 0.5, 0.5, 0.5, 1 )
- GuiText(menu_gui, 0, 0, "("..tostring(lobby_members).."/"..tostring(lobby_max_players)..") "..custom_lobby_string..lobby_name)
- end
- end
-
- GuiLayoutEnd(menu_gui)
- end
- end
- end
- else
- GuiText(menu_gui, 2, 0, GameTextGetTranslatedOrNot("$mp_no_lobbies_found"))
- end
- end
- GuiText(menu_gui, 2, 0, " ")
- if(lobby_filter_show_public)then
- GuiText(menu_gui, 2, 0, "----- "..GameTextGetTranslatedOrNot("$mp_public_lobbies").." -----")
- if(#lobbies.public > 0)then
- for k, v in ipairs(lobbies.public)do
- local lobby_mode_id = steam.matchmaking.getLobbyData(v, "gamemode")
- local active_mode = FindGamemode(steam.matchmaking.getLobbyData(v, "gamemode"))
- local lobby_name = steam.matchmaking.getLobbyData(v, "name")
- local custom_lobby_string = (active_mode and active_mode.custom_lobby_string) and active_mode.custom_lobby_string(v) or ""
-
- if(custom_lobby_string ~= "")then
- custom_lobby_string = custom_lobby_string .. " "
- end
-
- local lobby_members = steam.matchmaking.getNumLobbyMembers(v)
- local lobby_max_players = steam.matchmaking.getLobbyMemberLimit(v)
-
- if(lobby_name ~= nil and active_mode ~= nil and lobby_mode_id ~= nil and lobby_members ~= nil and lobby_max_players ~= nil and (lobby_filter_show_full or lobby_members < lobby_max_players) and (lobby_filter_max_players == 0 or lobby_max_players == lobby_filter_max_players))then
- GuiLayoutBeginHorizontal(menu_gui, 0, 0, true, 0, 0)
- if(not IsCorrectVersion(v))then
- --[[if(GuiButton(menu_gui, NewID(), 0, 0, GameTextGetTranslatedOrNot("$mp_version_mismatch").." "..lobby_name))then
- steam_utils.Leave(v)
- steam.matchmaking.joinLobby(v, function(e)
- end)
- end]]
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- if(GuiButton(menu_gui, NewID(), 0, 0, "[?]"))then
- -- nothing here
- end
- CustomTooltip(menu_gui, function()
-
- local info = VersionInfo(v)
-
- --GuiZSetForNextWidget(menu_gui, -6110)
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- --GuiText(menu_gui, 0, 0, "Hide Code")
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, GameTextGetTranslatedOrNot("$mp_version_mismatch"))
-
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, info.mp_version_string)
- if(not info.mp_version_same)then
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, info.mp_version_string_user)
- end
-
- GuiText(menu_gui, 0, 0, " ")
-
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, info.gamemode_version_string)
- if(not info.gamemode_missing and not info.gamemode_version_same)then
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, info.gamemode_version_string_user)
- end
-
- -- game version
- GuiText(menu_gui, 0, 0, " ")
-
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, info.game_version_string)
- if(not info.game_version_same)then
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, info.game_version_string_user)
- end
-
-
- end, -6200, 0, 0)
-
- GuiZSetForNextWidget(menu_gui, -6000)
- GuiColorSetForNextWidget( menu_gui, 0.5, 0.5, 0.5, 1 )
- GuiText(menu_gui, 0, 0, "("..tostring(lobby_members).."/"..tostring(lobby_max_players)..") "..custom_lobby_string..lobby_name)
- else
- if(active_mode ~= nil)then
- if(HasRequiredMods(v))then
- GuiZSetForNextWidget(menu_gui, -6000)
- if(GuiButton(menu_gui, NewID(), 0, 0, "("..tostring(lobby_members).."/"..tostring(lobby_max_players)..") "..custom_lobby_string..lobby_name))then
- steam_utils.Leave(v)
- steam.matchmaking.joinLobby(v, function(e)
- end)
- end
- else
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- if(GuiButton(menu_gui, NewID(), 0, 0, "[?]"))then
-
- end
- CustomTooltip(menu_gui, function()
- local info = ModInfo(v)
-
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- --GuiText(menu_gui, 0, 0, "Hide Code")
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, GameTextGetTranslatedOrNot("$mp_lobby_info_missing_mods"))
-
- local strings = split_message(info.missing_mods_string, 200) or {}
-
- for k, v in ipairs(strings)do
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, v)
- end
-
- end, -6200, 0, 0)
-
- GuiZSetForNextWidget(menu_gui, -6000)
- GuiColorSetForNextWidget( menu_gui, 0.5, 0.5, 0.5, 1 )
- GuiText(menu_gui, 0, 0, "("..tostring(lobby_members).."/"..tostring(lobby_max_players)..") "..custom_lobby_string..lobby_name)
- end
- else
- --[[if(GuiButton(menu_gui, NewID(), 0, 0, "("..lobby_mode_id..GameTextGetTranslatedOrNot("$mp_missing")..")("..tostring(lobby_members).."/"..tostring(lobby_max_players)..") "..lobby_name))then
-
- end]]
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- if(GuiButton(menu_gui, NewID(), 0, 0, "[?]"))then
-
- end
- CustomTooltip(menu_gui, function()
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- --GuiText(menu_gui, 0, 0, "Hide Code")
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, GameTextGetTranslatedOrNot("$mp_missing"))
-
- GuiColorSetForNextWidget( menu_gui, 0.8, 0.8, 0.8, 1.0 )
- GuiZSetForNextWidget(menu_gui, -6210)
- GuiText(menu_gui, 0, 0, string.format(GameTextGetTranslatedOrNot("mp_lobby_info_gm_missing"), lobby_mode_id, steam.matchmaking.getLobbyData(VersionInfo, "version")))
-
- end, -6200, 0, 0)
-
- GuiZSetForNextWidget(menu_gui, -6000)
- GuiColorSetForNextWidget( menu_gui, 0.5, 0.5, 0.5, 1 )
- GuiText(menu_gui, 0, 0, "("..tostring(lobby_members).."/"..tostring(lobby_max_players)..") "..custom_lobby_string..lobby_name)
- end
- end
-
-
- GuiLayoutEnd(menu_gui)
- end
- end
- else
- GuiText(menu_gui, 2, 0, GameTextGetTranslatedOrNot("$mp_no_lobbies_found"))
- end
- end
-
-
- --[[
- for i = 1, 40 do
- GuiText(menu_gui, 2, 0, " ")
- end
- ]]
-
- GuiLayoutEnd(menu_gui)
- end, function()
- gui_closed = true;
- invite_menu_open = false
- selected_player = nil
- end, "main_menu_gui")
-
- local filter_panel_width = 160
- DrawWindow(menu_gui, -4000, (screen_width / 2 - window_width / 2) - (filter_panel_width / 2) - 10, screen_height / 2, filter_panel_width, window_height, "Filters", true, function()
- GuiLayoutBeginVertical(menu_gui, 0, 0, true, 0, 0)
- local chk = function(val) return val and "[X]" or "[ ]" end
-
- if(GuiButton(menu_gui, NewID("LobbyFilter"), 0, 0, chk(lobby_filter_show_full) .. " Show Full"))then
- lobby_filter_show_full = not lobby_filter_show_full
- end
- if(GuiButton(menu_gui, NewID("LobbyFilter"), 0, 0, chk(lobby_filter_show_friends) .. " Friends"))then
- lobby_filter_show_friends = not lobby_filter_show_friends
- end
- if(GuiButton(menu_gui, NewID("LobbyFilter"), 0, 0, chk(lobby_filter_show_public) .. " Public"))then
- lobby_filter_show_public = not lobby_filter_show_public
- end
-
- GuiText(menu_gui, 2, 0, " ")
-
- local distance_order = {"close", "default", "far", "worldwide"}
- if(GuiButton(menu_gui, NewID("LobbyFilter"), 0, 0, "Dist: " .. distance[lobby_filter_distance]))then
- for i, d in ipairs(distance_order) do
- if(d == lobby_filter_distance)then
- lobby_filter_distance = distance_order[(i % #distance_order) + 1]
- refreshLobbies()
- break
- end
- end
- end
-
- GuiText(menu_gui, 2, 0, " ")
-
- local max_str = lobby_filter_max_players == 0 and "Any" or tostring(lobby_filter_max_players)
- GuiText(menu_gui, 2, 0, "Players: " .. max_str)
- local slider_val = GuiSlider(menu_gui, NewID("LobbyFilter"), 4, 0, "", lobby_filter_max_players, 0, 32, 0, 1, " $0", 120)
- lobby_filter_max_players = math.floor(slider_val)
-
- GuiLayoutEnd(menu_gui)
- end, nil, "lobby_filter_panel")
-
- end
- },
- {
- name = "Lobby",
- func = function()
- local window_width = 200
- local window_height = 280
-
-
- function string_to_number(str)
- local num = 0
- local validCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
- local str_len = #validCharacters
- for i=1, str_len do
- local ch = str:sub(i, i)
- local value = validCharacters:find(ch)
- value = value - 1
- num = num + math.pow(str_len, (#str - i)) * value
- end
- return num
- end
-
- if(not lobby_code)then
- -- force return to main menu
- print("Disconnected from lobby?? (no lobby code)")
- gui_closed = false
- gamemode_settings = {}
- initial_refreshes = 10
- invite_menu_open = false
- menu_status = status.main_menu
- show_lobby_code = false
- lobby_code = nil
- banned_members = {}
- return;
- end
-
- local window_width, x_pos = GetMenuSettings("center")
-
- DrawWindow(menu_gui, -5000, x_pos, screen_height / 2, window_width, window_height, function()
-
- GuiColorSetForNextWidget( menu_gui, 0, 0, 0, 0.3 )
- GuiText(menu_gui, 0, 0, GameTextGetTranslatedOrNot("$mp_lobby").." - ("..((not show_lobby_code) and censorString(steam.utils.compressSteamID(lobby_code)) or steam.utils.compressSteamID(lobby_code))..")")
-
- GuiColorSetForNextWidget( menu_gui, (74 / 2) / 255, (62 / 2) / 255, (46 / 2) / 255, 0.5 )
- --GuiImage(menu_gui, NewID("Lobby"), 1, 1.5, (show_lobby_code) and "mods/evaisa.mp/files/gfx/ui/hide.png" or "mods/evaisa.mp/files/gfx/ui/show.png", 0.5, 1)
-
-
- GuiColorSetForNextWidget( menu_gui, 74 / 255, 62 / 255, 46 / 255, 0.5 )
- if(GuiImageButton(menu_gui, NewID("Lobby"), 1, 1.5, "", (show_lobby_code) and "mods/evaisa.mp/files/gfx/ui/hide.png" or "mods/evaisa.mp/files/gfx/ui/show.png"))then
- show_lobby_code = not show_lobby_code
- GamePlaySound("data/audio/Desktop/ui.bank", "ui/button_click", 0, 0)
- end
-
- if(show_lobby_code)then
- CustomTooltip(menu_gui, function()
- --GuiZSetForNextWidget(menu_gui, -5110)
- GuiColorSetForNextWidget( menu_gui, 1, 1, 1, 0.8 )
- --GuiText(menu_gui, 0, 0, "Hide Code")
- GuiZSetForNextWidget(menu_gui, -5110)
- GuiText(menu_gui, 0, 0, GameTextGetTranslatedOrNot("$mp_hide_tooltip"))
- end, -5100, -60, -20)
- else
- CustomTooltip(menu_gui, function()
- --GuiZSetForNextWidget(menu_gui, -5110)
- GuiColorSetForNextWidget( menu_gui, 1, 1, 1, 0.8 )
- --GuiText(menu_gui, 0, 0, "Show Code")
- GuiZSetForNextWidget(menu_gui, -5110)
- GuiText(menu_gui, 0, 0, GameTextGetTranslatedOrNot("$mp_show_tooltip"))
- end, -5100, -68, -20)
- end
-
-
- --GuiImage(menu_gui, NewID("Lobby"), 6, 1.5, "mods/evaisa.mp/files/gfx/ui/copy.png", 0.5, 1)
-
- --[[GuiColorSetForNextWidget( menu_gui, 0, 0, 0, 0.5 )
- if(GuiButton(menu_gui, NewID("Lobby"), -1, 0, " "..GameTextGetTranslatedOrNot("$mp_copy")))then
- steam.utils.setClipboard(steam.utils.compressSteamID(lobby_code))
- end]]
-
- GuiColorSetForNextWidget( menu_gui, 74 / 255, 62 / 255, 46 / 255, 0.5 )
- if(GuiImageButton(menu_gui, NewID("Lobby"), 6, 1.5, "", "mods/evaisa.mp/files/gfx/ui/copy.png"))then
- steam.utils.setClipboard(steam.utils.compressSteamID(lobby_code))
- GamePlaySound("data/audio/Desktop/ui.bank", "ui/button_click", 0, 0)
- end
-
- CustomTooltip(menu_gui, function()
- --GuiZSetForNextWidget(menu_gui, -5110)
- GuiColorSetForNextWidget( menu_gui, 1, 1, 1, 0.8 )
- --GuiText(menu_gui, 0, 0, "Show Code")
- GuiZSetForNextWidget(menu_gui, -5110)
- GuiText(menu_gui, 0, 0, GameTextGetTranslatedOrNot("$mp_copy_tooltip"))
- end, -5100, -180, -20)
-
- end, true, function(window_x, window_y, window_width, window_height)
-
-
-
- local owner = steam.matchmaking.getLobbyOwner(lobby_code)
-
-
-
- --local _, _, _, _, _, width, height = GuiGetPreviousWidgetInfo(menu_gui)
-
- local current_button_height = 0
-
- -- old presets stuff
-
- --local lobby_presets_translation = GameTextGetTranslatedOrNot("$mp_lobby_presets")
- --local lobby_presets_button_text = lobby_presets_open and lobby_presets_translation.." >" or lobby_presets_translation.." <"
- --local text_width, text_height = GuiGetTextDimensions(menu_gui, lobby_presets_button_text)
- --current_button_height = current_button_height + text_height
- --local button_x_position = window_width - text_width
- GuiLayoutBeginVertical(menu_gui, 0, 0, true, 0, 0)
- --[[if(GuiButton(menu_gui, NewID("lobby_presets_button"), button_x_position, 0, lobby_presets_button_text))then
- lobby_presets_open = not lobby_presets_open
- custom_menu_close_callback()
- active_lobby_menu_right = nil
- selected_player = nil
- end]]
-
-
- --current_button_offset = current_button_offset + text_height
-
- if(lobby_menus ~= nil)then
- for i, lobby_menu in ipairs(lobby_menus)do
- if((lobby_menu.button_location == nil or lobby_menu.button_location == "main_window") and not lobby_menu.menu_left)then
- local button_string = GameTextGetTranslatedOrNot(lobby_menu.button_text)
-
- local truncate_chars = 20
- local truncate_string = button_string
- if(#button_string > truncate_chars)then
- truncate_string = utf8.sub(button_string, 1, truncate_chars).."..."
- end
-
- local actual_string = button_string
- if(last_button_hovered ~= lobby_menu.id)then
- actual_string = truncate_string
- end
-
-
- local button_text = active_lobby_menu_right == lobby_menu.id and actual_string.." >" or actual_string.." <"
-
- local text_width, text_height = GuiGetTextDimensions(menu_gui, button_text)
- button_x_position = window_width - text_width
- current_button_height = current_button_height + text_height
- if(GuiButton(menu_gui, NewID("lobby_menu_"..lobby_menu.id), button_x_position, 0, button_text))then
- if(active_lobby_menu_right == lobby_menu.id)then
- custom_menu_close_callback_right()
- active_lobby_menu_right = nil
- else
- custom_menu_close_callback_right()
- active_lobby_menu_right = lobby_menu.id
- end
-
- lobby_presets_open = false
- selected_player = nil
- end
-
- local _, _, hover = GuiGetPreviousWidgetInfo(menu_gui)
- if(hover)then
- --print("Hovering over: "..lobby_menu.id)
- last_button_hovered = lobby_menu.id
- end
- --current_button_offset = current_button_offset + text_height
- end
- end
- end
- GuiLayoutEnd(menu_gui)
-
- GuiLayoutBeginVertical(menu_gui, 0, 0, true, 0, 0)
-
-
- if(GuiButton(menu_gui, NewID("lobby_leave_button"), 0, 0, GameTextGetTranslatedOrNot("$mp_leave_lobby")))then
- steam_utils.Leave(lobby_code)
- return
- end
-
-
- local invite_translation = GameTextGetTranslatedOrNot("$mp_invite_players")
- if(GuiButton(menu_gui, NewID("lobby_invite_button"), 0, 0, invite_translation) and GameGetFrameNum() > (last_frame_overlay or 0) + 80)then
- -- need to delay this or noita gets angry??
- --steam.friends.activateGameOverlayInviteDialog(lobby_code)
- delay.new(5, function()
- steam.friends.activateGameOverlay("friends")
- end)
- last_frame_overlay = GameGetFrameNum()
- print("Opening invite menu")
- end
-
- if(lobby_menus ~= nil)then
- for i, lobby_menu in ipairs(lobby_menus)do
- if((lobby_menu.button_location == nil or lobby_menu.button_location == "main_window") and lobby_menu.menu_left)then
- local button_text = active_lobby_menu_left == lobby_menu.id and "< "..GameTextGetTranslatedOrNot(lobby_menu.button_text) or "> "..GameTextGetTranslatedOrNot(lobby_menu.button_text)
- local text_width, text_height = GuiGetTextDimensions(menu_gui, button_text)
- current_button_height = current_button_height + text_height
- if(GuiButton(menu_gui, NewID("lobby_menu_"..lobby_menu.id), 0, 0, button_text))then
- if(active_lobby_menu_left == lobby_menu.id)then
- custom_menu_close_callback_left()
- active_lobby_menu_left = nil
- else
- custom_menu_close_callback_left()
- active_lobby_menu_left = lobby_menu.id
- end
-
- selected_player = nil
- end
- --current_button_offset = current_button_offset + text_height
- end
- end
- end
-
- --[[
- local lobby_settings_translation = GameTextGetTranslatedOrNot("$mp_lobby_settings")
- if(GuiButton(menu_gui, NewID("lobby_settings_button"), 0, 0, lobby_settings_open and "< "..lobby_settings_translation or "> "..lobby_settings_translation))then
- lobby_settings_open = not lobby_settings_open
- invite_menu_open = false
- end
- ]]
-
- -- calculate relative offset from window_y
- local relative_offset = 33
-
- --GamePrint("relative_offset: "..tostring(relative_offset).."; current_button_height: "..tostring(current_button_height))
-
- local tw, th = GuiGetTextDimensions(menu_gui, "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
-
- local extra_offset = 0
- if(active_mode and active_mode.enable_spectator)then
- extra_offset = extra_offset + th
- end
-
- if(owner == steam_utils.getSteamID())then
- extra_offset = extra_offset + th
- end
-
- local lobby_in_progress = steam.matchmaking.getLobbyData(lobby_code, "in_progress") == "true"
-
- if(lobby_in_progress and not in_game)then
- extra_offset = extra_offset + th
- end
-
-
- local offset = 0
- if(current_button_height > relative_offset)then
- offset = current_button_height
- if(extra_offset < current_button_height - relative_offset)then
- offset = offset - extra_offset
- else
- offset = relative_offset
- end
- else
- offset = relative_offset
- end
-
- GuiLayoutEnd(menu_gui)
-
- GuiLayoutBeginVertical(menu_gui, 0, offset, true, 0, 0)
-
- local active_mode = FindGamemode(steam.matchmaking.getLobbyData(lobby_code, "gamemode"))
- local spectating = steamutils.IsSpectator(lobby_code)
-
-
-
- if(active_mode and active_mode.enable_spectator)then
- local is_busy = false
- local busy_reason = ""
- if(active_mode.custom_spectator_check)then
- local can_spectate, reason = active_mode.custom_spectator_check(lobby_code)
- if(not can_spectate)then
- GuiOptionsAddForNextWidget(menu_gui, GUI_OPTION.NonInteractive)
- GuiColorSetForNextWidget( menu_gui, 0.5, 0.5, 0.5, 1 )
- is_busy = true
- busy_reason = reason
- end
- end
- if(GuiButton(menu_gui, NewID("lobby_spectate_button"), 0, 0, spectating and GameTextGetTranslatedOrNot("$mp_spectator_mode_enabled")..(active_mode.spectator_unfinished_warning and " [Unfinished]" or "") or GameTextGetTranslatedOrNot("$mp_spectator_mode_disabled")..(active_mode.spectator_unfinished_warning and " [Unfinished]" or "")))then
- if(owner == steam_utils.getSteamID())then
- steam_utils.TrySetLobbyData(lobby_code, tostring(steam_utils.getSteamID()).."_spectator", spectating and "false" or "true")
-
- if(lobby_gamemode and game_in_progress)then
- in_game = true
- game_in_progress = true
-
- steam.matchmaking.setLobbyMemberData(lobby_code, "in_game", "true")
-
- gui_closed = true
-
- if(spectating)then
- mp_log:print("Checking if gamemode has spectate function")
- if(lobby_gamemode.spectate ~= nil)then
- mp_log:print("Starting gamemode in spectator mode")
- lobby_gamemode.spectate(lobby_code, true)
- elseif(lobby_gamemode.start ~= nil)then
- mp_log:print("Starting gamemode")
- lobby_gamemode.start(lobby_code, true)
- end
- else
- mp_log:print("Checking if gamemode has start function")
- if(lobby_gamemode.start ~= nil)then
- mp_log:print("Starting gamemode")
- lobby_gamemode.start(lobby_code, true)
- end
- end
- end
-
-
- else
- --steam.matchmaking.sendLobbyChatMsg(lobby_code, "spectate")
- steam_utils.send("spectate", {}, steam_utils.messageTypes.AllPlayers, lobby_code, true, true)
-
- is_awaiting_spectate = true
-
- delay.new(function()
- return steamutils.IsSpectator(lobby_code) ~= spectating
- end, function()
- is_awaiting_spectate = false
- if(lobby_gamemode and game_in_progress)then
- in_game = true
-
- steam.matchmaking.setLobbyMemberData(lobby_code, "in_game", "true")
-
- game_in_progress = true
-
- gui_closed = true
-
- if(spectating)then
- mp_log:print("Checking if gamemode has spectate function")
- if(lobby_gamemode.spectate ~= nil)then
- mp_log:print("Starting gamemode in spectator mode")
- lobby_gamemode.spectate(lobby_code, true)
- elseif(lobby_gamemode.start ~= nil)then
- mp_log:print("Starting gamemode")
- lobby_gamemode.start(lobby_code, true)
- end
- else
- mp_log:print("Checking if gamemode has start function")
- if(lobby_gamemode.start ~= nil)then
- mp_log:print("Starting gamemode")
- lobby_gamemode.start(lobby_code, true)
- end
- end
- end
- end)
- end
- end
- if(is_busy)then
- GuiTooltip(menu_gui, busy_reason, "")
- end
- end
-
-
- GuiText(menu_gui, 0, -6, " ")
-
-
- if(owner == steam_utils.getSteamID())then
-
- local start_string = GameTextGetTranslatedOrNot("$mp_start_game")
- if(steam.matchmaking.getLobbyData(lobby_code, "in_progress") == "true")then
- start_string = GameTextGetTranslatedOrNot("$mp_restart_game")
- end
-
- if(GuiButton(menu_gui, NewID("lobby_start_button"), 0, 0, start_string ))then
- gui_closed = not gui_closed
- invite_menu_open = false
-
- local start_data = {}
-
- if(active_mode and active_mode.start_data)then
- start_data = active_mode.start_data(lobby_code)
- end
-
- if(steam.matchmaking.getLobbyData(lobby_code, "in_progress") == "true")then
- --steam.matchmaking.sendLobbyChatMsg(lobby_code, "restart")
- steam_utils.send("restart", start_data, steam_utils.messageTypes.AllPlayers, lobby_code, true, true, 0)
- else
- --steam.matchmaking.sendLobbyChatMsg(lobby_code, "start")
- steam_utils.send("start", start_data, steam_utils.messageTypes.AllPlayers, lobby_code, true, true, 0)
- end
- steam_utils.TrySetLobbyData(lobby_code, "in_progress", "true")
- end
- end
-
- spectating = steamutils.IsSpectator(lobby_code)
-
- --print(tostring(spectating))
-
-
- local custom_enter_check = true
- local custom_enter_string = ""
- if(active_mode and active_mode.custom_enter_check)then
- custom_enter_check, custom_enter_string = active_mode.custom_enter_check(lobby_code)
- end
- if(lobby_in_progress and not in_game)then
- if(custom_enter_check)then
- if GuiButton(menu_gui, NewID("lobby_enter_button"), 0, 0, GameTextGetTranslatedOrNot("$mp_enter_game")) then
-
- local active_mode = FindGamemode(steam.matchmaking.getLobbyData(lobby_code, "gamemode"))
-
- mp_log:print("Attempting to load into gamemode: "..(active_mode and active_mode.name or "UNKNOWN"))
-
- if(active_mode)then
- local lobby_data_count = steam.matchmaking.getLobbyDataCount(lobby_code)
- for i = 1, lobby_data_count do
- local data = steam.matchmaking.getLobbyDataByIndex(lobby_code, i -1 )
-
- if(cached_lobby_data[data.key] ~= data.value)then
- cached_lobby_data[data.key] = data.value
- end
- debug_log:print("Lobby Data: ["..tostring(data.key).."] = "..tostring(data.value))
- end
-
- in_game = true
- steam.matchmaking.setLobbyMemberData(lobby_code, "in_game", "true")
-
- game_in_progress = true
-
- gui_closed = true
-
- mp_log:print("Attempting to start gamemode")
- if(spectating)then
- mp_log:print("Checking if gamemode has spectate function")
- if(active_mode.spectate ~= nil)then
- mp_log:print("Starting gamemode in spectator mode")
- active_mode.spectate(lobby_code, true)
- elseif(active_mode.start ~= nil)then
- mp_log:print("Starting gamemode")
- active_mode.start(lobby_code, true)
- end
- else
- mp_log:print("Checking if gamemode has start function")
- if(active_mode.start ~= nil)then
- mp_log:print("Starting gamemode")
- active_mode.start(lobby_code, true)
- end
- end
-
-
- end
- end
- else
- GuiColorSetForNextWidget( menu_gui, 0.5, 0.5, 0.5, 1 )
- GuiText(menu_gui, 0, 0, GameTextGetTranslatedOrNot("$mp_enter_game"))
- GuiTooltip(menu_gui, custom_enter_string, "")
- end
- end
-
-
- GuiText(menu_gui, 2, 0, "--------------------")
- local players = steam_utils.getLobbyMembers(lobby_code, true)
-
- for k, v in pairs(players) do
- GuiLayoutBeginHorizontal(menu_gui, 0, 0, true, 0, 0)
-
- local extra_x = 0
- local alpha = 1
- if(v.is_spectator)then
- alpha = 0.5
- extra_x = 0
- GuiImage(menu_gui, NewID("lobby_player"), 0, 0, "mods/evaisa.mp/files/gfx/ui/spectator.png", 1, 1, 1, 0)
- GuiTooltip(menu_gui, GameTextGetTranslatedOrNot("$mp_spectator_hover"), "")
- end
-
-
- GuiImage(menu_gui, NewID("lobby_player"), extra_x, 0, steam_utils.getUserAvatar(v.id), alpha, 10 / 32, 10 / 32, 0)
-
- if(v.id ~= steam_utils.getSteamID() and owner == steam_utils.getSteamID())then
- if(GuiButton(menu_gui, NewID("lobby_player"), 2, 0, GameTextGetTranslatedOrNot("$mp_kick")))then
- steam.matchmaking.kickUserFromLobby(lobby_code, v.id, GameTextGetTranslatedOrNot("$mp_kick_notification"))
- end
- if(GuiButton(menu_gui, NewID("lobby_player"), 0, 0, GameTextGetTranslatedOrNot("$mp_ban")))then
-
- popup.create("ban_player_blacklist", GameTextGetTranslatedOrNot("$mp_blacklist_player"),
- {
- GameTextGetTranslatedOrNot("$mp_blacklist_player_description"),
- {
- text = GameTextGetTranslatedOrNot("$mp_blacklist_player_description_2"),
- color = {214 / 255, 60 / 255, 60 / 255, 1}
- },
- }, {
- {
- text = GameTextGetTranslatedOrNot("$mp_blacklist_player_option_1"),
- callback = function()
- steam.matchmaking.kickUserFromLobby(lobby_code, v.id, GameTextGetTranslatedOrNot("$mp_ban_notification"))
- steam_utils.TrySetLobbyData(lobby_code, "banned_"..tostring(v.id), "true")
- banned_members[tostring(v.id)] = true
- end
- },
- {
- text = GameTextGetTranslatedOrNot("$mp_blacklist_player_option_2"),
- callback = function()
- steam.matchmaking.kickUserFromLobby(lobby_code, v.id, GameTextGetTranslatedOrNot("$mp_ban_notification"))
- steam_utils.TrySetLobbyData(lobby_code, "banned_"..tostring(v.id), "true")
- banned_members[tostring(v.id)] = true
- steam_utils.BlacklistPlayer(v.id)
- end
- },
- {
- text = GameTextGetTranslatedOrNot("$mp_blacklist_player_option_3"),
- callback = function()
- -- nothing!!
- end
- }
- }, -6000)
-
- --[[
- steam.matchmaking.kickUserFromLobby(lobby_code, v.id, GameTextGetTranslatedOrNot("$mp_ban_notification"))
- steam_utils.TrySetLobbyData(lobby_code, "banned_"..tostring(v.id), "true")
- banned_members[tostring(v.id)] = true
- ]]
-
- end
- if(GuiButton(menu_gui, NewID("lobby_player"), 0, 0, GameTextGetTranslatedOrNot("$mp_owner")))then
- steam.matchmaking.setLobbyOwner(lobby_code, v.id)
- banned_members = {}
- end
- end
-
- if(v.id == owner)then
- GuiImage(menu_gui, NewID("lobby_player"), 2, -3, "mods/evaisa.mp/files/gfx/ui/crown.png", 1, 1, 1, 0)
- --selected_player
- if(selected_player == v.id)then
- GuiColorSetForNextWidget( menu_gui, 1, 1, 0.2, alpha )
- else
- GuiColorSetForNextWidget( menu_gui, 1, 1, 1, alpha )
- end
- if(GuiButton(menu_gui, NewID("lobby_player"), -5, 0, tostring(v.name)))then
- lobby_presets_open = false
- custom_menu_close_callback_right()
- active_lobby_menu_right = nil
- if(selected_player == v.id)then
- selected_player = nil
- else
- selected_player = v.id
- end
- end
- else
- if(selected_player == v.id)then
- GuiColorSetForNextWidget( menu_gui, 1, 1, 0.2, alpha )
- else
- GuiColorSetForNextWidget( menu_gui, 1, 1, 1,alpha )
- end
-
- if(GuiButton(menu_gui, NewID("lobby_player"), 2, 0, tostring(v.name)))then
- lobby_presets_open = false
- custom_menu_close_callback_right()
- active_lobby_menu_right = nil
- if(selected_player == v.id)then
- selected_player = nil
- else
- selected_player = v.id
- end
- end
- end
-
- --[[
- local player_mod_data = getLobbyUserData(lobby_code, v.id) or {}
-
- CustomTooltip(menu_gui, function()
- for k, v in pairs(player_mod_data) do
- GuiColorSetForNextWidget( menu_gui, 1, 1, 1, 0.8 )
- GuiZSetForNextWidget(menu_gui, -5110)
- GuiText(menu_gui, 0, 0, v.name .. " ( "..v.id.." )")
- end
- end, -5100, 0, 0)
- ]]
-
- GuiLayoutEnd(menu_gui)
-
- --GuiLayoutEnd(menu_gui)
- GuiText(menu_gui, 0, -6, " ")
- end
-
- --[[
- for i = 1, 40 do
- GuiText(menu_gui, 2, 0, " ")
- end
- ]]
-
- GuiLayoutEnd(menu_gui)
- end, function()
- gui_closed = true;
- invite_menu_open = false
- end, "lobby_gui")
-
- if(invite_menu_open)then
-
- friendfilters_ingame = friendfilters_ingame or false
- friendfilters_inlobby = friendfilters_inlobby or false
- friendfilters_offline = friendfilters_offline or false
- friendfilters_busy = friendfilters_busy or false
- friendfilters_away = friendfilters_away or false
-
- friends_cache = friends_cache or {
- friends = nil,
- state = {},
- game_info = {},
- }
-
- DrawWindow(menu_gui, -5500 ,((screen_width / 2) - (window_width / 2)) - (188 / 2) - 10, screen_height / 2, 188, window_height, "Friends", true, function()
- local do_update = GameGetFrameNum() % 60 == 0
-
- GuiLayoutBeginVertical(menu_gui, 0, 0, true, 0, 0)
-
- if(do_update or friends_cache.friends == nil)then
- friends_cache.friends = steamutils.getSteamFriends();
- friends_cache.state = {}
- friends_cache.game_info = {}
- end
-
- local friends = friends_cache.friends
-
- local only_ingame = GameTextGetTranslatedOrNot("$mp_invite_only_ingame")
- if(GuiButton(menu_gui, NewID("Invite"), 0, 0, friendfilters_ingame and "[X] "..only_ingame or "[ ] "..only_ingame))then
- friendfilters_ingame = not friendfilters_ingame
- end
-
- local show_in_lobby = GameTextGetTranslatedOrNot("$mp_invite_in_lobby")
- if(GuiButton(menu_gui, NewID("Invite"), 0, 0, friendfilters_inlobby and "[X] "..show_in_lobby or "[ ] "..show_in_lobby))then
- friendfilters_inlobby = not friendfilters_inlobby
- end
-
- local show_offline = GameTextGetTranslatedOrNot("$mp_invite_offline")
- if(GuiButton(menu_gui, NewID("Invite"), 0, 0, friendfilters_offline and "[X] "..show_offline or "[ ] "..show_offline))then
- friendfilters_offline = not friendfilters_offline
- end
-
- local show_busy = GameTextGetTranslatedOrNot("$mp_invite_busy")
- if(GuiButton(menu_gui, NewID("Invite"), 0, 0, friendfilters_busy and "[X] "..show_busy or "[ ] "..show_busy))then
- friendfilters_busy = not friendfilters_busy
- end
-
- local show_away = GameTextGetTranslatedOrNot("$mp_invite_away")
- if(GuiButton(menu_gui, NewID("Invite"), 0, 0, friendfilters_away and "[X] "..show_away or "[ ] "..show_away))then
- friendfilters_away = not friendfilters_away
- end
-
- GuiText(menu_gui, 2, 0, "--------------------")
-
- for k, v in pairs(friends)do
- local state = friends_cache.state[v.id] or steam.friends.getFriendPersonaState(v.id)
- local game_info = friends_cache.game_info[v.id] or steam.friends.getFriendGamePlayed(v.id)
-
- --[[
- local state = steam.friends.getFriendPersonaState(v.id)
- local game_info = steam.friends.getFriendGamePlayed(v.id)
- ]]
-
- local online_filter_pass = state == 1 or (state == 0 and friendfilters_offline) or (state == 2 and friendfilters_busy) or (state == 3 and friendfilters_away) or (state == 4 and friendfilters_away)
-
- local ingame_filter_pass = (not game_info and not friendfilters_ingame) or (game_info and game_info.gameID ~= game_id and not friendfilters_ingame ) or (game_info and game_info.gameID == game_id)
-
- local inlobby_filter_pass = (not game_info) or (game_info and game_info.gameID ~= game_id) or (game_info and game_info.gameID == game_id and tostring(game_info.lobbyID) ~= "0" and friendfilters_inlobby) or (game_info and game_info.gameID == game_id and tostring(game_info.lobbyID) == "0")
-
-
- if(online_filter_pass and ingame_filter_pass and inlobby_filter_pass)then
- GuiLayoutBeginHorizontal(menu_gui, 0, 0, true, 0, 0)
- if(GuiButton(menu_gui, NewID("Invite"), 0, 0, GameTextGetTranslatedOrNot("$mp_invite").." "))then
- if(lobby_code ~= nil)then
- if(steam.matchmaking.inviteUserToLobby(lobby_code, v.id))then
- mp_log:print("Invited "..v.name.." to lobby")
- else
- mp_log:print("Failed to invite "..v.name.." to lobby")
- end
- end
- end
- GuiText(menu_gui, 2, 0, v.name)
- GuiLayoutEnd(menu_gui)
- end
- end
-
- for i = 1, 40 do
- --[[
- GuiText(menu_gui, 2, 0, " ")
- ]]
- end
-
- GuiLayoutEnd(menu_gui)
- end, nil, "invite_gui", 2, 2, true)
-
- end
-
- if(selected_player ~= nil)then
- local selected_player_name = steamutils.getTranslatedPersonaName(selected_player)
-
- local window_width, x_pos = GetMenuSettings("right")
- DrawWindow(menu_gui, -5500 ,x_pos, screen_height / 2, window_width, window_height, GameTextGetTranslatedOrNot("$mp_mods").." ("..selected_player_name..")", true, function()
- GuiLayoutBeginVertical(menu_gui, 0, 0, true, 0, 0)
-
- local player_mod_data = getLobbyUserData(lobby_code, selected_player) or {}
-
- local mod_count = 0
-
- -- Define a Lua function to sanitize a URL input
- function sanitize_url(url)
- -- Initialize an empty string to store the sanitized URL
- local sanitized_url = ""
-
- -- Check if the URL starts with "https://"
- if url:sub(1, 8) ~= "https://" then
- -- Inform user if the URL is not allowed
- mp_log:print("Invalid input URL: '"..url.."', Must start with 'https://'.")
- -- Return empty string
- return sanitized_url
- end
-
- -- Add "https://" to the sanitized URL
- sanitized_url = "https://"
-
- -- Iterate over each character in the input URL (starting from position 9, after "https://")
- for i = 9, #url do
- -- Extract the current character
- local char = url:sub(i, i)
-
- -- Check if the character is part of the whitelist (i.e., only alphanumeric, dash, underscore, period, colon, slash,
- -- question mark, equal sign, plus sign, ampersand, or percent sign)
- if char:match("[%w%-%_%.%:%/%?%=%+&%%]") then
- -- If the character is part of the whitelist, append it to the sanitized URL
- sanitized_url = sanitized_url .. char
- end
- end
-
- mp_log:print("Sanitized URL: " .. sanitized_url)
-
- -- Return the sanitized URL
- return sanitized_url
- end
-
-
-
- for k, v in pairs(player_mod_data) do
- local description_truncated = v.description
-
- -- remove anything after a /n (newline)
- local newline_pos = string.find(description_truncated, "\\n")
- if(newline_pos ~= nil)then
- description_truncated = description_truncated:sub(1, newline_pos - 1)
- end
- if(#description_truncated > 100)then
- description_truncated = description_truncated:sub(1, 100) .. "..."
- end
-
- GuiColorSetForNextWidget( menu_gui, 1, 1, 1, 0.8 )
- GuiZSetForNextWidget(menu_gui, -5510)
- --GamePrint(tostring(v.workshop_item_id))
- --GuiLayoutBeginHorizontal(menu_gui, 0, 0, true)
-
- if(v.workshop_item_id ~= 0 and v.workshop_item_id ~= "0")then
- if(GuiButton(menu_gui, NewID("mod_list"), 0, 0, v.name .. (v.id ~= nil and " ( "..v.id.." )" or "")))then
- --steam.utils.openWorkshopItem(v.workshop_item_id)
- popup.create("open_steam_url", v.name, GameTextGetTranslatedOrNot("$mp_open_steam_url_warning"), {
- {
- text="Yes",
- callback = function()
- os.execute("start steam://openurl/https://steamcommunity.com/sharedfiles/filedetails/?id="..v.workshop_item_id)
- end
- },
- {
- text="No",
- callback = function()
- end
- }
- }, -20000)
-
- end
- GuiTooltip(menu_gui, GameTextGetTranslatedOrNot("$mp_open_steam_url_tooltip"), description_truncated)
- elseif(v.download_link ~= nil and v.download_link ~= "")then
- if(GuiButton(menu_gui, NewID("mod_list"), 0, 0, v.name .. (v.id ~= nil and " ( "..v.id.." )" or "")))then
- --os.execute("start "..v.workshop_item_id)
- local url = sanitize_url(v.download_link)
-
-
- popup.create("open_mod_download_page", v.name, string.format(GameTextGetTranslatedOrNot("$mp_open_download_page_warning"), "\""..url.."\""), {
- {
- text="Yes",
- callback = function()
- os.execute("start explorer \""..url.."\"")
- end
- },
- {
- text="No",
- callback = function()
- end
- }
- }, -20000)
-
- end
- GuiTooltip(menu_gui, GameTextGetTranslatedOrNot("$mp_open_download_page_tooltip"), description_truncated)
- else
- GuiText(menu_gui, 0, 0, v.name .. (v.id ~= nil and " ( "..v.id.." )" or ""))
- GuiTooltip(menu_gui, description_truncated, "")
- end
-
- local mod_required = (steam.matchmaking.getLobbyData(lobby_code, "mod_required_"..v.id) == "true") or false
-
- local required_text = mod_required and GameTextGetTranslatedOrNot("$mp_required") or GameTextGetTranslatedOrNot("$mp_not_required")
-
- GuiZSetForNextWidget(menu_gui, -5510)
-
- if(mod_required)then
- GuiColorSetForNextWidget( menu_gui, 1, 0.129, 0, 0.8 )
- else
- GuiColorSetForNextWidget( menu_gui, 0.314, 1, 0, 0.8 )
- end
-
- if(steamutils.IsOwner())then
- if(GuiButton(menu_gui, NewID("mod_list"), 0, 0, required_text))then
- steam_utils.TrySetLobbyData(lobby_code, "mod_required_"..v.id, tostring(not mod_required))
- if(not mod_required)then
- local required_mods = (steam.matchmaking.getLobbyData(lobby_code, "required_mods") ~= nil and steam.matchmaking.getLobbyData(lobby_code, "required_mods") ~= "") and bitser.loads(steam.matchmaking.getLobbyData(lobby_code, "required_mods")) or {}
-
- table.insert(required_mods, {v.id, v.name})
-
- steam_utils.TrySetLobbyData(lobby_code, "required_mods", bitser.dumps(required_mods))
- else
- local required_mods = (steam.matchmaking.getLobbyData(lobby_code, "required_mods") ~= nil and steam.matchmaking.getLobbyData(lobby_code, "required_mods") ~= "") and bitser.loads(steam.matchmaking.getLobbyData(lobby_code, "required_mods")) or {}
-
- for i, mod in ipairs(required_mods) do
- if(mod.id == v.id)then
- table.remove(required_mods, i)
- break
- end
- end
-
- steam_utils.TrySetLobbyData(lobby_code, "required_mods", bitser.dumps(required_mods))
- end
- end
- else
- GuiText(menu_gui, 0, 0, required_text)
- end
-
-
- GuiText(menu_gui, 0, -8, " ")
-
- mod_count = mod_count + 1
- end
- --GuiLayoutEnd(menu_gui)
-
- --[[
- for i = 1, 50 - mod_count do
- GuiText(menu_gui, 2, 0, " ")
- end
- ]]
-
- GuiLayoutEnd(menu_gui)
- end, nil, "mod_list_gui")
-
- end
-
- if(lobby_code == nil)then
- active_lobby_menu_right = nil
- active_lobby_menu_left = nil
- end
-
- if(active_lobby_menu_right ~= nil)then
- if(lobby_menus ~= nil)then
- for i, lobby_menu in ipairs(lobby_menus)do
- if(lobby_menu.id == active_lobby_menu_right)then
-
- local menu_width, pos_x = GetMenuSettings("right")
-
- DrawWindow(menu_gui, -5500 , pos_x, screen_height / 2, menu_width, window_height, GameTextGetTranslatedOrNot(lobby_menu.name), true, function(win_x, win_y, win_w, win_h)
- get_widget_info = function()
- local clicked, right_clicked, hovered, x, y, width, height, draw_x, draw_y, draw_width, draw_height = GuiGetPreviousWidgetInfo(menu_gui)
- local window_y = ((screen_height / 2) - (window_height / 2)) + 12
- local window_height = window_height
-
- --[[GuiLayoutBeginLayer(menu_gui)
- GuiText(menu_gui, 0, window_y, "------------------")
- GuiText(menu_gui, 0, window_y + window_height, "------------------")
- GuiLayoutEndLayer(menu_gui)]]
-
- local mouse_x, mouse_y = input:GetUIMousePos(menu_gui)
-
-
-
- if(mouse_x < win_x or mouse_x > win_x + win_w or mouse_y < win_y or mouse_y > win_y + win_h + 5)then
- hovered = false
- right_clicked = false
- clicked = false
- end
-
- return (y + height > window_y and y < window_y + window_height), clicked, right_clicked, hovered, x, y, width, height, draw_x, draw_y, draw_width, draw_height
- end
- if(lobby_menu.draw)then
- lobby_menu.draw(lobby_code, menu_gui, function(id, force) return NewID(id or lobby_menu.id, force) end)
- end
- end, function()
- active_lobby_menu_right = nil
- lobby_menu.close()
- end, lobby_menu.id, nil, nil, nil, true)
- end
- end
- end
- end
-
-
- if(active_lobby_menu_left ~= nil)then
- if(lobby_menus ~= nil)then
- for i, lobby_menu in ipairs(lobby_menus)do
- if(lobby_menu.id == active_lobby_menu_left)then
- local menu_width, pos_x = GetMenuSettings("left")
- DrawWindow(menu_gui, -5500 , pos_x, screen_height / 2, menu_width, window_height, GameTextGetTranslatedOrNot(lobby_menu.name), true, function(win_x, win_y, win_w, win_h)
- get_widget_info = function()
- local clicked, right_clicked, hovered, x, y, width, height, draw_x, draw_y, draw_width, draw_height = GuiGetPreviousWidgetInfo(menu_gui)
- local window_y = ((screen_height / 2) - (window_height / 2)) + 12
- local window_height = window_height
-
- --[[GuiLayoutBeginLayer(menu_gui)
- GuiText(menu_gui, 0, window_y, "------------------")
- GuiText(menu_gui, 0, window_y + window_height, "------------------")
- GuiLayoutEndLayer(menu_gui)]]
-
- local mouse_x, mouse_y = input:GetUIMousePos(menu_gui)
-
-
-
- if(mouse_x < win_x or mouse_x > win_x + win_w or mouse_y < win_y or mouse_y > win_y + win_h + 5)then
- hovered = false
- right_clicked = false
- clicked = false
- end
-
- return (y + height > window_y and y < window_y + window_height), clicked, right_clicked, hovered, x, y, width, height, draw_x, draw_y, draw_width, draw_height
- end
- if(lobby_menu.draw)then
- lobby_menu.draw(lobby_code, menu_gui, function(id, force) return NewID(id or lobby_menu.id, force) end)
- end
- end, function()
- active_lobby_menu_left = nil
- lobby_menu.close()
- end, lobby_menu.id, nil, nil, nil, true)
- end
- end
- end
- end
-
- --[[
- if(lobby_settings_open and lobby_code ~= nil)then
-
- local owner = steam.matchmaking.getLobbyOwner(lobby_code)
-
- local internal_types = { "Public", "Private", "FriendsOnly"}
- local internal_type_map = { Public = 1, Private = 2, FriendsOnly = 3 }
-
-
- edit_lobby_type = internal_type_map[steam_utils.GetLobbyData("LobbyType")]
-
- local active_mode = FindGamemode(steam_utils.GetLobbyData("gamemode"))
-
- local true_max = 32
-
- local default_max_players = 8
-
- edit_lobby_max_players = steam_utils.getSteamID() and (edit_lobby_max_players or steam.matchmaking.getLobbyMemberLimit(lobby_code)) or steam.matchmaking.getLobbyMemberLimit(lobby_code)
-
- edit_lobby_name = owner == steam_utils.getSteamID() and (edit_lobby_name or steam_utils.GetLobbyData("name")) or steam_utils.GetLobbyData("name")
-
- edit_lobby_seed = owner == steam_utils.getSteamID() and (edit_lobby_seed or steam_utils.GetLobbyData("seed")) or steam_utils.GetLobbyData("seed")
-
- DrawWindow(menu_gui, -5500 ,((screen_width / 2) - (window_width / 2)) - (188 / 2) - 10, screen_height / 2, 188, window_height, GameTextGetTranslatedOrNot("$mp_lobby_settings"), true, function()
- local current_y = 0
- local box_w = 180
-
- -- Lobby Type Field
- local lobby_type_string = get_split_string(GameTextGetTranslatedOrNot("$mp_lobby_type")..": "..lobby_types[edit_lobby_type], 150)
-
- local chunks = select(2, lobby_type_string:gsub('\n', '\n'))
-
- local last_w, last_h = GuiGetTextDimensions(menu_gui, lobby_type_string)
- local box_h = last_h + (chunks <= 1 and 2 or 0)
-
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, 0, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
-
- if(GuiTextButton(menu_gui, function() return NewID("EditLobby") end, 4, 2, lobby_type_string, -5600, 1))then
- edit_lobby_type = edit_lobby_type + 1
- if(edit_lobby_type > #lobby_types and owner == steam_utils.getSteamID())then
- edit_lobby_type = 1
- end
- settings_changed = true
- end
-
- current_y = current_y + box_h + 2
-
- -- Lobby name field
- local lobby_name_string = GameTextGetTranslatedOrNot("$mp_lobby_name")..": "
- local last_w, last_h = GuiGetTextDimensions(menu_gui, lobby_name_string)
- local box_h = last_h + 18
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
- GuiText(menu_gui, 4, current_y + 2, lobby_name_string)
- name_change_frame = name_change_frame or nil
- local lobby_name_value = GuiTextInput(menu_gui, NewID("EditLobby"), 4, current_y + last_h + 2, edit_lobby_name, 156, 25, "qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM!@#$%^&*()_' ")
- local _, _, hover = GuiGetPreviousWidgetInfo(menu_gui)
-
- if(hover)then
- GameAddFlagRun("chat_bind_disabled")
- end
- if(lobby_name_value ~= edit_lobby_name and owner == steam_utils.getSteamID())then
- edit_lobby_name = lobby_name_value
- name_change_frame = GameGetFrameNum()
- end
-
- if(name_change_frame and GameGetFrameNum() - name_change_frame > 30)then
- settings_changed = true
- name_change_frame = nil
- end
-
- current_y = current_y + box_h + 2
-
- -- lobby max players field
- local max_player_string = GameTextGetTranslatedOrNot("$mp_max_players")..": "
- local last_w, last_h = GuiGetTextDimensions(menu_gui, max_player_string)
- local box_h = last_h + 16
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
- GuiText(menu_gui, 4, current_y + 2, max_player_string)
- max_player_change_frame = max_player_change_frame or nil
- local slider_value = GuiSlider(menu_gui, NewID("EditLobby"), 2, current_y + last_h + 2, "", edit_lobby_max_players, 2, true_max, default_max_players, 1, " ", 146)
-
- GuiColorSetForNextWidget(menu_gui, 1, 1, 1, 0.7)
- local value_text = tostring(math.floor(slider_value))
- GuiText(menu_gui, 153, current_y + last_h + 1, value_text)
-
- if(slider_value ~= edit_lobby_max_players and owner == steam_utils.getSteamID())then
- edit_lobby_max_players = slider_value
- max_player_change_frame = GameGetFrameNum()
- end
-
- if(max_player_change_frame and GameGetFrameNum() - max_player_change_frame > 30)then
- settings_changed = true
- max_player_change_frame = nil
- end
-
- current_y = current_y + box_h + 2
-
- -- world seed field
- local seed_string = GameTextGetTranslatedOrNot("$mp_world_seed")..": "
- local last_w, last_h = GuiGetTextDimensions(menu_gui, seed_string)
- local box_h = last_h + 18
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
- GuiText(menu_gui, 4, current_y + 2, seed_string)
- seed_change_frame = seed_change_frame or nil
- local edit_lobby_seed_value = GuiTextInput(menu_gui, NewID("EditLobby"), 4, current_y + last_h + 2, edit_lobby_seed, 156, 25, "1234567890")
- local _, _, hover = GuiGetPreviousWidgetInfo(menu_gui)
- if(hover)then
- GameAddFlagRun("chat_bind_disabled")
- end
- if(edit_lobby_seed_value ~= edit_lobby_seed and owner == steam_utils.getSteamID())then
- edit_lobby_seed = edit_lobby_seed_value
- seed_change_frame = GameGetFrameNum()
- end
-
- if(seed_change_frame and GameGetFrameNum() - seed_change_frame > 30)then
- settings_changed = true
- seed_change_frame = nil
- end
-
- current_y = current_y + box_h + 2
-
- for k, setting in ipairs(active_mode.settings or {})do
- if(owner ~= steam_utils.getSteamID())then
- gamemode_settings[setting.id] = steam.matchmaking.getLobbyData(lobby_code, "setting_"..setting.id)
- end
-
- if(gamemode_settings[setting.id] == nil)then
- gamemode_settings[setting.id] = setting.default
- print("Setting "..setting.id.." to default: "..tostring(setting.default))
- --settings_changed = true
- --GlobalsSetValue("setting_next_"..setting.id, tostring(setting.default))
- else
-
- if(setting.type == "bool" and type(gamemode_settings[setting.id]) == "string")then
- if(gamemode_settings[setting.id] == "true")then
- gamemode_settings[setting.id] = true
- else
- gamemode_settings[setting.id] = false
- end
- elseif(setting.type == "slider" and type(gamemode_settings[setting.id]) == "string")then
- gamemode_settings[setting.id] = tonumber(gamemode_settings[setting.id])
- end
- end
-
- if(gamemode_settings[setting.id] ~= nil)then
- local setting_next = GlobalsGetValue("setting_next_"..setting.id)
- if(setting_next ~= nil)then
- if(setting_next ~= tostring(gamemode_settings[setting.id]))then
- GlobalsSetValue("setting_next_"..setting.id, tostring(gamemode_settings[setting.id]))
- end
- end
- end
-
- if(setting.require == nil or setting.require(setting))then
- --print(setting.id.."; "..tostring(setting.require).."; "..(setting.require and tostring(setting.require(setting)) or "nil"))
- if(setting.type == "enum")then
- local selected_name = ""
- local selected_index = nil
-
- local selected_value = gamemode_settings[setting.id]
- --print("Selected value: "..tostring(selected_value))
- if(selected_value == nil)then
- selected_value = setting.default
- gamemode_settings[setting.id] = setting.default
- settings_changed = true
- end
-
- for k, v in ipairs(setting.options)do
- if(v[1] == selected_value)then
- selected_name = v[2]
- selected_index = k
- end
- end
-
- -- if selected index is nil, reset to default
- if(selected_index == nil)then
- for k, v in ipairs(setting.options)do
- if(v[1] == setting.default)then
- selected_name = v[2]
- selected_index = k
- settings_changed = true
- gamemode_settings[setting.id] = setting.default
- end
- end
- end
-
- local enum_string = get_split_string(GameTextGetTranslatedOrNot(setting.name or "")..": "..GameTextGetTranslatedOrNot(selected_name or ""), 150)
- local chunks = select(2, enum_string:gsub('\n', '\n'))
- local last_w, last_h = GuiGetTextDimensions(menu_gui, enum_string)
- local box_h = last_h + (chunks <= 1 and 2 or 0)
-
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
- if(setting.options[selected_index][3] ~= nil)then
- local info = setting.options[selected_index][3]
- local info_name = "???"
- local info_desc = ""
- if(type(info) == "function")then
- info_name, info_desc = info()
- elseif(type(info) == "table")then
- info_name, info_desc = info[1], info[2]
- else
- info_name = info
- end
-
- if(info_name ~= nil)then
- GuiColorSetForNextWidget( menu_gui, 1, 0.4, 0.4, 1.0 )
- GuiText(menu_gui, 0, 0, "[?]")
- GuiTooltip(menu_gui, GameTextGetTranslatedOrNot(info_name or ""), GameTextGetTranslatedOrNot(info_desc or ""))
- end
- end
-
- if(GuiTextButton(menu_gui, function() return NewID("EditLobby") end, 4, current_y + 2, enum_string, -5600, 1, nil, nil, nil, nil, nil, function() GuiTooltip(menu_gui, GameTextGetTranslatedOrNot(setting.name or ""), GameTextGetTranslatedOrNot(setting.description or "")) end))then
- selected_index = selected_index + 1
- if(selected_index > #setting.options)then
- selected_index = 1
- end
- gamemode_settings[setting.id] = setting.options[selected_index][1]
- settings_changed = true
- end
-
-
-
- current_y = current_y + box_h + 2
- elseif(setting.type == "bool")then
- local bool_string = get_split_string(GameTextGetTranslatedOrNot(setting.name or "")..":"..(gamemode_settings[setting.id] and GameTextGetTranslatedOrNot("$mp_setting_enabled") or GameTextGetTranslatedOrNot("$mp_setting_disabled")), 170)
- local chunks = select(2, bool_string:gsub('\n', '\n'))
- local last_w, last_h = GuiGetTextDimensions(menu_gui, bool_string)
- local box_h = last_h + (chunks <= 1 and 2 or 0)
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
-
- local r, g, b, a = 1, 1, 1, 1
-
- -- split bool string by :
- local str1, str2 = bool_string:match("([^,]+:)([^,]+)")
-
- if(gamemode_settings[setting.id])then
- r, g, b, a = 0.4, 1, 0.4, 1
- else
- r, g, b, a = 1, 0.4, 0.4, 1
- end
-
-
- if(GuiTextButton(menu_gui, function() return NewID("EditLobby") end, 4, current_y + 2, {
- {
- text = str1,
- color = {1, 1, 1, 1}
- },
- {
- text = str2,
- color = {r, g, b, a}
- }
- }, -5600, 1, r, g, b, a, 170, function() GuiTooltip(menu_gui, GameTextGetTranslatedOrNot(setting.name or ""), GameTextGetTranslatedOrNot(setting.description or "")) end))then
- gamemode_settings[setting.id] = not gamemode_settings[setting.id]
- settings_changed = true
- end
- GuiTooltip(menu_gui, GameTextGetTranslatedOrNot(setting.name or ""), GameTextGetTranslatedOrNot(setting.description or ""))
- current_y = current_y + box_h + 2
- elseif(setting.type == "slider")then
-
- setting.display_multiplier = setting.display_multiplier or 1
- setting.formatting_string = setting.formatting_string or " $0"
- setting.formatting_func = setting.formatting_func or function(value) return value end
- setting.modifier = setting.modifier
-
- if(setting.modifier == nil)then
- setting.modifier = function(value) return value end
- end
-
- setting.display_fractions = setting.display_fractions or false
-
- local slider_string = get_split_string(GameTextGetTranslatedOrNot(setting.name or "")..": ", 150)
-
- local chunks = select(2, slider_string:gsub('\n', '\n'))
-
- local last_w, last_h = GuiGetTextDimensions(menu_gui, slider_string)
- local box_h = last_h + 16
- Gui9Piece(menu_gui, function() return NewID("EditLobby") end, 0, current_y, box_w, box_h, 0.1, -5600, "mods/evaisa.mp/files/gfx/ui/9piece_white.xml", 3)
- GuiTextMultiline(menu_gui, 4, current_y + 2, slider_string, -5600, 1, 1, 1, 1, 1, 170, function() GuiTooltip(menu_gui, GameTextGetTranslatedOrNot(setting.name), GameTextGetTranslatedOrNot(setting.description)) end)
-
-
- local slider_value = GuiSlider(menu_gui, NewID("EditLobby"), 2, current_y + last_h + 2, "", gamemode_settings[setting.id], setting.min, setting.max, setting.default, setting.display_multiplier, " ", 146)
- slider_value = setting.modifier(slider_value)
- local clicked, _, hovered = GuiGetPreviousWidgetInfo(menu_gui)
- GuiTooltip(menu_gui, GameTextGetTranslatedOrNot(setting.name), GameTextGetTranslatedOrNot(setting.description))
-
- -- take setting.formatting_string, replace $0 with slider_value, take display multiplier into account
- GuiColorSetForNextWidget(menu_gui, 1, 1, 1, 0.7)
- local value_text = string.gsub(setting.formatting_string, "$0", tostring(setting.display_fractions and (slider_value * setting.display_multiplier) or math.floor(slider_value * setting.display_multiplier)))
- value_text = setting.formatting_func(value_text)
- GuiText(menu_gui, 150, current_y + last_h + 1, value_text)
-
- was_slider_changed = was_slider_changed or {}
-
- if(tostring(slider_value) ~= tostring(gamemode_settings[setting.id]))then
-
- gamemode_settings[setting.id] = slider_value
- was_slider_changed[setting.id] = GameGetFrameNum()
- end
-
- if(was_slider_changed[setting.id] and (GameGetFrameNum() - was_slider_changed[setting.id]) > 30)then
-
- settings_changed = true
- was_slider_changed[setting.id] = nil
-
- --GlobalsSetValue("setting_next_"..setting.id, tostring(gamemode_settings[setting.id]))
- end
-
- current_y = current_y + box_h + 2
- end
- end
-
- if(settings_changed and owner == steam_utils.getSteamID())then
- steam.matchmaking.setLobbyMemberLimit(lobby_code, edit_lobby_max_players)
- steam_utils.TrySetLobbyData(code, "max_players", tostring(edit_lobby_max_players))
- steam_utils.TrySetLobbyData(lobby_code, "name", edit_lobby_name)
-
- steam_utils.TrySetLobbyData(lobby_code, "seed", edit_lobby_seed)
- for k, setting in ipairs(active_mode.settings or {})do
- steam_utils.TrySetLobbyData(lobby_code, "setting_"..setting.id, tostring(gamemode_settings[setting.id]))
- mp_log:print("Updated gamemode setting: "..setting.id.." to "..tostring(gamemode_settings[setting.id]))
- end
- print("Updating lobby type: "..internal_types[edit_lobby_type])
- steam.matchmaking.setLobbyType(lobby_code, internal_types[edit_lobby_type])
- steam_utils.send("refresh", {}, steam_utils.messageTypes.AllPlayers, lobby_code, true, true)
- mp_log:print("Updated limit: "..tostring(edit_lobby_max_players))
- mp_log:print("Updated name: "..tostring(edit_lobby_name))
- mp_log:print("Updated type: "..tostring(internal_types[edit_lobby_type]))
- settings_changed = false
- --print("lobby settings changed!")
- end
-
- end
-
-
- end, nil, "lobby_settings_gui", 2, 2, true)
-
- end]]
- end
- },
- {
- name = "CreateLobby",
- func = function()
-
-
- local window_width = 200
- local window_height = 180
-
- local window_text = GameTextGetTranslatedOrNot("$mp_create_lobby")
-
- lobby_type = lobby_type or 1
- gamemode_index = gamemode_index or 1
-
- local true_max = 250
-
- local default_max_players = 8
-
- lobby_max_players = lobby_max_players or default_max_players
-
- local default_lobby_name = steamutils.getTranslatedPersonaName(steam_utils.getSteamID())
-
- -- if default lobby name ends with "s" add ' otherwise add 's
-
- if(string.sub(default_lobby_name, -1) == "s")then
- default_lobby_name = string.format(GameTextGetTranslatedOrNot("$mp_default_lobby_name_s"), default_lobby_name)
- else
- default_lobby_name = string.format(GameTextGetTranslatedOrNot("$mp_default_lobby_name"), default_lobby_name)
- end
-
- lobby_name = lobby_name or default_lobby_name
- lobby_seed = lobby_seed or tostring(rand.range(1, 4294967295))
-
- DrawWindow(menu_gui, -6000, screen_width / 2, screen_height / 2, window_width, window_height, window_text, true, function()
- GuiLayoutBeginVertical(menu_gui, 0, 0, true, 0, 0)
-
- if(GuiButton(menu_gui, NewID("CreateLobby"), 0, 0, GameTextGetTranslatedOrNot("$mp_return_menu")))then
- if(lobby_code ~= nil)then
- steam_utils.Leave(lobby_code)
- lobby_code = nil
- end
- invite_menu_open = false
- selected_player = nil
- menu_status = status.main_menu
- initial_refreshes = 10
- return
- end
-
- GuiText(menu_gui, 2, 0, "--------------------")
- GuiText(menu_gui, 2, 0, " ")
-
-
- if(#gamemodes > 0)then
-
- local internal_types = { "Public", "Private", "FriendsOnly",}
-
- if(GuiButton(menu_gui, NewID("CreateLobby"), 2, 0, GameTextGetTranslatedOrNot("$mp_lobby_type")..": "..lobby_types[lobby_type]))then
- lobby_type = lobby_type + 1
- if(lobby_type > #lobby_types)then
- lobby_type = 1
- end
- end
-
-
- --[[if(GuiButton(menu_gui, NewID("CreateLobby"), 2, 1, GameTextGetTranslatedOrNot("$mp_gamemode")..": "..GameTextGetTranslatedOrNot(gamemodes[gamemode_index].name)))then
- gamemode_index = gamemode_index + 1
- if(gamemode_index > #gamemodes)then
- gamemode_index = 1
- end
- end]]
-
- GuiLayoutBeginHorizontal(menu_gui, 0, 0, true, 0, 0)
- GuiText(menu_gui, 2, 1, GameTextGetTranslatedOrNot("$mp_lobby_name")..": ")
- local lobby_name_value = GuiTextInput(menu_gui, NewID("CreateLobby"), 2, 1, lobby_name, 120, 25, "qwertyuiopasdfghjklzxcvbnm1234567890QWERTYUIOPASDFGHJKLZXCVBNM!@#$%^&*()_' ")
- if(lobby_name_value ~= lobby_name)then
- lobby_name = lobby_name_value
- end
- GuiLayoutEnd(menu_gui)
-
- GuiLayoutBeginHorizontal(menu_gui, 0, 0, true, 0, 0)
- GuiText(menu_gui, 2, 3, GameTextGetTranslatedOrNot("$mp_max_players")..": ")
- local slider_value = GuiSlider(menu_gui, NewID("CreateLobby"), 0, 4, "", lobby_max_players, 2, true_max, default_max_players, 1, " $0", 120)
- if(slider_value ~= lobby_max_players)then
- lobby_max_players = slider_value
- end
- GuiLayoutEnd(menu_gui)
-
- GuiLayoutBeginHorizontal(menu_gui, 0, 0, true, 0, 0)
- GuiText(menu_gui, 2, 4, GameTextGetTranslatedOrNot("$mp_world_seed")..": ")
- local lobby_seed_value = GuiTextInput(menu_gui, NewID("CreateLobby"), 2, 4, lobby_seed, 120, 10, "1234567890")
- if(lobby_seed_value ~= lobby_seed)then
- lobby_seed = lobby_seed_value
- end
- GuiLayoutEnd(menu_gui)
-
- GuiText(menu_gui, 2, 0, " ")
-
- if(GuiButton(menu_gui, NewID("CreateLobby"), 2, 0, GameTextGetTranslatedOrNot("$mp_create_lobby")))then
- CreateLobby(internal_types[lobby_type], lobby_max_players, function (code)
- msg.log("Created new lobby!")
- print("Created new lobby!")
-
- for k, setting in ipairs(gamemodes[gamemode_index].settings or {})do
- if(gamemode_settings[setting.id] == nil)then
- gamemode_settings[setting.id] = setting.default
-
- steam_utils.TrySetLobbyData(code, "setting_"..setting.id, tostring(setting.default))
- end
- end
-
- for k, data in pairs(gamemodes[gamemode_index].default_data or {})do
- steam_utils.TrySetLobbyData(code, k, data)
- end
-
- print("Setting all lobby data.")
-
- steam_utils.TrySetLobbyData(code, "name", lobby_name)
- steam_utils.TrySetLobbyData(code, "gamemode", tostring(gamemodes[gamemode_index].id))
- steam_utils.TrySetLobbyData(code, "gamemode_version", tostring(gamemodes[gamemode_index].version))
- steam_utils.TrySetLobbyData(code, "game_version_hash", tostring(noita_version_hash))
- steam_utils.TrySetLobbyData(code, "game_version", tostring(noita_version))
- steam_utils.TrySetLobbyData(code, "gamemode_name", tostring(gamemodes[gamemode_index].name))
- steam_utils.TrySetLobbyData(code, "seed", lobby_seed)
- steam_utils.TrySetLobbyData(code, "version", tostring(MP_VERSION))
- steam_utils.TrySetLobbyData(code, "in_progress", "false")
- steam_utils.TrySetLobbyData(code, "allow_in_progress_joining", gamemodes[gamemode_index].allow_in_progress_joining ~= nil and tostring(gamemodes[gamemode_index].allow_in_progress_joining) or "true")
- steam_utils.TrySetLobbyData(code, "max_players", tostring(lobby_max_players))
-
- edit_lobby_type = lobby_type -- steam.matchmaking.getLobbyData(code, "LobbyType")
- edit_lobby_max_players = lobby_max_players -- steam.matchmaking.getLobbyMemberLimit(code)"MaxPlayers"
- edit_lobby_name = lobby_name -- steam.matchmaking.getLobbyData(code, "name")
- edit_lobby_seed = lobby_seed -- steam.matchmaking.getLobbyData(code, "seed")
-
-
- if(dev_mode)then
- steam_utils.TrySetLobbyData(code, "System", "NoitaOnlineDev")
- end
-
- steam.friends.setRichPresence( "status", "Noita Online || "..tostring(gamemodes[gamemode_index].name).." - Waiting for players" )
- steam.friends.setRichPresence( "steam_player_group", lobby_name )
- steam.friends.setRichPresence( "steam_player_group_size", "1" )
- --steam.friends.setRichPresence( "connect", "lobby:"..code )
-
- lobby_code = code
-
- local blacklisted_players = steam_utils.GetBlacklistedPlayers()
- for i, player in ipairs(blacklisted_players)do
- steam_utils.TrySetLobbyData(lobby_code, "banned_"..tostring(player), "true")
- banned_members[tostring(player)] = true
- end
- end)
- end
- else
- GuiText(menu_gui, 2, 0, GameTextGetTranslatedOrNot("$mp_no_gamemodes"))
- end
-
- --[[
- for i = 1, 40 do
- GuiText(menu_gui, 2, 0, " ")
- end
- ]]
-
- GuiLayoutEnd(menu_gui)
- end, function()
- gui_closed = true;
- invite_menu_open = false
- selected_player = nil
- end, "create_lobby_gui")
-
- end
- },
- {
- name = "JoinLobby",
- func = function()
-
-
- local window_width = 200
- local window_height = 180
-
- local window_text = GameTextGetTranslatedOrNot("$mp_join_lobby")
-
- lobby_code_input = lobby_code_input or ""
-
-
-
- DrawWindow(menu_gui, -6000, screen_width / 2, screen_height / 2, window_width, window_height, window_text, true, function()
- GuiLayoutBeginVertical(menu_gui, 0, 0, true, 0, 0)
-
- if(GuiButton(menu_gui, NewID("JoinLobby"), 0, 0, GameTextGetTranslatedOrNot("$mp_return_menu")))then
- if(lobby_code ~= nil)then
- steam_utils.Leave(lobby_code)
- lobby_code = nil
- end
- invite_menu_open = false
- lobby_code_input = ""
- menu_status = status.main_menu
- initial_refreshes = 10
- return
- end
-
- GuiText(menu_gui, 2, 0, "--------------------")
-
-
- if(GuiButton(menu_gui, NewID("JoinLobby"), 2, 0, GameTextGetTranslatedOrNot("$mp_paste_code")))then
- -- Check if code only contains capital letters and is 25 characters or less
- local code = steam.utils.getClipboard()
-
- -- toupper
- code = code:upper()
-
- if(code ~= nil and code:match("^[%u]+$") and #code <= 25)then
- lobby_code_input = code
- end
-
- end
-
- GuiLayoutBeginHorizontal(menu_gui, 0, 0, true, 0, 0)
- GuiText(menu_gui, 2, 1, GameTextGetTranslatedOrNot("$mp_lobby_code")..": ")
-
- local real_code = lobby_code_input
-
- local censored_code = ""
-
- if(ModSettingGet("evaisa.mp.hide_lobby_code"))then
-
-
-
- for i = 1, #real_code do
- censored_code = censored_code.."*"
- end
- else
- censored_code = real_code
- end
-
- lobby_code_input = GuiTextInput(menu_gui, NewID("JoinLobby"), 2, 1, censored_code, 120, 25, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
-
- if(ModSettingGet("evaisa.mp.hide_lobby_code"))then
- -- uncensor new input by merging it with the real code
- if(#lobby_code_input < #real_code)then
- lobby_code_input = real_code:sub(1, #lobby_code_input)
- elseif(#lobby_code_input > #real_code)then
- -- take new characters from lobby_code_input and merge them with real_code
- local extra = lobby_code_input:sub(#real_code + 1)
- lobby_code_input = real_code..extra
- else
- lobby_code_input = real_code
- end
- end
-
- -- touppercase the input
- lobby_code_input = lobby_code_input:upper()
-
-
-
- --[[if(lobby_code_input ~= lobby_code_value)then
- lobby_code_input = lobby_code_value
- end]]
-
- --[[
- lobby_code_box = lobby_code_box or text_input.create(chat_gui, 2, screen_height - 16, window_width + 2, "", 100, nil, ";", 0)
-
- lobby_code_input = lobby_code_input or ""
-
- lobby_code_box.text = lobby_code_input
- lobby_code_box:transform(2, screen_height - 16, window_width + 2)
-
- lobby_code_box:update()
-
- lobby_code_box:draw()
-
-
- lobby_code_input = lobby_code_box.text
- ]]
-
-
- GuiLayoutEnd(menu_gui)
-
-
- GuiText(menu_gui, 2, 0, " ")
-
- if(GuiButton(menu_gui, NewID("JoinLobby"), 2, 0, GameTextGetTranslatedOrNot("$mp_join_lobby")))then
- if(lobby_code_input ~= "" and #lobby_code_input > 5)then
- lobby_code_decompressed = steam.utils.decompressSteamID(lobby_code_input)
- steam.matchmaking.joinLobby(lobby_code_decompressed, function(data)
- if(data.response == 2)then
- steam_utils.Leave(data.lobbyID)
- invite_menu_open = false
- selected_player = nil
- menu_status = status.joining_lobby
- show_lobby_code = false
- lobby_code = nil
- end
- end)
- end
- lobby_code_input = ""
- end
-
- --[[
- for i = 1, 40 do
- GuiText(menu_gui, 2, 0, " ")
- end
- ]]
-
- GuiLayoutEnd(menu_gui)
- end, function()
- gui_closed = true;
- invite_menu_open = false
- selected_player = nil
- end, "join_lobby_gui")
-
- end
- },
- {
- name = "Disconnected",
- func = function()
- local window_width = 200
- local window_height = 180
-
- local window_text = GameTextGetTranslatedOrNot("$mp_disconnected")
-
- lobby_code_input = lobby_code_input or ""
-
-
-
- DrawWindow(menu_gui, -6000, screen_width / 2, screen_height / 2, window_width, window_height, window_text, true, function()
- GuiLayoutBeginVertical(menu_gui, 0, 0, true, 0, 0)
- if(GuiButton(menu_gui, NewID("JoinLobby"), 0, 0, GameTextGetTranslatedOrNot("$mp_return_menu")))then
- if(lobby_code ~= nil)then
- steam_utils.Leave(lobby_code)
- lobby_code = nil
- end
- invite_menu_open = false
- selected_player = nil
- lobby_code_input = ""
- menu_status = status.main_menu
- initial_refreshes = 10
- return
- end
-
- GuiText(menu_gui, 2, 0, "--------------------")
- GuiText(menu_gui, 2, 0, " ")
-
- GuiText(menu_gui, 2, 0, GameTextGetTranslatedOrNot("$mp_disconnected"))
- GuiText(menu_gui, 2, 0, GameTextGetTranslatedOrNot("$mp_reason")..": "..disconnect_message)
-
- --[[
- for i = 1, 40 do
- GuiText(menu_gui, 2, 0, " ")
- end
- ]]
-
- GuiLayoutEnd(menu_gui)
- end, function()
- gui_closed = true;
- invite_menu_open = false
- selected_player = nil
- end, "disconnected_gui")
- end
- }
-}
-
-GuiZSetForNextWidget(menu_gui, 0)
-if (GameGetIsGamepadConnected()) then
- GuiOptionsAddForNextWidget(menu_gui, GUI_OPTION.NonInteractive)
-end
-
-if (not IsPaused()) then
- if (not GameHasFlagRun("chat_input_hovered")) then
- if ((bindings:IsJustDown("lobby_menu_open_kb") or bindings:IsJustDown("lobby_menu_open_gp")) and not GameHasFlagRun("chat_bind_disabled")) then
- gui_closed = not gui_closed
- invite_menu_open = false
- selected_player = nil
- GamePlaySound("data/audio/Desktop/ui.bank", "ui/button_click", 0, 0)
- end
- end
-
- if(GuiImageButton(menu_gui, NewID("MenuButton"), screen_width - 20, screen_height - 20, "", "mods/evaisa.mp/files/gfx/ui/menu.png"))then
- gui_closed = not gui_closed
- invite_menu_open = false
- selected_player = nil
- GamePlaySound("data/audio/Desktop/ui.bank", "ui/button_click", 0, 0)
- end
-
- if(not gui_closed)then
- local version_string = "Noita Online (build "..tostring(MP_VERSION).." "..GameTextGetTranslatedOrNot(VERSION_FLAVOR_TEXT)..")"
- if(lobby_code ~= nil)then
- local active_mode = FindGamemode(steam.matchmaking.getLobbyData(lobby_code, "gamemode"))
- if(active_mode ~= nil)then
- version_string = version_string.." - "..GameTextGetTranslatedOrNot(active_mode.name or "").." (build "..tostring(active_mode.version or "").." "..GameTextGetTranslatedOrNot(active_mode.version_flavor_text or "")..")"
- if(active_mode.version_display)then
- version_string = active_mode.version_display(version_string)
- end
- end
- end
- local text_width, text_height = GuiGetTextDimensions(menu_gui, version_string)
- GuiZSetForNextWidget(menu_gui, 100)
- GuiText(menu_gui, screen_width / 2 - text_width / 2, screen_height - text_height, version_string)
- --print(version_string)
- windows[menu_status].func()
- end
-end
\ No newline at end of file
diff --git a/files/scripts/player_update.lua b/files/scripts/player_update.lua
deleted file mode 100644
index 3932893..0000000
--- a/files/scripts/player_update.lua
+++ /dev/null
@@ -1,10 +0,0 @@
-local player = GetUpdatedEntityID()
-
-local x, y = EntityGetTransform(player)
-
-local controls_component = EntityGetFirstComponentIncludingDisabled(player, "ControlsComponent")
-
-local aiming_vector_x, aiming_vector_y = ComponentGetValue2(controls_component, "mAimingVector")
-local aiming_vector_normalized_x, aiming_vector_normalized_y = ComponentGetValue2(controls_component, "mAimingVectorNormalized")
-local aiming_vector_non_zero_latest_x, aiming_vector_non_zero_latest_y = ComponentGetValue2(controls_component, "mAimingVectorNonZeroLatest")
-
diff --git a/files/scripts/popup.lua b/files/scripts/popup.lua
deleted file mode 100644
index 805a1ba..0000000
--- a/files/scripts/popup.lua
+++ /dev/null
@@ -1,160 +0,0 @@
-dofile_once("data/scripts/lib/utilities.lua")
-
-active_popups = active_popups or {}
-
-local popups = {}
-
-popups.create = function(id, name, description, options, z_index)
- local popup = {}
- popup.id = id
- popup.name = name
- popup.description = description
- popup.options = options
- popup.gui = GuiCreate()
- popup.current_id = 124
- popup.z_index = z_index or 0
- popup.marked_for_destruction = false
- popup.start = function(self)
- GuiStartFrame(popup.gui)
- self.current_id = 124
- end
- popup.new_id = function(self)
- self.current_id = self.current_id + 1
- return self.current_id
- end
- popup.destroy = function(self)
- self.marked_for_destruction = true
- end
-
- -- if active popups already contains popup with same id, remove it and GuiDestroy
- for i = #active_popups, 1, -1 do
- local active_popup = active_popups[i]
- if (active_popup.id == popup.id) then
- table.remove(active_popups, i)
- GuiDestroy(active_popup.gui)
- end
- end
-
- table.insert(active_popups, popup)
-
- return popup
-end
-
-popups.update = function()
- local to_destroy = {}
-
- -- iterate in reverse
- for i = #active_popups, 1, -1 do
- local popup = active_popups[i]
-
- popup:start()
-
- -- if marked for destruction, remove from active_popups and GuiDestroy
- if (popup.marked_for_destruction) then
- table.remove(active_popups, i)
- table.insert(to_destroy, popup.gui)
- goto continue
- end
-
- local screen_width, screen_height = GuiGetScreenDimensions(popup.gui)
-
- local z_index = popup.z_index - (i + 10)
-
- --print("z_index: " .. tostring(z_index))
- --print(pretty.table(popup))
-
- GuiBeginAutoBox(popup.gui)
- GuiLayoutBeginVertical(popup.gui, 0, 0)
- if (popup.name) then
- GuiColorSetForNextWidget(popup.gui, 1, 1, 1, 1)
- local text_width, text_height = GuiGetTextDimensions(popup.gui, GameTextGetTranslatedOrNot(popup.name))
- GuiZSetForNextWidget(popup.gui, z_index - 1)
- GuiOptionsAddForNextWidget(popup.gui, GUI_OPTION.Align_HorizontalCenter)
- GuiText(popup.gui, (screen_width / 2), (screen_height / 2) - (text_height / 2), GameTextGetTranslatedOrNot(popup.name))
- end
- if (popup.description) then
- if(type(popup.description) == "string")then
- GuiColorSetForNextWidget(popup.gui, 1, 1, 1, 0.8)
- local text_width, text_height = GuiGetTextDimensions(popup.gui, GameTextGetTranslatedOrNot(popup.description))
- GuiZSetForNextWidget(popup.gui, z_index - 1)
- GuiOptionsAddForNextWidget(popup.gui, GUI_OPTION.Align_HorizontalCenter)
- GuiText(popup.gui, (screen_width / 2), 0, GameTextGetTranslatedOrNot(popup.description))
- elseif(type(popup.description) == "table")then
- for i, line in ipairs(popup.description) do
- if(type(line) == "string")then
- GuiColorSetForNextWidget(popup.gui, 1, 1, 1, 0.8)
- local text_width, text_height = GuiGetTextDimensions(popup.gui, GameTextGetTranslatedOrNot(line))
- GuiZSetForNextWidget(popup.gui, z_index - 1)
- GuiOptionsAddForNextWidget(popup.gui, GUI_OPTION.Align_HorizontalCenter)
- GuiText(popup.gui, (screen_width / 2), 0, GameTextGetTranslatedOrNot(line))
- elseif(type(line) == "table")then
- local text_string = GameTextGetTranslatedOrNot(line.text)
- local text_color = line.color
-
- if(text_color)then
- GuiColorSetForNextWidget(popup.gui, text_color[1], text_color[2], text_color[3], text_color[4])
- else
- GuiColorSetForNextWidget(popup.gui, 1, 1, 1, 0.8)
- end
-
- local text_width, text_height = GuiGetTextDimensions(popup.gui, text_string)
- GuiZSetForNextWidget(popup.gui, z_index - 1)
- GuiOptionsAddForNextWidget(popup.gui, GUI_OPTION.Align_HorizontalCenter)
- GuiText(popup.gui, (screen_width / 2), 0, text_string)
- end
- end
- elseif(type(popup.description) == "function")then
- local text_string = popup.description(popup)
- GuiColorSetForNextWidget(popup.gui, 1, 1, 1, 0.8)
- local text_width, text_height = GuiGetTextDimensions(popup.gui, GameTextGetTranslatedOrNot(text_string))
- GuiZSetForNextWidget(popup.gui, z_index - 1)
- GuiOptionsAddForNextWidget(popup.gui, GUI_OPTION.Align_HorizontalCenter)
- GuiText(popup.gui, (screen_width / 2), 0, GameTextGetTranslatedOrNot(text_string))
- end
- end
-
-
- local final_options = {}
- for j, option in ipairs(popup.options) do
- local id = popup:new_id()
- local text_width, text_height = GuiGetTextDimensions(popup.gui, GameTextGetTranslatedOrNot(option.text))
- table.insert(final_options, { id = id, option = option, width = text_width })
- end
-
- GuiLayoutBeginHorizontal(popup.gui, 0, 0, false, 0, 0)
- -- center buttons next to eachother, with a bit of padding
- local total_width = 0
- for j, option in ipairs(final_options) do
- total_width = total_width + option.width
- if (j ~= #final_options) then
- total_width = total_width + 20
- end
- end
- local x = (screen_width / 2) - (total_width / 2)
- for j, option in ipairs(final_options) do
- GuiColorSetForNextWidget(popup.gui, 1, 1, 1, 1)
- GuiZSetForNextWidget(popup.gui, z_index - 1)
- if (GuiButton(popup.gui, option.id, j == 1 and x or 20, 4, GameTextGetTranslatedOrNot(option.option.text))) then
- table.remove(active_popups, i)
- table.insert(to_destroy, popup.gui)
- option.option.callback()
- end
- end
-
- GuiLayoutEnd(popup.gui)
-
- GuiLayoutEnd(popup.gui)
-
- GuiZSetForNextWidget(popup.gui, z_index)
- GuiEndAutoBoxNinePiece(popup.gui, 5, 0, 0, true)
-
- ::continue::
- end
-
- for i, gui in ipairs(to_destroy) do
- GuiDestroy(gui)
- popup.destroyed = true
- end
-end
-
-return popups
diff --git a/files/scripts/text_input.lua b/files/scripts/text_input.lua
deleted file mode 100644
index aa8cab5..0000000
--- a/files/scripts/text_input.lua
+++ /dev/null
@@ -1,214 +0,0 @@
-local text_input = {}
-
-text_input.create = function(gui, x, y, width, default_text, character_limit, allowed_characters, banned_characters, z_index)
- local input_instance = {}
- input_instance.gui = gui
- input_instance.x = x
- input_instance.y = y
- input_instance.width = width
- input_instance.default_text = default_text
- input_instance.character_limit = character_limit or 0
- input_instance.allowed_characters = {}
- input_instance.banned_characters = {}
- input_instance.z_index = z_index or 0
- input_instance.text = default_text or ""
- input_instance.cursor_pos = 0
- input_instance.cursor_timer = 0
- input_instance.cursor_visible = true
- input_instance.focus = false
- input_instance.id = 159023
-
- allowed_characters = allowed_characters or nil
-
- mp_log:print("Creating text input with allowed characters: " .. tostring(allowed_characters))
-
- -- add allowed characters
-
- if(allowed_characters ~= nil)then
- for char_index = 1, utf8.len(allowed_characters) do
- local character = utf8.sub(allowed_characters, char_index, char_index)
- input_instance.allowed_characters[character] = true
- end
- end
-
- -- add banned characters
-
- if(banned_characters ~= nil)then
- for char_index = 1, utf8.len(banned_characters) do
- local character = utf8.sub(banned_characters, char_index, char_index)
- input_instance.banned_characters[character] = true
- end
- end
-
- input_instance.new_id = function(self)
- self.id = self.id + 1
- return self.id
- end
-
- input_instance.start_frame = function(self)
- self.id = 0
- end
-
- input_instance.transform = function(self, x, y, width)
- self.width = width
- self.x = x
- self.y = y
- end
-
- input_instance.update = function(self)
-
- local mouse_x, mouse_y = input:GetUIMousePos(self.gui)
- local left_clicked = input:WasMousePressed("left")
-
- -- check if we are clicking on the input
- if(left_clicked and mouse_x >= self.x + 2 and mouse_x <= (self.x + 2) + (self.width - 4) and mouse_y >= self.y + 2 and mouse_y <= self.y + 12)then
- self.focus = true
- mp_log:print("Chat input selected.")
- elseif(left_clicked)then
- self.focus = false
- end
-
- if(not self.focus)then
- return
- end
-
- -- calculate cursor visibility
- self.cursor_timer = self.cursor_timer + 1
- if (self.cursor_timer > 30) then
- self.cursor_timer = 0
- self.cursor_visible = not self.cursor_visible
- end
-
- --print(json.stringify(input:GetChars()))
-
- --[[
- if(left_clicked)then
- -- calculate the cursor position
- local cursor_x = mouse_x - (self.x + 2)
- local cursor_pos = 0
- local text_width = 0
-
-
- end
- ]]
-
- -- handle ctrl + v for pasting
- if((input:IsKeyDown("left ctrl") or input:IsKeyDown("right ctrl")) and input:GetInput("v"))then
- local clipboard = input:GetClipboardText()
- if(clipboard ~= nil)then
- self.text = utf8.sub(self.text, 1, self.cursor_pos) .. clipboard .. utf8.sub(self.text, self.cursor_pos + 1)
- self.cursor_pos = self.cursor_pos + utf8.len(clipboard)
- end
- elseif(input:GetInput("space"))then
-
- -- make sure we are not over the character limit
- if(self.character_limit > 0 and utf8.len(self.text) >= self.character_limit)then
- return
- end
-
- self.text = utf8.sub(self.text, 1, self.cursor_pos) .. " " .. utf8.sub(self.text, self.cursor_pos + 1)
- self.cursor_pos = self.cursor_pos + 1
- if(self.cursor_pos > utf8.len(self.text))then
- self.cursor_pos = utf8.len(self.text)
- end
- elseif(input:GetInput("backspace"))then
- self.text = utf8.sub(self.text, 1, self.cursor_pos - 1) .. utf8.sub(self.text, self.cursor_pos + 1)
- self.cursor_pos = math.max(0, self.cursor_pos - 1)
- elseif(input:GetInput("delete"))then
- self.text = utf8.sub(self.text, 1, self.cursor_pos) .. utf8.sub(self.text, self.cursor_pos + 2)
- elseif(input:GetInput("left") and (input:IsKeyDown("left ctrl") or input:IsKeyDown("right ctrl")))then
- -- skip back one word
- local new_cursor_pos = self.cursor_pos
- while(new_cursor_pos > 0)do
- new_cursor_pos = new_cursor_pos - 1
- local char = utf8.sub(self.text, new_cursor_pos, new_cursor_pos)
- if(char == " ")then
- break
- end
- end
- self.cursor_pos = new_cursor_pos
- elseif(input:GetInput("right") and (input:IsKeyDown("left ctrl") or input:IsKeyDown("right ctrl")))then
- -- skip forward one word
- local new_cursor_pos = self.cursor_pos
- while(new_cursor_pos < utf8.len(self.text))do
- new_cursor_pos = new_cursor_pos + 1
- local char = utf8.sub(self.text, new_cursor_pos, new_cursor_pos)
- if(char == " ")then
- break
- end
- end
- self.cursor_pos = new_cursor_pos
- elseif(input:GetInput("left"))then
- self.cursor_pos = math.max(0, self.cursor_pos - 1)
- elseif(input:GetInput("right"))then
- self.cursor_pos = math.min(self.cursor_pos + 1, utf8.len(self.text))
- else
- local chars = input:GetChars() or {}
-
- for k, v in ipairs(chars)do
-
- -- make sure we are not over the character limit
- if(self.character_limit > 0 and utf8.len(self.text) >= self.character_limit)then
- return
- end
-
- --print("Char: " .. tostring(v))
- if (#(self.allowed_characters) == 0 or self.allowed_characters[v]) then
- if (self.banned_characters[v]) then
- return
- end
- self.text = utf8.sub(self.text, 1, self.cursor_pos) .. v .. utf8.sub(self.text, self.cursor_pos + 1)
-
- self.cursor_pos = self.cursor_pos + utf8.len(v)
- end
- end
- end
-
- end
-
- input_instance.draw = function(self)
- self:start_frame()
-
- local scroll_container_id = 35238523 + GameGetFrameNum() % 2
- GuiBeginScrollContainer(self.gui, scroll_container_id, self.x + 2, self.y + 2, self.width - 4, 8, false, 0, 0)
-
- -- split text at cursor position
- local text_before_cursor = utf8.sub(self.text, 1, self.cursor_pos)
- local text_after_cursor = utf8.sub(self.text, self.cursor_pos + 1)
- local text_width, text_height = GuiGetTextDimensions(self.gui, self.text)
-
- -- Check if the text_width is more significant than the container width, then get the cursor width
- local cursor_width = 0
- if text_width > self.width then
- local text_before_cursor = utf8.sub(self.text, 1, self.cursor_pos)
- cursor_width = GuiGetTextDimensions(self.gui, text_before_cursor)
- end
-
- -- calculate text offset
- local text_offset_x = math.max(0, cursor_width - (self.width - 6))
-
- GuiLayoutBeginHorizontal(self.gui, -text_offset_x, -1, true)
-
- if(self.focus)then
- -- draw text before cursor
- GuiText(self.gui, 0, 0, text_before_cursor)
-
- -- draw cursor
- GuiImage(self.gui, self:new_id(), -2, 1, "mods/evaisa.mp/files/gfx/ui/input_cursor.png", self.cursor_visible and 1 or 0, 1, 1)
-
- -- draw text after cursor
- GuiText(self.gui, -2, 0, text_after_cursor)
- else
- GuiText(self.gui, 0, 0, self.text)
- end
- GuiLayoutEnd(self.gui)
-
-
-
- GuiEndScrollContainer(self.gui)
- end
-
- return input_instance
-end
-
-return text_input
diff --git a/files/scripts/utils.lua b/files/scripts/utils.lua
deleted file mode 100644
index c5ebe7e..0000000
--- a/files/scripts/utils.lua
+++ /dev/null
@@ -1,13 +0,0 @@
-players = players or {}
-
-function AllPlayers()
- return players
-end
-
-function AddPlayer(player)
- players[player.id] = player
-end
-
-function RemovePlayer(player_id)
- players[player_id] = nil
-end
\ No newline at end of file
diff --git a/files/scripts/voice_hud.lua b/files/scripts/voice_hud.lua
deleted file mode 100644
index 25c53ee..0000000
--- a/files/scripts/voice_hud.lua
+++ /dev/null
@@ -1,69 +0,0 @@
-dofile_once("data/scripts/lib/utilities.lua")
-
-voice_hud_gui = voice_hud_gui or GuiCreate()
-
-GuiStartFrame(voice_hud_gui)
-
-if IsPaused() then return end
-
-GuiOptionsAdd(voice_hud_gui, GUI_OPTION.NoPositionTween)
-
-local screen_width, screen_height = GuiGetScreenDimensions(voice_hud_gui)
-
-local smallfolk = dofile_once("mods/evaisa.mp/lib/smallfolk.lua")
-
-local raw = GlobalsGetValue("evaisa.mp.speaking_players", "")
-local speaking = (raw ~= "" and smallfolk.loads(raw)) or {}
-
-local frame = GameGetFrameNum()
-
-local entries = {}
-for steam_id, data in pairs(speaking) do
- if frame - data.frame < 12 then
- table.insert(entries, { steam_id = steam_id, data = data })
- end
-end
-
-if #entries == 0 then return end
-
-table.sort(entries, function(a, b) return a.data.name < b.data.name end)
-
-local avatar_size = 10
-local entry_w = 80
-local entry_h = avatar_size + 2
-local pad = 2
-local gap = 2
-local border = 2
-local total_h = #entries * (entry_h + gap) - gap
-local x = 4
-local y = screen_height - 4 - total_h
-
-for i, e in ipairs(entries) do
- local level = e.data.level or 0
- local max_lvl = 0.1
- local filled_w = math.max(0, math.floor(math.min(level / max_lvl, 1.0) * entry_w))
- local ey = y + (i - 1) * (entry_h + gap)
- local id_base = 7180000 + i * 10
-
- GuiZSetForNextWidget(voice_hud_gui, 20)
- GuiImageNinePiece(voice_hud_gui, id_base + 2, x, ey, entry_w, entry_h)
-
- if filled_w > 0 then
- local is_local = e.data.is_local
- GuiZSetForNextWidget(voice_hud_gui, 19)
- if is_local then
- GuiColorSetForNextWidget(voice_hud_gui, 0.3, 0.75, 0.35, 0.55)
- else
- GuiColorSetForNextWidget(voice_hud_gui, 0.25, 0.55, 0.85, 0.55)
- end
- GuiImage(voice_hud_gui, id_base + 1, x, ey, "mods/evaisa.mp/files/gfx/ui/1pixel.png", 1, filled_w, entry_h, 0)
- end
-
- local avatar_path = steam_utils.getUserAvatar(steam.extra.parseUint64(e.steam_id))
- GuiZSetForNextWidget(voice_hud_gui, 18)
- GuiImage(voice_hud_gui, id_base + 3, x + pad, ey + 1, avatar_path, 1, avatar_size / 32, avatar_size / 32, 0)
-
- GuiZSetForNextWidget(voice_hud_gui, 18)
- GuiColorSetForNextWidget(voice_hud_gui, 1, 1, 1, 0.95)
- GuiText(voice_hud_gui, x + pad + avatar_size + pad, ey + 2, e.data.name)
-end
diff --git a/files/scripts/voicechat_test.lua b/files/scripts/voicechat_test.lua
deleted file mode 100644
index d6aa00d..0000000
--- a/files/scripts/voicechat_test.lua
+++ /dev/null
@@ -1,232 +0,0 @@
-local vc_test = {}
-
-local STATE_IDLE = "idle"
-local STATE_RECORDING = "recording"
-local STATE_STOPPED = "stopped"
-
-local INSTANT_DELAY_FRAMES = 2 * 60
-local MIC_TEST_DELAY_FRAMES = 30
-
-local state = STATE_IDLE
-local window_open = false
-local instant_mode = false
-local mic_test_mode = false
-local recorded_audio = nil
-local instant_queue = {}
-local mic_test_queue = {}
-local gui_id_base = 9700
-local noita_gui = nil
-
-local function loopback_receive(chunk)
- if voicechat == nil then return end
- if voicechat.is_recording() then
- voicechat.record_chunk(chunk)
- end
- if instant_mode then
- table.insert(instant_queue, { data = chunk, frame = GameGetFrameNum() + INSTANT_DELAY_FRAMES })
- end
- if mic_test_mode then
- table.insert(mic_test_queue, { data = chunk, frame = GameGetFrameNum() + MIC_TEST_DELAY_FRAMES })
- end
-end
-
-vc_test.toggle_window = function()
- window_open = not window_open
-end
-
-vc_test.is_open = function()
- return window_open
-end
-
-vc_test.is_mic_testing = function()
- return mic_test_mode
-end
-
-vc_test.toggle_mic_test = function()
- mic_test_mode = not mic_test_mode
- mic_test_queue = {}
-end
-
-vc_test.loopback_receive = loopback_receive
-
-local function start_recording()
- if voicechat == nil then return end
- state = STATE_RECORDING
- recorded_audio = nil
- instant_queue = {}
- voicechat.start_recording()
-end
-
-local function stop_recording()
- if voicechat == nil then return end
- recorded_audio = voicechat.stop_recording()
- state = STATE_STOPPED
-end
-
-local function play_recorded()
- if voicechat == nil or recorded_audio == nil or recorded_audio == "" then return end
- voicechat.play_direct(recorded_audio)
-end
-
-vc_test.update = function()
- if not window_open and not mic_test_mode then return end
-
- if mic_test_mode and #mic_test_queue > 0 then
- local frame = GameGetFrameNum()
- local i = 1
- while i <= #mic_test_queue do
- local entry = mic_test_queue[i]
- if frame >= entry.frame then
- if voicechat ~= nil then
- voicechat.play_direct(entry.data)
- end
- table.remove(mic_test_queue, i)
- else
- i = i + 1
- end
- end
- end
-
- if not window_open then return end
-
- if instant_mode and #instant_queue > 0 then
- local frame = GameGetFrameNum()
- local i = 1
- while i <= #instant_queue do
- local entry = instant_queue[i]
- if frame >= entry.frame then
- if voicechat ~= nil then
- voicechat.play_voice(entry.data, 0, 0)
- end
- table.remove(instant_queue, i)
- else
- i = i + 1
- end
- end
- end
-
- if imgui ~= nil then
- vc_test.draw_imgui()
- else
- vc_test.draw_gui()
- end
-end
-
-vc_test.draw_imgui = function()
- if imgui.Begin("Voice Chat Test [Ctrl+Shift+V]") then
- imgui.Text("Loopback test: audio is captured, sent through")
- imgui.Text("the network message system to yourself, then recorded.")
- imgui.Separator()
-
- local _, new_instant = imgui.Checkbox("Instant Playback (2s delay)", instant_mode)
- if new_instant ~= instant_mode then
- instant_mode = new_instant
- instant_queue = {}
- end
-
- imgui.Separator()
-
- if state == STATE_IDLE then
- if imgui.Button("Start Recording") then
- start_recording()
- end
- elseif state == STATE_RECORDING then
- imgui.TextColored(1, 0.2, 0.2, 1, "* Recording...")
- if imgui.Button("Stop Recording") then
- stop_recording()
- end
- elseif state == STATE_STOPPED then
- local audio_len = recorded_audio and #recorded_audio or 0
- local seconds = audio_len / (8000 * 2)
- imgui.Text(string.format("Recorded: %.2f seconds (%d bytes)", seconds, audio_len))
-
- if imgui.Button("Play") then
- play_recorded()
- end
- imgui.SameLine()
- if imgui.Button("Record Again") then
- start_recording()
- end
- imgui.SameLine()
- if imgui.Button("Clear") then
- state = STATE_IDLE
- recorded_audio = nil
- end
- end
-
- imgui.Separator()
- local status_str = "Status: " .. state
- if instant_mode and #instant_queue > 0 then
- status_str = status_str .. " | queued: " .. #instant_queue
- end
- imgui.Text(status_str)
- end
- imgui.End()
-end
-
-local function get_gui()
- if noita_gui == nil then
- noita_gui = GuiCreate()
- end
- return noita_gui
-end
-
-vc_test.draw_gui = function()
- local gui = get_gui()
- GuiStartFrame(gui)
-
- local win_x = 10
- local win_y = 80
- local im_id = gui_id_base
-
- local function next_id()
- im_id = im_id + 1
- return im_id
- end
-
- GuiText(gui, win_x, win_y, "[ Voice Chat Test ] (Ctrl+Shift+V to close)")
-
- local instant_label = instant_mode and "[x] Instant Playback (5s delay)" or "[ ] Instant Playback (5s delay)"
- local instant_clicked = GuiButton(gui, next_id(), win_x, win_y + 12, instant_label)
- if instant_clicked then
- instant_mode = not instant_mode
- instant_queue = {}
- end
-
- if state == STATE_IDLE then
- local clicked = GuiButton(gui, next_id(), win_x, win_y + 26, "Start Recording")
- if clicked then
- start_recording()
- end
- elseif state == STATE_RECORDING then
- GuiText(gui, win_x, win_y + 26, "* Recording (Ctrl+Shift+V toggles window)")
- local clicked = GuiButton(gui, next_id(), win_x, win_y + 38, "Stop Recording")
- if clicked then
- stop_recording()
- end
- elseif state == STATE_STOPPED then
- local audio_len = recorded_audio and #recorded_audio or 0
- local seconds = audio_len / (8000 * 2)
- GuiText(gui, win_x, win_y + 26, string.format("Recorded: %.1fs (%d bytes)", seconds, audio_len))
-
- local play_clicked = GuiButton(gui, next_id(), win_x, win_y + 38, "Play")
- if play_clicked then
- play_recorded()
- end
- local again_clicked = GuiButton(gui, next_id(), win_x + 32, win_y + 38, "Record Again")
- if again_clicked then
- start_recording()
- end
- local clear_clicked = GuiButton(gui, next_id(), win_x, win_y + 50, "Clear")
- if clear_clicked then
- state = STATE_IDLE
- recorded_audio = nil
- end
- end
-
- if instant_mode and #instant_queue > 0 then
- GuiText(gui, win_x, win_y + 64, "Queued chunks: " .. #instant_queue)
- end
-end
-
-return vc_test
diff --git a/icon.png b/icon.png
deleted file mode 100644
index ab8f1e6..0000000
Binary files a/icon.png and /dev/null differ
diff --git a/ideas.txt b/ideas.txt
deleted file mode 100644
index b99ad18..0000000
--- a/ideas.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-the players get dropped in an arena, dropping random wands and gold nuggets into the arena, then after one kills the other the losing player gets to pick a perk.
-Then both players get teleported to a shop area where they can edit their wands and buy spells
-after another countdown they get teleported to the arena again
-repeat
-
-might have random effects that can happen in the arena each time, like enemies spawning or players getting random buffs or debuffs etc
-different each round
\ No newline at end of file
diff --git a/init.lua b/init.lua
deleted file mode 100644
index 1fedad5..0000000
--- a/init.lua
+++ /dev/null
@@ -1,2061 +0,0 @@
---------- STATIC VARIABLES ---------
-
-game_id = 881100
-
--- load version numbers
-dofile("mods/evaisa.mp/version.lua")
-
-noita_online_download = "https://github.com/EvaisaDev/noita-online/releases"
-exceptions_in_logger = true
-dev_mode = false
-debugging = false
-disable_print = true
-trailer_mode = false
-disable_error_catching = false
-
------------------------------------
-
-popup = dofile("mods/evaisa.mp/files/scripts/popup.lua")
-try = dofile("mods/evaisa.mp/lib/try_catch.lua")
-local ffi = require"ffi"
-
------ check if thingy is installed ------
-local failed_to_load = false
-try(function()
- local _ = ffi.load("msvcp140.dll")
-end).catch(function(ex)
- print("Failed to load msvcp140.dll")
- failed_to_load = true
-end)
-
-
------- TRANSLATIONS -------
-
-dofile("mods/evaisa.mp/lib/translations.lua")
-
-register_localizations("mods/evaisa.mp/translations.csv", 2)
-
----------------------------
-
------- Path definitions -------
-package.path = package.path .. ";./mods/evaisa.mp/lib/?.lua"
-package.path = package.path .. ";./mods/evaisa.mp/lib/?/init.lua"
-package.cpath = package.cpath .. ";./mods/evaisa.mp/bin/?.dll"
-package.cpath = package.cpath .. ";./mods/evaisa.mp/bin/?.exe"
-
-local function load(modulename)
- local errmsg = ""
- for path in string.gmatch(package.path, "([^;]+)") do
- local filename = string.gsub(path, "%?", modulename)
- local file = io.open(filename, "rb")
- if file then
- -- Compile and return the module
- return assert(loadstring(assert(file:read("*a")), filename))
- end
- errmsg = errmsg .. "\n\tno file '" .. filename .. "' (checked with custom loader)"
- end
- return errmsg
-end
-
----------------------------
-
-
-
-string.bytes = function(str)
- local bytes = 0
- for i = 1, #str do
- bytes = bytes + str:byte(i)
- end
- return bytes
-end
-
-get_content = ModTextFileGetContent
-set_content = ModTextFileSetContent
-
-dofile("mods/evaisa.mp/lib/ffi_extensions.lua")
-
-
-
-
--- do not apply any callbacks or anything because this is fucked up and evil
-if(not failed_to_load)then
-
- ----------------- Gui Option Jankery ----------------
-
- local gui_option_cache = {}
-
- local gui_option_add = GuiOptionsAdd
- local gui_option_remove = GuiOptionsRemove
-
- function GuiOptionsAdd(gui, option)
- gui_option_cache[gui] = gui_option_cache[gui] or {}
- gui_option_cache[gui][option] = true
- gui_option_add(gui, option)
- end
-
- function GuiOptionsRemove(gui, option)
- if(gui_option_cache[gui] and gui_option_cache[gui][option])then
- gui_option_remove(gui, option)
- gui_option_cache[gui][option] = nil
- end
- end
-
- -- epic new function truly
- function GuiOptionsHas(gui, option)
- return gui_option_cache[gui] and gui_option_cache[gui][option]
- end
-
- function GuiOptionsList(gui)
- local options = {}
-
- if(gui_option_cache[gui])then
- for k, v in pairs(gui_option_cache[gui])do
- table.insert(options, k)
- end
- end
-
- return options
- end
-
- local gamemode_path = nil
-
- -- Old function, doesn't work properly if multiple installs of mod exists and i do not know how to solve this.
- function GetGamemodeFilePath()
-
- if(gamemode_path)then
- return gamemode_path
- end
-
- debug_log:print("GetGamemodeFilePath")
-
- local save_folder = os.getenv('APPDATA'):gsub("\\Roaming", "") ..
- "\\LocalLow\\Nolla_Games_Noita\\save00\\mod_config.xml"
-
- local file_path = nil
-
- local file, err = io.open(save_folder, 'rb')
- if file then
-
- debug_log:print("Found mod_config.xml")
-
- local content = file:read("*all")
-
- local subscribed_items = steam.UGC.getSubscribedItems()
- local item_infos = {}
-
- for _, v in ipairs(subscribed_items) do
-
- local success, size, folder, timestamp = steam.UGC.getItemInstallInfo(v)
- if (success) then
- item_infos[tostring(v)] = {size = size, folder = folder, timestamp = timestamp}
- end
-
- end
-
-
- local parsedModData = nxml.parse(content)
- for elem in parsedModData:each_child() do
- if (elem.name == "Mod") then
- local modID = elem.attr.name
- local steamID = elem.attr.workshop_item_id
-
- local infoFile = "mods/" .. modID .. "/mod.xml"
- if (steamID ~= "0") then
- if(item_infos[steamID])then
- infoFile = item_infos[steamID].folder .. "/mod.xml"
- else
- debug_log:print("Failed to find item info for: " .. steamID)
- infoFile = nil
- end
- end
-
- if(infoFile)then
-
- local file2, err = io.open(infoFile, 'rb')
- if file2 then
- local content2 = file2:read("*all")
- if(content2 ~= nil and content2 ~= "")then
- local parsedModInfo = nxml.parse(content2)
-
- local is_game_mode = parsedModInfo.attr.is_game_mode == "1"
-
- if (ModIsEnabled(modID) and is_game_mode) then
- if steamID == "0" then
- file_path = "mods/" .. modID
- else
- file_path = item_infos[steamID].folder
- end
- break
- end
- end
- else
- debug_log:print("Failed to open mod.xml: " .. infoFile)
- debug_log:print("Error: " .. tostring(err))
- end
- end
-
- end
- end
- file:close()
-
-
- end
- debug_log:print("Gamemode path: " .. tostring(file_path))
-
- gamemode_path = file_path
-
- return file_path
- end
-
- function GetModFilePath(mod_id, steam_id)
- local file_path = nil
-
- if(not steam_id or steam_id == "" or steam_id == "0")then
- file_path = "mods/" .. mod_id
- else
- local subscribed_items = steam.UGC.getSubscribedItems()
- local item_infos = {}
-
- for _, v in ipairs(subscribed_items) do
-
- local success, size, folder, timestamp = steam.UGC.getItemInstallInfo(v)
- if (success) then
- item_infos[tostring(v)] = {size = size, folder = folder, timestamp = timestamp}
- end
-
- end
-
- if(item_infos[steam_id])then
- file_path = item_infos[steam_id].folder
- end
- end
-
- return file_path
- end
-
-
- if(trailer_mode)then
- ModMagicNumbersFileAdd("mods/evaisa.mp/magic_numbers_trailer.xml")
- end
-
- if(ModIsEnabled("NoitaDearImGui"))then
- imgui = load_imgui({mod="noita-online", version="1.20"})
- implot = imgui.implot
- end
-
- local inspect = dofile("mods/evaisa.mp/lib/inspect.lua")
-
- zstandard = require("zstd")
- zstd = zstandard:new()
-
- table.insert(package.loaders, 2, load)
-
- logger = require("logger")("noita_online_logs")
- mp_log = logger.init("noita-online.log")
- networking_log = logger.init("networking.log")
- debug_log = logger.init("debugging.log")
- exception_log = logger.init(os.date("%Y-%m-%d_%H-%M-%S")..".log", false, nil, "noita_online_logs/exceptions")
- debug_info = logger.init("debug_info.log", nil, true, nil, true)
-
- if(not debugging)then
- networking_log.enabled = false
- end
-
- --fontbuilder = dofile("mods/evaisa.mp/lib/fontbuilder.lua")
-
- game_config = dofile("mods/evaisa.mp/lib/game_config.lua")
-
- local function readWord(file)
- local byte1, byte2 = file:read(1), file:read(1)
- if not byte1 or not byte2 then
- return nil
- end
- return byte1:byte() + byte2:byte() * 256
- end
-
- local function readDword(file)
- local word1, word2 = readWord(file), readWord(file)
- if not word1 or not word2 then
- return nil
- end
- return word1 + word2 * 65536
- end
-
- local function checkLAA(filename)
- local file, err = io.open(filename, "rb")
- if not file then
- print("Error opening file: " .. err)
- return false
- end
-
- file:seek("set", 0x3C)
- local peOffset = readDword(file)
-
- file:seek("set", peOffset + 4) -- Go to IMAGE_FILE_HEADER
- local characteristicsOffset = peOffset + 22 -- Offset of "Characteristics" field
-
- file:seek("set", characteristicsOffset)
- local characteristics = readWord(file)
-
- file:close()
-
- return bit.band(characteristics, 0x20) == 0x20 -- Properly check the IMAGE_FILE_LARGE_ADDRESS_AWARE flag
- end
-
- lobby_data_last_frame = {}
- lobby_data_updated_this_frame = {}
-
- ModRegisterAudioEventMappings("mods/evaisa.mp/GUIDs.txt")
-
- dofile_once("mods/evaisa.mp/files/scripts/gui_utils.lua")
-
- dofile("data/scripts/lib/coroutines.lua")
- nxml = dofile("mods/evaisa.mp/lib/nxml.lua")
-
- try(function()
- require 'lua-utf8'
- end).catch(function(ex)
- exception_log:print(tostring(ex))
- if(exceptions_in_logger)then
- old_print(tostring(ex))
- end
- end)
-
-
- pngencoder = require("pngencoder")
-
- dofile_once("mods/evaisa.mp/bin/NoitaPatcher/load.lua")
-
- np = require("noitapatcher")
-
- bitser = require("bitser")
- smallfolk = require("smallfolk")
- binser = require("binser")
- --zstandard = require("zstd")
- --zstd = zstandard:new()
- delay = dofile("mods/evaisa.mp/lib/delay.lua")
- streaming = dofile("mods/evaisa.mp/lib/streaming.lua")
- voicechat = dofile("mods/evaisa.mp/lib/voicechat.lua")
- vc_test = dofile("mods/evaisa.mp/files/scripts/voicechat_test.lua")
- vad_hold_frames_remaining = 0
-
- local function get_mic_above_threshold()
- local level = voicechat.get_mic_level()
- local threshold = tonumber(ModSettingGet("evaisa.mp.voicechat_vad_threshold")) or 0.04
- if level >= threshold then
- vad_hold_frames_remaining = 45
- return true
- elseif vad_hold_frames_remaining > 0 then
- vad_hold_frames_remaining = vad_hold_frames_remaining - 1
- return true
- end
- return false
- end
-
- local profiler_ui = dofile("mods/evaisa.mp/lib/profiler_ui.lua")
-
-
- debug_info:print("Build: " .. tostring(MP_VERSION))
-
- rng = dofile("mods/evaisa.mp/lib/rng.lua")
- rand = nil
-
- in_game = false
- Spawned = false
- Starting = nil
-
- cached_lobby_data = {}
-
- lobby_gamemode = nil
-
- local function unlock_hidden_chat_player()
- if(not GameHasFlagRun("player_locked_chat"))then
- return
- end
-
- local players = EntityGetWithTag("player_unit")
- if(players == nil or players[1] == nil)then
- GameRemoveFlagRun("player_locked_chat")
- return
- end
-
- if(not GameHasFlagRun("player_locked"))then
- local controls = EntityGetFirstComponentIncludingDisabled(players[1], "ControlsComponent")
- if(controls ~= nil)then
- ComponentSetValue2(controls, "enabled", true)
- end
- end
-
- GameRemoveFlagRun("player_locked_chat")
- end
-
- local function should_hide_online_ui_for_arena()
- if(lobby_code == nil or not ModIsEnabled("evaisa.arena"))then
- return false
- end
-
- if(not ModSettingGet("evaisa.arena.hide_ui_in_combat"))then
- return false
- end
-
- if((steam.matchmaking.getLobbyData(lobby_code, "arena_state") or "lobby") ~= "arena")then
- return false
- end
-
- return GameHasFlagRun("evaisa_arena_hide_ui")
- end
-
- local function reset_online_ui_for_arena()
- chat_open = false
- chat_opened_with_bind = false
- if(chat_input ~= nil)then
- chat_input.focus = false
- end
- if(GameHasFlagRun("chat_input_hovered"))then
- GameRemoveFlagRun("chat_input_hovered")
- end
- GameRemoveFlagRun("chat_bind_disabled")
- unlock_hidden_chat_player()
-
- gui_closed = true
- invite_menu_open = false
- mod_list_open = false
- lobby_settings_open = false
- lobby_presets_open = false
- was_lobby_presets_open = false
- selected_player = nil
- show_lobby_code = false
- end
-
-
-
- debug_info:print("Dev mode: " .. tostring(dev_mode))
-
- local fs = require("fs")
-
- local sha1 = require "sha1"
-
- function GetNoitaVersionHash()
- local file = "_version_hash.txt"
- local f = io.open(file, "r")
- if f then
- local hash = f:read("*all")
- f:close()
- return hash
- end
- return nil
- end
-
- local function sleep(ms)
- -- loop for n ms
- local t0 = os.clock()
- while os.clock() - t0 <= ms / 1000 do
- end
- end
-
-
-
- noita_version = np.GetVersionString()
-
- if(GameIsBetaBuild())then
- noita_version = noita_version .. " (beta)"
- end
-
- --[[function GetContentHash()
- local file = "data\\data.wak"
-
- -- try to run certutil
- local handle = io.popen("certutil -hashfile " .. file .. " SHA1")
-
- if not handle then
- return "Unknown"
- end
-
- local result = handle:read("*a")
- handle:close()
-
- local hash = string.match(result, "SHA1 hash of " .. file .. ":\n([%w]+)\n")
-
- if hash then
- return hash
- end
-
- -- try to run hasher.exe instead
- debug_log:print("Used hasher.exe to get the data.wak hash")
-
- local handle = io.popen("mods\\evaisa.mp\\bin\\hasher.exe \"" .. file .. "\"")
-
- if not handle then
- return "Unknown"
- end
-
- local result = handle:read("*a")
- handle:close()
-
- if not result then
- return "Unknown"
- end
-
- -- remove surrounding newlines
- result = result:gsub("^%s*(.-)%s*$", "%1")
-
- return result
- end]]
-
-
-
- --noita_version_hash = GetContentHash()
-
- --print("Noita version hash: " .. noita_version_hash)
-
-
- --debug_info:print("Noita hash: " .. tostring(noita_version_hash))
-
- --[[last_noita_version = ModSettingGet("evaisa.mp.last_noita_version_hash") or ""
- laa_check_done = true
- if(noita_version_hash ~= nil)then
- mp_log:print("Noita version hash: " .. noita_version_hash)
- if(last_noita_version ~= noita_version_hash)then
- ModSettingSet("evaisa.mp.last_noita_version_hash", noita_version_hash)
- --laa_check_done = false
- else
- --laa_check_done = true
- end
- end]]
- base64 = require("base64")
-
- msg = require("msg")
- pretty = require("pretty_print")
-
-
-
- debug_info:print("Beta build: " .. tostring(GameIsBetaBuild()))
- debug_info:print("Using controller: " .. tostring(GameGetIsGamepadConnected()))
-
- function RepairDataFolder()
- local data_folder_name = os.getenv('APPDATA'):gsub("\\Roaming", "") ..
- "\\LocalLow\\Nolla_Games_Noita\\save00\\evaisa.mp_data"
- -- remove the folder
- os.execute('del /q "' .. data_folder_name .. '\\*.*"')
- print("Repaired data folder.")
- GamePrint("Repairing data folder")
- end
-
- local serialization_version = "3"
- if ((ModSettingGet("last_serialization_version") or "1") ~= serialization_version) then
- RepairDataFolder()
- ModSettingSet("last_serialization_version", serialization_version)
- end
-
- np.InstallShootProjectileFiredCallbacks()
- np.EnableGameSimulatePausing(false)
- np.InstallDamageDetailsPatch()
- np.SilenceLogs("Warning - streaming didn\'t find any chunks it could stream away...\n")
- --[[np.EnableExtendedLogging(true)
- np.EnableLogFiltering(true)
-
- function FilterLog(source, function_name, line, ...)
- debug_log:print(source .. " " .. function_name .. " " .. line .. " " .. table.concat({...}, " "))
- return false
- end]]
-
- np.EnableLogFiltering(true)
-
- function FilterLog(source, function_name, line, ...)
- debug_log:print(source .. " " .. function_name .. " " .. line .. " " .. table.concat({...}, " "))
- -- if contains "Lua error" or "Stack traceback"
- if (string.find(table.concat({...}, " "), "Lua error") or string.find(table.concat({...}, " "), "Stack traceback")) then
- exception_log:print(source .. " " .. function_name .. " " .. line .. " " .. table.concat({...}, " "))
- return true
- end
- return false
- end
-
- --GameSDK = require("game_sdk")
-
- steam = require("luasteam")
-
-
- --GameSDK = nil
- --discord_sdk = nil
-
- --require("physics")
- steamutils = dofile_once("mods/evaisa.mp/lib/steamutils.lua")
- clear_avatar_cache()
- json = dofile_once("mods/evaisa.mp/lib/json.lua")
-
- pretty = require("pretty_print")
-
- local is_invalid_version = (PhysicsBodyIDGetBodyAABB == nil)
-
- --GamePrint("Making api call")
-
- dofile("mods/evaisa.mp/files/scripts/debugging.lua")
-
- dofile("mods/evaisa.mp/lib/character_support.lua")
-
- local old_print = print
- print = function(...)
- if not disable_print then
- local content = ...
- local source = debug.getinfo(2).source
- local line = debug.getinfo(2).currentline
-
- old_print(table.concat({"[" .. source .. ":" .. tostring(line) .. "]", ... }, " "))
- end
- end
-
- function OnPausePreUpdate()
- if voicechat ~= nil then
- if not GameHasFlagRun("evaisa.mp.voicechat_capture_opened") then
- local dev_name = ModSettingGet("evaisa.mp.mic_device_name") or ""
- voicechat.open_capture(dev_name ~= "" and dev_name or nil)
- GameAddFlagRun("evaisa.mp.voicechat_capture_opened")
- end
- if GlobalsGetValue("evaisa.mp.request_mic_test_toggle") == "1" then
- GlobalsSetValue("evaisa.mp.request_mic_test_toggle", "0")
- if vc_test ~= nil then
- vc_test.toggle_mic_test()
- end
- end
- if vc_test ~= nil then
- GlobalsSetValue("evaisa.mp.mic_test_active", vc_test.is_mic_testing() and "1" or "0")
- end
- local vc_mic_testing = vc_test ~= nil and vc_test.is_mic_testing()
- local mic_above_threshold = get_mic_above_threshold()
- local chunk = voicechat.capture_tick(vc_mic_testing and mic_above_threshold)
- if chunk ~= nil and vc_mic_testing then
- vc_test.loopback_receive(chunk)
- end
- if vc_test ~= nil then
- vc_test.update()
- end
- GlobalsSetValue("evaisa.mp.mic_level", tostring(voicechat.get_mic_level()))
- end
- end
-
-
- function OnPausedChanged(paused, is_wand_pickup)
- local players = EntityGetWithTag("player_unit") or {}
-
- if(not is_wand_pickup)then
- if(imgui)then
- profiler_ui.apply_profiler_rate()
- end
- end
-
- if (players[1]) then
- np.RegisterPlayerEntityId(players[1])
- local inventory_gui = EntityGetFirstComponentIncludingDisabled(players[1], "InventoryGuiComponent")
- local controls_component = EntityGetFirstComponentIncludingDisabled(players[1], "ControlsComponent")
- if (paused) then
- --EntitySetComponentIsEnabled(players[1], inventory_gui, false)
- np.EnableInventoryGuiUpdate(false)
- np.EnablePlayerItemPickUpper(false)
- ComponentSetValue2(controls_component, "enabled", false)
- else
- --EntitySetComponentIsEnabled(players[1], inventory_gui, true)
- np.EnableInventoryGuiUpdate(true)
- np.EnablePlayerItemPickUpper(true)
- ComponentSetValue2(controls_component, "enabled", true)
- end
- end
-
- if (paused) then
- GameAddFlagRun("game_paused")
- --GamePrint("paused")
- else
- GameRemoveFlagRun("game_paused")
- --GamePrint("unpaused")
- end
- end
-
- function IsPaused()
- return steam_overlay_open or GameHasFlagRun("game_paused")
- end
-
- if type(Steam) == 'boolean' then Steam = nil end
-
- activity = activity or nil
-
-
- game_in_progress = false
-
- gamemode_settings = gamemode_settings or {}
-
- dofile("mods/evaisa.mp/files/scripts/lobby_handler.lua")
- dofile_once("mods/evaisa.mp/files/scripts/utils.lua")
- dofile_once("data/scripts/lib/utilities.lua")
- input = nil
- bindings = nil
-
- bytes_sent = 0
- last_bytes_sent = 0
- bytes_received = 0
- last_bytes_received = 0
-
- bytes_sent_per_type = {}
- bytes_received_per_type = {}
-
- active_members = {}
- member_message_frames = {}
- gamemode_index = 1
-
- gamemodes = {}
-
- function FindGamemode(id)
- for k, v in pairs(gamemodes) do
- if (v.id == id) then
- return v, k
- end
- end
- return nil
- end
-
- function TryHandleMessage(lobby_code, event, message, user, ignore)
- print("Received message: " .. tostring(event) .. " with content: " .. tostring(message) .. " from user: " .. tostring(user))
- try(function()
- if (event == "voice" and message ~= nil and voicechat ~= nil) then
- if lobby_gamemode ~= nil and lobby_gamemode.user_can_speak and not lobby_gamemode.user_can_speak(user) then
- return
- end
- local global_vol = tonumber(ModSettingGet("evaisa.mp.voicechat_volume")) or 1.0
- local player_vol = tonumber(ModSettingGet("evaisa.mp.player_vol_" .. tostring(user))) or 1.0
- local vx, vy = message.x or 0, message.y or 0
- if lobby_gamemode ~= nil and lobby_gamemode.enable_proximity_vc and lobby_gamemode.get_voice_positions then
- local positions = lobby_gamemode.get_voice_positions(user)
- if positions ~= nil then
- for i, pos in ipairs(positions) do
- local opts = lobby_gamemode.get_voice_opts and lobby_gamemode.get_voice_opts(i) or nil
- voicechat.play_voice(message.pcm, pos[1], pos[2], global_vol, player_vol, opts)
- end
- goto voice_played
- end
- end
- voicechat.play_voice(message.pcm, vx, vy, global_vol, player_vol)
- ::voice_played::
-
- local smallfolk = dofile_once("mods/evaisa.mp/lib/smallfolk.lua")
- local raw = GlobalsGetValue("evaisa.mp.speaking_players", "")
- local speaking = (raw ~= "" and smallfolk.loads(raw)) or {}
- local user_str = tostring(user)
- if speaking[user_str] == nil then
- local name = ""
- if lobby_code ~= nil then
- local members = steam_utils.getLobbyMembers(lobby_code, true)
- for _, m in pairs(members) do
- if tostring(m.id) == user_str then
- name = tostring(m.name)
- break
- end
- end
- end
- speaking[user_str] = { name = name, frame = GameGetFrameNum(), level = 0.0 }
- else
- speaking[user_str].frame = GameGetFrameNum()
- end
- local n = #message.pcm / 2
- local sum_sq = 0.0
- for i = 1, #message.pcm, 2 do
- local lo = message.pcm:byte(i)
- local hi = message.pcm:byte(i + 1) or 0
- local s = (lo + hi * 256)
- if s >= 32768 then s = s - 65536 end
- s = s / 32768.0
- sum_sq = sum_sq + s * s
- end
- speaking[user_str].level = (n > 0) and math.sqrt(sum_sq / n) or 0
- GlobalsSetValue("evaisa.mp.speaking_players", smallfolk.dumps(speaking))
- return
- end
-
- if (lobby_gamemode ~= nil) then
- local owner = steam.matchmaking.getLobbyOwner(lobby_code)
-
- local from_owner = user == owner
-
- if (from_owner and event == "start" or event == "restart") then
-
- print("Starting game")
-
- if(lobby_gamemode.apply_start_data)then
- lobby_gamemode.apply_start_data(lobby_code, message)
- end
-
- if(event == "restart")then
- StopGame()
- end
-
- if(owner == steam_utils.getSteamID())then
- Starting = 5
- else
- Starting = 30
- end
- elseif (from_owner and event == "refresh") then
-
- print("Refreshing lobby data")
-
- if handleVersionCheck() and handleModCheck() then
- if handleGamemodeVersionCheck(lobby_code) then
- if (lobby_gamemode) then
- --game_in_progress = false
- --print("Refreshing lobby data in 30 frames")
- delay.new(30, function()
- for k, setting in ipairs(lobby_gamemode.settings or {}) do
- gamemode_settings[setting.id] = steam.matchmaking.getLobbyData(lobby_code, "setting_" ..
- setting.id)
- end
-
- if (lobby_gamemode.refresh) then
- lobby_gamemode.refresh(lobby_code)
- end
- end, function(frames) end)
-
-
- else
- disconnect({
- lobbyID = lobby_code,
- message = string.format(GameTextGetTranslatedOrNot("$mp_gamemode_missing"), tostring(lobby_gamemode.id))--"Gamemode missing: " .. tostring(lobby_gamemode.id)
- })
- end
- end
- end
- elseif (owner == steam_utils.getSteamID() and event == "spectate") then
- print("Toggling spectator for " .. tostring(steamutils.getTranslatedPersonaName(user)))
- local spectating = steamutils.IsSpectator(lobby_code, user)
- steam_utils.TrySetLobbyData(lobby_code, tostring(user) .. "_spectator", spectating and "false" or "true")
- end
-
- --print("ignore? "..tostring(ignore))
-
- if (lobby_gamemode.received and not ignore) then
- lobby_gamemode.received(lobby_code, event, message, user)
- end
- end
- end).catch(function(ex)
- exception_log:print(tostring(ex))
- if(exceptions_in_logger)then
- old_print(tostring(ex))
- end
- end)
- end
-
- function HandleMessage(v, ignore)
-
- if(is_awaiting_spectate)then
- return
- end
-
- local data = steamutils.parseData(v.data)
-
- bytes_received = bytes_received + v.msg_size
-
- if (lobby_gamemode == nil) then
- return
- end
-
- -- old api
- if (lobby_gamemode.message and not ignore) then
- lobby_gamemode.message(lobby_code, data, v.user)
- end
-
- print("Received raw message: " .. tostring(v.data) .. " from user: " .. tostring(v.user) .. " with size: " .. tostring(v.msg_size))
-
- if (data[1] and type(data[1]) == "string") then
- if(bytes_received_per_type[data[1]] == nil)then
- bytes_received_per_type[data[1]] = 0
- end
- bytes_received_per_type[data[1]] = bytes_received_per_type[data[1]] + v.msg_size
- local event = data[1]
- local message = data[2]
- local frame = data[3]
-
- if (data[3]) then
- if (not member_message_frames[tostring(v.user)] or member_message_frames[tostring(v.user)] <= frame) then
- member_message_frames[tostring(v.user)] = frame
- TryHandleMessage(lobby_code, event, message, v.user, ignore)
- end
- else
- TryHandleMessage(lobby_code, event, message, v.user, ignore)
- end
- else
- print("Invalid message: "..tostring(data))
- print(inspect(data))
- end
- end
-
- local function ReceiveMessages(ignore)
- -- 10 available channels should be enough
- --for i = 0, 10 do
- --print("Polling messages on channel " .. tostring(i))
- if(is_awaiting_spectate)then
- return
- end
- local messages = steam.networking.pollMessages(0) or {}
- if(#messages > 0)then
- --print("Received " .. tostring(#messages) .. " messages")
- for k, v in ipairs(messages) do
- HandleMessage(v, ignore)
- end
- end
- --end
- end
-
- ----- debugging spell stuff ------
-
-
- --ModTextFileSetContent("mods/gun_flag.lua", [[
- --for i, action in ipairs(actions)do
- -- if(i > 4)then
- -- action.spawn_requires_flag = action.id
- -- end
- --end
- --]])
-
- --ModLuaFileAppend("data/scripts/gun/gun_actions.lua", "mods/gun_flag.lua")
-
- ----------------------------------
-
- local spawned_popup = false
- local init_cleanup = false
- local connection_popup_open = false
- local connection_popup_was_open_timer = 0
- local laa_check_busy = false
- local invalid_version_popup_open = false
-
- function OnWorldPreUpdate()
- try(function()
- if(GameHasFlagRun("mp_blocked_load"))then
- return
- end
-
- -- this code handles unpausing the mod after closing steam overlay
- --[[if(steam_overlay_closed and GameGetFrameNum() > steam_overlay_closed_frame + 60)then
- steam_overlay_closed = false
- steam_overlay_open = false
- end]]
-
- if(imgui)then
- profiler_ui.pre_update()
- else
- if (input ~= nil and input:WasKeyPressed("f8")) then
- GamePrint("Cannot use profiler without dear imgui installed.")
- end
- end
- --input:Update()
-
- wake_up_waiting_threads(1)
- --math.randomseed( os.time() )
-
- if (not IsPaused()) then
- popup.update()
- end
-
-
- if (not failed_to_load) and steam and GameGetFrameNum() >= 60 then
-
-
- --[[if(not laa_check_done)then
- laa_enabled = checkLAA("noita.exe")
- print("LAA: " .. tostring(laa_enabled))
-
-
- if(not laa_enabled)then
- laa_check_busy = true
- popup.create("laa_message", GameTextGetTranslatedOrNot("$mp_laa_message"), {
- GameTextGetTranslatedOrNot("$mp_laa_description"),
- {
- text = GameTextGetTranslatedOrNot("$mp_laa_warning"),
- color = {217 / 255,52 / 255,52 / 255, 1}
- }
- }, {
- {
- text = GameTextGetTranslatedOrNot("$mp_laa_patch"),
- callback = function()
- LAAPatch("noita.exe", "noita")
- laa_check_busy = false
- end
- },
- {
- text = GameTextGetTranslatedOrNot("$mp_close_popup"),
- callback = function()
- laa_check_busy = false
- end
- },
- }, -6000)
- end
- laa_check_done = true
- end]]
-
- if(is_invalid_version)then
-
- if(not invalid_version_popup_open)then
- invalid_version_popup_open = true
- popup.create("invalid_version_message", GameTextGetTranslatedOrNot("$mp_invalid_version"),
- GameTextGetTranslatedOrNot("$mp_invalid_version_description"), {
- {
- text = GameTextGetTranslatedOrNot("$mp_close_popup"),
- callback = function()
- invalid_version_popup_open = false
- end
- }
- }, -6000)
-
- end
- return
- end
-
- if(not laa_check_busy)then
- if(not steam.user.loggedOn())then
- if(GameGetFrameNum() % (300) == 0)then
- GamePrint("Failed to connect to steam servers, are you logged into steam friends list?")
- end
-
- if(connection_popup_was_open_timer > 0)then
- connection_popup_was_open_timer = connection_popup_was_open_timer - 1
- end
-
-
-
- if(not connection_popup_open and connection_popup_was_open_timer <= 0)then
- connection_popup_open = true
- connection_popup_was_open_timer = 60 * 60 * 2
- popup.create("connection_message", GameTextGetTranslatedOrNot("$mp_steam_connection_failed_title"),
- GameTextGetTranslatedOrNot("$mp_steam_connection_failed_description"), {
- {
- text = GameTextGetTranslatedOrNot("$mp_close_popup"),
- callback = function()
- if(lobby_code ~= nil)then
- connection_popup_open = false
- end
- end
- }
- }, -6000)
- end
- end
-
- --[[if(GameSDK ~= nil and discord_sdk ~= nil)then
- GameSDK.runCallbacks(discord_sdk.corePtr)
- end]]
-
-
- if(input == nil)then
- input = dofile_once("mods/evaisa.mp/lib/input.lua")
- end
-
- if(bindings == nil)then
- bindings = dofile_once("mods/evaisa.mp/lib/keybinds.lua")
-
- -- keyboards bindings
- bindings:RegisterBinding("chat_submit", "Noita Online [keyboard]", "Chat Send", "Key_RETURN", "key", false, true, false, false)
- bindings:RegisterBinding("chat_submit2", "Noita Online [keyboard]", "Chat Send Alt", "Key_KP_ENTER", "key", false, true, false, false)
- bindings:RegisterBinding("chat_open_kb", "Noita Online [keyboard]", "Open Chat", "", "key", false, true, false, false)
- bindings:RegisterBinding("lobby_menu_open_kb", "Noita Online [keyboard]", "Open Lobby Menu", "", "key", false, true, false, false)
- bindings:RegisterBinding("ptt", "Noita Online [keyboard]", "Push-to-Talk", "Key_x", "key", true, true, true, false)
- bindings:RegisterBinding("lobby_menu_open_gp", "Noita Online [gamepad]", "Open Lobby Menu", "", "button", false, false, true, false, true)
-
- -- loop through gamemodes
- for k, v in ipairs(gamemodes) do
- if(v.binding_register ~= nil)then
- v.binding_register(bindings)
- end
- end
- end
-
- if(init_cleanup == false)then
- local lastCode = ModSettingGet("last_lobby_code")
- --print("Code: "..tostring(lastCode))
- if (steam) then
- if (lastCode ~= nil and lastCode ~= "") then
- local lobCode = steam.extra.parseUint64(lastCode)
- if (tostring(lobCode) ~= "0") then
- if (steam.extra.isSteamIDValid(lobCode)) then
- gamemode_settings = {}
-
- steam_utils.Leave(lobCode)
- end
- end
- ModSettingRemove("last_lobby_code")
- lobby_code = nil
- end
- end
- init_cleanup = true
- end
-
- --pretty.table(steam.networking)
- lobby_code = lobby_code or nil
-
- ResetIDs()
- ResetWindowStack()
-
- --print(fs.cd())
- if(should_hide_online_ui_for_arena())then
- reset_online_ui_for_arena()
- else
- dofile("mods/evaisa.mp/files/scripts/lobby_ui.lua")
- dofile("mods/evaisa.mp/files/scripts/chat_ui.lua")
- end
-
- if (GameGetFrameNum() % (600) == 0) then
- steamutils.CheckLocalLobbyData()
- end
-
- if (lobby_code ~= nil) then
-
- if (lobby_gamemode == nil) then
- return
- end
-
- delay.update()
-
- if(Starting ~= nil)then
- Starting = Starting - 1
- if(Starting < 0)then
- Starting = 0
- end
- end
-
- if(Starting == 0)then
- StartGame()
- Starting = nil
- end
-
- --game_in_progress = steam.matchmaking.getLobbyData(lobby_code, "in_progress") == "true"
-
- --print("a")
-
-
- --print("b")
-
- if (GameGetFrameNum() % Random(59,61) == 0) then
-
- steam_utils.updateCacheSpectators(lobby_code)
-
- last_bytes_sent = bytes_sent
- last_bytes_received = bytes_received
- bytes_sent = 0
- bytes_received = 0
-
- local function format_bytes(bytes)
- return bytes < 1024 and tostring(bytes) .. " B/s" or tostring(math.floor(bytes / 1024)) .. " KB/s"
- end
-
- local output_string = last_bytes_sent < 1024 and tostring(last_bytes_sent) .. " B/s" or tostring(math.floor(last_bytes_sent / 1024)) .. " KB/s"
-
- local input_string = last_bytes_received < 1024 and tostring(last_bytes_received) .. " B/s" or tostring(math.floor(last_bytes_received / 1024)) .. " KB/s"
-
- local network_string = "Data throughput: ".."in: " .. input_string .. " | out: " .. output_string
-
- for k, v in pairs(bytes_sent_per_type) do
- if(bytes_received_per_type[k] == nil)then
- bytes_received_per_type[k] = 0
- end
- local sent = v
- local received = bytes_received_per_type[k]
- network_string = network_string .. "\n["..k.."]: out: "..format_bytes(sent).." | in: "..format_bytes(received)
- end
-
- bytes_sent_per_type = {}
- bytes_received_per_type = {}
-
- networking_log:print(network_string.."\n")
- end
- --[[
- local players = get_players()
-
- if(players[1] ~= nil)then
- local player = players[1]
-
- GetUpdatedEntityID = function()
- return player
- end
- dofile("mods/evaisa.mp/files/scripts/player_update.lua")
- end
- ]]
- --print("c")
-
- byte_rate_gui = byte_rate_gui or GuiCreate()
- GuiStartFrame(byte_rate_gui)
-
- local screen_width, screen_height = GuiGetScreenDimensions(byte_rate_gui)
-
- local output_string = last_bytes_sent < 1024 and tostring(last_bytes_sent) .. " B/s" or
- tostring(math.floor(last_bytes_sent / 1024)) .. " KB/s"
-
- local input_string = last_bytes_received < 1024 and tostring(last_bytes_received) .. " B/s" or
- tostring(math.floor(last_bytes_received / 1024)) .. " KB/s"
-
- local text_width, text_height = GuiGetTextDimensions(byte_rate_gui,
- "in: " .. input_string .. " | out: " .. output_string)
-
- if(not IsPaused() and debugging)then
- GuiText(byte_rate_gui, screen_width - text_width - 50, 1, "in: " .. input_string .. " | out: " ..
- output_string)
- end
- --print("d")
-
- --print("Game in progress: "..tostring(game_in_progress))
-
- if (game_in_progress) then
- --print("the hell??")
-
- if (lobby_gamemode.update) then
- lobby_gamemode.update(lobby_code)
- end
-
-
- end
-
- if(lobby_gamemode.lobby_update ~= nil)then
- lobby_gamemode.lobby_update(lobby_code)
- end
-
- if(voicechat ~= nil) then
- if GlobalsGetValue("evaisa.mp.mic_device_changed", "0") == "1" then
- GlobalsSetValue("evaisa.mp.mic_device_changed", "0")
- local dev_name = ModSettingGet("evaisa.mp.mic_device_name") or ""
- voicechat.open_capture(dev_name ~= "" and dev_name or nil)
- end
-
- local vc_test_recording = vc_test ~= nil and vc_test.is_open() and voicechat.is_recording()
-
- if not GameHasFlagRun("evaisa.mp.voicechat_capture_opened") and (ModSettingGet("evaisa.mp.voicechat_enabled") or vc_test_recording) then
- GameAddFlagRun("evaisa.mp.voicechat_capture_opened")
- local dev_name = ModSettingGet("evaisa.mp.mic_device_name") or ""
- voicechat.open_capture(dev_name ~= "" and dev_name or nil)
- end
-
- local lx, ly = lobby_gamemode.get_listener_position()
- if lx == nil then
- lx, ly = 0, 0
- end
- voicechat.update_listener(lx, ly)
-
-
- local vc_mic_testing = vc_test ~= nil and vc_test.is_mic_testing()
- local mic_above_threshold = get_mic_above_threshold()
- local my_id = steam_utils.getSteamID()
- local can_speak = lobby_gamemode == nil or lobby_gamemode.user_can_speak == nil or lobby_gamemode.user_can_speak(my_id)
- local ptt_held = can_speak and (
- vc_test_recording
- or (vc_mic_testing and mic_above_threshold)
- or (bindings ~= nil and bindings:IsDown("ptt") and ModSettingGet("evaisa.mp.voicechat_enabled") and mic_above_threshold)
- or (ModSettingGet("evaisa.mp.voicechat_vad_mode") and ModSettingGet("evaisa.mp.voicechat_enabled")
- and mic_above_threshold)
- )
- local chunk = voicechat.capture_tick(ptt_held)
- if not can_speak and my_id ~= nil then
- local sf2 = dofile_once("mods/evaisa.mp/lib/smallfolk.lua")
- local raw2 = GlobalsGetValue("evaisa.mp.speaking_players", "")
- if raw2 ~= "" then
- local sp = sf2.loads(raw2)
- if sp[tostring(my_id)] ~= nil then
- sp[tostring(my_id)] = nil
- GlobalsSetValue("evaisa.mp.speaking_players", sf2.dumps(sp))
- end
- end
- end
- if chunk ~= nil then
- local px, py = 0, 0
- if players ~= nil and players[1] ~= nil then
- px, py = EntityGetTransform(players[1])
- end
-if lobby_gamemode ~= nil and lobby_gamemode.enable_proximity_vc and lobby_gamemode.get_voice_positions then
- local positions = lobby_gamemode.get_voice_positions(steam_utils.getSteamID())
- if positions ~= nil and positions[1] ~= nil then
- px, py = positions[1][1], positions[1][2]
- end
- end
-
- if vc_mic_testing then
- vc_test.loopback_receive(chunk)
- elseif vc_test ~= nil and vc_test.is_open() then
- vc_test.loopback_receive(chunk)
- else
-
- steamutils.send("voice", {pcm = chunk, x = px, y = py},
- steam_utils.messageTypes.OtherPlayers, lobby_code, true, true)
- if ModSettingGet("evaisa.mp.voicechat_intercom_monitor") and lobby_gamemode ~= nil and lobby_gamemode.get_voice_positions then
- local monitor_positions = lobby_gamemode.get_voice_positions(steam_utils.getSteamID())
- if monitor_positions ~= nil then
- local global_vol = tonumber(ModSettingGet("evaisa.mp.voicechat_volume")) or 1.0
- for i, pos in ipairs(monitor_positions) do
- local opts = lobby_gamemode.get_voice_opts and lobby_gamemode.get_voice_opts(i) or nil
- voicechat.play_voice(chunk, pos[1], pos[2], global_vol, 1.0, opts)
- end
- end
- end
- local my_id = steam_utils.getSteamID()
- if my_id ~= nil then
- local sf2 = dofile_once("mods/evaisa.mp/lib/smallfolk.lua")
- local raw2 = GlobalsGetValue("evaisa.mp.speaking_players", "")
- local sp = (raw2 ~= "" and sf2.loads(raw2)) or {}
- local id_str = tostring(my_id)
- local n = #chunk / 2
- local sum_sq = 0.0
- for ci = 1, #chunk, 2 do
- local lo = chunk:byte(ci)
- local hi = chunk:byte(ci + 1) or 0
- local s = (lo + hi * 256)
- if s >= 32768 then s = s - 65536 end
- s = s / 32768.0
- sum_sq = sum_sq + s * s
- end
- local lvl = (n > 0) and math.sqrt(sum_sq / n) or 0
- if sp[id_str] == nil then
- sp[id_str] = { name = steamutils.getTranslatedPersonaName(my_id) or "", frame = GameGetFrameNum(), level = lvl, is_local = true }
- else
- sp[id_str].frame = GameGetFrameNum()
- sp[id_str].level = lvl
- sp[id_str].is_local = true
- end
- GlobalsSetValue("evaisa.mp.speaking_players", sf2.dumps(sp))
- end
- end
- end
-
- voicechat.update()
- end
-
- ReceiveMessages(not game_in_progress)
- end
-
- if vc_test ~= nil then
- if input ~= nil and input:IsKeyDown("left ctrl") and input:IsKeyDown("left shift") and input:WasKeyPressed("v") then
- vc_test.toggle_window()
- end
- vc_test.update()
- end
-
- if voicechat ~= nil then
- dofile("mods/evaisa.mp/files/scripts/voice_hud.lua")
- end
- end
- end
- end).catch(function(ex)
- exception_log:print(tostring(ex))
- if(exceptions_in_logger)then
- old_print(tostring(ex))
- end
- end)
- end
-
- function OnProjectileFired(shooter_id, projectile_id, rng, position_x, position_y, target_x, target_y, send_message,
- unknown1, multicast_index, unknown3)
- try(function()
- if steam then
- --pretty.table(steam.networking)
- lobby_code = lobby_code or nil
-
- if (lobby_code ~= nil) then
-
- if (lobby_gamemode ~= nil and game_in_progress) then
- if (lobby_gamemode.on_projectile_fired) then
- lobby_gamemode.on_projectile_fired(lobby_code, shooter_id, projectile_id, rng, position_x, position_y,
- target_x, target_y, send_message, unknown1, multicast_index, unknown3)
- end
- end
- end
- end
- end).catch(function(ex)
- exception_log:print(tostring(ex))
- if(exceptions_in_logger)then
- old_print(tostring(ex))
- end
- end)
- end
-
- function OnProjectileFiredPost(shooter_id, projectile_id, rng, position_x, position_y, target_x, target_y, send_message,
- unknown1, multicast_index, unknown3)
- try(function()
- if steam then
- --pretty.table(steam.networking)
- lobby_code = lobby_code or nil
-
- if (lobby_code ~= nil) then
-
- if (lobby_gamemode ~= nil and game_in_progress) then
- if (lobby_gamemode.on_projectile_fired_post) then
- lobby_gamemode.on_projectile_fired_post(lobby_code, shooter_id, projectile_id, rng, position_x,
- position_y, target_x, target_y, send_message, unknown1, multicast_index, unknown3)
- end
- end
- end
- end
- end).catch(function(ex)
- exception_log:print(tostring(ex))
- if(exceptions_in_logger)then
- old_print(tostring(ex))
- end
- end)
- end
-
-
-
- function OnWorldPostUpdate()
- try(function()
- if steam then
- --pretty.table(steam.networking)
- lobby_code = lobby_code or nil
-
- if (lobby_code ~= nil) then
-
- if (lobby_gamemode ~= nil and game_in_progress) then
- if (lobby_gamemode.late_update) then
- lobby_gamemode.late_update(lobby_code)
- end
-
- --[[
- local messages = steam.networking.pollMessages() or {}
- for k, v in ipairs(messages)do
- bytes_received = bytes_received + v.msg_size
- if(lobby_gamemode.message)then
- lobby_gamemode.message(lobby_code, steamutils.parseData(v.data), v.user)
- end
- end
- ]]
- --ReceiveMessages(lobby_gamemode)
- end
- end
- end
- GameRemoveFlagRun("chat_bind_disabled")
- lobby_data_updated_this_frame = {}
- if(bindings ~= nil and not IsPaused())then
- bindings:Update()
- end
-
-
- if(imgui)then
- profiler_ui.post_update()
- end
-
- end).catch(function(ex)
- exception_log:print(tostring(ex))
- if(exceptions_in_logger)then
- old_print(tostring(ex))
- end
- end)
- end
-
-
-
- function steam.matchmaking.onLobbyEnter(data)
- try(function()
-
- print(tostring(data.response))
-
-
- clear_avatar_cache()
- for k, v in pairs(active_members) do
- active_members[k] = nil
- member_message_frames[k] = nil
- lobby_members = {}
- lobby_members_ids = {}
- steam.networking.closeSession(v)
- mp_log:print("Closed session with " .. steamutils.getTranslatedPersonaName(v))
- end
- input:Clear()
- Starting = nil
- in_game = false
- game_in_progress = false
-
- local user = steam_utils.getSteamID()
-
- steamutils.getUserAvatar(user)
-
-
- if (data.response == 1) then
- lobby_code = data.lobbyID
- mp_log:print("Code set to: " .. tostring(lobby_code) .. "[" .. type(lobby_code) .. "]")
- ModSettingSet("last_lobby_code", tostring(lobby_code))
- lobby_gamemode = FindGamemode(steam.matchmaking.getLobbyData(lobby_code, "gamemode"))
-
- local lobby_data_count = steam.matchmaking.getLobbyDataCount(lobby_code)
- for i = 1, lobby_data_count do
- local data = steam.matchmaking.getLobbyDataByIndex(lobby_code, i -1 )
-
- if(cached_lobby_data[data.key] ~= data.value)then
- cached_lobby_data[data.key] = data.value
- end
- print("Lobby Data: ["..tostring(data.key).."] = "..tostring(data.value))
- end
-
-
- if handleVersionCheck() and handleModCheck() then
- if handleGamemodeVersionCheck(lobby_code) then
- if (lobby_gamemode) then
- steam.matchmaking.setLobbyMemberData(lobby_code, "in_game", "false")
-
-
- defineLobbyUserData(lobby_code)
-
- delay.new(30, function()
- for k, setting in ipairs(lobby_gamemode.settings or {}) do
- gamemode_settings[setting.id] = steam.matchmaking.getLobbyData(lobby_code, "setting_" ..
- setting.id)
- end
-
- if (lobby_gamemode.refresh) then
- lobby_gamemode.refresh(lobby_code)
- end
- end, function(frames) end)
-
- --[[game_in_progress = steam.matchmaking.getLobbyData(lobby_code, "in_progress") == "true"
- if(game_in_progress)then
- gui_closed = true
- end]]
-
- if (lobby_gamemode ~= nil) then
- local lobby_name = steam.matchmaking.getLobbyData(lobby_code, "name")
- steam.friends.setRichPresence( "status", "Noita Online || "..GameTextGetTranslatedOrNot(tostring(lobby_gamemode.name)))
- steam.friends.setRichPresence( "steam_player_group", lobby_name )
-
- local member_count = steam.matchmaking.getNumLobbyMembers(lobby_code)
-
- steam.friends.setRichPresence( "steam_player_group_size", tostring(member_count) )
- active_mode = lobby_gamemode
- get_preset_folder_name()
- generate_lobby_menus_list()
- lobby_gamemode.enter(lobby_code)
- end
-
-
-
-
- end
- end
- end
- else
-
- --[[
- k_EChatRoomEnterResponseSuccess 1 Success.
- k_EChatRoomEnterResponseDoesntExist 2 Chat doesn't exist (probably closed).
- k_EChatRoomEnterResponseNotAllowed 3 General Denied - You don't have the permissions needed to join the chat.
- k_EChatRoomEnterResponseFull 4 Chat room has reached its maximum size.
- k_EChatRoomEnterResponseError 5 Unexpected Error.
- k_EChatRoomEnterResponseBanned 6 You are banned from this chat room and may not join.
- k_EChatRoomEnterResponseLimited 7 Joining this chat is not allowed because you are a limited user (no value on account).
- k_EChatRoomEnterResponseClanDisabled 8 Attempt to join a clan chat when the clan is locked or disabled.
- k_EChatRoomEnterResponseCommunityBan 9 Attempt to join a chat when the user has a community lock on their account.
- k_EChatRoomEnterResponseMemberBlockedYou 10 Join failed - a user that is in the chat has blocked you from joining.
- k_EChatRoomEnterResponseYouBlockedMember 11 Join failed - you have blocked a user that is already in the chat.
- k_EChatRoomEnterResponseRatelimitExceeded 15 Join failed - too many join attempts in a very short period of time.
- ]]
-
- local responses = {
- [2] = "$lobby_error_doesnt_exist", -- Lobby code doesn't exist
- [3] = "$lobby_error_no_permissions", -- You don't have permission to join the lobby
- [4] = "$lobby_error_full", -- Lobby is full
- [5] = "$lobby_error_unexpected", -- Unexpected error
- [6] = "$lobby_error_banned", -- You are banned from this lobby
- [7] = "$lobby_error_limited", -- Joining this lobby is not allowed because you are a limited user
- [8] = "$lobby_error_clan_disabled", -- Attempt to join a clan lobby when the clan is locked or disabled
- [9] = "$lobby_error_community_ban", -- Attempt to join a lobby when the user has a community lock on their account
- [10] = "$lobby_error_member_blocked_you", -- Join failed - a user that is in the lobby has blocked you from joining
- [11] = "$lobby_error_you_blocked_member", -- Join failed - you have blocked a user that is already in the lobby
- [15] = "$lobby_error_ratelimit_exceeded", -- Join failed - too many join attempts in a very short period of time
- }
-
- msg.log(GameTextGetTranslatedOrNot(responses[data.response] or "$lobby_error_unexpected"))
- end
- end).catch(function(ex)
- exception_log:print(tostring(ex))
- if(exceptions_in_logger)then
- old_print(tostring(ex))
- end
- end)
- end
-
- lobby_owner = nil
-
- local last_user_in_game_states = {}
-
- function steam.matchmaking.onLobbyDataUpdate(update_data)
- print("Lobby data updated")
- try(function()
- if(lobby_code ~= nil)then
- local current_lobby_data = {}
- local any_updated = false
-
-
- if(update_data.userID ~= update_data.lobbyID)then
- local in_game_state = steam.matchmaking.getLobbyMemberData(lobby_code, update_data.userID, "in_game")
- if(last_user_in_game_states[update_data.userID] ~= in_game_state)then
- print("User in game state changed")
- last_user_in_game_states[update_data.userID] = in_game_state
- steamutils.getLobbyMembers(lobby_code, true, true)
- end
- end
-
- local lobby_data_count = steam.matchmaking.getLobbyDataCount(lobby_code)
- for i = 1, lobby_data_count do
- local data = steam.matchmaking.getLobbyDataByIndex(lobby_code, i -1 )
- current_lobby_data[data.key] = data.value
-
- -- if data.key ends with _spectator, then we need to update the spectator list
- if(string.sub(data.key, -10) == "_spectator")then
- steamutils.getLobbyMembers(lobby_code, true, true)
- end
-
- if(cached_lobby_data[data.key] ~= data.value)then
- cached_lobby_data[data.key] = data.value
- end
-
- --print("Lobby data: " .. data.key .. " = " .. data.value)
- if(not lobby_data_last_frame[data.key] or lobby_data_last_frame[data.key] ~= data.value)then
- lobby_data_updated_this_frame[data.key] = true
- print("Updated lobby data: " .. data.key .. " to " .. data.value)
-
- -- handle special case update
- --edit_lobby_type = lobby_type -- steam.matchmaking.getLobbyData(code, "LobbyType")
- --edit_lobby_max_players = lobby_max_players -- steam.matchmaking.getLobbyMemberLimit(code)"MaxPlayers"
- --edit_lobby_name = lobby_name -- steam.matchmaking.getLobbyData(code, "name")
- --edit_lobby_seed = lobby_seed -- steam.matchmaking.getLobbyData(code, "seed")
-
- if(data.key == "LobbyType")then
- edit_lobby_type = data.value
- elseif(data.key == "max_players")then
- edit_lobby_max_players = data.value
- elseif(data.key == "name")then
- edit_lobby_name = data.value
- elseif(data.key == "seed")then
- edit_lobby_seed = data.value
- end
-
- any_updated = true
- end
- end
- lobby_data_last_frame = current_lobby_data
-
- if(not any_updated)then
- -- try to update lobby owner
- lobby_owner = steam.matchmaking.getLobbyOwner(lobby_code)
- end
- else
- lobby_data_last_frame = {}
- lobby_data_updated_this_frame = {}
- end
- end).catch(function(ex)
- exception_log:print(tostring(ex))
- if(exceptions_in_logger)then
- old_print(tostring(ex))
- end
- end)
- end
-
-
- ChatMemberStateChangeEnum = {
- k_EChatMemberStateChangeEntered = 1,
- k_EChatMemberStateChangeLeft = 2,
- k_EChatMemberStateChangeDisconnected = 4,
- k_EChatMemberStateChangeKicked = 8,
- k_EChatMemberStateChangeBanned = 10,
- }
-
- total_lobby_members = 0
-
- function steam.matchmaking.onLobbyChatUpdate(data)
- try(function()
-
- if handleBanCheck(data.userChanged) then
- return
- end
- if handleInProgressCheck(data.userChanged) then
- return
- end
-
- lobby_owner = steam.matchmaking.getLobbyOwner(lobby_code)
- total_lobby_members = steam.matchmaking.getNumLobbyMembers(lobby_code)
-
- if(lobby_code ~= nil)then
- steam_utils.getLobbyMembers(lobby_code, true, true)
-
- if (lobby_gamemode ~= nil) then
- local lobby_name = steam.matchmaking.getLobbyData(lobby_code, "name")
- steam.friends.setRichPresence( "status", "Noita Online || "..GameTextGetTranslatedOrNot(tostring(lobby_gamemode.name)))
- steam.friends.setRichPresence( "steam_player_group", lobby_name )
-
- local member_count = steam.matchmaking.getNumLobbyMembers(lobby_code)
-
- steam.friends.setRichPresence( "steam_player_group_size", tostring(member_count) )
-
- end
-
-
- if(data.chatMemberStateChange == ChatMemberStateChangeEnum.k_EChatMemberStateChangeEntered)then
-
- if (lobby_gamemode == nil) then
- return
- end
-
- print("A player joined!")
-
- local h = data.userChanged
-
- steamutils.getUserAvatar(h)
-
- getLobbyUserData(lobby_code, h, true)
-
- if (not active_members[tostring(h)]) then
- active_members[tostring(h)] = h
- end
-
- --print("Clearing frames for " .. tostring(h))
- member_message_frames[tostring(h)] = nil
-
- local name = steamutils.getTranslatedPersonaName(h)
-
- GamePrint(string.format(GameTextGetTranslatedOrNot("$mp_player_joined") ,tostring(name)))
-
-
-
- if(lobby_gamemode.player_join)then
- lobby_gamemode.player_join(lobby_code, h)
- end
- else
- local h = data.userChanged
-
- if(h == nil or tonumber(tostring(h)) == nil or tonumber(tostring(h)) == 0)then
- GamePrint("A player has left but their steamid was invalid: "..tostring(h))
- print("A player has left but their steamid was invalid: "..tostring(h))
- else
- GamePrint(string.format(GameTextGetTranslatedOrNot("$mp_player_left"), steamutils.getTranslatedPersonaName(h)))
- end
-
- active_members[tostring(h)] = nil
-
- --print("Clearing frames for " .. tostring(h))
- member_message_frames[tostring(h)] = nil
- steam.networking.closeSession(h)
- mp_log:print("Closed session with " .. steamutils.getTranslatedPersonaName(h))
-
- -- run gamemode on_leave
- if (lobby_gamemode and lobby_gamemode.disconnected ~= nil) then
- lobby_gamemode.disconnected(lobby_code, h)
- end
- end
- end
- end).catch(function(ex)
- exception_log:print(tostring(ex))
- if(exceptions_in_logger)then
- old_print(tostring(ex))
- end
- end)
- end
-
- function steam.matchmaking.onGameLobbyJoinRequested(data)
- ---pretty.table(data)
- if (steam.extra.isSteamIDValid(data.lobbyID)) then
- gamemode_settings = {}
- steam_utils.Leave(data.lobbyID)
- steam.matchmaking.joinLobby(data.lobbyID, function(e)
- if (e.response == 2) then
- cached_lobby_data = {}
- cached_lobby_user_data = {}
- steam_utils.Leave(e.lobbyID)
- invite_menu_open = false
- menu_status = status.main_menu
- initial_refreshes = 10
- show_lobby_code = false
- lobby_code = nil
- end
- end)
- else
- -- force refresh
- refreshLobbies()
- end
- end
-
- function steam.matchmaking.onLobbyChatMsgReceived(data)
- try(function()
- --pretty.table(data)
- --[[
- example data:
-
- {
- lobbyID = 9223372036854775807,
- userID = 76361198523269435,
- type = 1,
- chatID = 1,
- fromOwner = true,
- message = "disconnect;76561198983269435;You were kicked from the lobby."
- }
- ]]
- mp_log:print(tostring(data.message))
-
- handleDisconnect(data)
- handleChatMessage(data)
-
- end).catch(function(ex)
- exception_log:print(tostring(ex))
- if(exceptions_in_logger)then
- old_print(tostring(ex))
- end
- end)
- end
-
- --[[
- function steam.networking.onP2PSessionRequest(data)
- pretty.table(data)
- --steam.networking.acceptP2PSessionWithUser(data.userID)
- end
-
- function steam.networking.onP2PSessionConnectFail(data)
- pretty.table(data)
- end
- ]]
- function steam.networking.onSessionRequest(steamID)
- mp_log:print("Session request from [" .. tostring(steamutils.getTranslatedPersonaName(steamID)) .. "]")
- if (lobby_code ~= nil and steamutils.isInLobby(lobby_code, steamID)) then
- local success = steam.networking.acceptSession(steamID)
- mp_log:print("Session accepted: " .. tostring(success))
- end
- end
-
- function steam.networking.onSessionFailed(steamID, endReason, endDebug, connectionDescription)
- if (lobby_code ~= nil and steamutils.isInLobby(lobby_code, steamID)) then
- mp_log:print("Session failed with [" ..
- tostring(steamutils.getTranslatedPersonaName(steamID)) .. "]: " .. tostring(endReason))
- mp_log:print("Debug: " .. tostring(endDebug))
- mp_log:print("Connection description: " .. tostring(connectionDescription))
- end
- end
-
- steam_overlay_open = false
-
- function steam.friends.onGameOverlayActivated(data)
-
- -- print data
- --print(inspect(data))
-
-
- if (not data.active) then
- --print("Overlay closed")
- steam_overlay_open = false
- else
- --print("Overlay opened")
- steam_overlay_open = true
- end
- end
-
- function OnMagicNumbersAndWorldSeedInitialized()
- if(failed_to_load)then
- return
- end
-
- --print(json.stringify(char_ranges))
- -- write to file
- -- ModTextFileGetContent("data/translations/common.csv")
- -- using io library to write to "noita_online_logs/translations.csv"
- local file = io.open("noita_online_logs/translations.csv", "w")
- local translations_content = ModTextFileGetContent("data/translations/common.csv")
- file:write(translations_content)
- file:close()
-
- --print(translations_content)
- steam.init()
-
- __loaded["mods/evaisa.mp/data/gamemodes.lua"] = nil
- gamemodes = dofile("mods/evaisa.mp/data/gamemodes.lua")
-
-
- steam.friends.setRichPresence("status", "Noita Online - Menu")
-
- --[[if(GameSDK == nil)then
- GameSDK = require("game_sdk")
-
- discord_sdk = GameSDK.initialize(discord_app_id)
- end]]
-
-
-
-
- mod_data = ModData()
-
- debug_info:print("Gamemodes: [")
-
- -- get installed modes
- for k, v in ipairs(gamemodes)do
- debug_info:print(" "..tostring(v.id).."@"..tostring(v.version))
- end
-
- debug_info:print("]")
-
- debug_info:print("Installed mods: [")
- -- get installed mods
-
- for k, v in ipairs(ModGetActiveModIDs())do
- debug_info:print(" "..tostring(v))
- end
-
- debug_info:print("]")
-
-
- --[[
- http_get("http://evaisa.dev/noita-online-checksum.txt", function (data)
-
- Checksum_passed = data == Version_string
-
- if(Checksum_passed)then
- mp_log:print("Checksum passed: "..tostring(data))
- end
- end)]]
- end
-
- function OnWorldInitialized()
- --pretty.table(physics)
- ModTextFileGetContent = get_content
- ModTextFileSetContent = set_content
- end
-
- local fix_falsely_enabled_gamemodes = function()
- print("Fixing falsely enabled gamemodes")
-
- local save_folder = os.getenv('APPDATA'):gsub("\\Roaming", "") ..
- "\\LocalLow\\Nolla_Games_Noita\\save00\\mod_config.xml"
-
- local subscribed_items = steam.UGC.getSubscribedItems()
- local item_infos = {}
-
- for _, v in ipairs(subscribed_items) do
-
- local success, size, folder, timestamp = steam.UGC.getItemInstallInfo(v)
- if (success) then
- item_infos[tostring(v)] = {size = size, folder = folder, timestamp = timestamp}
- end
-
- end
-
- local file, err = io.open(save_folder, 'rb')
- if file then
-
- local content = file:read("*all")
-
- local parsedModData = nxml.parse(content)
- for elem in parsedModData:each_child() do
- if (elem.name == "Mod") then
- local modID = elem.attr.name
- local steamID = elem.attr.workshop_item_id
-
- if (ModIsEnabled(modID)) then
- local infoFile = "mods/" .. modID .. "/mod.xml"
- if (steamID ~= "0") then
- if(item_infos[steamID])then
- infoFile = item_infos[steamID].folder .. "/mod.xml"
- else
- debug_log:print("Failed to find item info for: " .. steamID)
- infoFile = nil
- end
- end
-
- if (infoFile ~= nil) then
- local file2, err = io.open(infoFile, 'rb')
- if file2 then
- local content2 = file2:read("*all")
- if(content2 ~= nil and content2 ~= "")then
- local parsedModInfo = nxml.parse(content2)
-
- local download_link = parsedModInfo.attr.download_link
- local is_game_mode = parsedModInfo.attr.is_game_mode == "1"
-
- if (elem.attr.enabled == "1" and is_game_mode) then
- elem.attr.enabled = "0"
- print("Disabling " .. modID)
- end
- end
- end
- end
- end
- end
- end
- file:close()
-
-
- local new_content = tostring(parsedModData)
-
- local file, err = io.open(save_folder, 'wb')
- if file then
- file:write(new_content)
- file:close()
- end
-
- end
- end
-
- function OnPlayerSpawned(player)
-
- if voicechat ~= nil then
- voicechat.enumerate_devices()
- end
-
- -- make popup
- local streaming, streaming_app = streaming.IsStreaming()
- if(ModSettingGet("evaisa.mp.streamer_mode_detection") and streaming and not ModSettingGet("evaisa.mp.streamer_mode"))then
- popup.create("streaming_message", GameTextGetTranslatedOrNot("$mp_streamer_mode_popup"),{
- {
- text = string.format(GameTextGetTranslatedOrNot("$mp_streamer_mode_popup_detected"), streaming_app),
- color = {217 / 255, 52 / 255, 52 / 255, 1}
- },
- GameTextGetTranslatedOrNot("$mp_streamer_mode_popup_desc"),
- GameTextGetTranslatedOrNot("$mp_streamer_mode_popup_desc2")
- }, {
- {
- text = GameTextGetTranslatedOrNot("$mp_streamer_mode_popup_enable"),
- callback = function()
- ModSettingSet("evaisa.mp.streamer_mode", true)
- end
- },
- {
- text = GameTextGetTranslatedOrNot("$mp_close_popup"),
- callback = function()
- end
- }
- }, -6000)
-
- end
-
- fix_falsely_enabled_gamemodes()
- ModSettingRemove("lobby_data_store")
- GameRemoveFlagRun("game_paused")
- rand = rng.new(os.time()+GameGetFrameNum())
- delay.reset()
- is_awaiting_spectate = false
- --ModSettingRemove("lobby_data_store")
- --print(pretty.table(bitser))
-
- -- replace contents of "mods/evaisa.forcerestart/filechange.txt" with a random number between 0 and 10000000
- --local file = io.open("mods/evaisa.forcerestart/filechange.txt", "w")
- --file:write(math.random(0, 10000000))
- --file:close()
-
- --mp_log:print(bitser.loads(""))
-
- Spawned = true
- end
-
-else
- function OnPlayerSpawned(player)
- popup.create("msvcp140_missing", GameTextGetTranslatedOrNot("$mp_msvcp140_missing"), {
- {
- text = GameTextGetTranslatedOrNot("$mp_msvcp140_missing_description"),
- color = {217 / 255,52 / 255,52 / 255, 1}
- },
- {
- text = GameTextGetTranslatedOrNot("$mp_msvcp140_missing_description_2"),
- color = {217 / 255,52 / 255,52 / 255, 1}
- },
- }, {
- {
- text = GameTextGetTranslatedOrNot("$mp_msvcp140_install"),
- callback = function()
- os.execute("start explorer \"https://aka.ms/vs/17/release/vc_redist.x86.exe\"")
- end
- }
- }, -6000)
- end
-
- function OnWorldPreUpdate()
- popup.update()
- end
-
-end
\ No newline at end of file
diff --git a/lib/base64.lua b/lib/base64.lua
deleted file mode 100644
index 6dfabb0..0000000
--- a/lib/base64.lua
+++ /dev/null
@@ -1,257 +0,0 @@
---- base64.lua
---
--- A simple Base64 encoder/decoder that uses a URL safe variant of the standard.
--- This implementation encodes character 62 as '-' (instead of '+') and character 63 as '_' (instead of '/').
--- In addition, padding is not used.
--- A full description of the specification can be found here: http://tools.ietf.org/html/rfc4648
---
--- To encode, use base64.encode(input), where input is a string of arbitrary bytes. The output is a Base64 encoded string.
--- To decode, use base64.decode(input), where input is a Base64 encoded string. The output is a string of arbitrary bytes.
---
--- For all input, input == base64.decode(base64.encode(input)).
---
--- This library has a dependency on LuaBit v0.4, which can be found here: http://luaforge.net/projects/bit/
---
--- Copyright (C) 2012 by Paul Moore
---
--- Permission is hereby granted, free of charge, to any person obtaining a copy
--- of this software and associated documentation files (the "Software"), to deal
--- in the Software without restriction, including without limitation the rights
--- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
--- copies of the Software, and to permit persons to whom the Software is
--- furnished to do so, subject to the following conditions:
---
--- The above copyright notice and this permission notice shall be included in
--- all copies or substantial portions of the Software.
---
--- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
--- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
--- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
--- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
--- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
--- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
--- THE SOFTWARE.
-
-require "bit"
-
-base64 = {}
-
---- octet -> char encoding.
-local ENCODABET = {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
- 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
- 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
- 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
- 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
- 'y', 'z'
-
-}
-
---- char -> octet encoding.
--- Offset by 44 (from index 1).
-local DECODABET = {
- 62, 0, 0, 52, 53, 54, 55, 56, 57, 58,
- 59, 60, 61, 0, 0, 0, 0, 0, 0, 0,
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
- 20, 21, 22, 23, 24, 25, 0, 0, 0, 0,
- 63, 0, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39
-}
-
---- Encodes a string into a Base64 string.
--- The input can be any string of arbitrary bytes.
---
--- @param input The input string.
--- @return The Base64 representation of the input string.
-function base64.encode (input)
-
- local bytes = { input:byte(i, #input) }
-
- local out = {}
-
- -- Go through each triplet of 3 bytes, which produce 4 octets.
- local i = 1
- while i <= #bytes - 2 do
- local buffer = 0
-
- -- Fill the buffer with the bytes, producing a 24-bit integer.
- local b = bit.lshift(bytes[i], 16)
- b = bit.band(b, 0xff0000)
- buffer = bit.bor(buffer, b)
-
- b = bit.lshift(bytes[i + 1], 8)
- b = bit.band(b, 0xff00)
- buffer = bit.bor(buffer, b)
-
- b = bit.band(bytes[i + 2], 0xff)
- buffer = bit.bor(buffer, b)
-
- -- Read out the 4 octets into the output buffer.
- b = bit.arshift(buffer, 18)
- b = bit.band(b, 0x3f)
- out[#out + 1] = ENCODABET[b + 1]
-
- b = bit.arshift(buffer, 12)
- b = bit.band(b, 0x3f)
- out[#out + 1] = ENCODABET[b + 1]
-
- b = bit.arshift(buffer, 6)
- b = bit.band(b, 0x3f)
- out[#out + 1] = ENCODABET[b + 1]
-
- b = bit.band(buffer, 0x3f)
- out[#out + 1] = ENCODABET[b + 1]
-
- i = i + 3
- end
-
- -- Special case 1: One byte extra, will produce 2 octets.
- if #bytes % 3 == 1 then
- local buffer = bit.lshift(bytes[i], 16)
- buffer = bit.band(buffer, 0xff0000)
-
- local b = bit.arshift(buffer, 18)
- b = bit.band(b, 0x3f)
- out[#out + 1] = ENCODABET[b + 1]
-
- b = bit.arshift(buffer, 12)
- b = bit.band(b, 0x3f)
- out[#out + 1] = ENCODABET[b + 1]
-
- -- Special case 2: Two bytes extra, will produce 3 octets.
- elseif #bytes % 3 == 2 then
- local buffer = 0
-
- local b = bit.lshift(bytes[i], 16)
- b = bit.band(b, 0xff0000)
- buffer = bit.bor(buffer, b)
-
- b = bit.lshift(bytes[i + 1], 8)
- b = bit.band(b, 0xff00)
- buffer = bit.bor(buffer, b)
-
- b = bit.arshift(buffer, 18)
- b = bit.band(b, 0x3f)
- out[#out + 1] = ENCODABET[b + 1]
-
- b = bit.arshift(buffer, 12)
- b = bit.band(b, 0x3f)
- out[#out + 1] = ENCODABET[b + 1]
-
- b = bit.arshift(buffer, 6)
- b = bit.band(b, 0x3f)
- out[#out + 1] = ENCODABET[b + 1]
- end
-
- return table.concat(out)
-
-end
-
---- Decodes a Base64 string into an output string of arbitrary bytes.
--- Currently does not check the input for valid Base64, so be careful.
---
--- @param input The Base64 input to decode.
--- @return The decoded Base64 string, as a string of bytes.
-function base64.decode (input)
-
- local out = {}
-
- -- Go through each group of 4 octets to obtain 3 bytes.
- local i = 1
- while i <= #input - 3 do
- local buffer = 0
-
- -- Read the 4 octets into the buffer, producing a 24-bit integer.
- local b = input:byte(i)
- b = DECODABET[b - 44]
- b = bit.lshift(b, 18)
- buffer = bit.bor(buffer, b)
- i = i + 1
-
- b = input:byte(i)
- b = DECODABET[b - 44]
- b = bit.lshift(b, 12)
- buffer = bit.bor(buffer, b)
- i = i + 1
-
- b = input:byte(i)
- b = DECODABET[b - 44]
- b = bit.lshift(b, 6)
- buffer = bit.bor(buffer, b)
- i = i + 1
-
- b = input:byte(i)
- b = DECODABET[b - 44]
- buffer = bit.bor(buffer, b)
- i = i + 1
-
- -- Append the 3 re-constructed bytes into the output buffer.
- b = bit.arshift(buffer, 16)
- b = bit.band(b, 0xff)
- out[#out + 1] = b
-
- b = bit.arshift(buffer, 8)
- b = bit.band(b, 0xff)
- out[#out + 1] = b
-
- b = bit.band(buffer, 0xff)
- out[#out + 1] = b
- end
-
- -- Special case 1: Only 2 octets remain, producing 1 byte.
- if #input % 4 == 2 then
- local buffer = 0
-
- local b = input:byte(i)
- b = DECODABET[b - 44]
- b = bit.lshift(b, 18)
- buffer = bit.bor(buffer, b)
- i = i + 1
-
- b = input:byte(i)
- b = DECODABET[b - 44]
- b = bit.lshift(b, 12)
- buffer = bit.bor(buffer, b)
- i = i + 1
-
- b = bit.arshift(buffer, 16)
- b = bit.band(b, 0xff)
- out[#out + 1] = b
-
- -- Special case 2: Only 3 octets remain, producing 2 bytes.
- elseif #input % 4 == 3 then
- local buffer = 0
-
- local b = input:byte(i)
- b = DECODABET[b - 44]
- b = bit.lshift(b, 18)
- buffer = bit.bor(buffer, b)
- i = i + 1
-
- b = input:byte(i)
- b = DECODABET[b - 44]
- b = bit.lshift(b, 12)
- buffer = bit.bor(buffer, b)
- i = i + 1
-
- b = input:byte(i)
- b = DECODABET[b - 44]
- b = bit.lshift(b, 6)
- buffer = bit.bor(buffer, b)
- i = i + 1
-
- b = bit.arshift(buffer, 16)
- b = bit.band(b, 0xff)
- out[#out + 1] = b
-
- b = bit.arshift(buffer, 8)
- b = bit.band(b, 0xff)
- out[#out + 1] = b
- end
-
- return string.char(unpack(out))
-
-end
-
-return base64
\ No newline at end of file
diff --git a/lib/binser.lua b/lib/binser.lua
deleted file mode 100644
index a427398..0000000
--- a/lib/binser.lua
+++ /dev/null
@@ -1,753 +0,0 @@
--- binser.lua
-
---[[
-Copyright (c) 2016-2019 Calvin Rose
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
-the Software, and to permit persons to whom the Software is furnished to do so,
-subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
-COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
-IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-]]
-
-local assert = assert
-local error = error
-local select = select
-local pairs = pairs
-local getmetatable = getmetatable
-local setmetatable = setmetatable
-local type = type
-local loadstring = loadstring or load
-local concat = table.concat
-local char = string.char
-local byte = string.byte
-local format = string.format
-local sub = string.sub
-local dump = string.dump
-local floor = math.floor
-local frexp = math.frexp
-local unpack = unpack or table.unpack
-local huge = math.huge
-
--- Lua 5.3 frexp polyfill
--- From https://github.com/excessive/cpml/blob/master/modules/utils.lua
-if not frexp then
- local log, abs, floor = math.log, math.abs, math.floor
- local log2 = log(2)
- frexp = function(x)
- if x == 0 then return 0, 0 end
- local e = floor(log(abs(x)) / log2 + 1)
- return x / 2 ^ e, e
- end
-end
-
-local function pack(...)
- return {...}, select("#", ...)
-end
-
-local function not_array_index(x, len)
- return type(x) ~= "number" or x < 1 or x > len or x ~= floor(x)
-end
-
-local function type_check(x, tp, name)
- assert(type(x) == tp,
- format("Expected parameter %q to be of type %q.", name, tp))
-end
-
-local bigIntSupport = false
-local isInteger
-if math.type then -- Detect Lua 5.3
- local mtype = math.type
- bigIntSupport = loadstring[[
- local char = string.char
- return function(n)
- local nn = n < 0 and -(n + 1) or n
- local b1 = nn // 0x100000000000000
- local b2 = nn // 0x1000000000000 % 0x100
- local b3 = nn // 0x10000000000 % 0x100
- local b4 = nn // 0x100000000 % 0x100
- local b5 = nn // 0x1000000 % 0x100
- local b6 = nn // 0x10000 % 0x100
- local b7 = nn // 0x100 % 0x100
- local b8 = nn % 0x100
- if n < 0 then
- b1, b2, b3, b4 = 0xFF - b1, 0xFF - b2, 0xFF - b3, 0xFF - b4
- b5, b6, b7, b8 = 0xFF - b5, 0xFF - b6, 0xFF - b7, 0xFF - b8
- end
- return char(212, b1, b2, b3, b4, b5, b6, b7, b8)
- end]]()
- isInteger = function(x)
- return mtype(x) == 'integer'
- end
-else
- isInteger = function(x)
- return floor(x) == x
- end
-end
-
--- Copyright (C) 2012-2015 Francois Perrad.
--- number serialization code modified from https://github.com/fperrad/lua-MessagePack
--- Encode a number as a big-endian ieee-754 double, big-endian signed 64 bit integer, or a small integer
-local function number_to_str(n)
- if isInteger(n) then -- int
- if n <= 100 and n >= -27 then -- 1 byte, 7 bits of data
- return char(n + 27)
- elseif n <= 8191 and n >= -8192 then -- 2 bytes, 14 bits of data
- n = n + 8192
- return char(128 + (floor(n / 0x100) % 0x100), n % 0x100)
- elseif bigIntSupport then
- return bigIntSupport(n)
- end
- end
- local sign = 0
- if n < 0.0 then
- sign = 0x80
- n = -n
- end
- local m, e = frexp(n) -- mantissa, exponent
- if m ~= m then
- return char(203, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
- elseif m == huge then
- if sign == 0 then
- return char(203, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
- else
- return char(203, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
- end
- elseif m == 0.0 and e == 0 then
- return char(0xCB, sign, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
- end
- e = e + 0x3FE
- if e < 1 then -- denormalized numbers
- m = m * 2 ^ (52 + e)
- e = 0
- else
- m = (m * 2 - 1) * 2 ^ 52
- end
- return char(203,
- sign + floor(e / 0x10),
- (e % 0x10) * 0x10 + floor(m / 0x1000000000000),
- floor(m / 0x10000000000) % 0x100,
- floor(m / 0x100000000) % 0x100,
- floor(m / 0x1000000) % 0x100,
- floor(m / 0x10000) % 0x100,
- floor(m / 0x100) % 0x100,
- m % 0x100)
-end
-
--- Copyright (C) 2012-2015 Francois Perrad.
--- number deserialization code also modified from https://github.com/fperrad/lua-MessagePack
-local function number_from_str(str, index)
- local b = byte(str, index)
- if not b then error("Expected more bytes of input.") end
- if b < 128 then
- return b - 27, index + 1
- elseif b < 192 then
- local b2 = byte(str, index + 1)
- if not b2 then error("Expected more bytes of input.") end
- return b2 + 0x100 * (b - 128) - 8192, index + 2
- end
- local b1, b2, b3, b4, b5, b6, b7, b8 = byte(str, index + 1, index + 8)
- if (not b1) or (not b2) or (not b3) or (not b4) or
- (not b5) or (not b6) or (not b7) or (not b8) then
- error("Expected more bytes of input.")
- end
- if b == 212 then
- local flip = b1 >= 128
- if flip then -- negative
- b1, b2, b3, b4 = 0xFF - b1, 0xFF - b2, 0xFF - b3, 0xFF - b4
- b5, b6, b7, b8 = 0xFF - b5, 0xFF - b6, 0xFF - b7, 0xFF - b8
- end
- local n = ((((((b1 * 0x100 + b2) * 0x100 + b3) * 0x100 + b4) *
- 0x100 + b5) * 0x100 + b6) * 0x100 + b7) * 0x100 + b8
- if flip then
- return (-n) - 1, index + 9
- else
- return n, index + 9
- end
- end
- if b ~= 203 then
- error("Expected number")
- end
- local sign = b1 > 0x7F and -1 or 1
- local e = (b1 % 0x80) * 0x10 + floor(b2 / 0x10)
- local m = ((((((b2 % 0x10) * 0x100 + b3) * 0x100 + b4) * 0x100 + b5) * 0x100 + b6) * 0x100 + b7) * 0x100 + b8
- local n
- if e == 0 then
- if m == 0 then
- n = sign * 0.0
- else
- n = sign * (m / 2 ^ 52) * 2 ^ -1022
- end
- elseif e == 0x7FF then
- if m == 0 then
- n = sign * huge
- else
- n = 0
- end
- else
- n = sign * (1.0 + m / 2 ^ 52) * 2 ^ (e - 0x3FF)
- end
- return n, index + 9
-end
-
-
-local function newbinser()
-
- -- unique table key for getting next value
- local NEXT = {}
- local CTORSTACK = {}
-
- -- NIL = 202
- -- FLOAT = 203
- -- TRUE = 204
- -- FALSE = 205
- -- STRING = 206
- -- TABLE = 207
- -- REFERENCE = 208
- -- CONSTRUCTOR = 209
- -- FUNCTION = 210
- -- RESOURCE = 211
- -- INT64 = 212
- -- TABLE WITH META = 213
-
- local mts = {}
- local ids = {}
- local serializers = {}
- local deserializers = {}
- local resources = {}
- local resources_by_name = {}
- local types = {}
-
- types["nil"] = function(x, visited, accum)
- accum[#accum + 1] = "\202"
- end
-
- function types.number(x, visited, accum)
- accum[#accum + 1] = number_to_str(x)
- end
-
- function types.boolean(x, visited, accum)
- accum[#accum + 1] = x and "\204" or "\205"
- end
-
- function types.string(x, visited, accum)
- local alen = #accum
- if visited[x] then
- accum[alen + 1] = "\208"
- accum[alen + 2] = number_to_str(visited[x])
- else
- visited[x] = visited[NEXT]
- visited[NEXT] = visited[NEXT] + 1
- accum[alen + 1] = "\206"
- accum[alen + 2] = number_to_str(#x)
- accum[alen + 3] = x
- end
- end
-
- local function check_custom_type(x, visited, accum)
- local res = resources[x]
- if res then
- accum[#accum + 1] = "\211"
- types[type(res)](res, visited, accum)
- return true
- end
- local mt = getmetatable(x)
- local id = mt and ids[mt]
- if id then
- local constructing = visited[CTORSTACK]
- if constructing[x] then
- error("Infinite loop in constructor.")
- end
- constructing[x] = true
- accum[#accum + 1] = "\209"
- types[type(id)](id, visited, accum)
- local args, len = pack(serializers[id](x))
- accum[#accum + 1] = number_to_str(len)
- for i = 1, len do
- local arg = args[i]
- types[type(arg)](arg, visited, accum)
- end
- visited[x] = visited[NEXT]
- visited[NEXT] = visited[NEXT] + 1
- -- We finished constructing
- constructing[x] = nil
- return true
- end
- end
-
- function types.userdata(x, visited, accum)
- if visited[x] then
- accum[#accum + 1] = "\208"
- accum[#accum + 1] = number_to_str(visited[x])
- else
- if check_custom_type(x, visited, accum) then return end
- error("Cannot serialize this userdata.")
- end
- end
-
- function types.table(x, visited, accum)
- if visited[x] then
- accum[#accum + 1] = "\208"
- accum[#accum + 1] = number_to_str(visited[x])
- else
- if check_custom_type(x, visited, accum) then return end
- visited[x] = visited[NEXT]
- visited[NEXT] = visited[NEXT] + 1
- local xlen = #x
- local mt = getmetatable(x)
- if mt then
- accum[#accum + 1] = "\213"
- types.table(mt, visited, accum)
- else
- accum[#accum + 1] = "\207"
- end
- accum[#accum + 1] = number_to_str(xlen)
- for i = 1, xlen do
- local v = x[i]
- types[type(v)](v, visited, accum)
- end
- local key_count = 0
- for k in pairs(x) do
- if not_array_index(k, xlen) then
- key_count = key_count + 1
- end
- end
- accum[#accum + 1] = number_to_str(key_count)
- for k, v in pairs(x) do
- if not_array_index(k, xlen) then
- types[type(k)](k, visited, accum)
- types[type(v)](v, visited, accum)
- end
- end
- end
- end
-
- types["function"] = function(x, visited, accum)
- if visited[x] then
- accum[#accum + 1] = "\208"
- accum[#accum + 1] = number_to_str(visited[x])
- else
- if check_custom_type(x, visited, accum) then return end
- visited[x] = visited[NEXT]
- visited[NEXT] = visited[NEXT] + 1
- local str = dump(x)
- accum[#accum + 1] = "\210"
- accum[#accum + 1] = number_to_str(#str)
- accum[#accum + 1] = str
- end
- end
-
- types.cdata = function(x, visited, accum)
- if visited[x] then
- accum[#accum + 1] = "\208"
- accum[#accum + 1] = number_to_str(visited[x])
- else
- if check_custom_type(x, visited, #accum) then return end
- error("Cannot serialize this cdata.")
- end
- end
-
- types.thread = function() error("Cannot serialize threads.") end
-
- local function deserialize_value(str, index, visited)
- local t = byte(str, index)
- if not t then return nil, index end
- if t < 128 then
- return t - 27, index + 1
- elseif t < 192 then
- local b2 = byte(str, index + 1)
- if not b2 then error("Expected more bytes of input.") end
- return b2 + 0x100 * (t - 128) - 8192, index + 2
- elseif t == 202 then
- return nil, index + 1
- elseif t == 203 or t == 212 then
- return number_from_str(str, index)
- elseif t == 204 then
- return true, index + 1
- elseif t == 205 then
- return false, index + 1
- elseif t == 206 then
- local length, dataindex = number_from_str(str, index + 1)
- local nextindex = dataindex + length
- if not (length >= 0) then error("Bad string length") end
- if #str < nextindex - 1 then error("Expected more bytes of string") end
- local substr = sub(str, dataindex, nextindex - 1)
- visited[#visited + 1] = substr
- return substr, nextindex
- elseif t == 207 or t == 213 then
- local mt, count, nextindex
- local ret = {}
- visited[#visited + 1] = ret
- nextindex = index + 1
- if t == 213 then
- mt, nextindex = deserialize_value(str, nextindex, visited)
- if type(mt) ~= "table" then error("Expected table metatable") end
- end
- count, nextindex = number_from_str(str, nextindex)
- for i = 1, count do
- local oldindex = nextindex
- ret[i], nextindex = deserialize_value(str, nextindex, visited)
- if nextindex == oldindex then error("Expected more bytes of input.") end
- end
- count, nextindex = number_from_str(str, nextindex)
- for i = 1, count do
- local k, v
- local oldindex = nextindex
- k, nextindex = deserialize_value(str, nextindex, visited)
- if nextindex == oldindex then error("Expected more bytes of input.") end
- oldindex = nextindex
- v, nextindex = deserialize_value(str, nextindex, visited)
- if nextindex == oldindex then error("Expected more bytes of input.") end
- if k == nil then error("Can't have nil table keys") end
- ret[k] = v
- end
- if mt then setmetatable(ret, mt) end
- return ret, nextindex
- elseif t == 208 then
- local ref, nextindex = number_from_str(str, index + 1)
- return visited[ref], nextindex
- elseif t == 209 then
- local count
- local name, nextindex = deserialize_value(str, index + 1, visited)
- count, nextindex = number_from_str(str, nextindex)
- local args = {}
- for i = 1, count do
- local oldindex = nextindex
- args[i], nextindex = deserialize_value(str, nextindex, visited)
- if nextindex == oldindex then error("Expected more bytes of input.") end
- end
- if not name or not deserializers[name] then
- error(("Cannot deserialize class '%s'"):format(tostring(name)))
- end
- local ret = deserializers[name](unpack(args))
- visited[#visited + 1] = ret
- return ret, nextindex
- elseif t == 210 then
- local length, dataindex = number_from_str(str, index + 1)
- local nextindex = dataindex + length
- if not (length >= 0) then error("Bad string length") end
- if #str < nextindex - 1 then error("Expected more bytes of string") end
- local ret = loadstring(sub(str, dataindex, nextindex - 1))
- visited[#visited + 1] = ret
- return ret, nextindex
- elseif t == 211 then
- local resname, nextindex = deserialize_value(str, index + 1, visited)
- if resname == nil then error("Got nil resource name") end
- local res = resources_by_name[resname]
- if res == nil then
- error(("No resources found for name '%s'"):format(tostring(resname)))
- end
- return res, nextindex
- else
- error("Could not deserialize type byte " .. t .. ".")
- end
- end
-
- local function serialize(...)
- local visited = {[NEXT] = 1, [CTORSTACK] = {}}
- local accum = {}
- for i = 1, select("#", ...) do
- local x = select(i, ...)
- types[type(x)](x, visited, accum)
- end
- return concat(accum)
- end
-
- local function make_file_writer(file)
- return setmetatable({}, {
- __newindex = function(_, _, v)
- file:write(v)
- end
- })
- end
-
- local function serialize_to_file(path, mode, ...)
- local file, err = io.open(path, mode)
- assert(file, err)
- local visited = {[NEXT] = 1, [CTORSTACK] = {}}
- local accum = make_file_writer(file)
- for i = 1, select("#", ...) do
- local x = select(i, ...)
- types[type(x)](x, visited, accum)
- end
- -- flush the writer
- file:flush()
- file:close()
- end
-
- local function writeFile(path, ...)
- return serialize_to_file(path, "wb", ...)
- end
-
- local function appendFile(path, ...)
- return serialize_to_file(path, "ab", ...)
- end
-
- local function deserialize(str, index)
- assert(type(str) == "string", "Expected string to deserialize.")
- local vals = {}
- index = index or 1
- local visited = {}
- local len = 0
- local val
- while true do
- local nextindex
- val, nextindex = deserialize_value(str, index, visited)
- if nextindex > index then
- len = len + 1
- vals[len] = val
- index = nextindex
- else
- break
- end
- end
- return vals, len
- end
-
- local function deserializeN(str, n, index)
- assert(type(str) == "string", "Expected string to deserialize.")
- n = n or 1
- assert(type(n) == "number", "Expected a number for parameter n.")
- assert(n > 0 and floor(n) == n, "N must be a poitive integer.")
- local vals = {}
- index = index or 1
- local visited = {}
- local len = 0
- local val
- while len < n do
- local nextindex
- val, nextindex = deserialize_value(str, index, visited)
- if nextindex > index then
- len = len + 1
- vals[len] = val
- index = nextindex
- else
- break
- end
- end
- vals[len + 1] = index
- return unpack(vals, 1, n + 1)
- end
-
- local function readFile(path)
- local file, err = io.open(path, "rb")
- assert(file, err)
- local str = file:read("*all")
- file:close()
- return deserialize(str)
- end
-
- -- Resources
-
- local function registerResource(resource, name)
- type_check(name, "string", "name")
- assert(not resources[resource],
- "Resource already registered.")
- assert(not resources_by_name[name],
- format("Resource %q already exists.", name))
- resources_by_name[name] = resource
- resources[resource] = name
- return resource
- end
-
- local function unregisterResource(name)
- type_check(name, "string", "name")
- assert(resources_by_name[name], format("Resource %q does not exist.", name))
- local resource = resources_by_name[name]
- resources_by_name[name] = nil
- resources[resource] = nil
- return resource
- end
-
- -- Templating
-
- local function normalize_template(template)
- local ret = {}
- for i = 1, #template do
- ret[i] = template[i]
- end
- local non_array_part = {}
- -- The non-array part of the template (nested templates) have to be deterministic, so they are sorted.
- -- This means that inherently non deterministicly sortable keys (tables, functions) should NOT be used
- -- in templates. Looking for way around this.
- for k in pairs(template) do
- if not_array_index(k, #template) then
- non_array_part[#non_array_part + 1] = k
- end
- end
- table.sort(non_array_part)
- for i = 1, #non_array_part do
- local name = non_array_part[i]
- ret[#ret + 1] = {name, normalize_template(template[name])}
- end
- return ret
- end
-
- local function templatepart_serialize(part, argaccum, x, len)
- local extras = {}
- local extracount = 0
- for k, v in pairs(x) do
- extras[k] = v
- extracount = extracount + 1
- end
- for i = 1, #part do
- local name
- if type(part[i]) == "table" then
- name = part[i][1]
- len = templatepart_serialize(part[i][2], argaccum, x[name], len)
- else
- name = part[i]
- len = len + 1
- argaccum[len] = x[part[i]]
- end
- if extras[name] ~= nil then
- extracount = extracount - 1
- extras[name] = nil
- end
- end
- if extracount > 0 then
- argaccum[len + 1] = extras
- else
- argaccum[len + 1] = nil
- end
- return len + 1
- end
-
- local function templatepart_deserialize(ret, part, values, vindex)
- for i = 1, #part do
- local name = part[i]
- if type(name) == "table" then
- local newret = {}
- ret[name[1]] = newret
- vindex = templatepart_deserialize(newret, name[2], values, vindex)
- else
- ret[name] = values[vindex]
- vindex = vindex + 1
- end
- end
- local extras = values[vindex]
- if extras then
- for k, v in pairs(extras) do
- ret[k] = v
- end
- end
- return vindex + 1
- end
-
- local function template_serializer_and_deserializer(metatable, template)
- return function(x)
- local argaccum = {}
- local len = templatepart_serialize(template, argaccum, x, 0)
- return unpack(argaccum, 1, len)
- end, function(...)
- local ret = {}
- local args = {...}
- templatepart_deserialize(ret, template, args, 1)
- return setmetatable(ret, metatable)
- end
- end
-
- -- Used to serialize classes withh custom serializers and deserializers.
- -- If no _serialize or _deserialize (or no _template) value is found in the
- -- metatable, then the metatable is registered as a resources.
- local function register(metatable, name, serialize, deserialize)
- if type(metatable) == "table" then
- name = name or metatable.name
- serialize = serialize or metatable._serialize
- deserialize = deserialize or metatable._deserialize
- if (not serialize) or (not deserialize) then
- if metatable._template then
- -- Register as template
- local t = normalize_template(metatable._template)
- serialize, deserialize = template_serializer_and_deserializer(metatable, t)
- else
- -- Register the metatable as a resource. This is semantically
- -- similar and more flexible (handles cycles).
- registerResource(metatable, name)
- return
- end
- end
- elseif type(metatable) == "string" then
- name = name or metatable
- end
- type_check(name, "string", "name")
- type_check(serialize, "function", "serialize")
- type_check(deserialize, "function", "deserialize")
- assert((not ids[metatable]) and (not resources[metatable]),
- "Metatable already registered.")
- assert((not mts[name]) and (not resources_by_name[name]),
- ("Name %q already registered."):format(name))
- mts[name] = metatable
- ids[metatable] = name
- serializers[name] = serialize
- deserializers[name] = deserialize
- return metatable
- end
-
- local function unregister(item)
- local name, metatable
- if type(item) == "string" then -- assume name
- name, metatable = item, mts[item]
- else -- assume metatable
- name, metatable = ids[item], item
- end
- type_check(name, "string", "name")
- mts[name] = nil
- if (metatable) then
- resources[metatable] = nil
- ids[metatable] = nil
- end
- serializers[name] = nil
- deserializers[name] = nil
- resources_by_name[name] = nil;
- return metatable
- end
-
- local function registerClass(class, name)
- name = name or class.name
- if class.__instanceDict then -- middleclass
- register(class.__instanceDict, name)
- else -- assume 30log or similar library
- register(class, name)
- end
- return class
- end
-
- return {
- VERSION = "0.0-8",
- -- aliases
- s = serialize,
- d = deserialize,
- dn = deserializeN,
- r = readFile,
- w = writeFile,
- a = appendFile,
-
- serialize = serialize,
- deserialize = deserialize,
- deserializeN = deserializeN,
- readFile = readFile,
- writeFile = writeFile,
- appendFile = appendFile,
- register = register,
- unregister = unregister,
- registerResource = registerResource,
- unregisterResource = unregisterResource,
- registerClass = registerClass,
-
- newbinser = newbinser
- }
-end
-
-return newbinser()
diff --git a/lib/bitser-test/.travis.yml b/lib/bitser-test/.travis.yml
deleted file mode 100644
index 9c5854a..0000000
--- a/lib/bitser-test/.travis.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-language: python
-sudo: false
-
-env:
- - LUA="luajit=2.0"
-
-before_install:
- - pip install hererocks
- - hererocks lua_install -r^ --$LUA
- - export PATH=$PATH:$PWD/lua_install/bin
-
-install:
- - luarocks install luacheck
- - luarocks install busted
- - luarocks install luacov
- - luarocks install luacov-coveralls
- - luarocks install middleclass
- - wget https://raw.githubusercontent.com/bartbes/slither/b9cf6daa1e8995093aa80a40ee9ff98402eeb602/slither.lua
- - wget https://raw.githubusercontent.com/vrld/hump/038bc9025f1cb850355f4b073357b087b8122da9/class.lua
-
-script:
- - luacheck --std max+busted bitser.lua spec --globals love --no-max-line-length
- - busted --verbose --coverage
-
-after_success:
- - luacov-coveralls --include bitser -e $TRAVIS_BUILD_DIR/lua_install
diff --git a/lib/bitser-test/LICENSE.txt b/lib/bitser-test/LICENSE.txt
deleted file mode 100644
index e48154f..0000000
--- a/lib/bitser-test/LICENSE.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright (c) 2022 Jasmijn Wellner
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
\ No newline at end of file
diff --git a/lib/bitser-test/README.md b/lib/bitser-test/README.md
deleted file mode 100644
index 68a5f61..0000000
--- a/lib/bitser-test/README.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# bitser
-
-[](https://travis-ci.org/gvx/bitser)
-[](https://coveralls.io/github/gvx/bitser?branch=master)
-
-Serializes and deserializes Lua values with LuaJIT.
-
-```lua
-local bitser = require 'bitser'
-
-bitser.register('someResource', someResource)
-bitser.registerClass(SomeClass)
-
-serializedString = bitser.dumps(someValue)
-someValue = bitser.loads(serializedString)
-```
-
-Documentation can be found in [USAGE.md](USAGE.md).
-
-Pull requests, bug reports and other feedback welcome! :heart:
-
-Bitser is released under the ISC license (functionally equivalent to the BSD
-2-Clause and MIT licenses).
-
-Please note that bitser requires LuaJIT for its `ffi` library and JIT compilation. Without JIT, it may or may not run, but it will be much slower than usual. This primarily affects Android and iOS, because JIT is disabled on those platforms.
-
-## Why would I use this?
-
-Because it's fast. Because it produces tiny output. Because the name means "snappier"
-or "unfriendlier" in Dutch. Because it's safe to use with untrusted data.
-
-Because it's inspired by [binser](https://github.com/bakpakin/binser), which is great.
-
-## How do I use the benchmark thingy?
-
-Download zero or more of [binser.lua](https://raw.githubusercontent.com/bakpakin/binser/master/binser.lua),
-[ser.lua](https://raw.githubusercontent.com/gvx/Ser/master/ser.lua),
-[smallfolk.lua](https://raw.githubusercontent.com/gvx/Smallfolk/master/smallfolk.lua),
-[serpent.lua](https://raw.githubusercontent.com/pkulchenko/serpent/master/src/serpent.lua) and
-[MessagePack.lua](https://raw.githubusercontent.com/fperrad/lua-MessagePack/master/src/MessagePack.lua), and run:
-
- love .
-
-You do need [LÖVE](https://love2d.org/) for that.
-
-You can add more cases in the folder `cases/` (check out `_new.lua`), and add other
-serializers to the benchmark in `main.lua`. If you do either of those things, please
-send me a pull request!
-
-## You can register classes?
-
-Yes. At the moment, bitser supports MiddleClass, SECL, hump.class, Slither and Moonscript classes (and
-probably some other class libraries by accident).
diff --git a/lib/bitser-test/USAGE.md b/lib/bitser-test/USAGE.md
deleted file mode 100644
index 8a83c14..0000000
--- a/lib/bitser-test/USAGE.md
+++ /dev/null
@@ -1,243 +0,0 @@
-* [Basic usage](#basic-usage)
-* [Serializing class instances](#serializing-class-instances)
-* [Advanced usage](#advanced-usage)
-* [Reference](#reference)
- * [`bitser.dumps`](#dumps)
- * [`bitser.dumpLoveFile`](#dumplovefile)
- * [`bitser.loads`](#loads)
- * [`bitser.loadData`](#loaddata)
- * [`bitser.loadLoveFile`](#loadlovefile)
- * [`bitser.includeMetatables`](#includeMetatables)
- * [`bitser.register`](#register)
- * [`bitser.registerClass`](#registerclass)
- * [`bitser.unregister`](#unregister)
- * [`bitser.unregisterClass`](#unregisterclass)
- * [`bitser.reserveBuffer`](#reservebuffer)
- * [`bitser.clearBuffer`](#clearbuffer)
-
-# Basic usage
-
-```lua
-local bitser = require 'bitser'
-
--- some_thing can be almost any lua value
-local binary_data = bitser.dumps(some_thing)
-
--- binary_data is a string containing some serialized value
-local copy_of_some_thing = bitser.loads(binary_data)
-```
-
-Bitser can't dump values of type `function`, `userdata` or `thread`, or anything that
-contains one of those. If you need to, look into [`bitser.register`](#register).
-
-# Serializing class instances
-
-All you need to make bitser correctly serialize your class instances is register that class:
-
-```lua
--- this is usually enough
-bitser.registerClass(MyClass)
-
--- if you use Slither, you can add it to __attributes__
-class 'MyClass' {
- __attributes__ = {bitser.registerClass},
- -- insert rest of class here
-}
-
-local data = bitser.dumps(MyClass(42))
-local instance = bitser.loads(data)
-```
-
-Note that classnames need to be unique to avoid confusion, so if you have two different classes named `Foo` you'll need to do
-something like:
-
-```lua
--- in module_a.lua
-bitser.registerClass('module_a.Foo', Foo)
-
--- in module_b.lua
-bitser.registerClass('module_b.Foo', Foo)
-```
-
-See the reference sections on [`bitser.registerClass`](#registerclass) and
-[`bitser.unregisterClass`](#unregisterclass) for more information.
-
-## Supported class libraries
-
-* MiddleClass
-* SECL
-* hump.class
-* Slither
-* Moonscript classes
-
-# Advanced usage
-
-If you use [LÖVE](https://love2d.org/), you'll want to use [`bitser.dumpLoveFile`](#dumplovefile) and [`bitser.loadLoveFile`](#loadlovefile) if you want to serialize to the save directory. You also might have images and other resources that you'll need to register, like follows:
-
-```lua
-function love.load()
- bad_guy_img = bitser.register('bad_guy_img', love.graphics.newImage('img/bad_guy.png'))
- if love.filesystem.exists('save_point.dat') then
- level_data = bitser.loadLoveFile('save_point.dat')
- else
- level_data = create_level_data()
- end
-end
-
-function save_point_reached()
- bitser.dumpLoveFile('save_point.dat', level_data)
-end
-```
-
-# Reference
-
-## dumps
-
-```lua
-string = bitser.dumps(value)
-```
-
-Basic serialization of `value` into a Lua string.
-
-See also: [`bitser.loads`](#loads).
-
-## dumpLoveFile
-
-```lua
-bitser.dumpLoveFile(file_name, value)
-```
-
-Serializes `value` and writes the result to `file_name` more efficiently than serializing to a string and writing
-that string to a file. Only useful if you're running [LÖVE](https://love2d.org/).
-
-See also: [`bitser.loadLoveFile`](#loadlovefile).
-
-## loads
-
-```lua
-value = bitser.loads(string)
-```
-
-Deserializes `value` from `string`.
-
-See also: [`bitser.dumps`](#dumps).
-
-## loadData
-
-```lua
-value = bitser.loadData(light_userdata, size)
-```
-
-Deserializes `value` from raw data. You probably won't need to use this function ever.
-
-When running [LÖVE](https://love2d.org/), you would use it like this:
-
-```lua
-value = bitser.loadData(data:getPointer(), data:getSize())
-```
-
-Where `data` is an instance of a subclass of [Data](https://love2d.org/wiki/Data).
-
-## loadLoveFile
-
-```lua
-value = bitser.loadLoveFile(file_name)
-```
-
-Reads from `file_name` and deserializes `value` more efficiently than reading the file and then deserializing that string.
-Only useful if you're running [LÖVE](https://love2d.org/).
-
-See also: [`bitser.dumpLoveFile`](#dumplovefile).
-
-## includeMetatables
-
-Controls whether bitser will (de)serialize metatables. true by default.
-
-```lua
-bitser.includeMetatables(bool)
-```
-
-## register
-
-```lua
-resource = bitser.register(name, resource)
-```
-
-Registers the value `resource` with the name `name`, which has to be a unique string. Registering static resources like images,
-functions, classes, huge strings and LuaJIT ctypes, makes sure bitser doesn't attempt to serialize them, but only stores a named
-reference to them.
-
-Returns the registered resource as a convenience.
-
-See also: [`bitser.unregister`](#unregister).
-
-## registerClass
-
-```lua
-class = bitser.registerClass(class)
-class = bitser.registerClass(name, class)
-class = bitser.registerClass(name, class, classkey, deserializer)
-```
-
-Registers the class `class`, so that bitser can correctly serialize and deserialize instances of `class`.
-
-Note that if you want to serialize the class _itself_, you'll need to [register the class as a resource](#register).
-
-Most of the time the first variant is enough, but some class libraries don't store the
-class name on the class object itself, in which case you'll need to use the second variant.
-
-Class names also have to be unique, so if you use multiple classes with the same name, you'll need to use the second
-variant as well to give them different names.
-
-The arguments `classkey` and `deserializer` exist so you can hook in unsupported class libraries without needing
-to patch bitser. [See the list of supported class libraries](#supported-class-libraries).
-
-If not nil, the argument `classkey` should be a string such that
-`rawget(obj, classkey) == class` for any `obj` whose type is `class`. This is done so that key is skipped for serialization.
-
-If not nil, the argument `deserializer` should be a function such that `deserializer(obj, class)` returns a valid
-instance of `class` with the properties of `obj`. `deserializer` is allowed to mutate `obj`.
-
-Returns the registered class as a convenience.
-
-See also: [`bitser.unregisterClass`](#unregisterclass).
-
-## unregister
-
-```lua
-bitser.unregister(name)
-```
-
-Deregisters the previously registered value with the name `name`.
-
-See also: [`bitser.register`](#register).
-
-## unregisterClass
-
-```lua
-bitser.unregisterClass(name)
-```
-
-Deregisters the previously registered class with the name `name`. Note that this works by name and not value,
-which is useful in a context where you don't have a reference to the class you want to unregister.
-
-See also: [`bitser.registerClass`](#registerclass).
-
-## reserveBuffer
-
-```lua
-bitser.reserveBuffer(num_bytes)
-```
-
-Makes sure the buffer used for reading and writing serialized data is at least `num_bytes` large.
-You probably don't need to ever use this function.
-
-## clearBuffer
-
-```lua
-bitser.clearBuffer()
-```
-
-Frees up the buffer used for reading and writing serialized data for garbage collection.
-You'll rarely need to use this function, except if you needed a huge buffer before and now only need a small buffer
-(or are done (de)serializing altogether). Most of the time, using this function will decrease performance needlessly.
diff --git a/lib/bitser-test/bitser.lua b/lib/bitser-test/bitser.lua
deleted file mode 100644
index a0a9b64..0000000
--- a/lib/bitser-test/bitser.lua
+++ /dev/null
@@ -1,530 +0,0 @@
---[[
-Copyright (c) 2020, Jasmijn Wellner
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-]]
-
-local VERSION = '1.1'
-
-local floor = math.floor
-local pairs = pairs
-local type = type
-local insert = table.insert
-local getmetatable = getmetatable
-local setmetatable = setmetatable
-
-local ffi = require("ffi")
-local buf_pos = 0
-local buf_size = -1
-local buf = nil
-local buf_is_writable = true
-local writable_buf = nil
-local writable_buf_size = nil
-local corrupt = false
-local includeMetatables = true -- togglable with bitser.includeMetatables(false)
-local SEEN_LEN = {}
-
-local function Buffer_prereserve(min_size)
- if buf_size < min_size then
- buf_size = min_size
- buf = ffi.new("uint8_t[?]", buf_size)
- buf_is_writable = true
- end
-end
-
-local function Buffer_clear()
- buf_size = -1
- buf = nil
- buf_is_writable = true
- corrupt = false
- writable_buf = nil
- writable_buf_size = nil
-end
-
-local function Buffer_makeBuffer(size)
- if not buf_is_writable then
- buf = writable_buf
- corrupt = false
- buf_size = writable_buf_size
- writable_buf = nil
- writable_buf_size = nil
- buf_is_writable = true
- end
- buf_pos = 0
- Buffer_prereserve(size)
-end
-
-local function Buffer_newReader(str)
- Buffer_makeBuffer(#str)
- ffi.copy(buf, str, #str)
-end
-
-local function Buffer_newDataReader(data, size)
- if buf_is_writable then
- writable_buf = buf
- writable_buf_size = buf_size
- end
- buf_is_writable = false
- corrupt = false
- buf_pos = 0
- buf_size = size
- buf = ffi.cast("uint8_t*", data)
-end
-
-local function Buffer_reserve(additional_size)
- while buf_pos + additional_size > buf_size do
- buf_size = buf_size * 2
- local oldbuf = buf
- buf = ffi.new("uint8_t[?]", buf_size)
- buf_is_writable = true
- ffi.copy(buf, oldbuf, buf_pos)
- end
-end
-
-local function Buffer_write_byte(x)
- Buffer_reserve(1)
- buf[buf_pos] = x
- buf_pos = buf_pos + 1
-end
-
-local function Buffer_write_raw(data, len)
- Buffer_reserve(len)
- ffi.copy(buf + buf_pos, data, len)
- buf_pos = buf_pos + len
-end
-
-local function Buffer_write_string(s)
- Buffer_write_raw(s, #s)
-end
-
-local function Buffer_write_data(ct, len, ...)
- Buffer_write_raw(ffi.new(ct, ...), len)
-end
-
-local function Buffer_ensure(numbytes)
- if buf_pos + numbytes > buf_size then
- print("malformed serialized data")
- corrupt = true
- return false
- end
- return true
-end
-
-local function Buffer_read_byte()
- if(not Buffer_ensure(1))then
-
- return nil
- end
-
- local x = buf[buf_pos]
- buf_pos = buf_pos + 1
- return x
-end
-
-local function Buffer_read_string(len)
- if(not Buffer_ensure(len))then
- return nil
- end
- local x = ffi.string(buf + buf_pos, len)
- buf_pos = buf_pos + len
- return x
-end
-
-local function Buffer_read_raw(data, len)
- ffi.copy(data, buf + buf_pos, len)
- buf_pos = buf_pos + len
- return data
-end
-
-local function Buffer_read_data(ct, len)
- return Buffer_read_raw(ffi.new(ct), len)
-end
-
-local resource_registry = {}
-local resource_name_registry = {}
-local class_registry = {}
-local class_name_registry = {}
-local classkey_registry = {}
-local class_deserialize_registry = {}
-
-local serialize_value
-
-local function write_number(value, _)
- if floor(value) == value and value >= -2147483648 and value <= 2147483647 then
- if value >= -27 and value <= 100 then
- --small int
- Buffer_write_byte(value + 27)
- elseif value >= -32768 and value <= 32767 then
- --short int
- Buffer_write_byte(250)
- Buffer_write_data("int16_t[1]", 2, value)
- else
- --long int
- Buffer_write_byte(245)
- Buffer_write_data("int32_t[1]", 4, value)
- end
- else
- --double
- Buffer_write_byte(246)
- Buffer_write_data("double[1]", 8, value)
- end
-end
-
-local function write_string(value, _)
- if #value < 32 then
- --short string
- Buffer_write_byte(192 + #value)
- else
- --long string
- Buffer_write_byte(244)
- write_number(#value)
- end
- Buffer_write_string(value)
-end
-
-local function write_nil(_, _)
- Buffer_write_byte(247)
-end
-
-local function write_boolean(value, _)
- Buffer_write_byte(value and 249 or 248)
-end
-
-local function write_table(value, seen)
- local classkey
- local metatable = getmetatable(value)
- local classname = (class_name_registry[value.class] -- MiddleClass
- or class_name_registry[value.__baseclass] -- SECL
- or class_name_registry[metatable] -- hump.class
- or class_name_registry[value.__class__] -- Slither
- or class_name_registry[value.__class]) -- Moonscript class
- if classname then
- classkey = classkey_registry[classname]
- Buffer_write_byte(242)
- serialize_value(classname, seen)
- elseif includeMetatables and metatable then
- Buffer_write_byte(253)
- else
- Buffer_write_byte(240)
- end
- local len = #value
- write_number(len, seen)
- for i = 1, len do
- serialize_value(value[i], seen)
- end
- local klen = 0
- for k in pairs(value) do
- if (type(k) ~= 'number' or floor(k) ~= k or k > len or k < 1) and k ~= classkey then
- klen = klen + 1
- end
- end
- write_number(klen, seen)
- for k, v in pairs(value) do
- if (type(k) ~= 'number' or floor(k) ~= k or k > len or k < 1) and k ~= classkey then
- serialize_value(k, seen)
- serialize_value(v, seen)
- end
- end
- if includeMetatables and metatable and not classname then
- serialize_value(metatable, seen)
- end
-end
-
-local function write_cdata(value, seen)
- local ty = ffi.typeof(value)
- if ty == value then
- -- ctype
- Buffer_write_byte(251)
- serialize_value(tostring(ty):sub(7, -2), seen)
- return
- end
- -- cdata
- Buffer_write_byte(252)
- serialize_value(ty, seen)
- local len = ffi.sizeof(value)
- write_number(len)
- Buffer_write_raw(ffi.typeof('$[1]', ty)(value), len)
-end
-
-local types = {number = write_number, string = write_string, table = write_table, boolean = write_boolean, ["nil"] = write_nil, cdata = write_cdata}
-
-serialize_value = function(value, seen)
- if seen[value] then
- local ref = seen[value]
- if ref < 64 then
- --small reference
- Buffer_write_byte(128 + ref)
- else
- --long reference
- Buffer_write_byte(243)
- write_number(ref, seen)
- end
- return
- end
- local t = type(value)
- if t ~= 'number' and t ~= 'boolean' and t ~= 'nil' and t ~= 'cdata' then
- seen[value] = seen[SEEN_LEN]
- seen[SEEN_LEN] = seen[SEEN_LEN] + 1
- end
- if resource_name_registry[value] then
- local name = resource_name_registry[value]
- if #name < 16 then
- --small resource
- Buffer_write_byte(224 + #name)
- Buffer_write_string(name)
- else
- --long resource
- Buffer_write_byte(241)
- write_string(name, seen)
- end
- return
- end
- (types[t] or
- error("cannot serialize type " .. t)
- )(value, seen)
-end
-
-local function serialize(value)
- Buffer_makeBuffer(4096)
- local seen = {[SEEN_LEN] = 0}
- serialize_value(value, seen)
-end
-
-local function add_to_seen(value, seen)
- insert(seen, value)
- return value
-end
-
-local function reserve_seen(seen)
- insert(seen, 42)
- return #seen
-end
-
-local function deserialize_value(seen)
- if(corrupt)then
- return nil
- end
-
- local t = Buffer_read_byte()
-
- if(t == nil)then
- return nil
- end
-
- if t < 128 then
- --small int
- return t - 27
- elseif t < 192 then
- --small reference
- return seen[t - 127]
- elseif t < 224 then
- --small string
- local buffer_data = Buffer_read_string(t - 192)
- if(buffer_data == nil)then
- return nil
- end
- return add_to_seen(buffer_data, seen)
- elseif t < 240 then
- --small resource
- local buffer_data = Buffer_read_string(t - 224)
- if(buffer_data == nil)then
- return nil
- end
- return add_to_seen(resource_registry[buffer_data], seen)
- elseif t == 240 or t == 253 then
- --table
- local v = add_to_seen({}, seen)
- local len = deserialize_value(seen)
- for i = 1, len do
- v[i] = deserialize_value(seen)
- end
- len = deserialize_value(seen)
- for _ = 1, len do
- local key = deserialize_value(seen)
- v[key] = deserialize_value(seen)
- end
- if t == 253 then
- if includeMetatables then
- setmetatable(v, deserialize_value(seen))
- end
- end
- return v
- elseif t == 241 then
- --long resource
- local idx = reserve_seen(seen)
- local value = resource_registry[deserialize_value(seen)]
- seen[idx] = value
- return value
- elseif t == 242 then
- --instance
- local instance = add_to_seen({}, seen)
- local classname = deserialize_value(seen)
- local class = class_registry[classname]
- local classkey = classkey_registry[classname]
- local deserializer = class_deserialize_registry[classname]
- local len = deserialize_value(seen)
- for i = 1, len do
- instance[i] = deserialize_value(seen)
- end
- len = deserialize_value(seen)
- for _ = 1, len do
- local key = deserialize_value(seen)
- instance[key] = deserialize_value(seen)
- end
- if classkey then
- instance[classkey] = class
- end
- return deserializer(instance, class)
- elseif t == 243 then
- --reference
- return seen[deserialize_value(seen) + 1]
- elseif t == 244 then
- --long string
- local buffer_data = Buffer_read_string(deserialize_value(seen))
- if(buffer_data == nil)then
- return nil
- end
- return add_to_seen(buffer_data, seen)
- elseif t == 245 then
- --long int
- return Buffer_read_data("int32_t[1]", 4)[0]
- elseif t == 246 then
- --double
- return Buffer_read_data("double[1]", 8)[0]
- elseif t == 247 then
- --nil
- return nil
- elseif t == 248 then
- --false
- return false
- elseif t == 249 then
- --true
- return true
- elseif t == 250 then
- --short int
- return Buffer_read_data("int16_t[1]", 2)[0]
- elseif t == 251 then
- --ctype
- return ffi.typeof(deserialize_value(seen))
- elseif t == 252 then
- local ctype = deserialize_value(seen)
- local len = deserialize_value(seen)
- local read_into = ffi.typeof('$[1]', ctype)()
- Buffer_read_raw(read_into, len)
- return ctype(read_into[0])
- else
- error("unsupported serialized type " .. t)
- end
-end
-
-local function deserialize_MiddleClass(instance, class)
- return setmetatable(instance, class.__instanceDict)
-end
-
-local function deserialize_SECL(instance, class)
- return setmetatable(instance, getmetatable(class))
-end
-
-local deserialize_humpclass = setmetatable
-
-local function deserialize_Slither(instance, class)
- return getmetatable(class).allocate(instance)
-end
-
-local function deserialize_Moonscript(instance, class)
- return setmetatable(instance, class.__base)
-end
-
-return {dumps = function(value)
- serialize(value)
- return ffi.string(buf, buf_pos)
-end, dumpLoveFile = function(fname, value)
- serialize(value)
- assert(love.filesystem.write(fname, ffi.string(buf, buf_pos)))
-end, loadLoveFile = function(fname)
- local serializedData, error = love.filesystem.newFileData(fname)
- assert(serializedData, error)
- Buffer_newDataReader(serializedData:getPointer(), serializedData:getSize())
- local value = deserialize_value({})
- -- serializedData needs to not be collected early in a tail-call
- -- so make sure deserialize_value returns before loadLoveFile does
- return value
-end, loadData = function(data, size)
- if size == 0 then
- error('cannot load value from empty data')
- end
- Buffer_newDataReader(data, size)
- return deserialize_value({})
-end, loads = function(str)
- if #str == 0 then
- error('cannot load value from empty string')
- end
- Buffer_newReader(str)
- return deserialize_value({})
-end, includeMetatables = function(bool)
- includeMetatables = not not bool
-end, register = function(name, resource)
- assert(not resource_registry[name], name .. " already registered")
- resource_registry[name] = resource
- resource_name_registry[resource] = name
- return resource
-end, unregister = function(name)
- resource_name_registry[resource_registry[name]] = nil
- resource_registry[name] = nil
-end, registerClass = function(name, class, classkey, deserializer)
- if not class then
- class = name
- name = class.__name__ or class.name or class.__name
- end
- if not classkey then
- if class.__instanceDict then
- -- assume MiddleClass
- classkey = 'class'
- elseif class.__baseclass then
- -- assume SECL
- classkey = '__baseclass'
- end
- -- assume hump.class, Slither, Moonscript class or something else that doesn't store the
- -- class directly on the instance
- end
- if not deserializer then
- if class.__instanceDict then
- -- assume MiddleClass
- deserializer = deserialize_MiddleClass
- elseif class.__baseclass then
- -- assume SECL
- deserializer = deserialize_SECL
- elseif class.__index == class then
- -- assume hump.class
- deserializer = deserialize_humpclass
- elseif class.__name__ then
- -- assume Slither
- deserializer = deserialize_Slither
- elseif class.__base then
- -- assume Moonscript class
- deserializer = deserialize_Moonscript
- else
- error("no deserializer given for unsupported class library")
- end
- end
- class_registry[name] = class
- classkey_registry[name] = classkey
- class_deserialize_registry[name] = deserializer
- class_name_registry[class] = name
- return class
-end, unregisterClass = function(name)
- class_name_registry[class_registry[name]] = nil
- classkey_registry[name] = nil
- class_deserialize_registry[name] = nil
- class_registry[name] = nil
-end, reserveBuffer = Buffer_prereserve, clearBuffer = Buffer_clear, version = VERSION}
diff --git a/lib/bitser-test/cases/_new.lua b/lib/bitser-test/cases/_new.lua
deleted file mode 100644
index 3ef06c3..0000000
--- a/lib/bitser-test/cases/_new.lua
+++ /dev/null
@@ -1,3 +0,0 @@
--- write your own!
--- data to be tested, repetitions, number of tries
-return {}, 10000, 3
\ No newline at end of file
diff --git a/lib/bitser-test/cases/bigtable.lua b/lib/bitser-test/cases/bigtable.lua
deleted file mode 100644
index 45e07c2..0000000
--- a/lib/bitser-test/cases/bigtable.lua
+++ /dev/null
@@ -1,7 +0,0 @@
-local t = {}
-
-for i = 1, 2000 do
- t[i] = 100
-end
-
-return t, 500, 5
\ No newline at end of file
diff --git a/lib/bitser-test/cases/cdata.lua b/lib/bitser-test/cases/cdata.lua
deleted file mode 100644
index 3227bed..0000000
--- a/lib/bitser-test/cases/cdata.lua
+++ /dev/null
@@ -1,20 +0,0 @@
-local ffi = require("ffi")
-
-ffi.cdef[[
-struct simple_struct {
- int a;
- int b;
-};
-
-struct nested_struct {
- int a;
- struct simple_struct b;
-};
-]]
-
-local int_data = ffi.new('int', 5)
-
-local struct_data = ffi.new('struct nested_struct', {10, {20, 30}})
-
-
-return {int_data, struct_data, {ffi.new("int",1),5,ffi.new("int",67)}}, 1000, 3
\ No newline at end of file
diff --git a/lib/bitser-test/cases/cthulhu.lua b/lib/bitser-test/cases/cthulhu.lua
deleted file mode 100644
index 179b89d..0000000
--- a/lib/bitser-test/cases/cthulhu.lua
+++ /dev/null
@@ -1,7 +0,0 @@
-local cthulhu = {{}, {}, {}}
-cthulhu.fhtagn = cthulhu
-cthulhu[1][cthulhu[2]] = cthulhu[3]
-cthulhu[2][cthulhu[1]] = cthulhu[2]
-cthulhu[3][cthulhu[3]] = cthulhu
-
-return cthulhu, 10000, 3
\ No newline at end of file
diff --git a/lib/bitser-test/cases/intkeys.lua b/lib/bitser-test/cases/intkeys.lua
deleted file mode 100644
index bcfb1ef..0000000
--- a/lib/bitser-test/cases/intkeys.lua
+++ /dev/null
@@ -1,7 +0,0 @@
-local t = {}
-
-for i = 1, 200 do
- t[math.random(1000)] = math.random(100)
-end
-
-return t, 30000, 5
\ No newline at end of file
diff --git a/lib/bitser-test/cases/metatable.lua b/lib/bitser-test/cases/metatable.lua
deleted file mode 100644
index c3a2069..0000000
--- a/lib/bitser-test/cases/metatable.lua
+++ /dev/null
@@ -1,5 +0,0 @@
--- test metatables
-local metatable = {__mode = 'k', foo={1,2,3,4,5,6,7,8,10,11,12}}
-metatable.__index = metatable
-
-return setmetatable({test=true}, metatable), 10000, 3
diff --git a/lib/bitser-test/cases/shared_table.lua b/lib/bitser-test/cases/shared_table.lua
deleted file mode 100644
index 429b64b..0000000
--- a/lib/bitser-test/cases/shared_table.lua
+++ /dev/null
@@ -1,6 +0,0 @@
-local t = {}
-local x = {10, 50, 40, 30, 20}
-for i = 1, 40 do
- t[i] = x
-end
-return t, 10000, 3
\ No newline at end of file
diff --git a/lib/bitser-test/conf.lua b/lib/bitser-test/conf.lua
deleted file mode 100644
index ebf29ea..0000000
--- a/lib/bitser-test/conf.lua
+++ /dev/null
@@ -1,4 +0,0 @@
-function love.conf(t)
- t.version = "11.3"
- t.console = true
-end
\ No newline at end of file
diff --git a/lib/bitser-test/main.lua b/lib/bitser-test/main.lua
deleted file mode 100644
index 9286ba2..0000000
--- a/lib/bitser-test/main.lua
+++ /dev/null
@@ -1,195 +0,0 @@
-local found_bitser, bitser = pcall(require, 'bitser')
-local found_binser, binser = pcall(require, 'binser')
-local found_ser, ser = pcall(require, 'ser')
-local found_serpent, serpent = pcall(require, 'serpent')
-local found_smallfolk, smallfolk = pcall(require, 'smallfolk')
-local found_msgpack, msgpack = pcall(require, 'MessagePack')
-
-local cases
-local selected_case = 1
-
-local sers = {}
-local desers = {}
-
-if found_bitser then
- sers.bitser = bitser.dumps
- desers.bitser = bitser.loads
- bitser.reserveBuffer(1024 * 1024)
-end
-
-if found_binser then
- sers.binser = binser.s
- desers.binser = binser.d
-end
-
-if found_ser then
- sers.ser = ser
- desers.ser = loadstring
-end
-
-if found_serpent then
- sers.serpent = serpent.dump
- desers.serpent = loadstring
-end
-
-if found_smallfolk then
- sers.smallfolk = smallfolk.dumps
- desers.smallfolk = smallfolk.loads
-end
-
-if found_msgpack then
- sers.msgpack = msgpack.pack
- desers.msgpack = msgpack.unpack
-end
-
-local view_absolute = true
-local resultname = "serialisation time in seconds"
-
-function love.load()
- cases = love.filesystem.getDirectoryItems("cases")
- state = 'select_case'
- love.graphics.setBackgroundColor(1, 230/256, 220/256)
- love.graphics.setColor(40/256, 30/256, 0/256)
- love.window.setTitle("Select a benchmark testcase")
-end
-
-function love.keypressed(key)
- if state == 'select_case' then
- if key == 'up' then
- selected_case = (selected_case - 2) % #cases + 1
- elseif key == 'down' then
- selected_case = selected_case % #cases + 1
- elseif key == 'return' then
- state = 'calculate_results'
- love.window.setTitle("Running benchmark...")
- end
- elseif state == 'results' then
- if key == 'r' then
- view_absolute = not view_absolute
- elseif key == 'right' then
- if results == results_ser then
- results = results_deser
- resultname = "deserialisation time in seconds"
- elseif results == results_deser then
- results = results_size
- resultname = "size of output in bytes"
- elseif results == results_size then
- results = results_ser
- resultname = "serialisation time in seconds"
- end
- elseif key == 'left' then
- if results == results_ser then
- results = results_size
- resultname = "size of output in bytes"
- elseif results == results_deser then
- results = results_ser
- resultname = "serialisation time in seconds"
- elseif results == results_size then
- results = results_deser
- resultname = "deserialisation time in seconds"
- end
- elseif key == 'escape' then
- state = 'select_case'
- love.window.setTitle("Select a benchmark testcase")
- end
- end
-end
-
-function love.draw()
- if state == 'select_case' then
- for i, case in ipairs(cases) do
- love.graphics.print(case, selected_case == i and 60 or 20, i * 20)
- end
- local i = 2
- love.graphics.print('serialisation libraries installed:', 200, 20)
- for sername in pairs(sers) do
- love.graphics.print(sername, 200, i * 20)
- i = i + 1
- end
- elseif state == 'calculate_results' then
- love.graphics.print("Running benchmark...", 20, 20)
- love.graphics.print("This may take a while", 20, 40)
- state = 'calculate_results_2'
- elseif state == 'calculate_results_2' then
- local data, iters, tries = love.filesystem.load("cases/" .. cases[selected_case])()
- results_ser = {}
- results = results_ser
- resultname = "serialisation time in seconds"
- results_size = {}
- results_deser = {}
- errors = {}
- for sername, serializer in pairs(sers) do
- results_ser[sername] = math.huge
- results_deser[sername] = math.huge
- end
- local outputs = {}
- for try = 1, tries do
- for sername, serializer in pairs(sers) do
- local output
- local success, diff = pcall(function()
- local t = os.clock()
- for i = 1, iters do
- output = serializer(data)
- end
- return os.clock() - t
- end)
- if not success and not errors[sername] then
- errors[sername] = diff
- elseif success and diff < results_ser[sername] then
- results_ser[sername] = diff
- end
- if try == 1 then
- outputs[sername] = output
- results_size[sername] = output and #output or math.huge
- end
- end
- end
- for try = 1, tries do
- for sername, deserializer in pairs(desers) do
- local input = outputs[sername]
- local success, diff = pcall(function()
- local t = os.clock()
- for i = 1, iters / 10 do
- deserializer(input)
- end
- return os.clock() - t
- end)
- if not success and not errors[sername] then
- errors[sername] = diff
- elseif success and diff < results_deser[sername] then
- results_deser[sername] = diff
- end
- end
- end
- state = 'results'
- love.window.setTitle("Results for " .. cases[selected_case])
- elseif state == 'results' then
- local results_min = math.huge
- local results_max = -math.huge
- for sername, result in pairs(results) do
- if result < results_min then
- results_min = result
- end
- if result > results_max and result < math.huge then
- results_max = result
- end
- end
- if view_absolute then results_min = 0 end
- local i = 1
- for sername, result in pairs(results) do
- love.graphics.print(sername, 20, i * 20)
- if result == math.huge then
- love.graphics.setColor(220/256, 30/256, 0)
- love.graphics.rectangle('fill', 100, i * 20, 780 - 100, 18)
- love.graphics.setColor(40/256, 30/256, 0)
- love.graphics.print(errors[sername], 102, i * 20 + 2)
- else
- love.graphics.rectangle('fill', 100, i * 20, (780 - 100) * (result - results_min) / (results_max - results_min), 18)
- end
- i = i + 1
- end
- love.graphics.print(results_min, 100, i * 20)
- love.graphics.print(results_max, 780 - love.graphics.getFont():getWidth(results_max), i * 20)
- love.graphics.print(resultname .." (smaller is better; try left, right, R, escape)", 100, i * 20 + 20)
- end
-end
diff --git a/lib/bitser-test/spec/bitser_spec.lua b/lib/bitser-test/spec/bitser_spec.lua
deleted file mode 100644
index c292b99..0000000
--- a/lib/bitser-test/spec/bitser_spec.lua
+++ /dev/null
@@ -1,351 +0,0 @@
-local ffi = require 'ffi'
-
-_G.love = {filesystem = {newFileData = function()
- return {getPointer = function()
- local buf = ffi.new("uint8_t[?]", #love.s)
- ffi.copy(buf, love.s, #love.s)
- return buf
- end, getSize = function()
- return #love.s
- end}
-end, write = function(_, s)
- love.s = s
- return true
-end}}
-
-local bitser = require 'bitser'
-
-local function serdeser(value)
- return bitser.loads(bitser.dumps(value))
-end
-
-local function test_serdeser(value)
- assert.are.same(serdeser(value), value)
-end
-
-local function test_serdeser_idempotent(value)
- assert.are.same(bitser.dumps(serdeser(value)), bitser.dumps(value))
-end
-
-describe("bitser", function()
- it("serializes simple values", function()
- test_serdeser(true)
- test_serdeser(false)
- test_serdeser(nil)
- test_serdeser(1)
- test_serdeser(-1)
- test_serdeser(0)
- test_serdeser(100000000)
- test_serdeser(1.234)
- test_serdeser(10 ^ 20)
- test_serdeser(1/0)
- test_serdeser(-1/0)
- test_serdeser("")
- test_serdeser("hullo")
- test_serdeser([[this
- is a longer string
- such a long string
- that it won't fit
- in the "short string" representation
- no it won't
- listen to me
- it won't]])
- local nan = serdeser(0/0)
- assert.is_not.equal(nan, nan)
- end)
- it("serializes simple tables", function()
- test_serdeser({})
- test_serdeser({10, 11, 12})
- test_serdeser({foo = 10, bar = 99, [true] = false})
- test_serdeser({[1000] = 9000})
- test_serdeser({{}})
- end)
- it("serializes tables with tables as keys", function()
- local thekey = {"Heyo"}
- assert.are.same(thekey, (next(serdeser({[thekey] = 12}))))
- end)
- it("serializes cyclic tables", function()
- local cthulhu = {{}, {}, {}}
- cthulhu.fhtagn = cthulhu
- --note: this does not test tables as keys because assert.are.same doesn't like that
- cthulhu[1].cthulhu = cthulhu[3]
- cthulhu[2].cthulhu = cthulhu[2]
- cthulhu[3].cthulhu = cthulhu
-
- test_serdeser(cthulhu)
- end)
- it("serializes resources", function()
- local temp_resource = {}
- bitser.register("temp_resource", temp_resource)
- assert.are.equal(serdeser({this = temp_resource}).this, temp_resource)
- bitser.unregister("temp_resource")
- end)
- it("serializes many resources", function()
- local max = 1000
- local t = {}
- for i = 1, max do
- bitser.register(tostring(i), i)
- t[i] = i
- end
- test_serdeser(t)
- for i = 1, max do
- bitser.unregister(tostring(i))
- end
- end)
- it("serializes deeply nested tables", function()
- local max = 1000
- local t = {}
- for _ = 1, max do
- t.t = {}
- t = t.t
- end
- test_serdeser(t)
- end)
- it("serializes MiddleClass instances", function()
- local class = require("middleclass")
- local Horse = bitser.registerClass(class('Horse'))
- function Horse:initialize(name)
- self.name = name
- self[1] = 'instance can be sequence'
- end
- local bojack = Horse('Bojack Horseman')
- test_serdeser(bojack)
- assert.is_true(serdeser(bojack):isInstanceOf(Horse))
- bitser.unregisterClass('Horse')
- end)
- it("serializes SECL instances", function()
- local class_mt = {}
-
- function class_mt:__index(key)
- return self.__baseclass[key]
- end
-
- local class = setmetatable({ __baseclass = {} }, class_mt)
-
- function class:new(...)
- local c = {}
- c.__baseclass = self
- setmetatable(c, getmetatable(self))
- if c.init then
- c:init(...)
- end
- return c
- end
-
- local Horse = bitser.registerClass('Horse', class:new())
- function Horse:init(name)
- self.name = name
- self[1] = 'instance can be sequence'
- end
- local bojack = Horse:new('Bojack Horseman')
- test_serdeser(bojack)
- assert.are.equal(serdeser(bojack).__baseclass, Horse)
- bitser.unregisterClass('Horse')
- end)
- it("serializes hump.class instances", function()
- local class = require("class")
- local Horse = bitser.registerClass('Horse', class{})
- function Horse:init(name)
- self.name = name
- self[1] = 'instance can be sequence'
- end
- local bojack = Horse('Bojack Horseman')
- test_serdeser(bojack)
- assert.are.equal(getmetatable(serdeser(bojack)), Horse)
- bitser.unregisterClass('Horse')
- end)
- it("serializes Slither instances", function()
- local class = require("slither")
- local Horse = class 'Horse' {
- __attributes__ = {bitser.registerClass},
- __init__ = function(self, name)
- self.name = name
- self[1] = 'instance can be sequence'
- end
- }
- local bojack = Horse('Bojack Horseman')
- test_serdeser(bojack)
- assert.is_true(class.isinstance(serdeser(bojack), Horse))
- bitser.unregisterClass('Horse')
- end)
- it("serializes Moonscript class instances", function()
- local Horse
- do
- local _class_0
- local _base_0 = {}
- _base_0.__index = _base_0
- _class_0 = setmetatable({
- __init = function(self, name)
- self.name = name
- self[1] = 'instance can be sequence'
- end,
- __base = _base_0,
- __name = "Horse"}, {
- __index = _base_0,
- __call = function(cls, ...)
- local _self_0 = setmetatable({}, _base_0)
- cls.__init(_self_0, ...)
- return _self_0
- end
- })
- _base_0.__class = _class_0
- Horse = _class_0
- end
- assert.are.same(Horse.__name, "Horse") -- to shut coveralls up
- bitser.registerClass(Horse)
- local bojack = Horse('Bojack Horseman')
- test_serdeser(bojack)
- local new_bojack = serdeser(bojack)
- assert.are.equal(new_bojack.__class, Horse)
- bitser.unregisterClass('Horse')
- end)
- it("serializes custom class instances", function()
- local Horse_mt = bitser.registerClass('Horse', {__index = {}}, nil, setmetatable)
- local function Horse(name)
- local self = {}
- self.name = name
- self[1] = 'instance can be sequence'
- return setmetatable(self, Horse_mt)
- end
- local bojack = Horse('Bojack Horseman')
- test_serdeser(bojack)
- assert.are.equal(getmetatable(serdeser(bojack)), Horse_mt)
- bitser.unregisterClass('Horse')
- end)
- it("serializes classes that repeat keys", function()
- local my_mt = {"hi"}
- local works = { foo = 'a', bar = {baz = 'b'}, }
- local broken = { foo = 'a', bar = {foo = 'b'}, }
- local more_broken = {
- foo = 'a',
- baz = {foo = 'b', bar = 'c'},
- quz = {bar = 'd', bam = 'e'}
- }
- setmetatable(works, my_mt)
- setmetatable(broken, my_mt)
- setmetatable(more_broken, my_mt)
- bitser.registerClass("Horse", my_mt, nil, setmetatable)
- test_serdeser(works)
- test_serdeser(broken)
- test_serdeser(more_broken)
- bitser.unregisterClass('Horse')
- end)
- it("serializes big data", function()
- local text = "this is a lot of nonsense, please disregard, we need a lot of data to get past 4 KiB (114 characters should do it)"
- local t = {}
- for i = 1, 40 do
- t[i] = text .. i -- no references allowed!
- end
- test_serdeser(t)
- end)
- it("serializes many references", function()
- local max = 1000
- local t = {}
- local t2 = {}
- for i = 1, max do
- t.t = {}
- t = t.t
- t2[i] = t
- end
- test_serdeser({t, t2})
- end)
- it("serializes resources with long names", function()
- local temp_resource = {}
- bitser.register("temp_resource_or_whatever", temp_resource)
- assert.are.equal(serdeser({this = temp_resource}).this, temp_resource)
- bitser.unregister("temp_resource_or_whatever")
- end)
- it("serializes resources with the same name as serialized strings", function()
- local temp_resource = {}
- bitser.register('temp', temp_resource)
- test_serdeser({temp='temp', {temp_resource}})
- bitser.unregister('temp')
- end)
- it("serializes resources with the same long name as serialized strings", function()
- local temp_resource = {}
- bitser.register('temp_resource_or_whatever', temp_resource)
- test_serdeser({temp_resource_or_whatever='temp_resource_or_whatever', {temp_resource}})
- bitser.unregister('temp_resource_or_whatever')
- end)
- it("cannot serialize functions", function()
- assert.has_error(function() bitser.dumps(function() end) end, "cannot serialize type function")
- end)
- it("cannot serialize unsupported class libraries without explicit deserializer", function()
- assert.has_error(function() bitser.registerClass('Horse', {mane = 'majestic'}) end, "no deserializer given for unsupported class library")
- end)
- it("cannot deserialize values from unassigned type bytes", function()
- assert.has_error(function() bitser.loads("\254") end, "unsupported serialized type 254")
- assert.has_error(function() bitser.loads("\255") end, "unsupported serialized type 255")
- end)
- it("can load from raw data", function()
- assert.are.same(bitser.loadData(ffi.new("uint8_t[4]", 195, 103, 118, 120), 4), "gvx")
- end)
- it("will not read from zero length data", function()
- assert.has_error(function() bitser.loadData(ffi.new("uint8_t[1]", 0), 0) end)
- end)
- it("will not read from zero length string", function()
- assert.has_error(function() bitser.loads("") end)
- end)
- it("will not read past the end of the buffer", function()
- assert.has_error(function() bitser.loadData(ffi.new("uint8_t[4]", 196, 103, 118, 120), 4) end)
- end)
- it("can clear the buffer", function()
- bitser.clearBuffer()
- end)
- it("can write to new buffer after reading from read-only buffer", function()
- test_serdeser("bitser")
- bitser.loadData(ffi.new("uint8_t[4]", 195, 103, 118, 120), 4)
- test_serdeser("bitser")
- end)
- it("can dump and load LÖVE files", function()
- local v = {value = "value"}
- bitser.dumpLoveFile("some_file_name", v)
- assert.are.same(v, bitser.loadLoveFile("some_file_name"))
- end)
- it("can read and write simple cdata", function()
- test_serdeser(ffi.new('double', 42.5))
- end)
- it("can read and write cdata with a registered ctype", function()
- pcall(ffi.cdef,[[
- struct some_struct {
- int a;
- double b;
- };
- ]])
- local value = ffi.new('struct some_struct', 42, 1.25)
- bitser.register('struct_type', ffi.typeof(value))
- test_serdeser_idempotent(value)
- bitser.unregister('struct_type')
- end)
- it("can read and write cdata without registering its ctype", function()
- pcall(ffi.cdef,[[
- struct some_struct {
- int a;
- double b;
- };
- ]])
- local value = ffi.new('struct some_struct', 42, 1.25)
- test_serdeser_idempotent(value)
- end)
- it("cannot read from anonymous structs", function()
- local v = bitser.dumps(ffi.new('struct { int a; }'))
- assert.has_error(function() bitser.loads(v) end)
- end)
- it("can read and write simple multiple cdata of the same ctype without getting confused", function()
- test_serdeser({ffi.new('double', 42.5), ffi.new('double', 12), ffi.new('double', 0.01)})
- end)
- it("can read and write metatables by default", function()
- local t = setmetatable({foo="foo"}, {__index = {bar="bar"}})
- test_serdeser(t)
- assert.are.same(getmetatable(t), getmetatable(serdeser(t)))
- assert.are.same(serdeser(t).bar, "bar")
- end)
- it("ignores metatables if the feature is explicitly disabled", function()
- bitser.includeMetatables(false)
- local t = setmetatable({foo="foo"}, {__index = {bar="bar"}})
- test_serdeser(t)
- assert.is_nil(getmetatable(serdeser(t)))
- assert.is_nil(serdeser(t).bar)
- bitser.includeMetatables(true) -- revert back to default for potential other tests
- end)
-end)
diff --git a/lib/bitser.lua b/lib/bitser.lua
deleted file mode 100644
index b76a9d7..0000000
--- a/lib/bitser.lua
+++ /dev/null
@@ -1,496 +0,0 @@
---[[
-Copyright (c) 2020, Jasmijn Wellner
-
-Permission to use, copy, modify, and/or distribute this software for any
-purpose with or without fee is hereby granted, provided that the above
-copyright notice and this permission notice appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-]]
-
-local VERSION = '1.1'
-
-local floor = math.floor
-local pairs = pairs
-local type = type
-local insert = table.insert
-local getmetatable = getmetatable
-local setmetatable = setmetatable
-
-local ffi = require("ffi")
-local buf_pos = 0
-local buf_size = -1
-local buf = nil
-local buf_is_writable = true
-local writable_buf = nil
-local writable_buf_size = nil
-local includeMetatables = true -- togglable with bitser.includeMetatables(false)
-local SEEN_LEN = {}
-
-local function Buffer_prereserve(min_size)
- if buf_size < min_size then
- buf_size = min_size
- buf = ffi.new("uint8_t[?]", buf_size)
- buf_is_writable = true
- end
-end
-
-local function Buffer_clear()
- buf_size = -1
- buf = nil
- buf_is_writable = true
- writable_buf = nil
- writable_buf_size = nil
-end
-
-local function Buffer_makeBuffer(size)
- if not buf_is_writable then
- buf = writable_buf
- buf_size = writable_buf_size
- writable_buf = nil
- writable_buf_size = nil
- buf_is_writable = true
- end
- buf_pos = 0
- Buffer_prereserve(size)
-end
-
-local function Buffer_newReader(str)
- Buffer_makeBuffer(#str)
- ffi.copy(buf, str, #str)
-end
-
-local function Buffer_newDataReader(data, size)
- if buf_is_writable then
- writable_buf = buf
- writable_buf_size = buf_size
- end
- buf_is_writable = false
- buf_pos = 0
- buf_size = size
- buf = ffi.cast("uint8_t*", data)
-end
-
-local function Buffer_reserve(additional_size)
- while buf_pos + additional_size > buf_size do
- buf_size = buf_size * 2
- local oldbuf = buf
- buf = ffi.new("uint8_t[?]", buf_size)
- buf_is_writable = true
- ffi.copy(buf, oldbuf, buf_pos)
- end
-end
-
-local function Buffer_write_byte(x)
- Buffer_reserve(1)
- buf[buf_pos] = x
- buf_pos = buf_pos + 1
-end
-
-local function Buffer_write_raw(data, len)
- Buffer_reserve(len)
- ffi.copy(buf + buf_pos, data, len)
- buf_pos = buf_pos + len
-end
-
-local function Buffer_write_string(s)
- Buffer_write_raw(s, #s)
-end
-
-local function Buffer_write_data(ct, len, ...)
- Buffer_write_raw(ffi.new(ct, ...), len)
-end
-
-local function Buffer_ensure(numbytes)
- if buf_pos + numbytes > buf_size then
- error("malformed serialized data")
- end
-end
-
-local function Buffer_read_byte()
- Buffer_ensure(1)
- local x = buf[buf_pos]
- buf_pos = buf_pos + 1
- return x
-end
-
-local function Buffer_read_string(len)
- Buffer_ensure(len)
- local x = ffi.string(buf + buf_pos, len)
- buf_pos = buf_pos + len
- return x
-end
-
-local function Buffer_read_raw(data, len)
- ffi.copy(data, buf + buf_pos, len)
- buf_pos = buf_pos + len
- return data
-end
-
-local function Buffer_read_data(ct, len)
- return Buffer_read_raw(ffi.new(ct), len)
-end
-
-local resource_registry = {}
-local resource_name_registry = {}
-local class_registry = {}
-local class_name_registry = {}
-local classkey_registry = {}
-local class_deserialize_registry = {}
-
-local serialize_value
-
-local function write_number(value, _)
- if floor(value) == value and value >= -2147483648 and value <= 2147483647 then
- if value >= -27 and value <= 100 then
- --small int
- Buffer_write_byte(value + 27)
- elseif value >= -32768 and value <= 32767 then
- --short int
- Buffer_write_byte(250)
- Buffer_write_data("int16_t[1]", 2, value)
- else
- --long int
- Buffer_write_byte(245)
- Buffer_write_data("int32_t[1]", 4, value)
- end
- else
- --double
- Buffer_write_byte(246)
- Buffer_write_data("double[1]", 8, value)
- end
-end
-
-local function write_string(value, _)
- if #value < 32 then
- --short string
- Buffer_write_byte(192 + #value)
- else
- --long string
- Buffer_write_byte(244)
- write_number(#value)
- end
- Buffer_write_string(value)
-end
-
-local function write_nil(_, _)
- Buffer_write_byte(247)
-end
-
-local function write_boolean(value, _)
- Buffer_write_byte(value and 249 or 248)
-end
-
-local function write_table(value, seen)
- local classkey
- local metatable = getmetatable(value)
- local classname = (class_name_registry[value.class] -- MiddleClass
- or class_name_registry[value.__baseclass] -- SECL
- or class_name_registry[metatable] -- hump.class
- or class_name_registry[value.__class__] -- Slither
- or class_name_registry[value.__class]) -- Moonscript class
- if classname then
- classkey = classkey_registry[classname]
- Buffer_write_byte(242)
- serialize_value(classname, seen)
- elseif includeMetatables and metatable then
- Buffer_write_byte(253)
- else
- Buffer_write_byte(240)
- end
- local len = #value
- write_number(len, seen)
- for i = 1, len do
- serialize_value(value[i], seen)
- end
- local klen = 0
- for k in pairs(value) do
- if (type(k) ~= 'number' or floor(k) ~= k or k > len or k < 1) and k ~= classkey then
- klen = klen + 1
- end
- end
- write_number(klen, seen)
- for k, v in pairs(value) do
- if (type(k) ~= 'number' or floor(k) ~= k or k > len or k < 1) and k ~= classkey then
- serialize_value(k, seen)
- serialize_value(v, seen)
- end
- end
- if includeMetatables and metatable and not classname then
- serialize_value(metatable, seen)
- end
-end
-
-local function write_cdata(value, seen)
- local ty = ffi.typeof(value)
- if ty == value then
- -- ctype
- Buffer_write_byte(251)
- serialize_value(tostring(ty):sub(7, -2), seen)
- return
- end
- -- cdata
- Buffer_write_byte(252)
- serialize_value(ty, seen)
- local len = ffi.sizeof(value)
- write_number(len)
- Buffer_write_raw(ffi.typeof('$[1]', ty)(value), len)
-end
-
-local types = {number = write_number, string = write_string, table = write_table, boolean = write_boolean, ["nil"] = write_nil, cdata = write_cdata}
-
-serialize_value = function(value, seen)
- if seen[value] then
- local ref = seen[value]
- if ref < 64 then
- --small reference
- Buffer_write_byte(128 + ref)
- else
- --long reference
- Buffer_write_byte(243)
- write_number(ref, seen)
- end
- return
- end
- local t = type(value)
- if t ~= 'number' and t ~= 'boolean' and t ~= 'nil' and t ~= 'cdata' then
- seen[value] = seen[SEEN_LEN]
- seen[SEEN_LEN] = seen[SEEN_LEN] + 1
- end
- if resource_name_registry[value] then
- local name = resource_name_registry[value]
- if #name < 16 then
- --small resource
- Buffer_write_byte(224 + #name)
- Buffer_write_string(name)
- else
- --long resource
- Buffer_write_byte(241)
- write_string(name, seen)
- end
- return
- end
- (types[t] or
- error("cannot serialize type " .. t)
- )(value, seen)
-end
-
-local function serialize(value)
- Buffer_makeBuffer(4096)
- local seen = {[SEEN_LEN] = 0}
- serialize_value(value, seen)
-end
-
-local function add_to_seen(value, seen)
- insert(seen, value)
- return value
-end
-
-local function reserve_seen(seen)
- insert(seen, 42)
- return #seen
-end
-
-local function deserialize_value(seen)
- local t = Buffer_read_byte()
- if t < 128 then
- --small int
- return t - 27
- elseif t < 192 then
- --small reference
- return seen[t - 127]
- elseif t < 224 then
- --small string
- return add_to_seen(Buffer_read_string(t - 192), seen)
- elseif t < 240 then
- --small resource
- return add_to_seen(resource_registry[Buffer_read_string(t - 224)], seen)
- elseif t == 240 or t == 253 then
- --table
- local v = add_to_seen({}, seen)
- local len = deserialize_value(seen)
- for i = 1, len do
- v[i] = deserialize_value(seen)
- end
- len = deserialize_value(seen)
- for _ = 1, len do
- local key = deserialize_value(seen)
- v[key] = deserialize_value(seen)
- end
- if t == 253 then
- if includeMetatables then
- setmetatable(v, deserialize_value(seen))
- end
- end
- return v
- elseif t == 241 then
- --long resource
- local idx = reserve_seen(seen)
- local value = resource_registry[deserialize_value(seen)]
- seen[idx] = value
- return value
- elseif t == 242 then
- --instance
- local instance = add_to_seen({}, seen)
- local classname = deserialize_value(seen)
- local class = class_registry[classname]
- local classkey = classkey_registry[classname]
- local deserializer = class_deserialize_registry[classname]
- local len = deserialize_value(seen)
- for i = 1, len do
- instance[i] = deserialize_value(seen)
- end
- len = deserialize_value(seen)
- for _ = 1, len do
- local key = deserialize_value(seen)
- instance[key] = deserialize_value(seen)
- end
- if classkey then
- instance[classkey] = class
- end
- return deserializer(instance, class)
- elseif t == 243 then
- --reference
- return seen[deserialize_value(seen) + 1]
- elseif t == 244 then
- --long string
- return add_to_seen(Buffer_read_string(deserialize_value(seen)), seen)
- elseif t == 245 then
- --long int
- return Buffer_read_data("int32_t[1]", 4)[0]
- elseif t == 246 then
- --double
- return Buffer_read_data("double[1]", 8)[0]
- elseif t == 247 then
- --nil
- return nil
- elseif t == 248 then
- --false
- return false
- elseif t == 249 then
- --true
- return true
- elseif t == 250 then
- --short int
- return Buffer_read_data("int16_t[1]", 2)[0]
- elseif t == 251 then
- --ctype
- return ffi.typeof(deserialize_value(seen))
- elseif t == 252 then
- local ctype = deserialize_value(seen)
- local len = deserialize_value(seen)
- local read_into = ffi.typeof('$[1]', ctype)()
- Buffer_read_raw(read_into, len)
- return ctype(read_into[0])
- else
- error("unsupported serialized type " .. t)
- end
-end
-
-local function deserialize_MiddleClass(instance, class)
- return setmetatable(instance, class.__instanceDict)
-end
-
-local function deserialize_SECL(instance, class)
- return setmetatable(instance, getmetatable(class))
-end
-
-local deserialize_humpclass = setmetatable
-
-local function deserialize_Slither(instance, class)
- return getmetatable(class).allocate(instance)
-end
-
-local function deserialize_Moonscript(instance, class)
- return setmetatable(instance, class.__base)
-end
-
-return {dumps = function(value)
- serialize(value)
- return ffi.string(buf, buf_pos)
-end, dumpLoveFile = function(fname, value)
- serialize(value)
- assert(love.filesystem.write(fname, ffi.string(buf, buf_pos)))
-end, loadLoveFile = function(fname)
- local serializedData, error = love.filesystem.newFileData(fname)
- assert(serializedData, error)
- Buffer_newDataReader(serializedData:getPointer(), serializedData:getSize())
- local value = deserialize_value({})
- -- serializedData needs to not be collected early in a tail-call
- -- so make sure deserialize_value returns before loadLoveFile does
- return value
-end, loadData = function(data, size)
- if size == 0 then
- error('cannot load value from empty data')
- end
- Buffer_newDataReader(data, size)
- return deserialize_value({})
-end, loads = function(str)
- if #str == 0 then
- error('cannot load value from empty string')
- end
- Buffer_newReader(str)
- return deserialize_value({})
-end, includeMetatables = function(bool)
- includeMetatables = not not bool
-end, register = function(name, resource)
- assert(not resource_registry[name], name .. " already registered")
- resource_registry[name] = resource
- resource_name_registry[resource] = name
- return resource
-end, unregister = function(name)
- resource_name_registry[resource_registry[name]] = nil
- resource_registry[name] = nil
-end, registerClass = function(name, class, classkey, deserializer)
- if not class then
- class = name
- name = class.__name__ or class.name or class.__name
- end
- if not classkey then
- if class.__instanceDict then
- -- assume MiddleClass
- classkey = 'class'
- elseif class.__baseclass then
- -- assume SECL
- classkey = '__baseclass'
- end
- -- assume hump.class, Slither, Moonscript class or something else that doesn't store the
- -- class directly on the instance
- end
- if not deserializer then
- if class.__instanceDict then
- -- assume MiddleClass
- deserializer = deserialize_MiddleClass
- elseif class.__baseclass then
- -- assume SECL
- deserializer = deserialize_SECL
- elseif class.__index == class then
- -- assume hump.class
- deserializer = deserialize_humpclass
- elseif class.__name__ then
- -- assume Slither
- deserializer = deserialize_Slither
- elseif class.__base then
- -- assume Moonscript class
- deserializer = deserialize_Moonscript
- else
- error("no deserializer given for unsupported class library")
- end
- end
- class_registry[name] = class
- classkey_registry[name] = classkey
- class_deserialize_registry[name] = deserializer
- class_name_registry[class] = name
- return class
-end, unregisterClass = function(name)
- class_name_registry[class_registry[name]] = nil
- classkey_registry[name] = nil
- class_deserialize_registry[name] = nil
- class_registry[name] = nil
-end, reserveBuffer = Buffer_prereserve, clearBuffer = Buffer_clear, version = VERSION}
diff --git a/lib/character_support.lua b/lib/character_support.lua
deleted file mode 100644
index 73b5519..0000000
--- a/lib/character_support.lua
+++ /dev/null
@@ -1,137 +0,0 @@
-char_ranges = {
- ["data/fonts/generated/notosans_zhcn_48.bin"] = {
- {32, 254},
- {8220, 8221},
- {8734, 8734},
- {12289, 12290},
- {12298, 12299},
- {13312, 19902},
- {19968, 40958},
- {65281, 65281},
- {65288, 65289},
- {65292, 65292},
- {65306, 65306},
- {65311, 65311},
- {177984, 178206},
- },
- ["data/fonts/generated/notosans_jp_48.bin"] = {
- {32, 254},
- {8230, 8230},
- {8734, 8734},
- {12289, 12290},
- {12293, 12293},
- {12300, 12301},
- {12352, 12446},
- {12448, 12542},
- {19968, 40894},
- {65281, 65281},
- {65288, 65289},
- {65306, 65306},
- {65311, 65311},
- },
- ["data/fonts/generated/notosans_ko_48.bin"] = {
- {32, 254},
- {4352, 4606},
- {8734, 8734},
- {12592, 12686},
- {43360, 43390},
- {44032, 55202},
- {55216, 55294},
- },
- ["data/fonts/font_pixel.xml"] = {
-
- }
-}
-
-language_fonts = {
- ["简体中文"] = "data/fonts/generated/notosans_zhcn_48.bin",
- ["日本語"] = "data/fonts/generated/notosans_jp_48.bin",
- ["한국어"] = "data/fonts/generated/notosans_ko_48.bin",
-}
-
-get_font_characters = function(font)
- local font_data_text = get_content(font)
-
- local font_parsed = nxml.parse(font_data_text)
-
- local chars = {}
-
- for elem in font_parsed:each_child() do
- if elem.name == "QuadChar" and elem.attr.id ~= nil then
- local char = tonumber(elem.attr.id)
- table.insert(chars, char)
- end
- end
-
- table.sort(chars)
-
- return chars
-end
-
--- only supports xml fonts
-register_font = function(font)
- local chars = get_font_characters(font)
-
- char_ranges[font] = {}
-
- local range_start = chars[1]
- local range_end = chars[1]
-
- for i = 2, #chars do
- local char = chars[i]
- if(char == range_end + 1)then
- range_end = char
- else
- table.insert(char_ranges[font], {range_start, range_end})
- range_start = char
- range_end = char
- end
- end
-
- table.insert(char_ranges[font], {range_start, range_end})
-end
-
-register_font("data/fonts/font_pixel.xml")
-register_font("data/fonts/font_pixel_big.xml")
-
-get_current_font = function(huge)
- local current_font = "data/fonts/font_pixel.xml"
-
- if(huge)then
- current_font = "data/fonts/font_pixel_huge.xml"
- end
-
- local lang = GameTextGetTranslatedOrNot("$current_language")
-
- if(language_fonts[lang])then
- current_font = language_fonts[lang]
- end
-
- return current_font
-end
-
-char_supported = function(font, char)
- local char_code = utf8.codepoint(char)
- for i = 1, #char_ranges[font] do
- local range = char_ranges[font][i]
- if(char_code >= range[1] and char_code <= range[2])then
- return true
- end
- end
- return false
-end
-
-string_supported = function(font, str)
- for i=1, utf8.len(str) do
- local char = utf8.sub(str, i, i)
- if not char_supported(font, char) then
- return false
- end
- end
- return true
-end
-
-check_string = function(str)
- local font = get_current_font()
- return string_supported(font, str)
-end
\ No newline at end of file
diff --git a/lib/data_store.lua b/lib/data_store.lua
deleted file mode 100644
index d19f43f..0000000
--- a/lib/data_store.lua
+++ /dev/null
@@ -1,85 +0,0 @@
-local ds = {}
-
-ds.new = function(path)
- -- Create an empty table to store data
- local data_store = {}
- -- Set the folder path where data will be stored
- local data_folder_name = path
-
- -- create folder if doesn't exist
- if not os.rename(data_folder_name, data_folder_name) then
- os.execute("mkdir \"" .. data_folder_name .. "\"")
- end
-
- -- Function to set the value for the given key
- function data_store.Set(key, value)
- -- Create the file path by joining the folder path and key
- local file_path = data_folder_name .. "\\" .. key
- -- Open or create the file for writing
- local file = io.open(file_path, "wb")
- -- Check if the file is successfully opened
- if file then
- -- mp_log:print("Writing to file: " .. file_path)
- -- Write the value to the file
- file:write(value)
- -- Close the file
- file:close()
- else
- -- Print an error message if the file cannot be opened
- mp_log:print("Error: Could not open the file for writing.")
- end
- end
-
- -- Function to get the value for the given key
- function data_store.Get(key)
- -- Create the file path by joining the folder path and key
- local file_path = data_folder_name .. "\\" .. key
- -- Open the file for reading
- local file, err = io.open(file_path, "rb")
- -- Check if the file is successfully opened
- if file then
- -- Read the content of the file
- local content = file:read("*all")
- -- Close the file
- file:close()
- -- Return the content of the file
- return content
- else
- -- Print an error message if the file cannot be opened
- mp_log:print("Error: Could not open the file ["..file_path.."] for reading.")
- mp_log:print(tostring(err))
- -- Return nil to indicate an error
- return nil
- end
- end
-
- -- Function to remove the value for the given key
- function data_store.Remove(key)
- -- Create the file path by joining the folder path and key
- local file_path = data_folder_name .. "\\" .. key
- -- Remove the file
- os.remove(file_path)
- end
-
- -- Function to get all the keys in the data store
- function data_store.Keys()
- -- Create an empty table to store the keys
- local keys = {}
- -- Create a handle to the directory
- local dir_handle = io.popen("dir \"" .. data_folder_name .. "\" /b")
- -- Loop through the directory
- for file in dir_handle:lines() do
- -- Add the file name to the keys table
- table.insert(keys, file)
- end
- -- Close the directory handle
- dir_handle:close()
- -- Return the keys table
- return keys
- end
-
- return data_store
-end
-
--- Return the data_store table to make its functions accessible
-return ds
\ No newline at end of file
diff --git a/lib/delay.lua b/lib/delay.lua
deleted file mode 100644
index 5013823..0000000
--- a/lib/delay.lua
+++ /dev/null
@@ -1,62 +0,0 @@
-local delay = {}
-local delay_queue = {}
-
-delay.reset = function()
- delay_queue = {}
-end
-
-delay.update = function()
- for i = #delay_queue, 1, -1 do
- local v = delay_queue[i]
-
- -- if v is null, remove it
- if(v == nil)then
- table.remove(delay_queue, i)
- return
- end
-
- --v.total_frames = v.total_frames or 0
- --v.total_frames = v.total_frames + 1
-
- --[[if(v.total_frames > 10 * 60 * 60)then
- table.remove(delay_queue, i)
- return
- end]]
-
- if(type(v.frames) == "number")then
- v.frames = v.frames - 1
- end
-
- if(v.tick_callback)then
- v.tick_callback(v.frames)
- end
-
- if((type(v.frames) == "number" and v.frames <= 0) or (type(v.frames) == "function" and v.frames()))then
- if(v.finish_callback)then
- v.finish_callback()
- end
- table.remove(delay_queue, i)
- end
- end
-end
-
-delay.new = function(frames, finish_callback, tick_callback)
- local self = {
- frames = frames,
- tick_callback = tick_callback,
- finish_callback = finish_callback
- }
- table.insert(delay_queue, self)
-
- self.clear = function()
- for i = #delay_queue, 1, -1 do
- if(delay_queue[i] == self)then
- table.remove(delay_queue, i)
- end
- end
- end
-
- return self
-end
-
-return delay
\ No newline at end of file
diff --git a/lib/ffi_extensions.lua b/lib/ffi_extensions.lua
deleted file mode 100644
index 742cf34..0000000
--- a/lib/ffi_extensions.lua
+++ /dev/null
@@ -1,240 +0,0 @@
--- Used to provide silent reimplementations of os.execute and io.popen
-
-if not jit or jit.os ~= "Windows" then
- return
-end
-
-
-local ffi = require("ffi")
-
-local C = ffi.C
-
-ffi.cdef[[
-typedef bool BOOLEAN;
-typedef uint16_t WORD;
-typedef uint32_t DWORD;
-typedef void *LPVOID;
-typedef unsigned char *LPBYTE;
-typedef char *LPSTR;
-typedef const char *LPCSTR;
-typedef void *HANDLE;
-typedef HANDLE *PHANDLE;
-typedef DWORD *LPDWORD;
-
-// Renamed to _SECURITY_ATTRIBUTES_2 to avoid conflict with lfs_ffi
-typedef struct _SECURITY_ATTRIBUTES_2 {
- DWORD nLength;
- LPVOID lpSecurityDescriptor;
- BOOLEAN bInheritHandle;
-} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
-typedef struct _STARTUPINFOA {
- DWORD cb;
- LPSTR lpReserved;
- LPSTR lpDesktop;
- LPSTR lpTitle;
- DWORD dwX;
- DWORD dwY;
- DWORD dwXSize;
- DWORD dwYSize;
- DWORD dwXCountChars;
- DWORD dwYCountChars;
- DWORD dwFillAttribute;
- DWORD dwFlags;
- WORD wShowWindow;
- WORD cbReserved2;
- LPBYTE lpReserved2;
- HANDLE hStdInput;
- HANDLE hStdOutput;
- HANDLE hStdError;
-} STARTUPINFOA, *LPSTARTUPINFOA;
-typedef struct _PROCESS_INFORMATION {
- HANDLE hProcess;
- HANDLE hThread;
- DWORD dwProcessId;
- DWORD dwThreadId;
-} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
-BOOLEAN CreatePipe(
- PHANDLE,
- PHANDLE,
- LPSECURITY_ATTRIBUTES,
- DWORD
-);
-BOOLEAN SetHandleInformation(
- HANDLE,
- DWORD,
- DWORD
-);
-HANDLE GetStdHandle(DWORD);
-BOOLEAN CreateProcessA(
- LPCSTR,
- LPCSTR,
- LPSECURITY_ATTRIBUTES,
- LPSECURITY_ATTRIBUTES,
- BOOLEAN,
- DWORD,
- LPVOID,
- LPCSTR,
- LPSTARTUPINFOA,
- LPPROCESS_INFORMATION
-);
-DWORD WaitForSingleObject(
- HANDLE,
- DWORD
-);
-BOOLEAN GetExitCodeProcess(
- HANDLE,
- LPDWORD
-);
-BOOLEAN CloseHandle(HANDLE);
-BOOLEAN ReadFile(
- HANDLE,
- LPVOID,
- DWORD,
- LPDWORD,
- void*
-);
-DWORD GetLastError();
-]]
-
-local EXIT_FAILURE = 1
-local STARTF_USESHOWWINDOW = 1
-local STARTF_USESTDHANDLES = 0x100
-local SW_HIDE = 0
-local CREATE_NO_WINDOW = 0x8000000
-local INFINITE = -1
-local HANDLE_FLAG_INHERIT = 1
-local STD_INPUT_HANDLE = -10
-local STD_ERROR_HANDLE = -12
-local ERROR_BROKEN_PIPE = 109
-
-function os.execute(commandLine)
- local si = ffi.new("STARTUPINFOA")
- si.cb = ffi.sizeof(si)
- si.dwFlags = STARTF_USESHOWWINDOW
- si.wShowWindow = SW_HIDE
-
- local pi = ffi.new("PROCESS_INFORMATION")
- if not C.CreateProcessA(nil, "cmd /C " .. commandLine, nil, nil, 0, CREATE_NO_WINDOW, nil, nil, si, pi) then
- return EXIT_FAILURE
- end
- C.WaitForSingleObject(pi.hProcess, INFINITE)
- local exitcode = ffi.new("DWORD[1]")
- local ok = C.GetExitCodeProcess(pi.hProcess, exitcode)
- C.CloseHandle(pi.hProcess)
- C.CloseHandle(pi.hThread)
- return ok and exitcode[0] or EXIT_FAILURE
-end
-
-local pfile = {}
-local pfile_mt = {__index = pfile}
-
-local function checkclosed(pfile)
- if pfile.pi == nil then
- error("attempt to use a closed file", 3)
- end
-end
-
-function pfile:read(n)
- checkclosed(self)
-
- local function fetch(cond)
- while cond() do
- if C.ReadFile(self.pipe_outRd[0], self.byteBuf, self.size, self.bytesRead, nil) then
- local data = ffi.string(self.byteBuf, self.bytesRead[0])
- if self.buffer:sub(-1) == "\r" and data:sub(1, 1) == "\n" then
- self.buffer = self.buffer:sub(1, -2)
- end
- self.buffer = self.buffer .. data:gsub("\r\n", "\n")
- else
- return C.GetLastError() == ERROR_BROKEN_PIPE
- end
- end
- return true
- end
-
- if type(n) == "number" then
- if not fetch(function() return #self.buffer < n end) then
- return nil
- end
- local out = self.buffer:sub(1, n)
- self.buffer = self.buffer:sub(n + 1)
- if out == "" then
- out = nil
- end
- return out
- elseif n == "*a" then
- if not fetch(function() return true end) then
- return nil
- end
- local out = self.buffer
- self.buffer = ""
- return out
- elseif n == "*l" then
- if not fetch(function() return not self.buffer:find("\n", nil, true) end) then
- return nil
- end
- local out
- local npos = self.buffer:find("\n", nil, true)
- if npos then
- out = self.buffer:sub(1, npos-1)
- self.buffer = self.buffer:sub(npos+1)
- else
- out = self.buffer
- self.buffer = ""
- if out == "" then
- out = nil
- end
- end
- return out
- else
- error("bad argument #1 to 'read' (invalid format)", 2)
- end
-end
-
-function pfile:lines()
- checkclosed(self)
- return function() return self:read("*l") end
-end
-
-function pfile:close()
- checkclosed(self)
- local pi = self.pi
- C.CloseHandle(self.pipe_outRd[0])
- C.WaitForSingleObject(pi.hProcess, INFINITE)
- local res = C.CloseHandle(pi.hProcess) and C.CloseHandle(pi.hThread)
- self.pi = nil
- return res
-end
-
-function io.popen(commandLine)
- local sa = ffi.new("SECURITY_ATTRIBUTES", ffi.sizeof("SECURITY_ATTRIBUTES"), nil, true)
-
- local pipe_outRd, pipe_outWr=ffi.new("HANDLE[1]"), ffi.new("HANDLE[1]")
- if not C.CreatePipe(pipe_outRd, pipe_outWr, sa, 0) or not C.SetHandleInformation(pipe_outRd[0], HANDLE_FLAG_INHERIT, 0) then
- return
- end
-
- local si = ffi.new("STARTUPINFOA")
- si.cb = ffi.sizeof(si)
- si.dwFlags = STARTF_USESHOWWINDOW + STARTF_USESTDHANDLES
- si.wShowWindow = SW_HIDE
- si.hStdInput = C.GetStdHandle(STD_INPUT_HANDLE)
- si.hStdOutput = pipe_outWr[0]
- si.hStdError = C.GetStdHandle(STD_ERROR_HANDLE)
-
- local pi = ffi.new("PROCESS_INFORMATION")
- if not C.CreateProcessA(nil, "cmd /C " .. commandLine, nil, nil, 1, CREATE_NO_WINDOW, nil, nil, si, pi) then
- return
- end
- C.CloseHandle(pipe_outWr[0])
-
- local size = 4096
- return setmetatable({
- pi = pi,
- pipe_outRd = pipe_outRd,
- size = size,
- byteBuf = ffi.new("char[?]", size),
- bytesRead = ffi.new("DWORD[1]"),
- buffer = ""
- }, pfile_mt)
-end
\ No newline at end of file
diff --git a/lib/fontbuilder.lua b/lib/fontbuilder.lua
deleted file mode 100644
index f5f143e..0000000
--- a/lib/fontbuilder.lua
+++ /dev/null
@@ -1,52 +0,0 @@
-local fontbuilder = {}
-
-fontbuilder.generate = function(font_lua_file, output_file)
-
- local nxml = dofile("mods/evaisa.mp/lib/nxml.lua")
-
- -- get folder path from font_lua_file
- local folder_path = font_lua_file:match("(.*/)")
- -- load font lua file
- loadfile(font_lua_file)()
-
- local texture = file
- local line_height = height
- local char_space = 1
- local word_space = 0
-
- -- create nxml
- local xml = nxml.parse("")
-
- -- create texture node
- local texture = nxml.parse(""..folder_path..texture.."")
- local line_height = nxml.parse(""..line_height.."")
- local char_space = nxml.parse(""..char_space.."")
- local word_space = nxml.parse(""..word_space.."")
-
- xml:add_child(texture)
- xml:add_child(line_height)
- xml:add_child(char_space)
- xml:add_child(word_space)
-
- for i = 1, #chars do
-
- --[[
-
-
- ]]
-
- --[[
- {char="〫",width=0,x=1,y=1,w=6,h=6,ox=-27,oy=29},
- ]]
- local char = nxml.parse("")
-
- xml:add_child(char)
- end
-
-
- -- write to file
- local file = io.open(output_file, "w")
- file:write(tostring(xml))
-end
-
-return fontbuilder
\ No newline at end of file
diff --git a/lib/fs.lua b/lib/fs.lua
deleted file mode 100644
index bc8c479..0000000
--- a/lib/fs.lua
+++ /dev/null
@@ -1,614 +0,0 @@
---[=[
-
- Portable filesystem API (Windows, Linux and OSX).
- Written by Cosmin Apreutesei. Public Domain.
-
-FEATURES
- * utf8 filenames on all platforms
- * symlinks and hard links on all platforms
- * memory mapping on all platforms
- * some error code unification for common error cases
- * cdata buffer-based I/O
- * platform-specific functionality exposed
-
-FILE OBJECTS
- fs.open(path[, mode|opt]) -> f open file
- f:close() close file
- f:closed() -> true|false check if file is closed
- fs.isfile(f) -> true|false check if f is a file object
- f.handle -> HANDLE Windows HANDLE (Windows platforms)
- f.fd -> fd POSIX file descriptor (POSIX platforms)
-PIPES
- fs.pipe() -> rf, wf create an anonymous pipe
- fs.pipe({path=,=} | path[,options]) -> pf create a named pipe (Windows)
- fs.pipe({path=,mode=} | path[,mode]) -> true create a named pipe (POSIX)
-STDIO STREAMS
- f:stream(mode) -> fs open a FILE* object from a file
- fs:close() close the FILE* object
-MEMORY STREAMS
- fs.open_buffer(buf, [size], [mode]) -> f create a memory stream
-FILE I/O
- f:read(buf, len) -> readlen read data from file
- f:readn(buf, n) -> true read exactly n bytes
- f:readall() -> buf, len read until EOF into a buffer
- f:write(s | buf,len) -> true write data to file
- f:flush() flush buffers
- f:seek([whence] [, offset]) -> pos get/set the file pointer
- f:truncate([opt]) truncate file to current file pointer
- f:buffered_read([bufsize]) -> read(buf, sz) get a buffered read function
-OPEN FILE ATTRIBUTES
- f:attr([attr]) -> val|t get/set attribute(s) of open file
-DIRECTORY LISTING
- fs.dir(dir, [dot_dirs]) -> d, next directory contents iterator
- d:next() -> name, d call the iterator explicitly
- d:close() close iterator
- d:closed() -> true|false check if iterator is closed
- d:name() -> s dir entry's name
- d:dir() -> s dir that was passed to fs.dir()
- d:path() -> s full path of the dir entry
- d:attr([attr, ][deref]) -> t|val get/set dir entry attribute(s)
- d:is(type, [deref]) -> t|f check if dir entry is of type
-FILE ATTRIBUTES
- fs.attr(path, [attr, ][deref]) -> t|val get/set file attribute(s)
- fs.is(path, [type], [deref]) -> t|f check if file exists or is of a certain type
-FILESYSTEM OPS
- fs.mkdir(path, [recursive], [perms]) make directory
- fs.cwd([path]) -> path get/set current working directory
- fs.cd([path]) -> path get/set current working directory
- fs.remove(path, [recursive]) remove file or directory (recursively)
- fs.move(path, newpath, [opt]) rename/move file on the same filesystem
-SYMLINKS & HARDLINKS
- fs.mksymlink(symlink, path, is_dir) create a symbolic link for a file or dir
- fs.mkhardlink(hardlink, path) create a hard link for a file
- fs.readlink(path) -> path dereference a symlink recursively
-COMMON PATHS
- fs.homedir() -> path get current user's home directory
- fs.tmpdir() -> path get temporary directory
- fs.exepath() -> path get the full path of the running executable
- fs.exedir() -> path get the directory of the running executable
- fs.scriptdir() -> path get the directory of the main script
-LOW LEVEL
- fs.wrap_handle(HANDLE) -> f wrap opened HANDLE (Windows)
- fs.wrap_fd(fd) -> f wrap opened file descriptor
- fs.wrap_file(FILE*) -> f wrap opened FILE* object
- fs.fileno(FILE*) -> fd get stream's file descriptor
-MEMORY MAPPING
- fs.map(...) -> map create a memory mapping
- f:map([offset],[size],[addr],[access]) -> map create a memory mapping
- map.addr a void* pointer to the mapped memory
- map.size size of the mapped memory in bytes
- map:flush([async, ][addr, size]) flush (parts of) the mapping to disk
- map:free() release the memory and associated resources
- fs.unlink_mapfile(tagname) remove the shared memory file from disk (Linux, OSX)
- map:unlink()
- fs.mirror_buffer([size], [addr]) -> map create a mirrored memory-mapped ring buffer
- fs.pagesize() -> bytes get allocation granularity
- fs.aligned_size(bytes[, dir]) -> bytes next/prev page-aligned size
- fs.aligned_addr(ptr[, dir]) -> ptr next/prev page-aligned address
-
-The `deref` arg is true by default, meaning that by default, symlinks are
-followed recursively and transparently where this option is available.
-
-All functions raise on user error and unrecoverable OS error, but return
-`nil,err` on recoverable failure. Functions which are listed as having no
-return value actually return true for indicating success. Recoverable errors
-are normalized and made portable, eg. 'not_found' (see full list below).
-
-FILE ATTRIBUTES
-
- attr | Win | OSX | Linux | Description
- --------------+--------+--------+----------+--------------------------------
- type | r | r | r | file type (see below)
- size | r | r | r | file size
- atime | rw | rw | rw | last access time (seldom correct)
- mtime | rw | rw | rw | last contents-change time
- btime | rw | r | | creation (aka "birth") time
- ctime | rw | r | r | last metadata-or-contents-change time
- target | r | r | r | symlink's target (nil if not symlink)
- dosname | r | | | 8.3 filename (Windows)
- archive | rw | | | archive bit (for backup programs)
- hidden | rw | | | hidden bit (don't show in Explorer)
- readonly | rw | | | read-only bit (can't open in write mode)
- system | rw | | | system bit
- temporary | rw | | | writes need not be commited to storage
- not_indexed | rw | | | exclude from indexing
- sparse_file | r | | | file is sparse
- reparse_point | r | | | has a reparse point or is a symlink
- compressed | r | | | file is compressed
- encrypted | r | | | file is encrypted
- perms | | rw | rw | permissions
- uid | | rw | rw | user id
- gid | | rw | rw | group id
- dev | | r | r | device id containing the file
- inode | | r | r | inode number (int64_t)
- volume | r | | | volume serial number
- id | r | | | file id (int64_t)
- nlink | r | r | r | number of hard links
- rdev | | r | r | device id (if special file)
- blksize | | r | r | block size for I/O
- blocks | | r | r | number of 512B blocks allocated
-
-On the table above, `r` means that the attribute is read/only and `rw` means
-that the attribute can be changed. Attributes can be queried and changed
-from different contexts via `f:attr()`, `fs.attr()` and `d:attr()`.
-
-NOTE: File sizes and offsets are Lua numbers not 64bit ints, so they can
-hold at most 8KTB. This will change when that becomes a problem.
-
-FILE TYPES
-
- name | Win | OSX | Linux | description
- -------------+--------+--------+----------+---------------------------------
- file | * | * | * | file is a regular file
- dir | * | * | * | file is a directory
- symlink | * | * | * | file is a symlink
- dev | * | | | file is a Windows device
- blockdev | | * | * | file is a block device
- chardev | | * | * | file is a character device
- pipe | | * | * | file is a pipe
- socket | | * | * | file is a socket
- unknown | | * | * | file type unknown
-
-
-NORMALIZED ERROR MESSAGES
-
- not_found file/dir/path not found
- io_error I/O error
- access_denied access denied
- already_exists file/dir already exists
- is_dir trying this on a directory
- not_empty dir not empty (for remove())
- io_error I/O error
- disk_full no space left on device
-
-File Objects -----------------------------------------------------------------
-
-fs.open(path[, mode|opt]) -> f
-
-Open/create a file for reading and/or writing. The second arg can be a string:
-
- 'r' : open; allow reading only (default)
- 'r+' : open; allow reading and writing
- 'w' : open and truncate or create; allow writing only
- 'w+' : open and truncate or create; allow reading and writing
- 'a' : open and seek to end or create; allow writing only
- 'a+' : open and seek to end or create; allow reading and writing
-
- ... or an options table with platform-specific options which represent
- OR-ed bitmask flags which must be given either as 'foo bar ...',
- {foo=true, bar=true} or {'foo', 'bar'}, eg. {sharing = 'read write'}
- sets the `dwShareMode` argument of CreateFile() to
- `FILE_SHARE_READ | FILE_SHARE_WRITE` on Windows.
- All fields and flags are documented in the code.
-
- field | OS | reference | default
- ----------+--------------+----------------------------------------+----------
- access | Windows | `CreateFile() / dwDesiredAccess` | 'file_read'
- sharing | Windows | `CreateFile() / dwShareMode` | 'file_read'
- creation | Windows | `CreateFile() / dwCreationDisposition` | 'open_existing'
- attrs | Windows | `CreateFile() / dwFlagsAndAttributes` | ''
- flags | Windows | `CreateFile() / dwFlagsAndAttributes` | ''
- flags | Linux, OSX | `open() / flags` | 'rdonly'
- mode | Linux, OSX | `octal or symbolic perms` | '0666' / 'rwx'
-
-The `mode` arg is passed to `unixperms.parse()`.
-
-Pipes ------------------------------------------------------------------------
-
-fs.pipe() -> rf, wf
-
- Create an anonymous (unnamed) pipe. Return two files corresponding to the
- read and write ends of the pipe.
-
- NOTE: If you're using async anonymous pipes in Windows _and_ you're
- also creating multiple Lua states _per OS thread_, make sure to set a unique
- `fs.lua_state_id` per Lua state to distinguish them. That is because
- in Windows, async anonymous pipes are emulated using named pipes.
-
-fs.pipe({path=,=} | path[,options]) -> pf
-
- Create or open a named pipe (Windows). Named pipes on Windows cannot
- be created in any directory like on POSIX systems, instead they must be
- created in the special directory called `\\.\pipe`. After creation,
- named pipes can be opened for reading and writing like normal files.
-
- Named pipes on Windows cannot be removed and are not persistent. They are
- destroyed automatically when the process that created them exits.
-
-fs.pipe({path=,mode=} | path[,mode]) -> true
-
- Create a named pipe (POSIX). Named pipes on POSIX are persistent and can be
- created in any directory as they are just a type of file.
-
-Stdio Streams ----------------------------------------------------------------
-
-f:stream(mode) -> fs
-
- Open a `FILE*` object from a file. The file should not be used anymore while
- a stream is open on it and `fs:close()` should be called to close the file.
-
-fs:close()
-
- Close the `FILE*` object and the underlying file object.
-
-Memory Streams ---------------------------------------------------------------
-
-fs.open_buffer(buf, [size], [mode]) -> f
-
- Create a memory stream for reading and writing data from and into a buffer
- using the file API. Only opening modes 'r' and 'w' are supported.
-
-File I/O ---------------------------------------------------------------------
-
-f:read(buf, len, [expires]) -> readlen
-
- Read data from file. Returns (and keeps returning) 0 on EOF or broken pipe.
-
-f:readn(buf, len, [expires]) -> true
-
- Read data from file until `len` is read.
- Partial reads are signaled with `nil, err, readlen`.
-
-f:readall([expires]) -> buf, len
-
- Read until EOF into a buffer.
-
-f:write(s | buf,len) -> true
-
- Write data to file.
- Partial writes are signaled with `nil, err, writelen`.
-
-f:flush()
-
- Flush buffers.
-
-f:seek([whence] [, offset]) -> pos
-
- Get/set the file pointer. Same semantics as standard `io` module seek
- i.e. `whence` defaults to `'cur'` and `offset` defaults to `0`.
-
-f:truncate(size, [opt])
-
- Truncate file to given `size` and move the current file pointer to `EOF`.
- This can be done both to shorten a file and thus free disk space, or to
- preallocate disk space to be subsequently filled (eg. when downloading a file).
-
- On Linux
-
- `opt` is an optional string for Linux which can contain any of the words
- `fallocate` (call `fallocate()`) and `fail` (do not call `ftruncate()`
- if `fallocate()` fails: return an error instead). The problem with calling
- `ftruncate()` if `fallocate()` fails is that on most filesystems, that
- creates a sparse file which doesn't help if what you want is to actually
- reserve space on the disk, hence the `fail` option. The default is
- `'fallocate fail'` which should never create a sparse file, but it can be
- slow on some file systems (when it's emulated) or it can just fail
- (like on virtual filesystems).
-
- Btw, seeking past EOF and writing something there will also create a sparse
- file, so there's no easy way out of this complexity.
-
- On Windows
-
- On NTFS truncation is smarter: disk space is reserved but no zero bytes are
- written. Those bytes are only written on subsequent write calls that skip
- over the reserved area, otherwise there's no overhead.
-
-f:buffered_read([bufsize]) -> read(buf, sz)
-
- Returns a `read(buf, sz) -> read_sz` function which reads ahead from file
- in order to lower the number of syscalls. `bufsize` specifies the buffer's
- size (default is `4096`).
-
-Open file attributes ---------------------------------------------------------
-
-f:attr([attr]) -> val|t
-
- Get/set attribute(s) of open file. `attr` can be:
- * nothing/nil: get the values of all attributes in a table.
- * string: get the value of a single attribute.
- * table: set one or more attributes.
-
-Directory listing ------------------------------------------------------------
-
-fs.dir([dir], [dot_dirs]) -> d, next
-
- Directory contents iterator. `dir` defaults to `'.'`. `dot_dirs=true` means
- include `.` and `..` entries (default is to exclude them).
-
- USAGE
-
- for name, d in fs.dir() do
- if not name then
- print('error: ', d)
- break
- end
- print(d:attr'type', name)
- end
-
- Always include the `if not name` condition when iterating. The iterator
- doesn't raise any errors. Instead it returns `false, err` as the
- last iteration when encountering an error. Initial errors from calling
- `fs.dir()` (eg. `'not_found'`) are passed to the iterator also, so the
- iterator must be called at least once to see them.
-
-d:next() -> name, d | false, err | nil
-
- Call the iterator explicitly.
-
-d:close()
-
- Close the iterator. Always call `d:close()` before breaking the for loop
- except when it's an error (in which case `d` holds the error message).
-
-d:closed() -> true|false
-
- Check if the iterator is closed.
-
-d:name() -> s
-
- The name of the current file or directory being iterated.
-
-d:dir() -> s
-
- The directory that was passed to `fs.dir()`.
-
-d:path() -> s
-
- The full path of the current dir entry (`d:dir()` combined with `d:name()`).
-
-d:attr([attr, ][deref]) -> t|val
-
- Get/set dir entry attribute(s).
-
- `deref` means return the attribute(s) of the symlink's target if the file is
- a symlink (`deref` defaults to `true`!). When `deref=true`, even the `'type'`
- attribute is the type of the target, so it will never be `'symlink'`.
-
- Some attributes for directory entries are free to get (but not for symlinks
- when `deref=true`) meaning that they don't require a system call for each
- file, notably `type` on all platforms, `atime`, `mtime`, `btime`, `size`
- and `dosname` on Windows and `inode` on Linux and OSX.
-
-d:is(type, [deref]) -> true|false
-
- Check if dir entry is of type.
-
-File attributes --------------------------------------------------------------
-
-fs.attr(path, [attr, ][deref]) -> t|val
-
- Get/set a file's attribute(s) given its path in utf8.
-
-fs.is(path, [type], [deref]) -> true|false
-
- Check if file exists or if it is of a certain type.
-
-Filesystem operations --------------------------------------------------------
-
-fs.mkdir(path, [recursive], [perms])
-
- Make directory. `perms` can be a number or a string passed to `unixperms.parse()`.
-
- NOTE: In recursive mode, if the directory already exists this function
- returns `true, 'already_exists'`.
-
-fs.cd([path]) -> path
-
- Get/set current directory.
-
-fs.remove(path, [recursive])
-
- Remove a file or directory (recursively if `recursive=true`).
-
-fs.move(path, newpath, [opt])
-
- Rename/move a file on the same filesystem. On Windows, `opt` represents
- the `MOVEFILE_*` flags and defaults to `'replace_existing write_through'`.
-
- This operation is atomic on all platforms.
-
-Symlinks & hardlinks ---------------------------------------------------------
-
-fs.mksymlink(symlink, path, is_dir)
-
- Create a symbolic link for a file or dir. The `is_dir` arg is required
- for Windows for creating symlinks to directories. It's ignored on Linux
- and OSX.
-
-fs.mkhardlink(hardlink, path)
-
- Create a hard link for a file.
-
-fs.readlink(path) -> path
-
- Dereference a symlink recursively. The result can be an absolute or
- relative path which can be valid or not.
-
-Memory Mapping ---------------------------------------------------------------
-
- FEATURES
- * file-backed and pagefile-backed (anonymous) memory maps
- * read-only, read/write and copy-on-write access modes plus executable flag
- * name-tagged memory maps for sharing memory between processes
- * mirrored memory maps for using with lock-free ring buffers.
- * synchronous and asynchronous flushing
-
- LIMITATIONS
- * I/O errors from accessing mmapped memory cause a crash (and there's
- nothing that can be done about that with the current ffi), which makes
- this API unsuitable for mapping files from removable media or recovering
- from write failures in general. For all other uses it is fine.
-
-fs.map(args_t) -> map
-fs.map(path, [access], [size], [offset], [addr], [tagname], [perms]) -> map
-f:map([offset], [size], [addr], [access])
-
- Create a memory map object. Args:
-
- * `path`: the file to map: optional; if nil, a portion of the system pagefile
- will be mapped instead.
- * `access`: can be either:
- * '' (read-only, default)
- * 'w' (read + write)
- * 'c' (read + copy-on-write)
- * 'x' (read + execute)
- * 'wx' (read + write + execute)
- * 'cx' (read + copy-on-write + execute)
- * `size`: the size of the memory segment (optional, defaults to file size).
- * if given it must be > 0 or an error is raised.
- * if not given, file size is assumed.
- * if the file size is zero the mapping fails with `'file_too_short'`.
- * if the file doesn't exist:
- * if write access is given, the file is created.
- * if write access is not given, the mapping fails with `'not_found'` error.
- * if the file is shorter than the required offset + size:
- * if write access is not given (or the file is the pagefile which
- can't be resized), the mapping fails with `'file_too_short'` error.
- * if write access is given, the file is extended.
- * if the disk is full, the mapping fails with `'disk_full'` error.
- * `offset`: offset in the file (optional, defaults to 0).
- * if given, must be >= 0 or an error is raised.
- * must be aligned to a page boundary or an error is raised.
- * ignored when mapping the pagefile.
- * `addr`: address to use (optional; an error is raised if zero).
- * it's best to provide an address that is above 4 GB to avoid starving
- LuaJIT which can only allocate in the lower 4 GB of the address space.
- * `tagname`: name of the memory map (optional; cannot be used with `file`;
- must not contain slashes or backslashes).
- * using the same name in two different processes (or in the same process)
- gives access to the same memory.
-
- Returns an object with the fields:
-
- * `addr` - a `void*` pointer to the mapped memory
- * `size` - the actual size of the memory block
-
- If the mapping fails, returns `nil,err` where `err` can be:
-
- * `'not_found'` - file not found.
- * `'file_too_short'` - the file is shorter than the required size.
- * `'disk_full'` - the file cannot be extended because the disk is full.
- * `'out_of_mem'` - size or address too large or specified address in use.
- * an OS-specific error message.
-
-NOTES
-
- * when mapping or resizing a `FILE` that was written to, the write buffers
- should be flushed first.
- * after mapping an opened file handle of any kind, that file handle should
- not be used anymore except to close it after the mapping is freed.
- * attempting to write to a memory block that wasn't mapped with write
- or copy-on-write access results in a crash.
- * changes done externally to a mapped file may not be visible immediately
- (or at all) to the mapped memory.
- * access to shared memory from multiple processes must be synchronized.
-
-map:free()
-
- Free the memory and all associated resources and close the file
- if it was opened by the `fs.map()` call.
-
-map:flush([async, ][addr, size]) -> true | nil,err
-
- Flush (part of) the memory to disk. If the address is not aligned,
- it will be automatically aligned to the left. If `async` is true,
- perform the operation asynchronously and return immediately.
-
-fs.unlink_mapfile(tagname)`
`map:unlink()
-
- Remove a (the) shared memory file from disk. When creating a shared memory
- mapping using `tagname`, a file is created on the filesystem on Linux
- and OS X (not so on Windows). That file must be removed manually when it is
- no longer needed. This can be done anytime, even while mappings are open and
- will not affect said mappings.
-
-fs.mirror_buffer([size], [addr]) -> map (OSX support is NYI)
-
- Create a mirrored buffer to use with a lock-free ring buffer. Args:
- * `size`: the size of the memory segment (optional; one page size
- by default. automatically aligned to the next page size).
- * `addr`: address to use (optional; can be anything convertible to `void*`).
-
- The result is a table with `addr` and `size` fields and all the mirror map
- objects in its array part (freeing the mirror will free all the maps).
- The memory block at `addr` is mirrored such that
- `(char*)addr[i] == (char*)addr[size+i]` for any `i` in `0..size-1`.
-
-fs.aligned_size(bytes[, dir]) -> bytes
-
- Get the next larger (dir = 'right', default) or smaller (dir = 'left') size
- that is aligned to a page boundary. It can be used to align offsets and sizes.
-
-fs.aligned_addr(ptr[, dir]) -> ptr
-
- Get the next (dir = 'right', default) or previous (dir = 'left') address that
- is aligned to a page boundary. It can be used to align pointers.
-
-fs.pagesize() -> bytes
-
- Get the current page size. Memory will always be allocated in multiples
- of this size and file offsets must be aligned to this size too.
-
-Async I/O --------------------------------------------------------------------
-
-Named pipes can be opened with `async = true` option which opens them
-in async mode, which uses the [sock](sock.md) scheduler to multiplex the I/O
-which means all I/O then must be performed inside sock threads.
-In this mode, the `read()` and `write()` methods take an additional `expires`
-arg that behaves just like with sockets.
-
-Programming Notes ------------------------------------------------------------
-
-### Filesystem operations are non-atomic
-
-Most filesystem operations are non-atomic (unless otherwise specified) and
-thus prone to race conditions. This library makes no attempt at fixing that
-and in fact it ignores the issue entirely in order to provide a simpler API.
-For instance, in order to change _only_ the "archive" bit of a file on
-Windows, the file attribute bits need to be read first (because WinAPI doesn't
-take a mask there). That's a TOCTTOU. Resolving a symlink or removing a
-directory recursively in userspace has similar issues. So never work on the
-(same part of the) filesystem from multiple processes without proper locking
-(watch Niall Douglas's "Racing The File System" presentation for more info).
-
-### Flushing does not protect against power loss
-
-Flushing does not protect against power loss on consumer hard drives because
-they usually don't have non-volatile write caches (and disabling the write
-cache is generally not possible nor feasible). Also, most Linux distros do
-not mount ext3 filesystems with the "barrier=1" option by default which means
-no power loss protection there either, even when the hardware works right.
-
-### File locking doesn't always work
-
-File locking APIs only work right on disk mounts and are buggy or non-existent
-on network mounts (NFS, Samba).
-
-### Async disk I/O
-
-Async disk I/O is a complete afterthought on all major Operating Systems.
-If your app is disk-bound just bite the bullet and make a thread pool.
-Read Arvid Norberg's article[1] for more info.
-
-[1] https://blog.libtorrent.org/2012/10/asynchronous-disk-io/
-
-]=]
-
-if not ... then require'fs_test'; return end
-
-local ffi = require'ffi'
-setfenv(1, require'fs_common')
-
-if win then
- require'fs_win'
-elseif linux or osx then
- require'fs_posix'
-else
- error'platform not Windows, Linux or OSX'
-end
-
-ffi.metatype(stream_ct, {__index = stream})
-ffi.metatype(dir_ct, {__index = dir})
-
-return fs
diff --git a/lib/fs_common.lua b/lib/fs_common.lua
deleted file mode 100644
index f454941..0000000
--- a/lib/fs_common.lua
+++ /dev/null
@@ -1,698 +0,0 @@
-
---portable filesystem API for LuaJIT / common code
---Written by Cosmin Apreutesei. Public Domain.
-
-if not ... then require'fs_test'; return end
-
-local ffi = require'ffi'
-local bit = require'bit'
-local glue = require'glue'
-local path = require'path'
-
-local min, max, floor, ceil, ln =
- math.min, math.max, math.floor, math.ceil, math.log
-
-local C = ffi.C
-
-local backend = setmetatable({}, {__index = _G})
-setfenv(1, backend)
-
-cdef = ffi.cdef
-x64 = ffi.arch == 'x64' or nil
-osx = ffi.os == 'OSX' or nil
-linux = ffi.os == 'Linux' or nil
-win = ffi.abi'win' or nil
-
---namespaces in which backends can add methods directly.
-fs = {} --fs module namespace
-file = {} --file object methods
-stream = {} --FILE methods
-dir = {} --dir listing object methods
-
-local uint64_ct = ffi.typeof'uint64_t'
-local void_ptr_ct = ffi.typeof'void*'
-local uintptr_ct = ffi.typeof'uintptr_t'
-
-local u8p = glue.u8p
-local readall = glue.readall
-
-memoize = glue.memoize
-assert = glue.assert
-buffer = glue.buffer
-update = glue.update
-
---error reporting ------------------------------------------------------------
-
-cdef'char *strerror(int errnum);'
-
-local errors = {
- [2] = 'not_found', --ENOENT, _open_osfhandle(), _fdopen(), open(), mkdir(),
- --rmdir(), opendir(), rename(), unlink()
- [5] = 'io_error', --EIO, readlink(), read()
- [13] = 'access_denied', --EACCESS, mkdir() etc.
- [17] = 'already_exists', --EEXIST, open(), mkdir()
- [20] = 'not_found', --ENOTDIR, opendir()
- [21] = 'is_dir', --EISDIR, unlink()
- [linux and 39 or osx and 66 or ''] = 'not_empty', --ENOTEMPTY, rmdir()
- [28] = 'disk_full', --ENOSPC: fallocate()
- [linux and 95 or ''] = 'not_supported', --EOPNOTSUPP: fallocate()
- [linux and 32 or ''] = 'eof', --EPIPE: write()
-}
-
-function check_errno(ret, errno, xtra_errors)
- if ret then return ret end
- errno = errno or ffi.errno()
- local err = errors[errno] or (xtra_errors and xtra_errors[errno])
- if not err then
- local s = C.strerror(errno)
- err = s ~= nil and ffi.string(s) or 'Error '..errno
- end
- return ret, err
-end
-
---flags arg parsing ----------------------------------------------------------
-
---turn a table of boolean options into a bit mask.
-local function table_flags(t, masks, strict)
- local bits = 0
- local mask = 0
- for k,v in pairs(t) do
- local flag
- if type(k) == 'string' and v then --flags as table keys: {flag->true}
- flag = k
- elseif type(k) == 'number'
- and floor(k) == k
- and type(v) == 'string'
- then --flags as array: {flag1,...}
- flag = v
- end
- local bitmask = masks[flag]
- if strict then
- assert(bitmask, 'invalid flag: "%s"', tostring(flag))
- end
- if bitmask then
- mask = bit.bor(mask, bitmask)
- if flag then
- bits = bit.bor(bits, bitmask)
- end
- end
- end
- return bits, mask
-end
-
---turn 'opt1 +opt2 -opt3' -> {opt1=true, opt2=true, opt3=false}
-local function string_flags(s, masks, strict)
- local t = {}
- for s in s:gmatch'[^ ,]+' do
- local m,s = s:match'^([%+%-]?)(.*)$'
- t[s] = m ~= '-'
- end
- return table_flags(t, masks, strict)
-end
-
---set one or more bits of a value without affecting other bits.
-function setbits(bits, mask, over)
- return over and bit.bor(bits, bit.band(over, bit.bnot(mask))) or bits
-end
-
---cache tuple(options_string, masks_table) -> bits, mask
-local cache = {}
-local function getcache(s, masks)
- cache[masks] = cache[masks] or {}
- local t = cache[masks][s]
- if not t then return end
- return t[1], t[2]
-end
-local function setcache(s, masks, bits, mask)
- cache[masks][s] = {bits, mask}
-end
-
-function flags(arg, masks, cur_bits, strict)
- if type(arg) == 'string' then
- local bits, mask = getcache(arg, masks)
- if not bits then
- bits, mask = string_flags(arg, masks, strict)
- setcache(arg, masks, bits, mask)
- end
- return setbits(bits, mask, cur_bits)
- elseif type(arg) == 'table' then
- local bits, mask = table_flags(arg, masks, strict)
- return setbits(bits, mask, cur_bits)
- elseif type(arg) == 'number' then
- return arg
- elseif arg == nil then
- return 0
- else
- assert(false, 'flags expected but "%s" given', type(arg))
- end
-end
-
---file objects ---------------------------------------------------------------
-
-function fs.isfile(f)
- return type(f) == 'table' and rawget(f, '__index') == file
-end
-
---returns a read(buf, maxsz) -> sz function which reads ahead from file.
-function file.buffered_read(f, bufsize)
- local ptr_ct = ffi.typeof'uint8_t*'
- local buf_ct = ffi.typeof'uint8_t[?]'
- local bufsize = bufsize or 4096
- local buf = buf_ct(bufsize)
- local ofs, len = 0, 0
- local eof = false
- return function(dst, sz)
- if not dst then --skip bytes (libjpeg semantics)
- local i, err = f:seek('cur') ; if not i then return nil, err end
- local j, err = f:seek('cur', sz); if not j then return nil, err end
- return j - i
- end
- local rsz = 0
- while sz > 0 do
- if len == 0 then
- if eof then
- return 0
- end
- ofs = 0
- local len1, err = f:read(buf, bufsize)
- if not len1 then return nil, err end
- len = len1
- if len == 0 then
- eof = true
- return rsz
- end
- end
- --TODO: benchmark: read less instead of copying.
- local n = min(sz, len)
- ffi.copy(ffi.cast(ptr_ct, dst) + rsz, buf + ofs, n)
- ofs = ofs + n
- len = len - n
- rsz = rsz + n
- sz = sz - n
- end
- return rsz
- end
-end
-
---stdio streams --------------------------------------------------------------
-
-cdef[[
-typedef struct FILE FILE;
-int fclose(FILE*);
-]]
-
-stream_ct = ffi.typeof'struct FILE'
-
-function stream.close(fs)
- local ok = C.fclose(fs) == 0
- if not ok then return check_errno(false) end
- return true
-end
-
---i/o ------------------------------------------------------------------------
-
-local whences = {set = 0, cur = 1, ['end'] = 2} --FILE_*
-function file:seek(whence, offset)
- if tonumber(whence) and not offset then --middle arg missing
- whence, offset = 'cur', tonumber(whence)
- end
- whence = whence or 'cur'
- offset = tonumber(offset or 0)
- whence = assert(whences[whence], 'invalid whence: "%s"', whence)
- return self:_seek(whence, offset)
-end
-
-function file:write(buf, sz, expires)
- sz = sz or #buf
- if sz == 0 then return true end --mask out null writes
- local sz0 = sz
- while true do
- local len, err = self:_write(buf, sz, expires)
- if len == sz then
- break
- elseif not len then --short write
- return nil, err, sz0 - sz
- end
- assert(len > 0)
- if type(buf) == 'string' then --only make pointer on the rare second iteration.
- buf = ffi.cast(u8p, buf)
- end
- buf = buf + len
- sz = sz - len
- end
- return true
-end
-
-function file:readn(buf, sz, expires)
- local sz0 = sz
- while sz > 0 do
- local len, err = self:read(buf, sz, expires)
- if not len or len == 0 then --short read
- return nil, err, sz0 - sz
- end
- buf = buf + len
- sz = sz - len
- end
- return true
-end
-
-local u8a = ffi.typeof'uint8_t[?]'
-function file:readall(expires)
- if self.type == 'file' then
- local size, err = self:attr'size'; if not size then return nil, err end
- local offset, err = self:seek(); if not offset then return nil, err end
- local sz = size - offset
- if sz == 0 then return nil, 0 end
- local buf = ffi.new(u8a, sz)
- local n, err = self:read(buf, sz)
- if not n then return nil, err end
- if n < sz then return nil, 'partial', buf, n end
- return buf, n
- elseif self.type == 'pipe' then
- return readall(self.read, self, expires)
- else
- assert(false)
- end
-end
-
---filesystem operations ------------------------------------------------------
-
-function fs.mkdir(dir, recursive, ...)
- if recursive then
- dir = path.normalize(dir) --avoid creating `dir` in `dir/..` sequences
- local t = {}
- while true do
- local ok, err, errno = mkdir(dir, ...)
- if ok then break end
- if err ~= 'not_found' then --other problem
- ok = err == 'already_exists' and #t == 0
- return ok, err, errno
- end
- table.insert(t, dir)
- dir = path.dir(dir)
- if not dir then --reached root
- return ok, err
- end
- end
- while #t > 0 do
- local dir = table.remove(t)
- local ok, err, errno = mkdir(dir, ...)
- if not ok then return ok, err, errno end
- end
- return true
- else
- return mkdir(dir, ...)
- end
-end
-
-local function remove(path)
- local type = fs.attr(path, 'type', false)
- if type == 'dir' or (win and type == 'symlink'
- and fs.is(path, 'dir'))
- then
- return rmdir(path)
- end
- return rmfile(path)
-end
-
---TODO: for Windows, this simple algorithm is not correct. On NTFS we
---should be moving all files to a temp folder and deleting them from there.
-local function rmdir_recursive(dir)
- for file, d in fs.dir(dir) do
- if not file then
- return file, d
- end
- local filepath = path.combine(dir, file)
- local ok, err
- local realtype = d:attr('type', false)
- if realtype == 'dir' then
- ok, err = rmdir_recursive(filepath)
- elseif win and realtype == 'symlink' and fs.is(filepath, 'dir') then
- ok, err = rmdir(filepath)
- else
- ok, err = rmfile(filepath)
- end
- if not ok then
- d:close()
- return ok, err
- end
- end
- return rmdir(dir)
-end
-
-function fs.remove(dirfile, recursive)
- if recursive then
- --not recursing if the dir is a symlink, unless it has an endsep!
- if not path.endsep(dirfile) then
- local type, err = fs.attr(dirfile, 'type', false)
- if not type then return nil, err end
- if type == 'symlink' then
- if win and fs.is(dirfile, 'dir') then
- return rmdir(dirfile)
- end
- return rmfile(dirfile)
- end
- end
- return rmdir_recursive(dirfile)
- else
- return remove(dirfile)
- end
-end
-
-function fs.cwd(path)
- if path then
- return chdir(path)
- else
- return getcwd()
- end
-end
-fs.cd = fs.cwd
-
---symlinks -------------------------------------------------------------------
-
-local function readlink_recursive(link, maxdepth)
- if not fs.is(link, 'symlink') then
- return link
- end
- if maxdepth == 0 then
- return nil, 'not_found'
- end
- local target, err = readlink(link)
- if not target then
- return nil, err
- end
- if path.isabs(target) then
- link = target
- else --relative symlinks are relative to their own dir
- local link_dir = path.dir(link)
- if not link_dir then
- return nil, 'not_found'
- elseif link_dir == '.' then
- link_dir = ''
- end
- link = path.combine(link_dir, target)
- end
- return readlink_recursive(link, maxdepth - 1)
-end
-
-function fs.readlink(link)
- return readlink_recursive(link, 32)
-end
-
---common paths ---------------------------------------------------------------
-
-function fs.exedir()
- return path.dir(fs.exepath())
-end
-
-fs.scriptdir = memoize(function()
- return path.normalize((path.combine(initial_cwd(), glue.bin)))
-end)
-
---file attributes ------------------------------------------------------------
-
-function file.attr(f, attr)
- if type(attr) == 'table' then
- return file_attr_set(f, attr)
- else
- return file_attr_get(f, attr)
- end
-end
-
-local function attr_args(attr, deref)
- if type(attr) == 'boolean' then --middle arg missing
- attr, deref = nil, attr
- end
- if deref == nil then
- deref = true --deref by default
- end
- return attr, deref
-end
-
-function fs.attr(path, ...)
- local attr, deref = attr_args(...)
- if attr == 'target' then
- --NOTE: posix doesn't need a type check here, but Windows does
- if not win or fs.is(path, 'symlink') then
- return readlink(path)
- else
- return nil --no error for non-symlink files
- end
- end
- if type(attr) == 'table' then
- return fs_attr_set(path, attr, deref)
- else
- return fs_attr_get(path, attr, deref)
- end
-end
-
-function fs.is(path, type, deref)
- if type == 'symlink' then
- deref = false
- end
- local ftype, err = fs.attr(path, 'type', deref)
- if not type and not ftype and err == 'not_found' then
- return false
- elseif not type and ftype then
- return true
- elseif not ftype then
- return nil, err
- else
- return ftype == type
- end
-end
-
---directory listing ----------------------------------------------------------
-
-local function dir_check(dir)
- assert(not dir:closed(), 'dir closed')
- assert(dir_ready(dir), 'dir not ready')
-end
-
-function fs.dir(dir, dot_dirs)
- dir = dir or '.'
- if dot_dirs then
- return fs_dir(dir)
- else --wrap iterator to skip `.` and `..` entries
- local next, dir = fs_dir(dir)
- local function wrapped_next(dir)
- while true do
- local file, err = next(dir)
- if file == nil then
- return nil
- elseif not file then
- return false, err
- elseif file ~= '.' and file ~= '..' then
- return file, dir
- end
- end
- end
- return wrapped_next, dir
- end
-end
-
-function dir.path(dir)
- return path.combine(dir:dir(), dir:name())
-end
-
-function dir.name(dir)
- dir_check(dir)
- return dir_name(dir)
-end
-
-local function dir_is_symlink(dir)
- return dir_attr_get(dir, 'type', false) == 'symlink'
-end
-
-function dir.attr(dir, ...)
- dir_check(dir)
- local attr, deref = attr_args(...)
- if attr == 'target' then
- if dir_is_symlink(dir) then
- return readlink(dir:path())
- else
- return nil --no error for non-symlink files
- end
- end
- if type(attr) == 'table' then
- return fs_attr_set(dir:path(), attr, deref)
- elseif not attr or (deref and dir_is_symlink(dir)) then
- return fs_attr_get(dir:path(), attr, deref)
- else
- local val, found = dir_attr_get(dir, attr)
- if found == false then --attr not found in state
- return fs_attr_get(dir:path(), attr)
- else
- return val
- end
- end
-end
-
-function dir.is(dir, type, deref)
- if type == 'symlink' then
- deref = false
- end
- return dir:attr('type', deref) == type
-end
-
---memory mapping -------------------------------------------------------------
-
-do
-local m = ffi.new[[
- union {
- struct { uint32_t lo; uint32_t hi; };
- uint64_t x;
- }
-]]
-function split_uint64(x)
- m.x = x
- return m.hi, m.lo
-end
-function join_uint64(hi, lo)
- m.hi, m.lo = hi, lo
- return m.x
-end
-end
-
-function fs.aligned_size(size, dir) --dir can be 'l' or 'r' (default: 'r')
- if ffi.istype(uint64_ct, size) then --an uintptr_t on x64
- local pagesize = fs.pagesize()
- local hi, lo = split_uint64(size)
- local lo = fs.aligned_size(lo, dir)
- return join_uint64(hi, lo)
- else
- local pagesize = fs.pagesize()
- if not (dir and dir:find'^l') then --align to the right
- size = size + pagesize - 1
- end
- return bit.band(size, bit.bnot(pagesize - 1))
- end
-end
-
-function fs.aligned_addr(addr, dir)
- return ffi.cast(void_ptr_ct,
- fs.aligned_size(ffi.cast(uintptr_ct, addr), dir))
-end
-
-function parse_access(s)
- assert(not s:find'[^rwcx]', 'invalid access flags')
- local write = s:find'w' and true or false
- local exec = s:find'x' and true or false
- local copy = s:find'c' and true or false
- assert(not (write and copy), 'invalid access flags')
- return write, exec, copy
-end
-
-function check_tagname(tagname)
- assert(not tagname:find'[/\\]', 'tagname cannot contain `/` or `\\`')
- return tagname
-end
-
-function file.map(f, ...)
- local access, size, offset, addr
- if type(t) == 'table' then
- access, size, offset, addr = t.access, t.size, t.offset, t.addr
- else
- offset, size, addr, access = ...
- end
- return fs.map(f, access or f.access, size, offset, addr)
-end
-
-function fs.map(t,...)
- local file, access, size, offset, addr, tagname, perms
- if type(t) == 'table' then
- file, access, size, offset, addr, tagname, perms =
- t.file, t.access, t.size, t.offset, t.addr, t.tagname, t.perms
- else
- file, access, size, offset, addr, tagname, perms = t, ...
- end
- assert(not file or type(file) == 'string' or fs.isfile(file), 'invalid file argument')
- assert(file or size, 'file and/or size expected')
- assert(not size or size > 0, 'size must be > 0')
- local offset = file and offset or 0
- assert(offset >= 0, 'offset must be >= 0')
- assert(offset == fs.aligned_size(offset), 'offset not page-aligned')
- local addr = addr and ffi.cast(void_ptr_ct, addr)
- assert(not addr or addr ~= nil, 'addr can\'t be zero')
- assert(not addr or addr == fs.aligned_addr(addr), 'addr not page-aligned')
- assert(not (file and tagname), 'cannot have both file and tagname')
- assert(not tagname or not tagname:find'\\', 'tagname cannot contain `\\`')
- return fs_map(file, access, size, offset, addr, tagname, perms)
-end
-
---memory streams -------------------------------------------------------------
-
-local vfile = {}
-
-function fs.open_buffer(buf, sz, mode)
- sz = sz or #buf
- mode = mode or 'r'
- assert(mode == 'r' or mode == 'w', 'invalid mode: "%s"', mode)
- local f = {
- buffer = ffi.cast(u8p, buf),
- size = sz,
- offset = 0,
- mode = mode,
- _buffer = buf, --anchor it
- __index = vfile,
- }
- return setmetatable(f, f)
-end
-
-function vfile.close(f) f._closed = true; return true end
-function vfile.closed(f) return f._closed end
-
-function vfile.flush(f)
- if f._closed then
- return nil, 'access_denied'
- end
- return true
-end
-
-function vfile.read(f, buf, sz)
- if f._closed then
- return nil, 'access_denied'
- end
- sz = min(max(0, sz), max(0, f.size - f.offset))
- ffi.copy(buf, f.buffer + f.offset, sz)
- f.offset = f.offset + sz
- return sz
-end
-
-function vfile.write(f, buf, sz)
- if f._closed then
- return nil, 'access_denied'
- end
- if f.mode ~= 'w' then
- return nil, 'access_denied'
- end
- sz = min(max(0, sz), max(0, f.size - f.offset))
- ffi.copy(f.buffer + f.offset, buf, sz)
- f.offset = f.offset + sz
- return sz
-end
-
-vfile.seek = file.seek
-
-function vfile._seek(f, whence, offset)
- if whence == 1 then --cur
- offset = f.offset + offset
- elseif whence == 2 then --end
- offset = f.size + offset
- end
- offset = max(offset, 0)
- f.offset = offset
- return offset
-end
-
-function vfile:truncate(size)
- local pos, err = f:seek(size)
- if not pos then return nil, err end
- f.size = size
- return true
-end
-
-vfile.buffered_read = file.buffered_read
-
-
-return backend
diff --git a/lib/fs_test.lua b/lib/fs_test.lua
deleted file mode 100644
index c6ffea8..0000000
--- a/lib/fs_test.lua
+++ /dev/null
@@ -1,1038 +0,0 @@
-local ffi = require'ffi'
-local fs = require'fs'
-local pp = require'pp'
-local time = require'time'
-local win = ffi.abi'win'
-local linux = ffi.os == 'Linux'
-local osx = ffi.os == 'OSX'
-local x64 = ffi.arch == 'x64'
-
---if luapower sits on a VirtualBox shared folder on a Windows host
---we can't mmap files, create symlinks or use locking on that, so we'll use
---$HOME, which is usually a disk mount.
-local prefix = win and '' or os.getenv'HOME'..'/'
-
-local test = setmetatable({}, {__newindex = function(t, k, v)
- rawset(t, k, v)
- rawset(t, #t+1, k)
-end})
-
---open/close -----------------------------------------------------------------
-
-function test.open_close()
- local testfile = 'fs_testfile'
- local f = assert(fs.open(testfile, 'w'))
- assert(fs.isfile(f))
- assert(not f:closed())
- assert(f:close())
- assert(f:closed())
- assert(fs.remove(testfile))
-end
-
-function test.open_not_found()
- local nonexistent = 'this_file_should_not_exist'
- local f, err = fs.open(nonexistent)
- assert(not f)
- assert(err == 'not_found')
-end
-
-function test.open_already_exists_file()
- local testfile = 'fs_testfile'
- local f = assert(fs.open(testfile, 'w'))
- assert(f:close())
- local f, err = fs.open(testfile,
- win and {
- access = 'write',
- creation = 'create_new',
- flags = 'backup_semantics'
- } or {
- flags = 'creat excl'
- })
- assert(not f)
- assert(err == 'already_exists')
- assert(fs.remove(testfile))
-end
-
-function test.open_already_exists_dir()
- local testfile = 'fs_test_dir_already_exists'
- fs.remove(testfile)
- assert(fs.mkdir(testfile))
- local f, err = fs.open(testfile,
- win and {
- access = 'write',
- creation = 'create_new',
- flags = 'backup_semantics'
- } or {
- flags = 'creat excl'
- })
- assert(not f)
- assert(err == 'already_exists')
- assert(fs.remove(testfile))
-end
-
-function test.open_dir()
- local testfile = 'fs_test_dir'
- local using_backup_semantics = true
- fs.remove(testfile, true)
- assert(fs.mkdir(testfile))
- local f, err = fs.open(testfile)
- if win and not using_backup_semantics then
- --using `backup_semantics` flag on CreateFile allows us to upen
- --directories like in Linux, otherwise we'd get an access_denied error.
- --Need more testing to see if this flag does not create other problems.
- assert(not f)
- assert(err == 'access_denied')
- else
- assert(f)
- assert(f:close())
- end
- assert(fs.remove(testfile))
-end
-
-function test.wrap_file() --indirectly tests wrap_fd() and wrap_handle()
- local name = 'fs_test_wrap_file'
- os.remove(name)
- local f = io.open(name, 'w')
- f:write'hello'
- f:flush()
- if linux then
- os.execute'sleep .2' --WTF??
- end
- local f2 = fs.wrap_file(f)
- assert(f2:attr'size' == 5)
- f:close()
- os.remove(name)
-end
-
---pipes ----------------------------------------------------------------------
-
-function test.pipe() --I/O test in proc_test.lua
- local rf, wf = assert(fs.pipe())
- rf:close()
- wf:close()
-end
-
---NOTE: I/O tests in proc_test.lua!
-function test.named_pipe_win()
- if not win then return end
- local opt = 'rw' --'rw single_instance'
- local name = [[\\.\pipe\fs_test_pipe]]
- local p1 = assert(fs.pipe(name, opt))
- local p2 = assert(fs.pipe(name, opt))
- p1:close()
- p2:close()
-end
-
---NOTE: I/O tests in proc_test.lua!
-function test.named_pipe_posix()
- if win then return end
- local opt = 'rw'
- local file = prefix..'fs_test_pipe'
- os.remove(file)
- local p = assert(fs.pipe(name, opt))
- p:close()
- os.remove(file)
-end
-
---i/o ------------------------------------------------------------------------
-
-function test.read_write()
- local testfile = 'fs_test_read_write'
- local sz = 4096
- local buf = ffi.new('uint8_t[?]', sz)
-
- --write some patterns
- local f = assert(fs.open(testfile, 'w'))
- for i=0,sz-1 do
- buf[i] = i
- end
- for i=1,4 do
- assert(f:write(buf, sz))
- end
- assert(f:close())
-
- --read them back
- local f = assert(fs.open(testfile))
- local t = {}
- while true do
- local readsz = assert(f:read(buf, sz))
- if readsz == 0 then break end
- t[#t+1] = ffi.string(buf, readsz)
- end
- assert(f:close())
-
- --check them out
- local s = table.concat(t)
- for i=1,#s do
- assert(s:byte(i) == (i-1) % 256)
- end
-
- assert(fs.remove(testfile))
-end
-
-function test.open_modes()
- local testfile = 'fs_test'
- --TODO:
- local f = assert(fs.open(testfile, 'w'))
- f:close()
- assert(fs.remove(testfile))
-end
-
-function test.seek()
- local testfile = 'fs_test'
- local f = assert(fs.open(testfile, 'w'))
-
- --test large file support by seeking out-of-bounds
- local newpos = x64 and 2^51 + 113 or 2^42 + 113
- local pos = assert(f:seek('set', newpos))
- assert(pos == newpos)
- local pos = assert(f:seek(-100))
- assert(pos == newpos -100)
- local pos = assert(f:seek('end', 100))
- assert(pos == 100)
-
- --write some data and check again
- local newpos = 1024^2
- local buf = ffi.new'char[1]'
- local pos = assert(f:seek('set', newpos))
- assert(pos == newpos) --seeked outside
- buf[0] = 0xaa
- f:write(buf, 1) --write outside cur
- local pos = assert(f:seek())
- assert(pos == newpos + 1) --cur advanced
- local pos = assert(f:seek('end'))
- assert(pos == newpos + 1) --end updated
- assert(f:seek'end' == newpos + 1)
- assert(f:close())
-
- assert(fs.remove(testfile))
-end
-
---streams --------------------------------------------------------------------
-
-function test.stream()
- local testfile = 'fs_test'
- local f = assert(assert(fs.open(testfile, 'w')):stream('w'))
- f:close()
- local f = assert(assert(fs.open(testfile, 'r')):stream('r'))
- f:close()
- assert(fs.remove(testfile))
-end
-
---truncate -------------------------------------------------------------------
-
-function test.truncate_seek()
- local testfile = prefix..'fs_test_truncate_seek'
- --truncate/grow
- local f = assert(fs.open(testfile, 'w'))
- local newpos = 1024^2
- assert(f:truncate(newpos))
- assert(f:seek() == newpos)
- assert(f:close())
- --check size
- local f = assert(fs.open(testfile, 'r+'))
- local pos = assert(f:seek'end')
- assert(pos == newpos)
- --truncate/shrink
- local pos = assert(f:seek('end', -100))
- assert(f:truncate(pos))
- assert(pos == newpos - 100)
- assert(f:close())
- --check size
- local f = assert(fs.open(testfile, 'r'))
- local pos = assert(f:seek'end')
- assert(pos == newpos - 100)
- assert(f:close())
-
- assert(fs.remove(testfile))
-end
-
---filesystem operations ------------------------------------------------------
-
-function test.cd_mkdir_remove()
- local testdir = 'fs_test_dir'
- local cd = assert(fs.cd())
- assert(fs.mkdir(testdir)) --relative paths should work
- assert(fs.cd(testdir)) --relative paths should work
- assert(fs.cd(cd))
- assert(fs.cd() == cd)
- assert(fs.remove(testdir)) --relative paths should work
-end
-
-function test.mkdir_recursive()
- assert(fs.mkdir('fs_test_dir/a/b/c', true))
- assert(fs.remove'fs_test_dir/a/b/c')
- assert(fs.remove'fs_test_dir/a/b')
- assert(fs.remove'fs_test_dir/a')
- assert(fs.remove'fs_test_dir')
-end
-
-function test.remove_recursive()
- local rootdir = prefix..'fs_test_rmdir_rec/'
- fs.remove(rootdir, true)
- local function mkdir(dir)
- assert(fs.mkdir(rootdir..dir, true))
- end
- local function mkfile(file)
- local f = assert(fs.open(rootdir..file, 'w'))
- assert(f:close())
- end
- mkdir'a/b/c'
- mkfile'a/b/c/f1'
- mkfile'a/b/c/f2'
- mkdir'a/b/c/d1'
- mkdir'a/b/c/d2'
- mkfile'a/b/f1'
- mkfile'a/b/f2'
- mkdir'a/b/d1'
- mkdir'a/b/d2'
- assert(fs.remove(rootdir, true))
-end
-
-function test.dir_empty()
- local d = 'fs_test_dir_empty/a/b'
- fs.remove('fs_test_dir_empty/', true)
- fs.mkdir(d, true)
- for name in fs.dir(d) do
- print(name)
- end
- fs.remove('fs_test_dir_empty/', true)
-end
-
-function test.mkdir_already_exists_dir()
- assert(fs.mkdir'fs_test_dir')
- local ok, err = fs.mkdir'fs_test_dir'
- assert(not ok)
- assert(err == 'already_exists')
- assert(fs.remove'fs_test_dir')
-end
-
-function test.mkdir_already_exists_file()
- local testfile = 'fs_test_dir_already_exists_file'
- local f = assert(fs.open(testfile, 'w'))
- assert(f:close())
- local ok, err = fs.mkdir(testfile)
- assert(not ok)
- assert(err == 'already_exists')
- assert(fs.remove(testfile))
-end
-
-function test.mkdir_not_found()
- local ok, err = fs.mkdir'fs_test_nonexistent/nonexistent'
- assert(not ok)
- assert(err == 'not_found')
-end
-
-function test.remove_not_found()
- local testfile = 'fs_test_rmdir'
- local ok, err = fs.remove(testfile)
- assert(not ok)
- assert(err == 'not_found')
-end
-
-function test.remove_not_empty()
- local dir1 = 'fs_test_rmdir'
- local dir2 = 'fs_test_rmdir/subdir'
- fs.remove(dir2)
- fs.remove(dir1)
- assert(fs.mkdir(dir1))
- assert(fs.mkdir(dir2))
- local ok, err = fs.remove(dir1)
- assert(not ok)
- assert(err == 'not_empty')
- assert(fs.remove(dir2))
- assert(fs.remove(dir1))
-end
-
-function test.remove_file()
- local name = 'fs_test_remove_file'
- os.remove(name)
- assert(io.open(name, 'w')):close()
- assert(fs.remove(name))
- assert(not io.open(name, 'r'))
-end
-
-function test.cd_not_found()
- local ok, err = fs.cd'fs_test_nonexistent/nonexistent'
- assert(not ok)
- assert(err == 'not_found')
-end
-
-function test.remove()
- local testfile = 'fs_test_remove'
- local f = assert(fs.open(testfile, 'w'))
- assert(f:close())
- assert(fs.remove(testfile))
- assert(not fs.open(testfile))
-end
-
-function test.remove_not_found()
- local testfile = 'fs_test_remove'
- local ok, err = fs.remove(testfile)
- assert(not ok)
- assert(err == 'not_found')
-end
-
-function test.move()
- local f1 = 'fs_test_move1'
- local f2 = 'fs_test_move2'
- local f = assert(fs.open(f1, 'w'))
- assert(f:close())
- assert(fs.move(f1, f2))
- assert(fs.remove(f2))
- assert(not fs.remove(f1))
-end
-
-function test.move_not_found()
- local ok, err = fs.move('fs_nonexistent_file', 'fs_nonexistent2')
- assert(not ok)
- assert(err == 'not_found')
-end
-
-function test.move_replace()
- local f1 = 'fs_test_move1'
- local f2 = 'fs_test_move2'
- local buf = ffi.new'char[1]'
-
- local f = assert(fs.open(f1, 'w'))
- buf[0] = ('1'):byte(1)
- f:write(buf, 1)
- assert(f:close())
-
- local f = assert(fs.open(f2, 'w'))
- buf[0] = ('2'):byte(1)
- assert(f:write(buf, 1))
- assert(f:close())
-
- assert(fs.move(f1, f2))
-
- local f = assert(fs.open(f2))
- assert(f:read(buf, 1))
- assert(buf[0] == ('1'):byte(1))
- assert(f:close())
-
- assert(fs.remove(f2))
-end
-
-function test.remove_not_found()
- local ok, err = fs.remove'fs_non_existent'
- assert(not ok)
- assert(err == 'not_found')
-end
-
---symlinks -------------------------------------------------------------------
-
-local function mksymlink_file(f1, f2)
- local buf = ffi.new'char[1]'
-
- fs.remove(f1)
- fs.remove(f2)
-
- local f = assert(fs.open(f2, 'w'))
- buf[0] = ('X'):byte(1)
- f:write(buf, 1)
- assert(f:close())
-
- time.sleep(0.1)
-
- assert(fs.mksymlink(f1, f2))
- assert(fs.is(f1, 'symlink'))
-
- local f = assert(fs.open(f1))
- assert(f:read(buf, 1))
- assert(buf[0] == ('X'):byte(1))
- assert(f:close())
-end
-
-function test.mksymlink_file()
- local f1 = prefix..'fs_test_symlink_file'
- local f2 = prefix..'fs_test_symlink_file_target'
- fs.remove(f1)
- fs.remove(f2)
- mksymlink_file(f1, f2)
- assert(fs.is(f1, 'symlink'))
- assert(fs.remove(f1))
- assert(fs.remove(f2))
-end
-
-function test.mksymlink_dir()
- local link = prefix..'fs_test_symlink_dir'
- local dir = prefix..'fs_test_symlink_dir_target'
- fs.remove(link)
- fs.remove(dir..'/test_dir')
- fs.remove(dir)
- assert(fs.mkdir(dir))
- assert(fs.mkdir(dir..'/test_dir'))
- assert(fs.mksymlink(link, dir, true))
- assert(fs.is(link..'/test_dir', 'dir'))
- assert(fs.remove(link..'/test_dir'))
- assert(fs.remove(link))
- assert(fs.remove(dir))
-end
-
-function test.readlink_file()
- local f1 = prefix..'fs_test_readlink_file'
- local f2 = prefix..'fs_test_readlink_file_target'
- mksymlink_file(f1, f2)
- assert(fs.readlink(f1) == f2)
- assert(fs.remove(f1))
- assert(fs.remove(f2))
-end
-
-function test.readlink_dir()
- local d1 = prefix..'fs_test_readlink_dir'
- local d2 = prefix..'fs_test_readlink_dir_target'
- fs.remove(d1)
- fs.remove(d2..'/test_dir')
- fs.remove(d2)
- fs.remove(d2)
- assert(fs.mkdir(d2))
- assert(fs.mkdir(d2..'/test_dir'))
- assert(fs.mksymlink(d1, d2, true))
- assert(fs.is(d1, 'symlink'))
- local t = {}
- for d in fs.dir(d1) do
- t[#t+1] = d
- end
- assert(#t == 1)
- assert(t[1] == 'test_dir')
- assert(fs.remove(d1..'/test_dir'))
- assert(fs.readlink(d1) == d2)
- assert(fs.remove(d1))
- assert(fs.remove(d2))
-end
-
---TODO: readlink() with relative symlink chain
---TODO: attr() with defer and symlink chain
---TODO: dir() with defer and symlink chain
-
-function test.attr_deref()
- --
-end
-
-function test.symlink_attr_deref()
- local f1 = prefix..'fs_test_readlink_file'
- local f2 = prefix..'fs_test_readlink_file_target'
- mksymlink_file(f1, f2)
- local lattr = assert(fs.attr(f1, false))
- local tattr1 = assert(fs.attr(f1, true))
- local tattr2 = assert(fs.attr(f2))
- assert(lattr.type == 'symlink')
- assert(tattr1.type == 'file')
- assert(tattr2.type == 'file')
- if win then
- assert(tattr1.id == tattr2.id) --same file
- else
- assert(tattr1.inode == tattr2.inode) --same file
- end
- assert(tattr1.btime == tattr2.btime)
- if win then
- assert(lattr.id ~= tattr1.id) --diff. file
- else
- assert(lattr.inode ~= tattr1.inode) --diff. file
- end
- assert(fs.remove(f1))
- assert(fs.remove(f2))
-end
-
---hardlinks ------------------------------------------------------------------
-
-function test.mkhardlink() --hardlinks only work for files in NTFS
- local f1 = prefix..'fs_test_hardlink'
- local f2 = prefix..'fs_test_hardlink_target'
- fs.remove(f1)
- fs.remove(f2)
-
- local buf = ffi.new'char[1]'
-
- local f = assert(fs.open(f2, 'w'))
- buf[0] = ('X'):byte(1)
- f:write(buf, 1)
- assert(f:close())
-
- assert(fs.mkhardlink(f1, f2))
-
- local f = assert(fs.open(f1))
- assert(f:read(buf, 1))
- assert(buf[0] == ('X'):byte(1))
- assert(f:close())
-
- assert(fs.remove(f1))
- assert(fs.remove(f2))
-end
-
---file times -----------------------------------------------------------------
-
-function test.times()
- local testfile = 'fs_test_time'
- fs.remove(testfile)
- local f = assert(fs.open(testfile, 'w'))
- local t = f:attr()
- assert(t.atime >= 0)
- assert(t.mtime >= 0)
- assert(win or t.ctime >= 0)
- assert(linux or t.btime >= 0)
- assert(f:close())
- assert(fs.remove(testfile))
-end
-
-function test.times_set()
- local testfile = prefix..'fs_test_time'
- local f = assert(fs.open(testfile, 'w'))
-
- --TODO: futimes() on OSX doesn't use tv_usec
- local frac = osx and 0 or 1/2
- local btime = os.time() - 7200 - frac
- local mtime = os.time() - 3600 - frac
- local ctime = os.time() - 2800 - frac
- local atime = os.time() - 1800 - frac
-
- assert(f:attr{btime = btime, mtime = mtime, ctime = ctime, atime = atime})
- local btime1 = f:attr'btime' --OSX has it but can't be changed currently
- local mtime1 = f:attr'mtime'
- local ctime1 = f:attr'ctime'
- local atime1 = f:attr'atime'
- assert(mtime == mtime1)
- assert(atime == atime1)
- if win then
- assert(btime == btime1)
- assert(ctime == ctime1)
- end
-
- --change only mtime, should not affect atime
- mtime = mtime + 100
- assert(f:attr{mtime = mtime})
- local mtime1 = f:attr().mtime
- local atime1 = f:attr().atime
- assert(mtime == mtime1)
- assert(atime == atime1)
-
- --change only atime, should not affect mtime
- atime = atime + 100
- assert(f:attr{atime = atime})
- local mtime1 = f:attr'mtime'
- local atime1 = f:attr'atime'
- assert(mtime == mtime1)
- assert(atime == atime1)
-
- assert(f:close())
- assert(fs.remove(testfile))
-end
-
---common paths ---------------------------------------------------------------
-
-function test.paths()
- print('homedir', fs.homedir())
- print('tmpdir ', fs.tmpdir())
- print('exepath', fs.exepath())
- print('exedir' , fs.exedir())
- print('scriptdir', fs.scriptdir())
-end
-
---file attributes ------------------------------------------------------------
-
-function test.attr()
- local testfile = 'fs_test.lua'
- local attr = assert(fs.attr(testfile, false))
- assert(attr.type == 'file')
- assert(attr.size > 10000)
- assert(attr.atime)
- assert(attr.mtime)
- assert(linux and attr.ctime or attr.btime)
- assert(not win or attr.archive)
- if not win then
- assert(attr.inode)
- assert(attr.uid >= 0)
- assert(attr.gid >= 0)
- assert(attr.perms >= 0)
- assert(attr.nlink >= 1)
- assert(attr.perms > 0)
- assert(attr.blksize > 0)
- assert(attr.blocks > 0)
- assert(attr.dev >= 0)
- end
-end
-
-function test.attr_set()
- --TODO
-end
-
---directory listing ----------------------------------------------------------
-
-function test.dir()
- local found
- local n = 0
- local files = {}
- for file, d in fs.dir() do
- if not file then break end
- found = found or file == 'fs_test.lua'
- n = n + 1
- local t = {}
- files[file] = t
- --these are fast to get on all platforms
- t.type = d:attr('type', false)
- t.inode = d:attr('inode', false) --missing on Windows, so nil
- --these are free to get on Windows but need a stat() call on POSIX
- if win then
- t.btime = assert(d:attr('btime', false))
- t.mtime = assert(d:attr('mtime', false))
- t.atime = assert(d:attr('atime', false))
- t.size = assert(d:attr('size' , false))
- end
- --getting all attrs is free on Windows but needs a stat() call on POSIX
- t._all_attrs = assert(d:attr(false))
- local noval, err = d:attr('non_existent_attr', false)
- assert(noval == nil) --non-existent attributes are free to get
- assert(not err) --and they are not an error
- --print('', d:attr('type', false), file)
- end
- assert(not files['.']) --skipping this by default
- assert(not files['..']) --skipping this by default
- assert(files['fs_test.lua'].type == 'file')
- local t = files['fs_test.lua']
- print(string.format(' found %d dir/file entries in cwd', n))
- assert(found, 'fs_test.lua not found in cwd')
-end
-
-function test.dir_not_found()
- local n = 0
- local err
- for file, err1 in fs.dir'nonexistent_dir' do
- if not file then
- err = err1
- break
- else
- n = n + 1
- end
- end
- assert(n == 0)
- assert(#err > 0)
- assert(err == 'not_found')
-end
-
-function test.dir_is_file()
- local n = 0
- local err
- for file, err1 in fs.dir'fs_test.lua' do
- if not file then
- err = err1
- break
- else
- n = n + 1
- end
- end
- assert(n == 0)
- assert(#err > 0)
- assert(err == 'not_found')
-end
-
---memory mapping -------------------------------------------------------------
-
---TODO: how to test for disk full on 32bit?
---TODO: offset + size -> invalid arg
---TODO: test flush() with invalid address and/or size (clamp them?)
---TODO: test exec flag by trying to execute code in it
---TODO: COW on opened file doesn't work on OSX
---TODO: test protect
-
-local mediumsize = 1024^2 * 10 + 1 -- 10 MB + 1 byte to make it non-aligned
-
-function test.pagesize()
- assert(fs.pagesize() > 0)
- assert(fs.pagesize() % 4096 == 0)
-end
-
-local function zerosize_file(filename)
- local file = filename or 'fs_test_zerosize'
- os.remove(file)
- local f = assert(io.open(file, 'w'))
- f:close()
- return file
-end
-
---[[
-function test.filesize()
- local file = zerosize_file()
- assert(mmap.filesize(file) == 0)
- assert(mmap.filesize(file, 123) == 123) --grow
- assert(mmap.filesize(file) == 123)
- assert(mmap.filesize(file, 63) == 63) --shrink
- assert(mmap.filesize(file) == 63)
- os.remove(file)
-end
-]]
-
-local function fill(map)
- assert(map.size/4 <= 2^32)
- local p = ffi.cast('int32_t*', map.addr)
- for i = 0, map.size/4-1 do
- p[i] = i
- end
-end
-
-local function check_filled(map, offset)
- local offset = (offset or 0) / 4
- local p = ffi.cast('int32_t*', map.addr)
- for i = 0, map.size/4-1 do
- assert(p[i] == i + offset)
- end
-end
-
-local function check_empty(map)
- local p = ffi.cast('int32_t*', map.addr)
- for i = 0, map.size/4-1 do
- assert(p[i] == 0)
- end
-end
-
-function test.map_anonymous_write(size)
- local map = assert(fs.map{access = 'w', size = size or mediumsize})
- check_empty(map)
- fill(map)
- check_filled(map)
- map:free()
-end
-
---NOTE: there's no point in making an unshareable read-only mapping.
-function test.map_anonymous_readonly_empty()
- local map = assert(fs.map{access = 'r', size = mediumsize})
- check_empty(map)
- map:free()
-end
-
-function test.map_file_read()
- local map = assert(fs.map{file = 'fs_test.lua'})
- assert(ffi.string(map.addr, map.size):find'test%.map_file_read')
- map:free()
-end
-
-function test.map_file_write()
- local file = prefix..'fs_test_mmap'
- os.remove(file)
- local map1 = assert(fs.map{file = file, size = mediumsize, access = 'w'})
- fill(map1)
- map1:free()
- local map2 = assert(fs.map{file = file, access = 'r'})
- check_filled(map2)
- map2:free()
- os.remove(file)
-end
-
-function test.map_file_write_live()
- local file = prefix..'fs_test_mmap'
- os.remove(file)
- local map1 = assert(fs.map{file = file, size = mediumsize, access = 'w'})
- local map2 = assert(fs.map{file = file, access = 'r'})
- fill(map1)
- map1:flush()
- check_filled(map2)
- map1:free()
- map2:free()
- os.remove(file)
-end
-
-function test.map_file_copy_on_write()
- local file = prefix..'fs_test_mmap'
- os.remove(file)
- local size = mediumsize
- local map = assert(fs.map{file = file, access = 'w', size = size})
- fill(map)
- map:free()
- local map = assert(fs.map{file = file, access = 'c'})
- assert(map.size == size)
- ffi.fill(map.addr, map.size, 123)
- map:flush()
- map:free()
- --check that the file wasn't altered by fill()
- local map = assert(fs.map{file = file})
- assert(map.size == size)
- check_filled(map)
- map:free()
- os.remove(file)
-end
-
-function test.map_file_copy_on_write_live()
- local file = prefix..'fs_test_mmap'
- --TODO: COW on opened file doesn't work on OSX
- if ffi.os == 'OSX' then return end
- os.remove(file)
- local size = mediumsize
- local mapw = assert(fs.map{file = file, access = 'w', size = size})
- local mapc = assert(fs.map{file = file, access = 'c'})
- local mapr = assert(fs.map{file = file, access = 'r'})
- assert(mapw.size == size)
- assert(mapc.size == size)
- assert(mapr.size == size)
- fill(mapw)
- mapw:flush()
- check_filled(mapc) --COW mapping sees writes from W mapping.
- ffi.fill(mapc.addr, mapc.size, 123)
- mapc:flush()
- for i=0,size-1 do
- assert(ffi.cast('char*', mapc.addr)[i] == 123)
- end
- check_filled(mapw) --W mapping doesn't see writes from COW mapping.
- check_filled(mapr) --R mapping doesn't see writes from COW mapping.
- mapw:free()
- mapc:free()
- mapr:free()
- os.remove(file)
-end
-
-function test.map_shared_via_tagname()
- local name = 'mmap_test_tagname'
- local size = mediumsize
- local map1 = assert(fs.map{tagname = name, access = 'w', size = size})
- local map2 = assert(fs.map{tagname = name, access = 'r', size = size})
- assert(map1:unlink()) --can be called while mappings are alive.
- assert(map2:unlink()) --ok even if file not found.
- assert(map1.addr ~= map2.addr)
- assert(map1.size == map2.size)
- fill(map1)
- map1:flush()
- check_filled(map2)
- map1:free()
- map2:free()
-end
-
-function test.map_file_exec()
- --TODO: test by exec'ing some code in the memory.
- local map = assert(fs.map{file = 'bin/mingw64/luajit.exe', access = 'x'})
- assert(ffi.string(map.addr, 2) == 'MZ')
- map:free()
-end
-
-function test.map_offset_live()
- local file = prefix..'fs_test_mmap'
- os.remove(file)
- local offset = fs.pagesize()
- local size = offset * 2
- local map1 = assert(fs.map{file = file, size = size, access = 'w'})
- local map2 = assert(fs.map{file = file, offset = offset})
- fill(map1)
- map1:flush()
- check_filled(map2, offset)
- map1:free()
- map2:free()
- os.remove(file)
-end
-
-function test.map_mirror_buffer(addr)
- local map = assert(fs.mirror_buffer(1, addr))
- local p = ffi.cast('char*', map.addr)
- p[0] = 123
- assert(p[map.size] == 123)
- map:free()
-end
-
-function test.map_mirror_buffer_fixed_addr()
- test.map_mirror_buffer(0x100000000)
-end
-
---mmap failure modes
-
-function test.map_invalid_size()
- local ok, err = pcall(fs.map, {file = 'fs_test.lua', size = 0})
- assert(not ok and err:find'size')
-end
-
-function test.map_invalid_offset()
- local ok, err = pcall(fs.map, {file = 'fs_test.lua', offset = 1})
- assert(not ok and err:find'aligned')
-end
-
-function test.map_invalid_address()
- local map, err = fs.map{
- size = fs.pagesize() * 1,
- addr = ffi.os == 'Windows' and fs.pagesize() --TODO: test not robust
- or ffi.cast('uintptr_t', -fs.pagesize()), --TODO: test not robust
- }
- assert(not map and err == 'out_of_mem')
-end
-
-function test.map_size_too_large()
- local size = 1024^3 * (ffi.abi'32bit' and 3 or 1024^3)
- local map, err = fs.map{access = 'w', size = size}
- assert(not map and err == 'out_of_mem')
-end
-
-function test.map_readonly_not_found()
- local map, err = fs.map{file = 'askdfask8920349zjk'}
- assert(not map and err == 'not_found')
-end
-
-function test.map_readonly_too_short()
- local map, err = fs.map{file = 'fs_test.lua', size = 1024*1000}
- assert(not map and err == 'file_too_short')
-end
-
-function test.map_readonly_too_short_zero()
- local map, err = fs.map{file = zerosize_file()}
- assert(not map and err == 'file_too_short')
-end
-
-function test.map_write_too_short_zero()
- local map, err = fs.map{file = zerosize_file(), access = 'w'}
- assert(not map and err == 'file_too_short')
-end
-
-function test.map_disk_full()
- local file = prefix..'fs_test_file_huge'
- os.remove(file)
- local map, err = fs.map{
- file = file,
- size = 1024^4, --let's see how this is gonna last...
- access = 'w',
- }
- os.remove(file)
- assert(not map and err == 'disk_full')
-end
-
---virtual files --------------------------------------------------------------
-
-function test.open_buffer()
- local sz = 100
- local buf = ffi.new('char[?]', sz)
- ffi.fill(buf, sz, 42)
- local f = assert(fs.open_buffer(buf, sz, 'w'))
- assert(f:seek(100) == 100)
- assert(f:seek(100) == 200)
- assert(f:seek() == 200)
- assert(f:seek('end', 0) == 100)
- assert(f:seek('set', 0) == 0)
- local buf = ffi.new('char[?]', 100)
- assert(f:seek(200) == 200)
- assert(f:read(buf, 10) == 0)
- assert(f:seek('set', 50) == 50)
- assert(f:read(buf, 1000) == 50)
- assert(ffi.string(buf, 50) == (string.char(42):rep(50)))
- assert(f:write(buf, 1000) == 0)
- assert(f:seek('set', 0))
- ffi.fill(buf, sz, 43)
- assert(f:write(buf, 1000) == 100)
- assert(ffi.string(buf, 100) == (string.char(43):rep(100)))
- assert(f:close())
- assert(f:closed())
- assert(f:read(buf, 1000) == nil)
- assert(f:write(buf, 1000) == nil)
-end
-
---test cmdline ---------------------------------------------------------------
-
-local name = ...
-if not name or name == 'fs_test' then
- --run all tests in the order in which they appear in the code.
- for i,k in ipairs(test) do
- if not k:find'^_' then
- print('test '..k)
- local ok, err = xpcall(test[k], debug.traceback)
- if not ok then
- print(err)
- end
- end
- end
-elseif test[name] then
- test[name](select(2, ...))
-else
- print('Unknown test "'..(name)..'".')
-end
diff --git a/lib/fs_win.lua b/lib/fs_win.lua
deleted file mode 100644
index 8f602f4..0000000
--- a/lib/fs_win.lua
+++ /dev/null
@@ -1,1644 +0,0 @@
-
---portable filesystem API for LuaJIT / Windows backend
---Written by Cosmin Apreutesei. Public Domain.
-
-if not ... then require'fs_test'; return end
-
-local ffi = require'ffi'
-local bit = require'bit'
-local bor, band, shl = bit.bor, bit.band, bit.lshift
-setfenv(1, require'fs_common')
-
-local C = ffi.C
-
-assert(win, 'platform not Windows')
-
---types, consts, utils -------------------------------------------------------
-
-if x64 then
- cdef'typedef int64_t ULONG_PTR;'
-else
- cdef'typedef int32_t ULONG_PTR;'
-end
-
-cdef[[
-typedef void VOID, *PVOID, *LPVOID;
-typedef VOID* HANDLE, *PHANDLE;
-typedef unsigned short WORD;
-typedef unsigned long DWORD, *PDWORD, *LPDWORD;
-typedef unsigned int UINT;
-typedef int BOOL;
-typedef ULONG_PTR SIZE_T;
-typedef const void* LPCVOID;
-typedef char* LPSTR;
-typedef const char* LPCSTR;
-typedef wchar_t WCHAR;
-typedef WCHAR* LPWSTR;
-typedef const WCHAR* LPCWSTR;
-typedef BOOL *LPBOOL;
-typedef void* HMODULE;
-typedef unsigned char UCHAR;
-typedef unsigned short USHORT;
-typedef long LONG;
-typedef unsigned long ULONG;
-typedef long long LONGLONG;
-
-typedef union {
- struct {
- DWORD LowPart;
- LONG HighPart;
- };
- struct {
- DWORD LowPart;
- LONG HighPart;
- } u;
- LONGLONG QuadPart;
-} LARGE_INTEGER, *PLARGE_INTEGER;
-
-typedef struct {
- DWORD nLength;
- LPVOID lpSecurityDescriptor;
- BOOL bInheritHandle;
-} SECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
-]]
-
-local INVALID_HANDLE_VALUE = ffi.cast('HANDLE', -1)
-
-local wbuf = buffer'WCHAR[?]'
-local libuf = ffi.new'LARGE_INTEGER[1]'
-
---error handling -------------------------------------------------------------
-
-cdef[[
-DWORD GetLastError(void);
-
-DWORD FormatMessageA(
- DWORD dwFlags,
- LPCVOID lpSource,
- DWORD dwMessageId,
- DWORD dwLanguageId,
- LPSTR lpBuffer,
- DWORD nSize,
- va_list *Arguments
-);
-]]
-
-local FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
-
-local errbuf = buffer'char[?]'
-
-local errors = {
- [0x002] = 'not_found' , --ERROR_FILE_NOT_FOUND, CreateFileW
- [0x003] = 'not_found' , --ERROR_PATH_NOT_FOUND, CreateDirectoryW
- [0x005] = 'access_denied' , --ERROR_ACCESS_DENIED, CreateFileW
- [0x01D] = 'io_error' , --ERROR_WRITE_FAULT, WriteFile
- [0x01E] = 'io_error' , --ERROR_READ_FAULT, ReadFile
- [0x050] = 'already_exists' , --ERROR_FILE_EXISTS, CreateFileW
- [0x091] = 'not_empty' , --ERROR_DIR_NOT_EMPTY, RemoveDirectoryW
- [0x0b7] = 'already_exists' , --ERROR_ALREADY_EXISTS, CreateDirectoryW
- [0x10B] = 'not_found' , --ERROR_DIRECTORY, FindFirstFileW
- [0x06D] = 'eof' , --ERROR_BROKEN_PIPE ReadFile, WriteFile
-}
-
-local mmap_errors = { --CreateFileMappingW, MapViewOfFileEx
- [0x0008] = 'file_too_short' , --ERROR_NOT_ENOUGH_MEMORY, readonly file too short
- [0x0057] = 'out_of_mem' , --ERROR_INVALID_PARAMETER, size or address too large
- [0x0070] = 'disk_full' , --ERROR_DISK_FULL
- [0x01E7] = 'out_of_mem' , --ERROR_INVALID_ADDRESS, address in use
- [0x03EE] = 'file_too_short' , --ERROR_FILE_INVALID, file has zero size
- [0x05AF] = 'out_of_mem' , --ERROR_COMMITMENT_LIMIT, swapfile too short
-}
-
-local function checkneq(fail_ret, ok_ret, err_ret, ret, err, xtra_errors)
- if ret ~= fail_ret then
- return ok_ret
- end
- err = err or C.GetLastError()
- local msg = errors[err] or (xtra_errors and xtra_errors[err])
- if not msg then
- local buf, bufsz = errbuf(512)
- local sz = C.FormatMessageA(
- FORMAT_MESSAGE_FROM_SYSTEM, nil, err, 0, buf, bufsz, nil)
- msg = sz > 0 and ffi.string(buf, sz):gsub('[\r\n]+$', '') or 'Error '..err
- end
- return err_ret, msg
-end
-
-local function checkh(ret, err)
- return checkneq(INVALID_HANDLE_VALUE, ret, nil, ret, err)
-end
-
-local function checknz(ret, err)
- return checkneq(0, true, false, ret, err)
-end
-
-local function checknil(ret, err, errors)
- return checkneq(nil, ret, nil, ret, err, errors)
-end
-
-local function checknum(ret, err)
- return checkneq(0, ret, nil, ret, err)
-end
-
---utf16/utf8 conversion ------------------------------------------------------
-
-cdef[[
-int MultiByteToWideChar(
- UINT CodePage,
- DWORD dwFlags,
- LPCSTR lpMultiByteStr,
- int cbMultiByte,
- LPWSTR lpWideCharStr,
- int cchWideChar
-);
-int WideCharToMultiByte(
- UINT CodePage,
- DWORD dwFlags,
- LPCWSTR lpWideCharStr,
- int cchWideChar,
- LPSTR lpMultiByteStr,
- int cbMultiByte,
- LPCSTR lpDefaultChar,
- LPBOOL lpUsedDefaultChar
-);
-]]
-
-local CP_UTF8 = 65001
-
-local wcsbuf = buffer'WCHAR[?]'
-
-local function wcs(s, msz, wbuf) --string -> WCHAR[?]
- msz = msz and msz + 1 or #s + 1
- wbuf = wbuf or wcsbuf
- local wsz = C.MultiByteToWideChar(CP_UTF8, 0, s, msz, nil, 0)
- assert(wsz > 0) --should never happen otherwise
- local buf = wbuf(wsz)
- local sz = C.MultiByteToWideChar(CP_UTF8, 0, s, msz, buf, wsz)
- assert(sz == wsz) --should never happen otherwise
- return buf
-end
-
-local mbsbuf = buffer'char[?]'
-
-local function mbs(ws, wsz, mbuf) --WCHAR* -> string
- wsz = wsz and wsz + 1 or -1
- mbuf = mbuf or mbsbuf
- local msz = C.WideCharToMultiByte(
- CP_UTF8, 0, ws, wsz, nil, 0, nil, nil)
- assert(msz > 0) --should never happen otherwise
- local buf = mbuf(msz)
- local sz = C.WideCharToMultiByte(
- CP_UTF8, 0, ws, wsz, buf, msz, nil, nil)
- assert(sz == msz) --should never happen otherwise
- return ffi.string(buf, sz-1)
-end
-
---open/close -----------------------------------------------------------------
-
-cdef[[
-HANDLE CreateFileW(
- LPCWSTR lpFileName,
- DWORD dwDesiredAccess,
- DWORD dwShareMode,
- LPSECURITY_ATTRIBUTES lpSecurityAttributes,
- DWORD dwCreationDisposition,
- DWORD dwFlagsAndAttributes,
- HANDLE hTemplateFile
-);
-BOOL CloseHandle(HANDLE hObject);
-]]
-
---CreateFile access rights flags
-local t = {
- --FILE_* (specific access rights)
- list_directory = 1, --dirs: allow listing
- read_data = 1, --files: allow reading data
- add_file = 2, --dirs: allow creating files
- write_data = 2, --files: allow writting data
- add_subdirectory = 4, --dirs: allow creating subdirs
- append_data = 4, --files: allow appending data
- create_pipe_instance = 4, --pipes: allow creating a pipe
- delete_child = 0x40, --dirs: allow deleting dir contents
- traverse = 0x20, --dirs: allow traversing (not effective)
- execute = 0x20, --exes: allow exec'ing
- read_attributes = 0x80, --allow reading attrs
- write_attributes = 0x100, --allow setting attrs
- read_ea = 8, --allow reading extended attrs
- write_ea = 0x10, --allow writting extended attrs
- --object's standard access rights
- delete = 0x00010000,
- read_control = 0x00020000, --allow r/w the security descriptor
- write_dac = 0x00040000,
- write_owner = 0x00080000,
- synchronize = 0x00100000,
- --STANDARD_RIGHTS_*
- standard_rights_required = 0x000F0000,
- standard_rights_read = 0x00020000, --read_control
- standard_rights_write = 0x00020000, --read_control
- standard_rights_execute = 0x00020000, --read_control
- standard_rights_all = 0x001F0000,
- --GENERIC_*
- generic_read = 0x80000000,
- generic_write = 0x40000000,
- generic_execute = 0x20000000,
- generic_all = 0x10000000,
-}
---FILE_ALL_ACCESS
-t.all_access = bor(
- t.standard_rights_required,
- t.synchronize,
- 0x1ff)
---FILE_GENERIC_*
-t.read = bor(
- t.standard_rights_read,
- t.read_data,
- t.read_attributes,
- t.read_ea,
- t.synchronize)
-t.write = bor(
- t.standard_rights_write,
- t.write_data,
- t.write_attributes,
- t.write_ea,
- t.append_data,
- t.synchronize)
-t.execute = bor(
- t.standard_rights_execute,
- t.read_attributes,
- t.execute,
- t.synchronize)
-local access_bits = t
-
---CreateFile sharing flags
-local sharing_bits = {
- --FILE_SHARE_*
- read = 0x00000001, --allow us/others to read
- write = 0x00000002, --allow us/others to write
- delete = 0x00000004, --allow us/others to delete or rename
-}
-
---CreateFile creation disposition flags
-local creation_bits = {
- create_new = 1, --create or fail
- create_always = 2, --open or create + truncate
- open_existing = 3, --open or fail
- open_always = 4, --open or create
- truncate_existing = 5, --open + truncate or fail
-}
-
-local FILE_ATTRIBUTE_NORMAL = 0x00000080 --for when no bits are set
-
---CreateFile flags & attributes
-local attr_bits = {
- --FILE_ATTRIBUTE_*
- readonly = 0x00000001,
- hidden = 0x00000002,
- system = 0x00000004,
- archive = 0x00000020,
- temporary = 0x00000100,
- sparse_file = 0x00000200,
- reparse_point = 0x00000400,
- compressed = 0x00000800,
- directory = 0x00000010,
- device = 0x00000040,
- --offline = 0x00001000, --reserved (used by Remote Storage)
- not_indexed = 0x00002000, --FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
- encrypted = 0x00004000,
- --virtual = 0x00010000, --reserved
-}
-
-local FILE_FLAG_OVERLAPPED = 0x40000000
-
-local flag_bits = {
- --FILE_FLAG_*
- write_through = 0x80000000,
- no_buffering = 0x20000000,
- random_access = 0x10000000,
- sequential_scan = 0x08000000,
- delete_on_close = 0x04000000,
- backup_semantics = 0x02000000,
- posix_semantics = 0x01000000,
- open_reparse_point = 0x00200000,
- open_no_recall = 0x00100000,
- first_pipe_instance = 0x00080000,
-}
-
-local str_opt = {
- r = {
- access = 'read',
- creation = 'open_existing',
- flags = 'backup_semantics',
- },
- ['r+'] = {
- access = 'read write',
- creation = 'open_existing',
- flags = 'backup_semantics',
- },
- w = {
- access = 'write',
- creation = 'create_always',
- flags = 'backup_semantics',
- },
- ['w+'] = {
- access = 'read write',
- creation = 'create_always',
- flags = 'backup_semantics',
- },
- a = {
- access = 'write',
- creation = 'open_always',
- flags = 'backup_semantics',
- seek_end = true,
- },
- ['a+'] = {
- access = 'read write',
- creation = 'open_always',
- flags = 'backup_semantics',
- seek_end = true,
- },
-}
-
-local function sec_attr(inheritable)
- if not inheritable then
- return nil
- end
- local sa = ffi.new'SECURITY_ATTRIBUTES'
- sa.nLength = ffi.sizeof(sa)
- sa.bInheritHandle = true
- return sa
-end
-
-function fs.open(path, opt)
- opt = opt or 'r'
- if type(opt) == 'string' then
- opt = assert(str_opt[opt], 'invalid option %s', opt)
- end
- local async = opt.async or opt.read_async or opt.write_async
- assert(not async or opt.is_pipe_end, 'only pipes can be async')
- local access = flags(opt.access or 'read', access_bits, nil, true)
- local sharing = flags(opt.sharing or 'read', sharing_bits, nil, true)
- local creation = flags(opt.creation or 'open_existing', creation_bits, nil, true)
- local attrbits = flags(opt.attrs, attr_bits, nil, true)
- attrbits = attrbits == 0 and FILE_ATTRIBUTE_NORMAL or attrbits
- local flagbits = flags(opt.flags, flag_bits)
- local attflags = bor(attrbits, flagbits, async and FILE_FLAG_OVERLAPPED or 0)
- local sa = sec_attr(opt.inheritable)
- local h, err = checkh(C.CreateFileW(
- wcs(path), access, sharing, sa, creation, attflags, nil
- ))
- if not h then return nil, err end
- local f, err = fs.wrap_handle(h,
- opt.async or opt.read_async,
- opt.async or opt.write_async,
- opt.is_pipe_end)
- if not f then return nil, err end
- if opt.seek_end then
- local pos, err = f:seek('end', 0)
- if not pos then
- f:close()
- return nil, err
- end
- end
- return f
-end
-
-function file.closed(f)
- return f.handle == INVALID_HANDLE_VALUE
-end
-
-function file.close(f)
- if f:closed() then return true end
- if f._read_async or f._write_async then
- local sock = require'sock'
- local ok, err = sock._unregister(f)
- if not ok then return false, err end
- end
- local ok, err = checknz(C.CloseHandle(f.handle))
- if not ok then return false, err end
- f.handle = INVALID_HANDLE_VALUE
- return true
-end
-
-function fs.wrap_handle(h, read_async, write_async, is_pipe_end)
-
- local f = {
- handle = h,
- s = h, --for async use with sock
- type = is_pipe_end and 'pipe' or 'file',
- debug_prefix = is_pipe_end and 'p' or 'f',
- _read_async = read_async and true or false,
- _write_async = write_async and true or false,
- __index = file,
- }
- setmetatable(f, f)
-
- if read_async or write_async then
- local sock = require'sock'
- local ok, err = sock._register(f)
- if not ok then
- assert(f:close())
- return nil, err
- end
- end
-
- return f
-end
-
-cdef[[
-int _fileno(struct FILE *stream);
-HANDLE _get_osfhandle(int fd);
-]]
-
-function fs.wrap_fd(fd, ...)
- local h = C._get_osfhandle(fd)
- if h == nil then return check_errno() end
- return fs.wrap_handle(h, ...)
-end
-
-function fs.fileno(file)
- local fd = C._fileno(file)
- return check_errno(fd ~= -1 and fd or nil)
-end
-
-function fs.wrap_file(file)
- local fd, err = fs.fileno(file)
- if not fd then return nil, err end
- return fs.wrap_fd(fd)
-end
-
-local HANDLE_FLAG_INHERIT = 1
-
-function file.set_inheritable(file, inheritable)
- assert(checknz(C.SetHandleInformation(
- file.handle, HANDLE_FLAG_INHERIT, inheritable and 1 or 0
- )))
-end
-
---pipes ----------------------------------------------------------------------
-
-cdef[[
-BOOL CreatePipe(
- PHANDLE hReadPipe,
- PHANDLE hWritePipe,
- LPSECURITY_ATTRIBUTES lpPipeAttributes,
- DWORD nSize
-);
-BOOL SetHandleInformation(
- HANDLE hObject,
- DWORD dwMask,
- DWORD dwFlags
-);
-HANDLE CreateNamedPipeW(
- LPWSTR lpName,
- DWORD dwOpenMode,
- DWORD dwPipeMode,
- DWORD nMaxInstances,
- DWORD nOutBufferSize,
- DWORD nInBufferSize,
- DWORD nDefaultTimeOut,
- LPSECURITY_ATTRIBUTES lpSecurityAttributes
-);
-
-DWORD GetCurrentThreadId();
-]]
-
---NOTE: FILE_FLAG_FIRST_PIPE_INSTANCE == WRITE_OWNER wtf?
-local pipe_flag_bits = update({
- r = 0x00000001, --PIPE_ACCESS_INBOUND
- w = 0x00000002, --PIPE_ACCESS_OUTBOUND
- rw = 0x00000003, --PIPE_ACCESS_DUPLEX
- single_instance = 0x00080000, --FILE_FLAG_FIRST_PIPE_INSTANCE
- write_through = 0x80000000, --FILE_FLAG_WRITE_THROUGH
- write_dac = 0x00040000, --WRITE_DAC
- write_owner = 0x00080000, --WRITE_OWNER
- system_security = 0x01000000, --ACCESS_SYSTEM_SECURITY
-}, flag_bits)
-
-local serial = 0
-
-function fs.pipe(path, opt)
- if type(path) == 'table' then
- path, opt = path.path, path
- end
- opt = opt or {}
- local async = opt.async or opt.read_async or opt.write_async
-
- if path then --named pipe
-
- local h, err = checkh(C.CreateNamedPipeW(
- wcs(path),
- flags(opt, pipe_flag_bits, async and FILE_FLAG_OVERLAPPED or 0),
- 0, --nothing interesting here
- opt.max_instances or 255,
- opt.write_buffer_size or 8192,
- opt.read_buffer_size or 8192,
- (opt.timeout or 0) * 1000,
- sec_attr(opt.inheritable)
- ))
- if not h then return nil, err end
-
- return fs.wrap_handle(h,
- opt.async or opt.read_async,
- opt.async or opt.write_async,
- true
- )
-
- else --unnamed pipe, return both ends
-
- --overlapped anon pipe, must emulate it, see:
- -- https://stackoverflow.com/questions/60645/overlapped-i-o-on-anonymous-pipe
- if async then
-
- serial = (serial + 1) % 0xffffffff
- local path = string.format([[\\.\pipe\LuaPipe.%08x.%08x.%08x]],
- C.GetCurrentThreadId(), fs.lua_state_id or 0, serial)
-
- local rf, err = fs.pipe{
- path = path,
- r = true,
- read_async = opt.read_async or opt.async,
- inheritable = opt.read_inheritable or opt.inheritable,
- max_instances = 1,
- timeout = opt.timeout or 120,
- }
- if not rf then
- return nil, err
- end
-
- local wf, err = fs.open(path, {
- access = 'generic_write',
- creation = 'open_existing',
- sharing = '',
- write_async = opt.write_async or opt.async,
- inheritable = opt.write_inheritable or opt.inheritable,
- is_pipe_end = true,
- })
- if not wf then
- rf:close()
- return nil, err
- end
-
- return rf, wf
-
- else --non-overlapped anon pipe, use native CreatePipe().
-
- local hs = ffi.new'HANDLE[2]'
- local sa = sec_attr(
- opt.inheritable
- or opt.read_inheritable
- or opt.write_inheritable
- )
- local ok, err = checknz(C.CreatePipe(hs, hs+1, sa, 0))
- if not ok then return nil, err end
- local rf = fs.wrap_handle(hs[0], nil, nil, true)
- local wf = fs.wrap_handle(hs[1], nil, nil, true)
- if opt.inheritable or opt.read_inheritable then rf:set_inheritable(true) end
- if opt.inheritable or opt.write_inheritable then wf:set_inheritable(true) end
- return rf, wf
-
- end
- end
-end
-
---stdio streams --------------------------------------------------------------
-
-cdef[[
-FILE *_fdopen(int fd, const char *mode);
-int _open_osfhandle(HANDLE osfhandle, int flags);
-]]
-
-function file.stream(f, mode)
- local flags = 0
- local fd = C._open_osfhandle(f.handle, flags)
- if fd == -1 then return check_errno() end
- local fs = C._fdopen(fd, mode)
- if fs == nil then return check_errno() end
- return fs
-end
-
---i/o ------------------------------------------------------------------------
-
-cdef[[
-BOOL ReadFile(
- HANDLE hFile,
- LPVOID lpBuffer,
- DWORD nNumberOfBytesToRead,
- LPDWORD lpNumberOfBytesRead,
- void* lpOverlapped
-);
-
-BOOL WriteFile(
- HANDLE hFile,
- LPCVOID lpBuffer,
- DWORD nNumberOfBytesToWrite,
- LPDWORD lpNumberOfBytesWritten,
- void* lpOverlapped
-);
-
-BOOL FlushFileBuffers(HANDLE hFile);
-
-BOOL SetFilePointerEx(
- HANDLE hFile,
- LARGE_INTEGER liDistanceToMove,
- PLARGE_INTEGER lpNewFilePointer,
- DWORD dwMoveMethod
-);
-]]
-
-local function read_overlapped(f, o, buf, sz)
- return C.ReadFile(f.handle, buf, sz, nil, o) ~= 0
-end
-
-local function write_overlapped(f, o, buf, sz)
- return C.WriteFile(f.handle, buf, sz, nil, o) ~= 0
-end
-
-local dwbuf = ffi.new'DWORD[1]'
-
-local function mask_eof(ret, err)
- if ret then return ret end
- if err == 'eof' then return 0 end --pipes do that
- return nil, err
-end
-function file.read(f, buf, sz, expires)
- assert(sz > 0) --because it returns 0 for EOF
- if f._read_async then
- local sock = require'sock'
- return mask_eof(sock._file_async_read(f, read_overlapped, buf, sz, expires))
- else
- local ok, err = mask_eof(checknz(C.ReadFile(f.handle, buf, sz, dwbuf, nil)))
- if not ok then return nil, err end
- return tonumber(dwbuf[0])
- end
-end
-
-function file._write(f, buf, sz, expires)
- if f._write_async then
- local sock = require'sock'
- return sock._file_async_write(f, write_overlapped, buf, sz, expires)
- else
- local ok, err = checknz(C.WriteFile(f.handle, buf, sz or #buf, dwbuf, nil))
- if not ok then return nil, err end
- return tonumber(dwbuf[0])
- end
-end
-
-function file.flush(f)
- return checknz(C.FlushFileBuffers(f.handle))
-end
-
-local ofsbuf = ffi.new'LARGE_INTEGER[1]'
-function file._seek(f, whence, offset)
- ofsbuf[0].QuadPart = offset
- local ok, err = checknz(C.SetFilePointerEx(f.handle, ofsbuf[0], libuf, whence))
- if not ok then return nil, err end
- return tonumber(libuf[0].QuadPart)
-end
-
---truncate -------------------------------------------------------------------
-
-cdef'BOOL SetEndOfFile(HANDLE hFile);'
-
---NOTE: seeking beyond file size and then truncating the file incurs no delay
---on NTFS, but that's not because the file becomes sparse (it doesn't, and
---disk space _is_ reserved), but because the extra zero bytes are not written
---until the first write call _that requires it_. This is a good optimization
---since usually the file will be written sequentially after the truncation
---in which case those extra zero bytes will never get a chance to be written.
-function file.truncate(f, size)
- local pos, err = f:seek('set', size)
- if not pos then return nil, err end
- return checknz(C.SetEndOfFile(f.handle))
-end
-
---filesystem operations ------------------------------------------------------
-
-cdef[[
-BOOL CreateDirectoryW(LPCWSTR, LPSECURITY_ATTRIBUTES);
-BOOL RemoveDirectoryW(LPCWSTR);
-int SetCurrentDirectoryW(LPCWSTR lpPathName);
-DWORD GetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer);
-BOOL DeleteFileW(LPCWSTR lpFileName);
-BOOL MoveFileExW(
- LPCWSTR lpExistingFileName,
- LPCWSTR lpNewFileName,
- DWORD dwFlags
-);
-]]
-
-function mkdir(path)
- return checknz(C.CreateDirectoryW(wcs(path), nil))
-end
-
-function rmdir(path)
- return checknz(C.RemoveDirectoryW(wcs(path)))
-end
-
-function chdir(path)
- initial_cwd()
- return checknz(C.SetCurrentDirectoryW(wcs(path)))
-end
-
-function getcwd()
- local sz, err = checknum(C.GetCurrentDirectoryW(0, nil))
- if not sz then return nil, err end
- local buf = wbuf(sz)
- local sz, err = checknum(C.GetCurrentDirectoryW(sz, buf))
- if not sz then return nil, err end
- return mbs(buf, sz)
-end
-initial_cwd = memoize(getcwd)
-
-function rmfile(path)
- return checknz(C.DeleteFileW(wcs(path)))
-end
-
-local move_bits = {
- --MOVEFILE_*
- replace_existing = 0x1,
- copy_allowed = 0x2,
- delay_until_reboot = 0x4,
- fail_if_not_trackable = 0x20,
- write_through = 0x8, --for when copy_allowed
-}
-
---NOTE: MoveFileExW is atomic if both files are on the same NTFS volume.
---TODO: implement this for file handles too: call SetFileInformationByHandle
---with FILE_RENAME_INFO and ReplaceIfExists.
-local default_move_opt = 'replace_existing write_through' --posix
-function fs.move(oldpath, newpath, opt)
- return checknz(C.MoveFileExW(
- wcs(oldpath),
- wcs(newpath, nil, wbuf),
- flags(opt or default_move_opt, move_bits, nil, true)
- ))
-end
-
---symlinks & hardlinks -------------------------------------------------------
-
-cdef[[
-BOOL CreateSymbolicLinkW (
- LPCWSTR lpSymlinkFileName,
- LPCWSTR lpTargetFileName,
- DWORD dwFlags
-);
-BOOL CreateHardLinkW(
- LPCWSTR lpFileName,
- LPCWSTR lpExistingFileName,
- LPSECURITY_ATTRIBUTES lpSecurityAttributes
-);
-
-BOOL DeviceIoControl(
- HANDLE hDevice,
- DWORD dwIoControlCode,
- LPVOID lpInBuffer,
- DWORD nInBufferSize,
- LPVOID lpOutBuffer,
- DWORD nOutBufferSize,
- LPDWORD lpBytesReturned,
- void* lpOverlapped
-);
-]]
-
-local SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1
-
-function fs.mksymlink(link_path, target_path, is_dir)
- local flags = is_dir and SYMBOLIC_LINK_FLAG_DIRECTORY or 0
- return checknz(C.CreateSymbolicLinkW(
- wcs(link_path),
- wcs(target_path, nil, wbuf),
- flags
- ))
-end
-
-function fs.mkhardlink(link_path, target_path)
- return checknz(C.CreateHardLinkW(
- wcs(link_path),
- wcs(target_path, nil, wbuf),
- nil
- ))
-end
-
-do
- local function CTL_CODE(DeviceType, Function, Method, Access)
- return bor(
- shl(DeviceType, 16),
- shl(Access , 14),
- shl(Function , 2),
- Method)
- end
- local FILE_DEVICE_FILE_SYSTEM = 0x00000009
- local METHOD_BUFFERED = 0
- local FILE_ANY_ACCESS = 0
- local FSCTL_GET_REPARSE_POINT = CTL_CODE(
- FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
- local readlink_opt = {
- access = 'read',
- sharing = 'read write delete',
- creation = 'open_existing',
- flags = 'backup_semantics open_reparse_point',
- attrs = 'reparse_point',
- }
-
- local REPARSE_DATA_BUFFER = ffi.typeof[[
- struct {
- ULONG ReparseTag;
- USHORT ReparseDataLength;
- USHORT Reserved;
- USHORT SubstituteNameOffset;
- USHORT SubstituteNameLength;
- USHORT PrintNameOffset;
- USHORT PrintNameLength;
- ULONG Flags;
- WCHAR PathBuffer[?];
- }
- ]]
-
- local szbuf = ffi.new'DWORD[1]'
- local buf, sz = nil, 128
-
- local ERROR_INSUFFICIENT_BUFFER = 122
- local ERROR_MORE_DATA = 234
-
- function readlink(path)
- local f, err = fs.open(path, readlink_opt)
- if not f then return nil, err end
- ::again::
- local buf = buf or REPARSE_DATA_BUFFER(sz)
- local ok = C.DeviceIoControl(
- f.handle, FSCTL_GET_REPARSE_POINT, nil, 0,
- buf, ffi.sizeof(buf), szbuf, nil
- ) ~= 0
- if not ok then
- local err = C.GetLastError()
- if err == ERROR_INSUFFICIENT_BUFFER or err == ERROR_MORE_DATA then
- buf, sz = nil, sz * 2
- goto again
- end
- f:close()
- return checknz(0, err)
- end
- f:close()
- return mbs(
- buf.PathBuffer + buf.SubstituteNameOffset / 2,
- buf.SubstituteNameLength / 2
- )
- end
-end
-
---common paths ---------------------------------------------------------------
-
-cdef[[
-DWORD GetTempPathW(DWORD nBufferLength, LPWSTR lpBuffer);
-DWORD GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize);
-]]
-
-function fs.homedir()
- return os.getenv'USERPROFILE'
-end
-
-function fs.tmpdir()
- local buf, bufsz = wbuf(256)
- local sz, err = checknum(C.GetTempPathW(bufsz, buf))
- if not sz then return nil, err end
- if sz > bufsz then
- buf, bufsz = wbuf(sz)
- local sz, err = checknum(C.GetTempPathW(bufsz, buf))
- if not sz then return nil, err end
- assert(sz <= bufsz)
- end
- return mbs(buf, sz-1) --strip trailing '\'
-end
-
-function fs.appdir(appname)
- local dir = os.getenv'LOCALAPPDATA'
- return dir and dir..'\\'..appname
-end
-
-local ERROR_INSUFFICIENT_BUFFER = 122
-
-function fs.exepath()
- local buf, bufsz = wbuf(256)
- ::again::
- local sz = C.GetModuleFileNameW(hmodule, buf, bufsz)
- if sz < 0 then
- local err = C.GetLastError()
- if err == ERROR_INSUFFICIENT_BUFFER then
- buf, bufsz = wbuf(bufsz * 2)
- goto again
- end
- return checknz(0, err)
- end
- return mbs(buf, sz)
-end
-
---file attributes ------------------------------------------------------------
-
-cdef[[
-typedef struct {
- DWORD dwLowDateTime;
- DWORD dwHighDateTime;
-} FILETIME;
-
-typedef struct {
- DWORD dwFileAttributes;
- FILETIME ftCreationTime;
- FILETIME ftLastAccessTime;
- FILETIME ftLastWriteTime;
- DWORD dwVolumeSerialNumber;
- DWORD nFileSizeHigh;
- DWORD nFileSizeLow;
- DWORD nNumberOfLinks;
- DWORD nFileIndexHigh;
- DWORD nFileIndexLow;
-} BY_HANDLE_FILE_INFORMATION, *LPBY_HANDLE_FILE_INFORMATION;
-
-BOOL GetFileInformationByHandle(
- HANDLE hFile,
- LPBY_HANDLE_FILE_INFORMATION lpFileInformation
-);
-
-typedef enum {
- FileBasicInfo = 0,
- FileStandardInfo = 1,
- FileNameInfo = 2,
- FileRenameInfo = 3,
- FileDispositionInfo = 4,
- FileAllocationInfo = 5,
- FileEndOfFileInfo = 6,
- FileStreamInfo = 7,
- FileCompressionInfo = 8,
- FileAttributeTagInfo = 9,
- FileIdBothDirectoryInfo = 10,
- FileIdBothDirectoryRestartInfo = 11,
- FileIoPriorityHintInfo = 12,
- FileRemoteProtocolInfo = 13,
- FileFullDirectoryInfo = 14,
- FileFullDirectoryRestartInfo = 15,
- FileStorageInfo = 16,
- FileAlignmentInfo = 17,
- FileIdInfo = 18,
- FileIdExtdDirectoryInfo = 19,
- FileIdExtdDirectoryRestartInfo = 20,
-} FILE_INFO_BY_HANDLE_CLASS;
-
-typedef struct {
- LARGE_INTEGER CreationTime;
- LARGE_INTEGER LastAccessTime;
- LARGE_INTEGER LastWriteTime;
- LARGE_INTEGER ChangeTime;
- DWORD FileAttributes;
-} FILE_BASIC_INFO, *PFILE_BASIC_INFO;
-
-BOOL GetFileInformationByHandleEx(
- HANDLE hFile,
- FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
- LPVOID lpFileInformation,
- DWORD dwBufferSize
-);
-
-BOOL SetFileInformationByHandle(
- HANDLE hFile,
- FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
- LPVOID lpFileInformation,
- DWORD dwBufferSize
-);
-
-typedef enum {
- GetFileExInfoStandard
-} GET_FILEEX_INFO_LEVELS;
-
-DWORD GetFinalPathNameByHandleW(
- HANDLE hFile,
- LPWSTR lpszFilePath,
- DWORD cchFilePath,
- DWORD dwFlags
-);
-]]
-
---FILETIME stores time in hundred-nanoseconds from `1601-01-01 00:00:00`.
---timestamp stores the time in seconds from `1970-01-01 00:00:00`.
-
-local TS_FT_DIFF = 11644473600 --seconds
-
-local function filetime(ts) --convert timestamp -> FILETIME
- return (ts + TS_FT_DIFF) * 1e7
-end
-
-local function timestamp(ft) --convert FILETIME as uint64 -> timestamp
- return tonumber(ft) * 1e-7 - TS_FT_DIFF
-end
-
-local function ft_timestamp(filetime) --convert FILETIME -> timestamp
- return timestamp(filetime.dwHighDateTime * 2^32 + filetime.dwLowDateTime)
-end
-
-local function filesize(high, low)
- return high * 2^32 + low
-end
-
-local function attrbit(bits, k)
- if k ~= 'directory' and k ~= 'device' and attr_bits[k] then
- return band(attr_bits[k], bits) ~= 0
- end
-end
-
-local function attrbits(bits, t)
- for name in pairs(attr_bits) do
- t[name] = attrbit(bits, name) or nil
- end
- return t
-end
-
-local changeable_attr_bits = {
- --FILE_ATTRIBUTE_* flags which can be changed directly
- readonly = attr_bits.readonly,
- hidden = attr_bits.hidden,
- system = attr_bits.system,
- archive = attr_bits.archive,
- temporary = attr_bits.temporary,
- not_indexed = attr_bits.not_indexed,
-}
-local function set_attrbits(cur_bits, t)
- cur_bits = cur_bits == FILE_ATTRIBUTE_NORMAL and 0 or cur_bits
- local bits = flags(t, changeable_attr_bits, cur_bits)
- return bits == 0 and FILE_ATTRIBUTE_NORMAL or bits
-end
-
-local IO_REPARSE_TAG_SYMLINK = 0xA000000C
-
-local function is_symlink(bits, reparse_tag)
- return band(bits, attr_bits.reparse_point) ~= 0
- and (not reparse_tag or reparse_tag == IO_REPARSE_TAG_SYMLINK)
-end
-
-local function filetype(bits, reparse_tag)
- return
- is_symlink(bits, reparse_tag) and 'symlink'
- or band(bits, attr_bits.directory) ~= 0 and 'dir'
- or band(bits, attr_bits.device ) ~= 0 and 'dev'
- or 'file'
-end
-
-local file_info_ct = ffi.typeof'BY_HANDLE_FILE_INFORMATION'
-local info
-local function file_get_info(f)
- info = info or file_info_ct()
- local ok, err = checknz(C.GetFileInformationByHandle(f.handle, info))
- if not ok then return nil, err end
- return info
-end
-
-local file_basic_info_ct = ffi.typeof'FILE_BASIC_INFO'
-local binfo
-local function file_get_basic_info(f)
- binfo = binfo or file_basic_info_ct()
- local ok, err = checknz(C.GetFileInformationByHandleEx(
- f.handle, C.FileBasicInfo, binfo, ffi.sizeof(binfo)
- ))
- if not ok then return nil, err end
- return binfo
-end
-
-local function file_set_basic_info(f, binfo)
- return checknz(C.SetFileInformationByHandle(
- f.handle, C.FileBasicInfo, binfo, ffi.sizeof(binfo)
- ))
-end
-
-local binfo_getters = {
- type = function(binfo) return filetype(binfo.FileAttributes) end,
- btime = function(binfo)
- return timestamp(binfo.CreationTime.QuadPart)
- end,
- atime = function(binfo)
- return timestamp(binfo.LastAccessTime.QuadPart)
- end,
- mtime = function(binfo)
- return timestamp(binfo.LastWriteTime.QuadPart) end,
- ctime = function(binfo)
- return timestamp(binfo.ChangeTime.QuadPart)
- end,
-}
-
-local info_getters = {
- volume = function(info)
- return info.dwVolumeSerialNumber
- end,
- size = function(info)
- return filesize(info.nFileSizeHigh, info.nFileSizeLow)
- end,
- nlink = function(info) return info.nNumberOfLinks end,
- id = function(info)
- return join_uint64(info.nFileIndexHigh, info.nFileIndexLow)
- end,
-}
-
-local function file_attr_get_all(f)
- local binfo, err = file_get_basic_info(f)
- if not binfo then return nil, err end
- local info, err = file_get_info(f)
- if not info then return nil, err end
- local t = attrbits(binfo.FileAttributes, {})
- for k, get in pairs(binfo_getters) do
- t[k] = get(binfo) or nil
- end
- for k, get in pairs(info_getters) do
- t[k] = get(info) or nil
- end
- return t
-end
-
-function file_attr_get(f, k)
- if not k then
- return file_attr_get_all(f)
- end
- local val = attrbit(0, k)
- if val ~= nil then
- local binfo, err = file_get_basic_info(f)
- if not binfo then return nil, err end
- return attrbit(binfo.FileAttributes)
- end
- local get = binfo_getters[k]
- if get then
- local binfo, err = file_get_basic_info(f)
- if not binfo then return nil, err end
- return get(binfo)
- end
- local get = info_getters[k]
- if get then
- local info, err = file_get_info(f)
- if not info then return nil, err end
- return get(info)
- end
- return nil
-end
-
-local function set_filetime(ft, ts)
- return ts and filetime(ts) or ft
-end
-function file_attr_set(f, t)
- local binfo, err = file_get_basic_info(f)
- if not binfo then return nil, err end
- binfo.FileAttributes = set_attrbits(binfo.FileAttributes, t)
- binfo.CreationTime.QuadPart =
- set_filetime(binfo.CreationTime.QuadPart, t.btime)
- binfo.LastAccessTime.QuadPart =
- set_filetime(binfo.LastAccessTime.QuadPart, t.atime)
- binfo.LastWriteTime.QuadPart =
- set_filetime(binfo.LastWriteTime.QuadPart, t.mtime)
- binfo.ChangeTime.QuadPart =
- set_filetime(binfo.ChangeTime.QuadPart, t.ctime)
- return file_set_basic_info(f, binfo)
-end
-
-function with_open_file(path, open_opt, func, ...)
- local f, err = fs.open(path, open_opt)
- if not f then return nil, err end
- local ret, err = func(f, ...)
- if ret == nil and err then return nil, err end
- local ok, err = f:close()
- if not ok then return nil, err end
- return ret
-end
-
-local open_opt = {
- access = 'read_attributes',
- sharing = 'read write delete',
- creation = 'open_existing',
- flags = 'backup_semantics', --for opening directories
-}
-local open_opt_symlink = {
- access = 'read_attributes',
- sharing = 'read write delete',
- creation = 'open_existing',
- flags = 'backup_semantics open_reparse_point',
- attrs = 'reparse_point',
-}
-function fs_attr_get(path, k, deref)
- local opt = deref and open_opt or open_opt_symlink
- return with_open_file(path, opt, file_attr_get, k)
-end
-
-local open_opt = {
- access = 'write_attributes',
- sharing = 'read write delete',
- creation = 'open_existing',
-}
-local open_opt_symlink = {
- access = 'write_attributes',
- sharing = 'read write delete',
- creation = 'open_existing',
- flags = 'backup_semantics open_reparse_point',
- attrs = 'reparse_point',
-}
-function fs_attr_set(path, t, deref)
- local opt = deref and open_opt or open_opt_symlink
- return with_open_file(path, opt, file_attr_set, t)
-end
-
---directory listing ----------------------------------------------------------
-
-cdef[[
-enum {
- MAX_PATH = 260
-};
-
-typedef struct {
- DWORD dwFileAttributes;
- FILETIME ftCreationTime;
- FILETIME ftLastAccessTime;
- FILETIME ftLastWriteTime;
- DWORD nFileSizeHigh;
- DWORD nFileSizeLow;
- DWORD dwReserved0; // reparse tag
- DWORD dwReserved1;
- WCHAR cFileName[MAX_PATH];
- WCHAR cAlternateFileName[14];
-} WIN32_FIND_DATAW, *LPWIN32_FIND_DATAW;
-
-HANDLE FindFirstFileW(LPCWSTR, LPWIN32_FIND_DATAW);
-BOOL FindNextFileW(HANDLE, LPWIN32_FIND_DATAW);
-BOOL FindClose(HANDLE);
-]]
-
-dir_ct = ffi.typeof[[
- struct {
- HANDLE _handle;
- WIN32_FIND_DATAW _fdata;
- DWORD _errcode; // return `false, err, errcode` on the next iteration
- int _loaded; // _fdata is loaded for the next iteration
- int _dirlen;
- char _dir[?];
- }
-]]
-
-function dir.close(dir)
- if dir:closed() then return true end
- local ok, err = checknz(C.FindClose(dir._handle))
- if not ok then return false, err end
- dir._handle = INVALID_HANDLE_VALUE
- return true
-end
-
-function dir.closed(dir)
- return dir._handle == INVALID_HANDLE_VALUE
-end
-
-function dir_ready(dir)
- return not (dir._loaded == 1 or dir._errcode ~= 0)
-end
-
-local ERROR_NO_MORE_FILES = 18
-
-function dir_name(dir)
- return mbs(dir._fdata.cFileName)
-end
-
-function dir.dir(dir)
- return ffi.string(dir._dir, dir._dirlen)
-end
-
-function dir.next(dir)
- if dir:closed() then
- if dir._errcode ~= 0 then
- local errcode = dir._errcode
- dir._errcode = 0
- return checknz(0, errcode)
- end
- return nil
- end
- if dir._loaded == 1 then
- dir._loaded = 0
- return dir:name(), dir
- else
- local ret = C.FindNextFileW(dir._handle, dir._fdata)
- if ret ~= 0 then
- return dir:name(), dir
- else
- local errcode = C.GetLastError()
- dir:close()
- if errcode == ERROR_NO_MORE_FILES then
- return nil
- end
- return checknz(0, errcode)
- end
- end
-end
-
-function fs_dir(path)
- assert(not path:find'[%*%?]') --no globbing allowed
- local dir = dir_ct(#path)
- dir._dirlen = #path
- ffi.copy(dir._dir, path, #path)
- dir._handle = C.FindFirstFileW(wcs(path .. '\\*'), dir._fdata)
- if dir._handle == INVALID_HANDLE_VALUE then
- dir._errcode = C.GetLastError()
- else
- dir._loaded = 1
- end
- return dir.next, dir
-end
-
-function dir_attr_get(dir, attr)
- if attr == 'type' then
- return filetype(dir._fdata.dwFileAttributes, dir._fdata.dwReserved0)
- elseif attr == 'atime' then
- return ft_timestamp(dir._fdata.ftLastAccessTime)
- elseif attr == 'mtime' then
- return ft_timestamp(dir._fdata.ftLastWriteTime)
- elseif attr == 'btime' then
- return ft_timestamp(dir._fdata.ftCreationTime)
- elseif attr == 'size' then
- return filesize(dir._fdata.nFileSizeHigh, dir._fdata.nFileSizeLow)
- elseif attr == 'dosname' then
- local s = mbs(dir._fdata.cAlternateFileName)
- return s ~= '' and s or nil
- else
- local val = attrbit(dir._fdata.dwFileAttributes, attr)
- if val ~= nil then return val end
- return nil, false --not found
- end
-end
-
---memory mapping -------------------------------------------------------------
-
-ffi.cdef[[
-typedef struct {
- WORD wProcessorArchitecture;
- WORD wReserved;
- DWORD dwPageSize;
- LPVOID lpMinimumApplicationAddress;
- LPVOID lpMaximumApplicationAddress;
- LPDWORD dwActiveProcessorMask;
- DWORD dwNumberOfProcessors;
- DWORD dwProcessorType;
- DWORD dwAllocationGranularity;
- WORD wProcessorLevel;
- WORD wProcessorRevision;
-} SYSTEM_INFO, *LPSYSTEM_INFO;
-
-VOID GetSystemInfo(LPSYSTEM_INFO lpSystemInfo);
-]]
-
-local pagesize
-function fs.pagesize()
- if not pagesize then
- local sysinfo = ffi.new'SYSTEM_INFO'
- C.GetSystemInfo(sysinfo)
- pagesize = sysinfo.dwAllocationGranularity
- end
- return pagesize
-end
-
-ffi.cdef[[
-HANDLE CreateFileMappingW(
- HANDLE hFile,
- LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
- DWORD flProtect,
- DWORD dwMaximumSizeHigh,
- DWORD dwMaximumSizeLow,
- LPCWSTR lpName
-);
-
-HANDLE OpenFileMappingW(
- DWORD dwDesiredAccess,
- BOOL bInheritHandle,
- LPCWSTR lpName
-);
-
-void* MapViewOfFileEx(
- HANDLE hFileMappingObject,
- DWORD dwDesiredAccess,
- DWORD dwFileOffsetHigh,
- DWORD dwFileOffsetLow,
- SIZE_T dwNumberOfBytesToMap,
- LPVOID lpBaseAddress
-);
-
-BOOL UnmapViewOfFile(LPCVOID lpBaseAddress);
-
-BOOL FlushViewOfFile(
- LPCVOID lpBaseAddress,
- SIZE_T dwNumberOfBytesToFlush
-);
-
-BOOL VirtualProtect(
- LPVOID lpAddress,
- SIZE_T dwSize,
- DWORD flNewProtect,
- PDWORD lpflOldProtect);
-]]
-
-local PAGE_READONLY = 0x0002
-local PAGE_READWRITE = 0x0004
-local PAGE_WRITECOPY = 0x0008 --no file auto-grow with this!
-local PAGE_EXECUTE_READ = 0x0020
-local PAGE_EXECUTE_READWRITE = 0x0040
-local PAGE_EXECUTE_WRITECOPY = 0x0080
-
-local function protect_flag(write, exec, copy)
- return exec and (
- copy and PAGE_EXECUTE_WRITECOPY
- or write and PAGE_EXECUTE_READWRITE
- or PAGE_EXECUTE_READ
- ) or (
- copy and PAGE_WRITECOPY
- or write and PAGE_READWRITE
- or PAGE_READONLY
- )
-end
-
-local FILE_MAP_COPY = 0x0001
-local FILE_MAP_WRITE = 0x0002
-local FILE_MAP_READ = 0x0004
-local FILE_MAP_EXECUTE = 0x0020
-
-function fs_map(file, access, size, offset, addr, tagname)
-
- local write, exec, copy = parse_access(access or '')
-
- --open the file, if any.
-
- local function exit(err)
- if file then file:close() end
- return nil, err
- end
-
- if type(file) == 'string' then
- local open_opt = {
- access = 'read'
- .. (exec and ' execute' or '')
- .. (write and ' write' or ''),
- sharing = 'read write delete',
- creation = write and 'open_always' or 'open_existing',
- }
- local err
- file, err = fs.open(file, open_opt)
- if not file then
- return nil, err
- end
- end
-
- --create file mapping.
-
- local protect = protect_flag(write, exec, copy)
- local size_hi, size_lo = split_uint64(size or 0) --0 means whole file
- local wtagname = tagname and wcs('Local\\'..check_tagname(tagname))
-
- local filemap, err = checknil(C.CreateFileMappingW(
- file and file.handle or INVALID_HANDLE_VALUE,
- nil, protect, size_hi, size_lo, wtagname
- ), nil, mmap_errors)
-
- if filemap == nil then
- if not file and err == 'file_too_short' then --opening the swap file
- err = 'out_of_mem'
- end
- return exit(err)
- end
-
- --map view of file.
-
- local access_bits = bor(
- not write and not copy and FILE_MAP_READ or 0,
- write and FILE_MAP_WRITE or 0,
- copy and FILE_MAP_COPY or 0,
- exec and FILE_MAP_EXECUTE or 0
- )
- local offset_hi, offset_lo = split_uint64(offset)
-
- local addr, err = checknil(C.MapViewOfFileEx(
- filemap, access_bits, offset_hi, offset_lo, size or 0, addr
- ), nil, mmap_errors)
-
- if addr == nil then
- C.CloseHandle(filemap)
- return exit(err)
- end
-
- --create the map object.
-
- local function free()
- C.UnmapViewOfFile(addr)
- C.CloseHandle(filemap)
- exit()
- end
-
- local function flush(self, async, addr, sz)
- if type(async) ~= 'boolean' then --async arg is optional
- async, addr, sz = false, async, addr
- end
- local addr = fs.aligned_addr(addr or self.addr, 'left')
- local ok, err = checknz(C.FlushViewOfFile(addr, sz or self.size))
- if not ok then return false, err end
- if not async and file then
- local ok, err = file:flush()
- if not ok then return false, err end
- end
- return true
- end
-
- --if size wasn't given, get the file size so that the user always knows
- --the actual size of the mapped memory.
- if not size then
- local filesize, err = file:attr'size'
- if not filesize then return nil, err end
- size = filesize - offset
- end
-
- local function unlink()
- return fs.unlink_mapfile(tagname)
- end
-
- return {addr = addr, size = size, free = free,
- flush = flush, unlink = unlink, access = access}
-
-end
-
-function fs.unlink_mapfile(tagname) --no-op
- check_tagname(tagname)
- return true
-end
-
-function fs.protect(addr, size, access)
- local protect = protect_flag(parse_access(access or 'x'))
- local old = ffi.new'DWORD[1]'
- local ok, err = checknz(C.VirtualProtect(addr, size, prot, old))
- if not ok then return false, err end
- return true
-end
-
---mirror buffer --------------------------------------------------------------
-
-function fs.mirror_buffer(size, addr)
-
- local size = fs.aligned_size(size or 1)
- local size_hi, size_lo = split_uint64(size * 2)
- local addr = ffi.cast('uint8_t*', addr)
-
- local filemap, err = checknil(C.CreateFileMappingW(
- INVALID_HANDLE_VALUE,
- nil, protect_flag(true), size_hi, size_lo, nil
- ), nil, mmap_errors)
-
- if filemap == nil then
- if not file and err == 'file_too_short' then
- err = 'out_of_mem'
- end
- return nil, err
- end
-
- local access_bits = bor(FILE_MAP_READ, FILE_MAP_WRITE)
-
- local addr1, addr2
-
- local function free()
- if addr1 then C.UnmapViewOfFile(addr1) end
- if addr2 then C.UnmapViewOfFile(addr2) end
- if filemap then C.CloseHandle(filemap) end
- end
-
- for i = 1, 100 do
-
- local addr, err = checknil(C.MapViewOfFileEx(
- filemap, access_bits, 0, 0, size * 2, addr
- ), nil, mmap_errors)
-
- if addr == nil then
- free()
- return nil, err
- end
-
- C.UnmapViewOfFile(addr)
-
- addr1, err = checknil(C.MapViewOfFileEx(
- filemap, access_bits, 0, 0, size, addr
- ), nil, mmap_errors)
-
- if not addr1 then
- goto skip
- end
-
- addr2, err = checknil(C.MapViewOfFileEx(
- filemap, access_bits, 0, 0, size, ffi.cast('uint8_t*', addr1) + size
- ), nil, mmap_errors)
-
- if not addr2 then
- C.UnmapViewOfFile(addr1)
- goto skip
- end
-
- C.CloseHandle(filemap)
- filemap = nil
-
- do return {addr = addr1, size = size, free = free} end
-
- ::skip::
- end
-
- free()
- return nil, 'max_tries'
-
-end
diff --git a/lib/game_config.lua b/lib/game_config.lua
deleted file mode 100644
index 47e2eea..0000000
--- a/lib/game_config.lua
+++ /dev/null
@@ -1,26 +0,0 @@
-local game_config = {}
-local nxml = dofile("mods/evaisa.mp/lib/nxml.lua")
-
-local config_xml = os.getenv('APPDATA'):gsub("\\Roaming", "") .. "\\LocalLow\\Nolla_Games_Noita\\save_shared\\config.xml"
-
--- if file exists, read it
-local config_file = io.open(config_xml, "r")
-
-local config_settings = {}
-
-if config_file then
- local config = config_file:read("*all")
- config_file:close()
-
- config_settings = nxml.parse(config)
-
- for key, value in pairs(config_settings.attr or {}) do
- config_settings[key] = value
- end
-end
-
-game_config.get = function(key)
- return config_settings[key]
-end
-
-return game_config
\ No newline at end of file
diff --git a/lib/glue.lua b/lib/glue.lua
deleted file mode 100644
index 9bcbe3f..0000000
--- a/lib/glue.lua
+++ /dev/null
@@ -1,1584 +0,0 @@
-
---Lua GLUE: Ideal for wood and paper.
---Written by Cosmin Apreutesei. Public domain.
-
-if not ... then require'glue_test'; return end
-
-local glue = {}
-
-local min, max, floor, ceil, ln, random =
- math.min, math.max, math.floor, math.ceil, math.log, math.random
-local insert, remove, sort, concat = table.insert, table.remove, table.sort, table.concat
-local char = string.char
-local type, select, unpack, pairs, rawget = type, select, unpack, pairs, rawget
-
---types ----------------------------------------------------------------------
-
-glue.isstr = function(s) return type(s) == 'string' end
-glue.isnum = function(x) return type(x) == 'number' end
-glue.isint = function(x) return type(x) == 'number' and floor(x) == x end
-glue.istab = function(x) return type(x) == 'table' end
-glue.isfunc = function(f) return type(f) == 'function' end
-
---math -----------------------------------------------------------------------
-
-function glue.round(x, p)
- p = p or 1
- return floor(x / p + .5) * p
-end
-
-function glue.floor(x, p)
- p = p or 1
- return floor(x / p) * p
-end
-
-function glue.ceil(x, p)
- p = p or 1
- return ceil(x / p) * p
-end
-
-glue.snap = glue.round
-
-function glue.clamp(x, x0, x1)
- return min(max(x, x0), x1)
-end
-
-function glue.lerp(x, x0, x1, y0, y1)
- return y0 + (x-x0) * ((y1-y0) / (x1 - x0))
-end
-
-function glue.nextpow2(x)
- return max(0, 2^(ceil(ln(x) / ln(2))))
-end
-
-function glue.sign(x)
- return x > 0 and 1 or x == 0 and 0 or -1
-end
-
-function glue.strict_sign(x)
- return x >= 0 and 1 or -1
-end
-
-function glue.repl(x, v, r)
- if x == v then return r else return x end
-end
-
-if jit then
- local str = require'ffi'.string
- function glue.random_string(n)
- local buf = glue.u32a(n/4+1)
- for i=0,n/4 do
- buf[i] = random(0, 2^32-1)
- end
- return str(buf, n)
- end
-else
- function glue.random_string(n)
- local t = {}
- for i=1,n do
- t[i] = random(0, 255)
- end
- return char(unpack(t))
- end
-end
-
-function glue.uuid()
- return ('%08x-%04x-%04x-%04x-%08x%04x'):format(
- random(0xffffffff), random(0xffff),
- 0x4000 + random(0x0fff), --4xxx
- 0x8000 + random(0x3fff), --10bb-bbbb-bbbb-bbbb
- random(0xffffffff), random(0xffff))
-end
-
---varargs --------------------------------------------------------------------
-
-if table.pack then
- glue.pack = table.pack
-else
- function glue.pack(...)
- return {n = select('#', ...), ...}
- end
-end
-
---always use this because table.unpack's default j is #t not t.n.
-function glue.unpack(t, i, j)
- return unpack(t, i or 1, j or t.n or #t)
-end
-
---tables ---------------------------------------------------------------------
-
-glue.empty = setmetatable({}, {
- __newindex = function() error'trying to set a field in glue.empty' end, --read-only
- __metatable = false,
-})
-
---count the keys in a table with an optional upper limit.
-function glue.count(t, maxn)
- local maxn = maxn or 1/0
- local n = 0
- for _ in pairs(t) do
- n = n + 1
- if n >= maxn then break end
- end
- return n
-end
-
---reverse keys with values.
-function glue.index(t)
- local dt={}
- for k,v in pairs(t) do dt[v]=k end
- return dt
-end
-
---put keys in a list, optionally sorted.
-local function desc_cmp(a, b) return a > b end
-function glue.keys(t, cmp)
- local dt={}
- for k in pairs(t) do
- dt[#dt+1]=k
- end
- if cmp == true or cmp == 'asc' then
- sort(dt)
- elseif cmp == 'desc' then
- sort(dt, desc_cmp)
- elseif cmp then
- sort(dt, cmp)
- end
- return dt
-end
-
-function glue.sortedkeys(t, cmp)
- return glue.keys(t, cmp or true)
-end
-
---stateless pairs() that iterate elements in key order.
-function glue.sortedpairs(t, cmp)
- local kt = glue.keys(t, cmp or true)
- local i = 0
- return function()
- i = i + 1
- return kt[i], t[kt[i]]
- end
-end
-
---update a table with the contents of other table(s).
-function glue.update(dt,...)
- for i=1,select('#',...) do
- local t=select(i,...)
- if t then
- for k,v in pairs(t) do dt[k]=v end
- end
- end
- return dt
-end
-
---add the contents of other table(s) without overwrite.
-function glue.merge(dt,...)
- for i=1,select('#',...) do
- local t=select(i,...)
- if t then
- for k,v in pairs(t) do
- if rawget(dt, k) == nil then dt[k]=v end
- end
- end
- end
- return dt
-end
-
---get the value of a table field, and if the field is not present in the
---table, create it as an empty table, and return it.
-function glue.attr(t, k, v0)
- local v = t[k]
- if v == nil then
- if v0 == nil then
- v0 = {}
- end
- v = v0
- t[k] = v
- end
- return v
-end
-
---lists ----------------------------------------------------------------------
-
---extend a list with the elements of other lists.
-function glue.extend(dt,...)
- for j=1,select('#',...) do
- local t=select(j,...)
- if t then
- local j = #dt
- for i=1,#t do dt[j+i]=t[i] end
- end
- end
- return dt
-end
-
---append non-nil arguments to a list.
-function glue.append(dt,...)
- local j = #dt
- for i=1,select('#',...) do
- dt[j+i] = select(i,...)
- end
- return dt
-end
-
---insert n elements at i, shifting elemens on the right of i (i inclusive)
---to the right.
-local function insert_n(t, i, n)
- if n == 1 then --shift 1
- insert(t, i, false)
- return
- end
- for p = #t,i,-1 do --shift n
- t[p+n] = t[p]
- end
-end
-
---remove n elements at i, shifting elements on the right of i (i inclusive)
---to the left.
-local function remove_n(t, i, n)
- n = min(n, #t-i+1)
- if n == 1 then --shift 1
- remove(t, i)
- return
- end
- for p=i+n,#t do --shift n
- t[p-n] = t[p]
- end
- for p=#t,#t-n+1,-1 do --clean tail
- t[p] = nil
- end
-end
-
---shift all the elements on the right of i (i inclusive) to the left
---or further to the right.
-function glue.shift(t, i, n)
- if n > 0 then
- insert_n(t, i, n)
- elseif n < 0 then
- remove_n(t, i, -n)
- end
- return t
-end
-
---map f over t or extract a column from a list of records.
-function glue.map(t, f, ...)
- local dt = {}
- if type(f) == 'function' then
- for k,v in pairs(t) do
- dt[k] = f(k, v, ...)
- end
- else
- for k,v in pairs(t) do
- local sel = v[f]
- if type(sel) == 'function' then --method to apply
- dt[k] = sel(v, ...)
- else --field to pluck
- dt[k] = sel
- end
- end
- end
- return dt
-end
-
---map f over t or extract a column from a list of records.
-function glue.imap(t, f, ...)
- local dt = {n = t.n}
- local n = t.n or #t
- if type(f) == 'function' then
- for i=1,n do
- dt[i] = f(t[i], ...)
- end
- else
- for i=1,n do
- local v = t[i]
- local sel = v[f]
- if type(sel) == 'function' then --method to apply
- dt[i] = sel(v, ...)
- else --field to pluck
- dt[i] = sel
- end
- end
- end
- return dt
-end
-
---arrays ---------------------------------------------------------------------
-
---scan list for value. works with ffi arrays too given i and j.
-function glue.indexof(v, t, eq, i, j)
- i = i or 1
- j = j or #t
- if eq then
- for i = i, j do
- if eq(t[i], v) then
- return i
- end
- end
- else
- for i = i, j do
- if t[i] == v then
- return i
- end
- end
- end
-end
-
---reverse elements of a list in place. works with ffi arrays too given i and j.
-function glue.reverse(t, i, j)
- i = i or 1
- j = (j or #t) + 1
- for k = 1, (j-i)/2 do
- t[i+k-1], t[j-k] = t[j-k], t[i+k-1]
- end
- return t
-end
-
---binary search for an insert position that keeps the table sorted.
---works with ffi arrays too if lo and hi are provided.
-local cmps = {}
-cmps['<' ] = function(t, i, v) return t[i] < v end
-cmps['>' ] = function(t, i, v) return t[i] > v end
-cmps['<='] = function(t, i, v) return t[i] <= v end
-cmps['>='] = function(t, i, v) return t[i] >= v end
-local less = cmps['<']
-function glue.binsearch(v, t, cmp, lo, hi)
- lo, hi = lo or 1, hi or #t
- cmp = cmp and cmps[cmp] or cmp or less
- local len = hi - lo + 1
- if len == 0 then return nil end
- if len == 1 then return not cmp(t, lo, v) and lo or nil end
- while lo < hi do
- local mid = floor(lo + (hi - lo) / 2)
- if cmp(t, mid, v) then
- lo = mid + 1
- if lo == hi and cmp(t, lo, v) then
- return nil
- end
- else
- hi = mid
- end
- end
- return lo
-end
-
---sortedarray ----------------------------------------------------------------
-
-do --array that stays sorted with insertion, searching and removal in O(log n).
- local sa = {}
- function sa:find(v) return glue.binsearch(v, self, self.cmp) end
- function sa:push(v) insert(self, self:find(v) or #self+1, v) end
- function sa:remove_value(v)
- local i = self:find(v)
- if not i then return nil end
- return remove(self, i)
- end
- function glue.sortedarray(t)
- return glue.object(sa, t)
- end
-end
-
---strings --------------------------------------------------------------------
-
---string submodule. has its own namespace which can be merged with _G.string.
-glue.string = {}
-
---split a string by a separator that can be a pattern or a plain string.
---return a stateless iterator for the pieces.
-local function iterate_once(s, s1)
- return s1 == nil and s or nil
-end
-function glue.string.gsplit(s, sep, start, plain)
- start = start or 1
- plain = plain or false
- if not s:find(sep, start, plain) then
- return iterate_once, s:sub(start)
- end
- local done = false
- local function pass(i, j, ...)
- if i then
- local seg = s:sub(start, i - 1)
- start = j + 1
- return seg, ...
- else
- done = true
- return s:sub(start)
- end
- end
- return function()
- if done then return end
- if sep == '' then done = true; return s:sub(start) end
- return pass(s:find(sep, start, plain))
- end
-end
-
-function glue.string.split(s, sep, start, plain)
- return glue.collect(glue.gsplit(s, sep, start, plain))
-end
-
-function glue.string.names(s)
- if type(s) ~= 'string' then
- return s
- end
- local t = {}
- for s in s:gmatch'[^%s]+' do
- t[#t+1] = s
- end
- return t
-end
-
-local function cap(a, b) return a:upper()..b end
-function glue.string.capitalize(s)
- return s:gsub('(%l)(%w*)', cap)
-end
-
---split a string into lines, optionally including the line terminator.
-function glue.string.lines(s, opt, i)
- local term = opt == '*L'
- local patt = term and '()([^\r\n]*()\r?\n?())' or '()([^\r\n]*)()\r?\n?()'
- i = i or 1
- local ended
- return function()
- if ended then return end
- local i0, s, i1, i2 = s:match(patt, i)
- ended = i1 == i2
- i = i2
- return s, i0, i1, i2
- end
-end
-
---outdent lines based on the indent of the first non-empty line.
-function glue.string.outdent(s, newindent)
- newindent = newindent or ''
- local indent
- local t = {}
- for s in glue.lines(s) do
- local indent1 = s:match'^([\t ]*)[^%s]'
- if not indent then
- indent = indent1
- elseif indent1 then
- if indent ~= indent1 then
- if #indent1 > #indent then --more indented
- if not glue.starts(indent1, indent) then
- indent = ''
- break
- end
- elseif #indent > #indent1 then --less indented
- if not glue.starts(indent, indent1) then
- indent = ''
- break
- end
- indent = indent1
- else --same length, diff contents.
- indent = ''
- break
- end
- end
- end
- t[#t+1] = s
- end
- if indent == '' and newindent == '' then
- return s
- end
- for i=1,#t do
- t[i] = newindent .. t[i]:sub(#indent + 1)
- end
- return concat(t, '\n'), indent
-end
-
---for a string, return a function that given a byte index in the string
---returns the line and column numbers corresponding to that index.
-function glue.string.lineinfo(s, i)
- if i then --simpler version with no garbage for when the index is given.
- assert(i > 0 and i <= #s + 1)
- local line, col = 1, 1
- local byte = string.byte
- for i = 1, i - 1 do
- col = col + 1
- if byte(s, i) == 10 then
- line = line + 1
- col = 1
- end
- end
- return line, col
- end
- --collect char indices of all the lines in s, incl. the index at #s + 1
- local t = {}
- for i in s:gmatch'()[^\r\n]*\r?\n?' do
- t[#t+1] = i
- end
- assert(#t >= 2)
- local function lineinfo(i)
- --do a binary search in t to find the line.
- --TODO: replace this with glue.binsearch().
- assert(i > 0 and i <= #s + 1)
- local min, max = 1, #t
- while true do
- local k = floor(min + (max - min) / 2)
- if i >= t[k] then
- if k == #t or i < t[k+1] then --found it
- return k, i - t[k] + 1
- else --look forward
- min = k
- end
- else --look backward
- max = k
- end
- end
- end
- return lineinfo
-end
-
---string trim12 from Lua wiki.
-function glue.string.trim(s)
- local from = s:match'^%s*()'
- return from > #s and '' or s:match('.*%S', from)
-end
-
-local function pad(s, n, c, dir)
- local pad = (c or ' '):rep(n - #s)
- return dir == 'l' and pad..s or dir == 'r' and s..pad or error'dir arg required'
-end
-glue.string.pad = pad
-function glue.string.lpad(s, n, c) return pad(s, n, c, 'l') end
-function glue.string.rpad(s, n, c) return pad(s, n, c, 'r') end
-
---escape a string so that it can be matched literally inside a pattern.
-local function format_ci_pat(c)
- return ('[%s%s]'):format(c:lower(), c:upper())
-end
-function glue.string.esc(s, mode) --escape is a reserved word in Terra
- s = s:gsub('%%','%%%%'):gsub('%z','%%z')
- :gsub('([%^%$%(%)%.%[%]%*%+%-%?])', '%%%1')
- if mode == '*i' then s = s:gsub('[%a]', format_ci_pat) end
- return s
-end
-
---string or number to hex.
-function glue.string.tohex(s, upper)
- if type(s) == 'number' then
- return (upper and '%08.8X' or '%08.8x'):format(s)
- end
- if upper then
- return (s:gsub('.', function(c)
- return ('%02X'):format(c:byte())
- end))
- else
- return (s:gsub('.', function(c)
- return ('%02x'):format(c:byte())
- end))
- end
-end
-
---hex to binary string.
-local function fromhex(s, isvalid)
- if not isvalid then
- if s:find'[^0-9a-fA-F]' then
- return nil
- end
- else
- s = s:gsub('[^0-9a-fA-F]', '')
- end
- if #s % 2 == 1 then
- return fromhex('0'..s)
- end
- return (s:gsub('..', function(cc)
- return char(assert(tonumber(cc, 16)))
- end))
-end
-glue.string.fromhex = fromhex
-
-function glue.string.starts(s, p) --5x faster than s:find'^...' in LuaJIT 2.1
- return s:sub(1, #p) == p
-end
-
-function glue.string.ends(s, p)
- return p == '' or s:sub(-#p) == p
-end
-
-function glue.string.subst(s, t, get_missing) --subst('{foo} {bar}', {foo=1, bar=2}) -> '1 2'
- if get_missing then
- local missing
- return s:gsub('{([_%w]+)}', function(s)
- if t[s] ~= nil then
- return t[s]
- else
- if not missing then missing = {} end
- missing[#missing + 1] = s
- end
- end), missing
- else
- return s:gsub('{([_%w]+)}', t)
- end
-end
-
-function glue.catargs(sep, ...)
- local n = select('#', ...)
- if n == 0 then
- return nil
- elseif n == 1 then
- local v = ...
- return v ~= nil and tostring(v) or nil
- elseif n == 2 then
- local v1, v2 = ...
- if v1 ~= nil then
- if v2 ~= nil then
- return v1 .. sep .. v2
- else
- return tostring(v1)
- end
- elseif v2 ~= nil then
- return tostring(v2)
- else
- return nil
- end
- else
- local t = {}
- for i = 1, n do
- local s = select(i, ...)
- if s ~= nil then
- t[#t+1] = tostring(s)
- end
- end
- return #t > 0 and concat(t, sep) or nil
- end
-end
-
---publish the string submodule in the glue namespace.
-glue.update(glue, glue.string)
-
---iterators ------------------------------------------------------------------
-
---run an iterator and collect the n-th return value into a list.
-local function select_at(i,...)
- return ...,select(i,...)
-end
-local function collect_at(i,f,s,v)
- local t = {}
- repeat
- v,t[#t+1] = select_at(i,f(s,v))
- until v == nil
- return t
-end
-local function collect_first(f,s,v)
- local t = {}
- repeat
- v = f(s,v); t[#t+1] = v
- until v == nil
- return t
-end
-function glue.collect(n,...)
- if type(n) == 'number' then
- return collect_at(n,...)
- else
- return collect_first(n,...)
- end
-end
-
---closures -------------------------------------------------------------------
-
---no-op filters.
-function glue.pass(...) return ... end
-function glue.noop() return end
-
---memoize for 0, 1, 2-arg and vararg and 1 retval functions.
-local weakvals_meta = {__mode = 'v'}
-local function weakvals(weak)
- return weak and setmetatable({}, weakvals_meta) or {}
-end
-local function memoize0(fn) --for strict no-arg functions
- local v, stored
- return function()
- if not stored then
- v = fn(); stored = true
- end
- return v
- end
-end
-local nilkey = {}
-local nankey = {}
-local function memoize1(fn, weak) --for strict single-arg functions
- local cache = weakvals(weak)
- return function(arg)
- local k = arg == nil and nilkey or arg ~= arg and nankey or arg
- local v = cache[k]
- if v == nil then
- v = fn(arg)
- cache[k] = v == nil and nilkey or v
- else
- if v == nilkey then v = nil end
- end
- return v
- end
-end
-local function memoize2(fn, weak) --for strict two-arg functions
- local cache = weakvals(weak)
- local pins = weak and weakvals(weak)
- return function(a1, a2)
- local k1 = a1 ~= a1 and nankey or a1 == nil and nilkey or a1
- local cache2 = cache[k1]
- if cache2 == nil then
- cache2 = weakvals(weak)
- cache[k1] = cache2
- end
- local k2 = a2 ~= a2 and nankey or a2 == nil and nilkey or a2
- local v = cache2[k2]
- if v == nil then
- v = fn(a1, a2)
- cache2[k2] = v == nil and nilkey or v
- if weak then --pin weak chained table to the return value.
- assert(type(v) == 'table')
- pins[cache2] = v
- end
- else
- if v == nilkey then v = nil end
- end
- return v
- end
-end
-local function memoize_vararg(fn, weak, minarg, maxarg)
- local cache = weakvals(weak)
- local values = weakvals(weak)
- local pins = weak and weakvals(weak)
- local pinstack = {}
- local inside
- return function(...)
- assert(not inside) --recursion not supported because of the pinstack.
- local inside = true
- local key = cache
- local narg = min(max(select('#',...), minarg), maxarg)
- for i = 1, narg do
- local a = select(i,...)
- local k = a ~= a and nankey or a == nil and nilkey or a
- local t = key[k]
- if not t then
- t = weakvals(weak)
- key[k] = t
- end
- if weak and i < narg then --collect to-be-pinned weak chained tables.
- pinstack[i] = t
- end
- key = t
- end
- local v = values[key]
- if v == nil then
- v = fn(...)
- values[key] = v == nil and nilkey or v
- if weak then --pin weak chained tables to the return value.
- for i = narg-1, 1, -1 do
- assert(type(v) == 'table')
- pins[pinstack[i]] = v
- pinstack[i] = nil
- end
- end
- end
- if v == nilkey then v = nil end
- inside = false
- return v
- end
-end
-local memoize_narg = {[0] = memoize0, memoize1, memoize2}
-local function choose_memoize_func(func, narg, weak)
- if type(narg) == 'function' then
- return choose_memoize_func(narg, nil, weak)
- elseif narg then
- local memoize_narg = (not (narg == 0 and weak)) and memoize_narg[narg]
- if memoize_narg then
- return memoize_narg
- else
- return memoize_vararg, narg, narg
- end
- else
- local info = debug.getinfo(func, 'u')
- if info.isvararg then
- return memoize_vararg, info.nparams, 1/0
- else
- return choose_memoize_func(func, info.nparams, weak)
- end
- end
-end
-function glue.memoize(func, narg, weak)
- local memoize, minarg, maxarg = choose_memoize_func(func, narg, weak)
- return memoize(func, weak, minarg, maxarg)
-end
-
---memoize a function with multiple return values.
-function glue.memoize_multiret(func, narg, weak)
- local memoize, minarg, maxarg = choose_memoize_func(func, narg, weak)
- local function wrapper(...)
- return glue.pack(func(...))
- end
- local func = memoize(wrapper, weak, minarg, maxarg)
- return function(...)
- return glue.unpack(func(...))
- end
-end
-
-local tuple_mt = {__call = glue.unpack}
-function tuple_mt:__tostring()
- local t = {}
- for i=1,self.n do
- t[i] = tostring(self[i])
- end
- return string.format('(%s)', concat(t, ', '))
-end
-function tuple_mt:__pwrite(write, write_value) --integration with the pp module.
- write'tuple('; write_value(self[1])
- for i=2,self.n do
- write','; write_value(self[i])
- end
- write')'
-end
-function glue.tuples(...)
- return glue.memoize(function(...)
- return setmetatable(glue.pack(...), tuple_mt)
- end, ...)
-end
-function glue.weaktuples(narg)
- return glue.tuples(narg, true)
-end
-local tspace
-function glue.tuple(...)
- tspace = tspace or glue.weaktuples()
- return tspace(...)
-end
-
---objects --------------------------------------------------------------------
-
---set up dynamic inheritance by creating or updating a table's metatable.
-function glue.inherit(t, parent)
- local meta = getmetatable(t)
- if meta then
- meta.__index = parent
- elseif parent ~= nil then
- setmetatable(t, {__index = parent})
- end
- return t
-end
-
---prototype-based dynamic inheritance with __call constructor.
-function glue.object(super, o, ...)
- o = o or {}
- o.__index = super
- o.__call = super and super.__call
- glue.update(o, ...) --add mixins, defaults, etc.
- return setmetatable(o, o)
-end
-
-local function install(self, combine, method_name, hook)
- rawset(self, method_name, combine(self[method_name], hook))
-end
-local function before(method, hook)
- if method then
- return function(self, ...)
- hook(self, ...)
- return method(self, ...)
- end
- else
- return hook
- end
-end
-function glue.before(self, method_name, hook)
- install(self, before, method_name, hook)
-end
-local function after(method, hook)
- if method then
- return function(self, ...)
- method(self, ...)
- return hook(self, ...)
- end
- else
- return hook
- end
-end
-function glue.after(self, method_name, hook)
- install(self, after, method_name, hook)
-end
-local function override(method, hook)
- local method = method or glue.noop
- return function(...)
- return hook(method, ...)
- end
-end
-function glue.override(self, method_name, hook)
- install(self, override, method_name, hook)
-end
-
---return a metatable that supports virtual properties.
---can be used with setmetatable() and ffi.metatype().
-function glue.gettersandsetters(getters, setters, super)
- local get = getters and function(t, k)
- local get = getters[k]
- if get then return get(t) end
- return super and super[k]
- end
- local set = setters and function(t, k, v)
- local set = setters[k]
- if set then set(t, v); return end
- rawset(t, k, v)
- end
- return {__index = get, __newindex = set}
-end
-
---os -------------------------------------------------------------------------
-
-glue.win = package.config:sub(1,1) == '\\'
-
---i/o ------------------------------------------------------------------------
-
---check if a file exists and can be opened for reading or writing.
-function glue.canopen(name, mode)
- local f = io.open(name, mode or (glue.win and 'rb' or 'r'))
- if f then f:close() end
- return f ~= nil and name or nil
-end
-
---read a file into a string (in binary mode by default).
-function glue.readfile(name, mode, open)
- open = open or io.open
- local f, err = open(name, mode=='t' and 'r' or (glue.win and 'rb' or 'r'))
- if not f then return nil, err end
- local s, err = f:read'*a'
- if s == nil then return nil, err end
- f:close()
- return s
-end
-
---read the output of a command into a string.
-function glue.readpipe(cmd, mode, open)
- return glue.readfile(cmd, mode, open or io.popen)
-end
-
---like os.rename() but behaves like POSIX on Windows too.
-if jit then
-
- local ffi = require'ffi'
-
- if ffi.os == 'Windows' then
-
- ffi.cdef[[
- int MoveFileExA(
- const char *lpExistingFileName,
- const char *lpNewFileName,
- unsigned long dwFlags
- );
- int GetLastError(void);
- ]]
-
- local MOVEFILE_REPLACE_EXISTING = 1
- local MOVEFILE_WRITE_THROUGH = 8
- local ERROR_FILE_EXISTS = 80
- local ERROR_ALREADY_EXISTS = 183
-
- function glue.replacefile(oldfile, newfile)
- if ffi.C.MoveFileExA(oldfile, newfile, 0) ~= 0 then
- return true
- end
- local err = ffi.C.GetLastError()
- if err == ERROR_FILE_EXISTS or err == ERROR_ALREADY_EXISTS then
- if ffi.C.MoveFileExA(oldfile, newfile,
- bit.bor(MOVEFILE_WRITE_THROUGH, MOVEFILE_REPLACE_EXISTING)) ~= 0
- then
- return true
- end
- err = ffi.C.GetLastError()
- end
- return nil, 'WinAPI error '..err
- end
-
- else
-
- function glue.replacefile(oldfile, newfile)
- return os.rename(oldfile, newfile)
- end
-
- end
-
-end
-
---write a string, number, table or the results of a read function to a file.
---uses binary mode by default. atomic by default.
-function glue.writefile(filename, s, mode, tmpfile)
- local append = mode == 'a' or mode == 'at'
- if tmpfile == nil and not append then
- tmpfile = true --enabled by default.
- end
- if tmpfile then
- if tmpfile == true then
- tmpfile = filename..'.tmp'
- end
- local ok, err = glue.writefile(tmpfile, s, mode, false)
- if not ok then
- return nil, err
- end
- local ok, err = glue.replacefile(tmpfile, filename)
- if not ok then
- os.remove(tmpfile)
- return nil, err
- else
- return true
- end
- end
- local m = append and (mode=='at' and 'a' or 'ab') or (mode=='t' and 'w' or 'wb')
- local f, err = io.open(filename, m)
- if not f then
- return nil, err
- end
- local ok, err = true
- if type(s) == 'table' then
- for i = 1, #s do
- ok, err = f:write(s[i])
- if not ok then break end
- end
- elseif type(s) == 'function' then
- local read = s
- while true do
- ok, err = xpcall(read, debug.traceback)
- if not ok or err == nil then break end
- ok, err = f:write(err)
- if not ok then break end
- end
- else --string or number
- ok, err = f:write(s)
- end
- f:close()
- if not ok then
- if not append then
- os.remove(filename)
- end
- return nil, err
- else
- return true
- end
-end
-
---virtualize the print function.
-function glue.printer(out, format)
- format = format or tostring
- return function(...)
- local n = select('#', ...)
- for i=1,n do
- out(format((select(i, ...))))
- if i < n then
- out'\t'
- end
- end
- out'\n'
- end
-end
-
---dates & timestamps ---------------------------------------------------------
-
---compute timestamp diff. to UTC because os.time() has no option for UTC.
-function glue.utc_diff(t)
- t = t or os.time()
- local ld = os.date('*t', t)
- ld.isdst = false --adjust for DST.
- local ud = os.date('!*t', t)
- local lt = os.time(ld)
- local ut = os.time(ud)
- return lt and ut and os.difftime(lt, ut)
-end
-
---overloading os.time to support UTC and get the date components as separate args.
-function glue.time(utc, y, m, d, h, M, s, isdst)
- if type(utc) ~= 'boolean' then --shift arg#1
- utc, y, m, d, h, M, s, isdst = nil, utc, y, m, d, h, M, s
- end
- if type(y) == 'table' then
- local t = y
- if utc == nil then utc = t.utc end
- y, m, d, h, M, s, isdst = t.year, t.month, t.day, t.hour, t.min, t.sec, t.isdst
- end
- if not y then
- return os.time()
- else
- s = s or 0
- local t = os.time{year = y, month = m or 1, day = d or 1, hour = h or 0,
- min = M or 0, sec = s, isdst = isdst}
- if not t then return nil end
- t = t + s - floor(s)
- local d = 0
- if utc then
- d = glue.utc_diff(t)
- if not d then return nil end
- end
- return t + s - floor(s) + d
- end
-end
-
---get the time at the start of the week of a given time, plus/minus a number of weeks.
-function glue.sunday(utc, t, offset)
- if type(utc) ~= 'boolean' then --shift arg#1
- utc, t, offset = false, utc, t
- end
- local d = os.date(utc and '!*t' or '*t', t)
- return glue.time(false, d.year, d.month, d.day - (d.wday - 1) + (offset or 0) * 7)
-end
-
---get the time at the start of the day of a given time, plus/minus a number of days.
-function glue.day(utc, t, offset)
- if type(utc) ~= 'boolean' then --shift arg#1
- utc, t, offset = false, utc, t
- end
- local d = os.date(utc and '!*t' or '*t', t)
- return glue.time(false, d.year, d.month, d.day + (offset or 0))
-end
-
---get the time at the start of the month of a given time, plus/minus a number of months.
-function glue.month(utc, t, offset)
- if type(utc) ~= 'boolean' then --shift arg#1
- utc, t, offset = false, utc, t
- end
- local d = os.date(utc and '!*t' or '*t', t)
- return glue.time(false, d.year, d.month + (offset or 0))
-end
-
---get the time at the start of the year of a given time, plus/minus a number of years.
-function glue.year(utc, t, offset)
- if type(utc) ~= 'boolean' then --shift arg#1
- utc, t, offset = false, utc, t
- end
- local d = os.date(utc and '!*t' or '*t', t)
- return glue.time(false, d.year + (offset or 0))
-end
-
-local function rel_time(s)
- if s > 2 * 365 * 24 * 3600 then
- return ('%d years'):format(floor(s / (365 * 24 * 3600)))
- elseif s > 2 * 30.5 * 24 * 3600 then
- return ('%d months'):format(floor(s / (30.5 * 24 * 3600)))
- elseif s > 1.5 * 24 * 3600 then
- return ('%d days'):format(floor(s / (24 * 3600)))
- elseif s > 2 * 3600 then
- return ('%d hours'):format(floor(s / 3600))
- elseif s > 2 * 60 then
- return ('%d minutes'):format(floor(s / 60))
- elseif s > 60 then
- return '1 minute'
- else
- return 'seconds'
- end
-end
-
-function glue.timeago(time, from_time)
- local s = os.difftime(from_time or os.time(), time)
- return string.format(s > 0 and '%s ago' or 'in %s', rel_time(math.abs(s)))
-end
-
---size formatting ------------------------------------------------------------
-
-local suffixes = {'k', 'M', 'G', 'T'}
-function glue.kbytes(x, decimals)
- if x > -1024 and x < 1024 then
- return tostring(x)
- end
- local base = ln(x) / ln(1024)
- local suffix = suffixes[floor(base)] or ''
- local fmt = decimals and decimals ~= 0 and '%.'..decimals..'f%s' or '%.0f%s'
- return (fmt):format(1024^(base - floor(base)), suffix)
-end
-
---error handling -------------------------------------------------------------
-
---allocation-free assert() with string formatting.
---NOTE: unlike standard assert(), this only returns the first argument
---to avoid returning the error message and it's args along with it so don't
---use it with functions returning multiple values when you want those values.
-function glue.assert(v, err, ...)
- if v then return v end
- err = err or 'assertion failed!'
- if select('#',...) > 0 then
- err = string.format(err, ...)
- end
- error(err, 2)
-end
-
---pcall with traceback. LuaJIT and Lua 5.2 only.
-local function pcall_error(e)
- return debug.traceback('\n'..tostring(e))
-end
-function glue.pcall(f, ...)
- return xpcall(f, pcall_error, ...)
-end
-
-local function unprotect(ok, result, ...)
- if not ok then return nil, result, ... end
- if result == nil then result = true end --to distinguish from error.
- return result, ...
-end
-
---wrap a function that raises errors on failure into a function that follows
---the Lua convention of returning nil,err on failure.
-function glue.protect(func)
- return function(...)
- return unprotect(pcall(func, ...))
- end
-end
-
---pcall with finally and except "clauses":
--- local ret,err = fpcall(function(finally, except)
--- local foo = getfoo()
--- finally(function() foo:free() end)
--- except(function(err) io.stderr:write(err, '\n') end)
--- emd)
---NOTE: a bit bloated at 2 tables and 4 closures. Can we reduce the overhead?
-local function fpcall(f,...)
- local fint, errt = {}, {}
- local function finally(f) fint[#fint+1] = f end
- local function onerror(f) errt[#errt+1] = f end
- local function err(e)
- for i=#errt,1,-1 do errt[i](e) end
- for i=#fint,1,-1 do fint[i]() end
- return tostring(e) .. '\n' .. debug.traceback()
- end
- local function pass(ok,...)
- if ok then
- for i=#fint,1,-1 do fint[i]() end
- end
- return ok,...
- end
- return pass(xpcall(f, err, finally, onerror, ...))
-end
-
-function glue.fpcall(...)
- return unprotect(fpcall(...))
-end
-
---fcall is like fpcall() but without the protection (i.e. raises errors).
-local function assert_fpcall(ok, ...)
- if not ok then error(..., 2) end
- return ...
-end
-function glue.fcall(...)
- return assert_fpcall(fpcall(...))
-end
-
---modules --------------------------------------------------------------------
-
---create a module table that dynamically inherits another module.
---naming the module returns the same module table for the same name.
-function glue.module(name, parent)
- if type(name) ~= 'string' then
- name, parent = parent, name
- end
- if type(parent) == 'string' then
- parent = require(parent)
- end
- parent = parent or _M
- local parent_P = parent and assert(parent._P, 'parent module has no _P') or _G
- local M = package.loaded[name]
- if M then
- return M, M._P
- end
- local P = {__index = parent_P}
- M = {__index = parent, _P = P}
- P._M = M
- M._M = M
- P._P = P
- setmetatable(P, P)
- setmetatable(M, M)
- if name then
- package.loaded[name] = M
- P[name] = M
- end
- setfenv(2, P)
- return M, P
-end
-
---setup a module to load sub-modules when accessing specific keys.
-function glue.autoload(t, k, v)
- local mt = getmetatable(t) or {}
- if not mt.__autoload then
- local old_index = mt.__index
- local submodules = {}
- mt.__autoload = submodules
- mt.__index = function(t, k)
- --overriding __index...
- if type(old_index) == 'function' then
- local v = old_index(t, k)
- if v ~= nil then return v end
- elseif type(old_index) == 'table' then
- local v = old_index[k]
- if v ~= nil then return v end
- end
- if submodules[k] then
- local mod
- if type(submodules[k]) == 'string' then
- mod = require(submodules[k]) --module
- else
- mod = submodules[k](k) --custom loader
- end
- submodules[k] = nil --prevent loading twice
- if type(mod) == 'table' then --submodule returned its module table
- assert(mod[k] ~= nil) --submodule has our symbol
- t[k] = mod[k]
- end
- return rawget(t, k)
- end
- end
- setmetatable(t, mt)
- end
- if type(k) == 'table' then
- glue.update(mt.__autoload, k) --multiple key -> module associations.
- else
- mt.__autoload[k] = v --single key -> module association.
- end
- return t
-end
-
---portable way to get script's directory, based on arg[0].
---NOTE: the path is not absolute, but relative to the current directory!
---NOTE: for bundled executables, this returns the executable's directory.
-local dir = rawget(_G, 'arg') and arg[0]
- and arg[0]:gsub('[/\\]?[^/\\]+$', '') or '' --remove file name
-glue.bin = dir == '' and '.' or dir
-
---allocation -----------------------------------------------------------------
-
---freelist for Lua tables.
-local function create_table()
- return {}
-end
-function glue.freelist(create, destroy)
- create = create or create_table
- destroy = destroy or glue.noop
- local t = {} --{freed_index -> e}
- local n = 0
- local function alloc()
- local e = t[n]
- if e then
- t[n] = false
- n = n - 1
- end
- return e or create()
- end
- local function free(e)
- destroy(e)
- n = n + 1
- t[n] = e
- end
- return alloc, free
-end
-
---ffi ------------------------------------------------------------------------
-
-if jit then
-
-local ffi = require'ffi'
-
-glue.i8p = ffi.typeof'int8_t*'
-glue.i8a = ffi.typeof'int8_t[?]'
-glue.u8p = ffi.typeof'uint8_t*'
-glue.u8a = ffi.typeof'uint8_t[?]'
-
-glue.i16p = ffi.typeof'int16_t*'
-glue.i16a = ffi.typeof'int16_t[?]'
-glue.u16p = ffi.typeof'uint16_t*'
-glue.u16a = ffi.typeof'uint16_t[?]'
-
-glue.i32p = ffi.typeof'int32_t*'
-glue.i32a = ffi.typeof'int32_t[?]'
-glue.u32p = ffi.typeof'uint32_t*'
-glue.u32a = ffi.typeof'uint32_t[?]'
-
-glue.i64p = ffi.typeof'int64_t*'
-glue.i64a = ffi.typeof'int64_t[?]'
-glue.u64p = ffi.typeof'uint64_t*'
-glue.u64a = ffi.typeof'uint64_t[?]'
-
-glue.f32p = ffi.typeof'float*'
-glue.f32a = ffi.typeof'float[?]'
-glue.f64p = ffi.typeof'double*'
-glue.f64a = ffi.typeof'double[?]'
-
---static, auto-growing buffer allocation pattern (ctype must be vla).
-function glue.buffer(ctype)
- local vla = ffi.typeof(ctype or glue.u8a)
- local buf, len = nil, -1
- return function(minlen)
- if minlen == false then
- buf, len = nil, -1
- elseif minlen > len then
- len = glue.nextpow2(minlen)
- buf = vla(len)
- end
- return buf, len
- end
-end
-
---like glue.buffer() but preserves data on reallocations
---also returns minlen instead of capacity.
-function glue.dynarray(ctype, min_capacity)
- ctype = ctype or glue.u8a
- local buffer = glue.buffer(ctype)
- local elem_size = ffi.sizeof(ctype, 1)
- local buf0, minlen0
- return function(minlen)
- local buf, len = buffer(max(min_capacity or 0, minlen))
- if buf ~= buf0 and buf ~= nil and buf0 ~= nil then
- ffi.copy(buf, buf0, minlen0 * elem_size)
- end
- buf0, minlen0 = buf, minlen
- return buf, minlen
- end
-end
-
-local intptr_ct = ffi.typeof'intptr_t'
-local intptrptr_ct = ffi.typeof'const intptr_t*'
-local intptr1_ct = ffi.typeof'intptr_t[1]'
-local voidptr_ct = ffi.typeof'void*'
-
---x86: convert a pointer's address to a Lua number.
-local function addr32(p)
- return tonumber(ffi.cast(intptr_ct, ffi.cast(voidptr_ct, p)))
-end
-
---x86: convert a number to a pointer, optionally specifying a ctype.
-local function ptr32(ctype, addr)
- if not addr then
- ctype, addr = voidptr_ct, ctype
- end
- return ffi.cast(ctype, addr)
-end
-
---x64: convert a pointer's address to a Lua number or possibly string.
-local function addr64(p)
- local np = ffi.cast(intptr_ct, ffi.cast(voidptr_ct, p))
- local n = tonumber(np)
- if ffi.cast(intptr_ct, n) ~= np then
- --address too big (ASLR? tagged pointers?): convert to string.
- return ffi.string(intptr1_ct(np), 8)
- end
- return n
-end
-
---x64: convert a number or string to a pointer, optionally specifying a ctype.
-local function ptr64(ctype, addr)
- if not addr then
- ctype, addr = voidptr_ct, ctype
- end
- if type(addr) == 'string' then
- return ffi.cast(ctype, ffi.cast(voidptr_ct,
- ffi.cast(intptrptr_ct, addr)[0]))
- else
- return ffi.cast(ctype, addr)
- end
-end
-
-glue.addr = ffi.abi'64bit' and addr64 or addr32
-glue.ptr = ffi.abi'64bit' and ptr64 or ptr32
-
-end --if jit
-
-if bit then
-
-local band, bor, bnot = bit.band, bit.bor, bit.bnot
-
---extract the bool value of a bitmask from a value.
-function glue.getbit(from, mask)
- return band(from, mask) == mask
-end
-
---set a single bit of a value without affecting other bits.
-function glue.setbit(over, mask, yes)
- return bor(yes and mask or 0, band(over, bnot(mask)))
-end
-
-local function bor_bit(bits, k, mask, strict)
- local b = bits[k]
- if b then
- return bit.bor(mask, b)
- elseif strict then
- error(string.format('invalid bit %s', k))
- else
- return mask
- end
-end
-function glue.bor(flags, bits, strict)
- local mask = 0
- if type(flags) == 'number' then
- return flags --passthrough
- elseif type(flags) == 'string' then
- for k in flags:gmatch'[^%s]+' do
- mask = bor_bit(bits, k, mask, strict)
- end
- elseif type(flags) == 'table' then
- for k,v in pairs(flags) do
- k = type(k) == 'number' and v or k
- mask = bor_bit(bits, k, mask, strict)
- end
- else
- error'flags expected'
- end
- return mask
-end
-
-end --if bit
-
---buffered I/O ---------------------------------------------------------------
-
-if jit then
-
-local ffi = require'ffi'
-
---make a `write(buf, sz)` that appends data to a dynarray accumulator.
-function glue.dynarray_pump(dynarr)
- dynarr = dynarr or glue.dynarray()
- local i = 0
- local function write(src, len)
- local dst = dynarr(i + len)
- ffi.copy(dst + i, src, len or #src)
- i = i + len
- return len
- end
- local function collect()
- return dynarr(i)
- end
- return write, collect
-end
-
---unlike a pump which copies the user's buffer, a loader provides a buffer
---for the user to fill up and mark (a portion of it) as filled.
-function glue.dynarray_loader(dynarr)
- dynarr = dynarr or glue.dynarray()
- local i = 0
- local function get(sz)
- return dynarr(i + sz) + i, sz
- end
- local function put(len)
- i = i + len
- end
- local function collect()
- return dynarr(i)
- end
- return get, put, collect
-end
-
---load up a dynarray with repeated reads given a `read(self, buf, sz, expires)` method.
-function glue.readall(read, self, ...)
- local get, put, collect = glue.dynarray_loader()
- while true do
- local buf, sz = get(4096)
- local len, err = read(self, buf, sz, ...)
- if not len then return nil, err, collect() end --short read
- if len == 0 then return collect() end --eof
- put(len)
- end
-end
-
-function glue.buffer_reader(p, n)
- return function(buf, sz)
- if p == nil then return p, n end
- sz = math.min(n, sz)
- if sz == 0 then return nil, 'eof' end
- ffi.copy(buf, p, sz)
- p = p + sz
- n = n - sz
- return sz
- end
-end
-
-end --if jit
-
-return glue
diff --git a/lib/glue.md b/lib/glue.md
deleted file mode 100644
index 5fe4559..0000000
--- a/lib/glue.md
+++ /dev/null
@@ -1,1341 +0,0 @@
----
-tagline: Ideal for wood and paper
-read this at: http://luapower.com/glue
----
-
-## `local glue = require'glue'`
-
-## API Summary
------------------------------------------------------------------- ---------------------------------------------------------
-__types__
-`glue.isstr` is string
-`glue.isnum` is number
-`glue.isint` is integer (includes 1/0 and -1/0)
-`glue.istab` is table
-`glue.isfunc` is function
-__math__
-`glue.round(x[, p]) -> y` round x to nearest integer or multiple of `p` (half up)
-`glue.snap(x[, p]) -> y` synonym for glue.round
-`glue.floor(x[, p]) -> y` round x down to nearest integer or multiple of `p`
-`glue.ceil(x[, p]) -> y` round x up to nearest integer or multiple of `p`
-`glue.clamp(x, min, max) -> y` clamp x in range
-`glue.lerp(x, x0, x1, y0, y1) -> y` linear interpolation
-`glue.sign(x) -> 1|0|-1` sign
-`glue.strict_sign(x) -> 1|-1` strict sign
-`glue.nextpow2(x) -> y` next power-of-2 number
-`glue.repl(x, v, r) -> x` replace v with r in x
-`glue.random_string(n) -> s` generate random string of length `n`
-`glue.uuid() -> s` generate random UUID v4
-__varargs__
-`glue.pack(...) -> t` pack varargs
-`glue.unpack(t, [i] [,j]) -> ...` unpack varargs
-__tables__
-`glue.empty` empty r/o table
-`glue.count(t[, maxn]) -> n` number of keys in table
-`glue.index(t) -> dt` switch keys with values
-`glue.keys(t[,sorted|cmp]) -> dt` make a list of all the keys
-`glue.sortedkeys(t[,cmp]) -> dt` make a sorted list of all keys
-`glue.sortedpairs(t [,cmp]) -> iter() -> k, v` like pairs() but in key order
-`glue.update(dt, t1, ...) -> dt` merge tables - overwrites keys
-`glue.merge(dt, t1, ...) -> dt` merge tables - no overwriting
-`glue.attr(t, k1 [,v])[k2] = v` autofield pattern
-__arrays__
-`glue.extend(dt, t1, ...) -> dt` extend an array
-`glue.append(dt, v1, ...) -> dt` append non-nil values to an array
-`glue.shift(t, i, n) -> t` shift array elements
-`glue.map(t, field|f,...) -> t` map f over pairs of t or select a column from an array of records
-`glue.imap(t, field|f,...) -> t` map f over ipairs of t or select a column from an array of records
-`glue.indexof(v, t, [i], [j]) -> i` scan array for value
-`glue.binsearch(v, t, [cmp], [i], [j]) -> i` binary search in sorted array
-`glue.sortedarray([sa]) -> sa` stay-sorted array with insertion and removal in O(log n)
-`glue.reverse(t, [i], [j]) -> t` reverse array in place
-__strings__
-`glue.gsplit(s,sep[,start[,plain]]) -> iter() -> e[,captures...]` split a string by a pattern
-`glue.split(s,sep[,start[,plain]]) -> {s1,...}` split a string by a pattern
-`glue.names('name1 ...') -> {'name1', ...}` split a string by whitespace
-`glue.capitalize(s) -> s` capitalize the first letter of every word in string
-`glue.lines(s, [opt], [init]) -> iter() -> s, i, j, k` iterate the lines of a string
-`glue.outdent(s, [indent]) -> s, indent` outdent/reindent text based on first line's indentation
-`glue.lineinfo(s, [i]) -> line, col` return text position from byte position
-`glue.trim(s) -> s` remove padding
-`glue.pad(s, n, [c], dir) -> s` pad string
-`glue.lpad(s, n, [c]) -> s` left-pad string
-`glue.rpad(s, n, [c]) -> s` right-pad string
-`glue.esc(s [,mode]) -> pat` escape magic pattern characters
-`glue.tohex(s|n [,upper]) -> s` string to hex
-`glue.fromhex(s[, isvalid]) -> s` hex to string
-`glue.starts(s, prefix) -> t|f` find if string `s` starts with string `prefix`
-`glue.ends(s, suffix) -> t|f` find if string `s` ends with string `suffix`
-`glue.subst(s, t) -> s` string interpolation of `{foo}` occurences
-`glue.catargs(sep, ...) -> s` concat non-nil args
-__iterators__
-`glue.collect([i,] iterator) -> t` collect iterated values into an array
-__stubs__
-`glue.pass(...) -> ...` does nothing, returns back all arguments
-`glue.noop(...)` does nothing, returns nothing
-__caching__
-`glue.memoize(f, [narg], [weak]) -> f` memoize pattern
-`glue.memoize_multiret(f, [narg], [weak]) -> f` memoize for multiple-return-value functions
-`glue.tuples([narg], [weak]) -> f(...) -> t` create a tuple space
-`glue.weaktuples([narg]) -> f(...) -> t` create a weak tuple space
-`glue.tuple(...) -> t` create a tuple in a global weak tuple space
-__objects__
-`glue.inherit(t, parent) -> t` set or clear inheritance
-`glue.object([super][, t], ...) -> t` create a class or object (see description)
-`glue.before(class, method_name, f)` call f at the beginning of a method
-`glue.after(class, method_name, f)` call f at the end of a method
-`glue.override(class, method_name, f)` override a method
-`glue.gettersandsetters([getters], [setters], [super]) -> mt` create a metatable that supports virtual properties
-__os__
-`glue.win` true if platform is Windows
-__i/o__
-`glue.canopen(filename[, mode]) -> filename | nil` check if a file exists and can be opened
-`glue.readfile(filename[, format][, open]) -> s | nil, err` read the contents of a file into a string
-`glue.readpipe(cmd[,format][, open]) -> s | nil, err` read the output of a command into a string
-`glue.writefile(filename, s|t|read, [format], [tmpfile])` write data to file safely
-`glue.printer(out[, format]) -> f` virtualize the print() function
-__time__
-`glue.time([utc, ][t]) -> ts` like `os.time()` with optional UTC and date args
-`glue.time([utc, ][y, [m], [d], [h], [min], [s], [isdst]]) -> ts` like `os.time()` with optional UTC and date args
-`glue.utc_diff([t]) -> seconds` seconds to UTC
-`glue.day([utc, ][ts], [plus_days]) -> ts` timestamp at day's beginning from `ts`
-`glue.month([utc, ][ts], [plus_months]) -> ts` timestamp at month's beginning from `ts`
-`glue.year([utc, ][ts], [plus_years]) -> ts` timestamp at year's beginning from `ts`
-`glue.timeago(ts[, from_ts]) -> s` format relative time
-__sizes__
-`glue.kbytes(x [,decimals]) -> s` format byte size in k/M/G/T-bytes
-__errors__
-`glue.assert(v [,message [,format_args...]]) -> v` assert with error message formatting
-`glue.protect(func) -> protected_func` wrap an error-raising function
-`glue.pcall(f, ...) -> true, ... | false, traceback` pcall with traceback
-`glue.fpcall(f, ...) -> result | nil, traceback` coding with finally and except (protected)
-`glue.fcall(f, ...) -> result` coding with finally and except
-__modules__
-`glue.module([name, ][parent]) -> M` create a module
-`glue.autoload(t, submodules) -> M` autoload table keys from submodules
-`glue.autoload(t, key, module|loader) -> t` autoload table keys from submodules
-`glue.bin` get the script's directory
-`glue.luapath(path [,index [,ext]])` insert a path in package.path
-`glue.cpath(path [,index])` insert a path in package.cpath
-__allocation__
-`glue.freelist([create], [destroy]) -> alloc, free` freelist allocation pattern
-`glue.buffer(ctype) -> alloc(minlen) -> buf,capacity` auto-growing buffer
-`glue.dynarray(ctype[,cap]) -> alloc(minlen|false) -> buf, minlen` auto-growing buffer that preserves data
-`glue.dynarray_pump([dynarray]) -> write(), collect()` make a buffer with a `write()` API for writing into
-`glue.dynarray_loader([dynarray]) -> get(), put(), collect()` make a buffer with a `get()/put()` API for writing into
-`glue.readall(read, self, ...) -> buf, len` repeat read based on a `read` function
-`glue.buffer_reader(buf, len) -> read` make a read function that consumes a buffer
-__ffi__
-`glue.addr(ptr) -> number | string` store pointer address in Lua value
-`glue.ptr([ctype, ]number|string) -> ptr` convert address to pointer
-`glue.getbit(val, mask) -> true|false` get the value of a single bit from an integer
-`glue.setbit(val, mask, bitval) -> val` set the value of a single bit from an integer
-`glue.bor(flags, bits, [strict]) -> mask` `bit.bor()` that takes a string or table
------------------------------------------------------------------- ---------------------------------------------------------
-
-## Math
-
-### `glue.round(x[, p]) -> y`
`glue.snap(x[, p]) -> y`
-
-Round a number towards nearest integer or multiple of `p`.
-Implemented as `math.floor(x / p + .5) * p`.
-Rounds half-up (i.e. it returns `-1` for `-1.5`).
-Works with numbers up to `+/-2^52`.
-It's not dead accurate as it returns eg. `1` instead of `0`
-for `0.49999999999999997` (the number right before `0.5`) which is < `0.5`.
-
-## `glue.floor(x[, p]) -> y`
-
-Round a number towards nearest smaller integer or multiple of `p`.
-Implemented as `math.floor(x / p) * p`.
-
-## `glue.ceil(x[, p]) -> y`
-
-Round a number towards nearest larger integer or multiple of `p`.
-Implemented as `math.ceil(x / p) * p`.
-
-### `glue.clamp(x, min, max)`
-
-Clamp a value in range. Implemented as `math.min(math.max(x, min), max)`,
-so if `max < min`, the result is `max`.
-
-### `glue.lerp(x, x0, x1, y0, y1) -> y`
-
-Linear interpolation, i.e. linearly project `x` in `x0..x1` range to
-the `y0..y1` range.
-
-### `glue.sign(x) -> 1|0|-1`
-
-Return sign of `x`.
-
-### `glue.strict_sign(x) -> 1|-1`
-
-Return strict sign of `x`.
-
-### `glue.nextpow2(x) -> y`
-
-Find the smallest `n` for which `x <= 2^n`.
-
-### `glue.repl(x, v, r) -> x`
-
-If x == v, return r, otherwise return x.
-
-### `glue.random_string(n) -> s`
-
-Generate random string of length `n`.
-
-### `glue.uuid() -> s`
-
-Generate random UUID (v4).
-
-Don't forget to seed the randomizer first, eg. with
-`math.randomseed(require'time'.clock())` or what have you.
-
-------------------------------------------------------------------------------
-
-## Varargs
-
-### `glue.pack(...) -> t`
-
-Pack varargs. Implemented as `n = select('#', ...), ...}`.
-
-### `glue.unpack(t,[i][,j]) -> ...`
-
-Unpack varargs. Implemented as `unpack(t, i or 1, j or t.n or #t)`.
-
-------------------------------------------------------------------------------
-
-## Tables
-
-### `glue.count(t[, maxn]) -> n`
-
-Count the keys in a table, optionally up to `maxn`.
-
-------------------------------------------------------------------------------
-
-### `glue.index(t) -> dt`
-
-Switch table keys with values.
-
-#### Examples
-
-Extract a rfc850 date from a string. Use lookup tables for weekdays and months.
-
-```lua
-local weekdays = glue.index{'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'}
-local months = glue.index{'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'}
-
---weekday "," SP 2DIGIT "-" month "-" 2DIGIT SP 2DIGIT ":" 2DIGIT ":" 2DIGIT SP "GMT"
---eg. Sunday, 06-Nov-94 08:49:37 GMT
-function rfc850date(s)
- local w,d,mo,y,h,m,s = s:match'([A-Za-z]+), (%d+)%-([A-Za-z]+)%-(%d+) (%d+):(%d+):(%d+) GMT'
- d,y,h,m,s = tonumber(d),tonumber(y),tonumber(h),tonumber(m),tonumber(s)
- w = assert(weekdays[w])
- mo = assert(months[mo])
- if y then y = y + (y > 50 and 1900 or 2000) end
- return {wday = w, day = d, year = y, month = mo, hour = h, min = m, sec = s}
-end
-
-for k,v in pairs(rfc850date'Sunday, 06-Nov-94 08:49:37 GMT') do
- print(k,v)
-end
-```
-
-Output
-
- day 6
- sec 37
- wday 1
- min 49
- year 1994
- month 11
- hour 8
-
-
-Copy-paste a bunch of defines from a C header file and create an inverse
-lookup table to find the name of a value at runtime.
-
-```lua
---from ibase.h
-info_end_codes = {
- isc_info_end = 1, --normal ending
- isc_info_truncated = 2, --receiving buffer too small
- isc_info_error = 3, --error, check status vector
- isc_info_data_not_ready = 4, --data not available for some reason
- isc_info_svc_timeout = 64, --timeout expired
-}
-info_end_code_names = glue.index(info_end_codes)
-print(info_end_code_names[64])
-```
-
-Output
-
- isc_info_svc_timeout
-
-------------------------------------------------------------------------------
-
-### `glue.keys(t[,sorted|cmp]) -> dt`
`glue.sortedkeys(t[,cmp]) -> dt`
-
-Make an array of all the keys of `t`, optionally sorted. The second arg
-can be `true`, `'asc'`, `'desc'` or a comparison function.
-
-#### Examples
-
-An API expects an array of things but you have them as keys in a table because
-you are indexing something on them.
-
-For instance, you have a table of the form `{socket = thread}` but
-`socket.select` wants an array of sockets.
-
-------------------------------------------------------------------------------
-
-### `glue.sortedpairs(t[,cmp]) -> iter() -> k,v`
-
-Like pairs() but in key order.
-
-The implementation creates a temporary table to sort the keys in.
-
-------------------------------------------------------------------------------
-
-### `glue.update(dt,t1,...) -> dt`
-
-Update a table with elements of other tables, overwriting any existing keys.
-
- * falsey arguments are skipped.
-
-#### Examples
-
-Create an options table by merging the options received as an argument
-(if any) over the default options.
-
-```lua
-function f(opts)
- opts = glue.update({}, default_opts, opts)
-end
-```
-
-Shallow table copy:
-
-```lua
-t = glue.update({}, t)
-```
-
-Static multiple inheritance:
-
-```lua
-C = glue.update({}, A, B)
-```
-
-------------------------------------------------------------------------------
-
-### `glue.merge(dt,t1,...) -> dt`
-
-Update a table with elements of other tables skipping on any existing keys.
-
- * falsey arguments are skipped.
-
-#### Examples
-
-Normalize a data object with default values:
-
-```lua
-glue.merge(t, defaults)
-```
-
-------------------------------------------------------------------------------
-
-### `glue.attr(t,k1[,v])[k2] = v`
-
-Idiom for `t[k1][k2] = v` with auto-creating of `t[k1]` if not present.
-
-------------------------------------------------------------------------------
-
-## Arrays
-
-### `glue.extend(dt,t1,...) -> dt`
-
-Extend an array with the elements of other arrays.
-
- * falsey arguments are skipped.
- * array elements are the ones from 1 to `#dt`.
-
-#### Uses
-
-Accumulating values from multiple array sources.
-
-------------------------------------------------------------------------------
-
-### `glue.append(dt,v1,...) -> dt`
-
-Append non-nil arguments to an array.
-
-#### Uses
-
-Appending an object to a flattened array of arrays (eg. appending a path
-element to a 2d path).
-
-------------------------------------------------------------------------------
-
-### `glue.shift(t,i,n) -> t`
-
-Shift all the array elements starting at index `i`, `n` positions to the left
-or further to the right.
-
-For a positive `n`, shift the elements further to the right, effectively
-creating room for `n` new elements at index `i`. When `n` is 1, the effect
-is the same as for `table.insert(t, i, t[i])`. The old values at index `i`
-to `i+n-1` are preserved, so `#t` still works after the shifting.
-
-For a negative `n`, shift the elements to the left, effectively removing
-`n` elements at index `i`. When `n` is -1, the effect is the same as for
-`table.remove(t, i)`.
-
-#### Uses
-
-Removing a portion of an array or making room for more elements inside the array.
-
-------------------------------------------------------------------------------
-
-### `glue.map(t, field|f,...) -> t`
-
-Map function `f(k, v, ...) -> v1` over the key-value pairs of `t` or.
-
-If `f` is not a function, then the values of `t` must be themselves tables,
-in which case `f` is a key to pluck from those tables. Plucked functions
-are called as methods and their result is selected instead. This allows eg.
-calling a method for each element in a table of objects and collecting
-the results in a table.
-
-------------------------------------------------------------------------------
-
-### `glue.imap(t, field|f,...) -> t`
-
-Map function `f(v, ...) -> v1` over the array elements of `t` taken to be
-from `1` up to `t.n or #t`.
-
-If `f` is not a function, then the values of `t` must be themselves tables,
-in which case `f` is a key to pluck from those tables. Plucked functions
-are called as methods and their result is selected instead. This allows eg.
-calling a method for each element in an array of objects and collecting
-the results in an array.
-
-------------------------------------------------------------------------------
-
-### `glue.indexof(v, t, [i], [j]) -> i`
-
-Scan an array for a value and if found, return the index.
-
-__NOTE:__ Works on ffi arrays too if `i` and `j` are provided.
-
-------------------------------------------------------------------------------
-
-### `glue.binsearch(v, t, [cmp], [i], [j]) -> i`
-
-Return the smallest index whereby inserting the value `v` in sorted array `t`
-will keep `t` sorted i.e. `t[i-1] < v` and `t[i] >= v`. Return `nil` if `v`
-is larger than the largest value or if `t` is empty.
-
-The comparison function `cmp` is called as `cmp(t, i, v)` and must return
-`true` when `t[i] < v`. Built-in functions are also available by passing
-one of `'<'`, `'>'`, `'<='`, `'>='`.
-
-__TIP:__ Use a `cmp` that returns `true` when `t[i] > v` to search in a
-reverse-sorted array (i.e. use `'>'`).
-
-__TIP:__ Use a `cmp` that returns `true` when `t[i] <= v` to get the *largest*
-index (as opposed to the *smallest* index) that will keep `t` sorted when
-inserting `v`, i.e. `t[i-1] <= v` and `t[i] > v`.
-
-__NOTE:__ Works on ffi arrays too if `i` and `j` are provided.
-
-------------------------------------------------------------------------------
-
-### `glue.sortedarray([sa]) -> sa`
-
-Creates an array that stays sorted with insertion, searching and removal
-in O(log n) leveraging binary search.
-
- * if given an existing `sa` to be wrapped, it must be already sorted.
- * `sa.cmp` is used for `cmp` in `binarysearch()`.
- * use `sa:push(v)` to add values.
- * use `sa:find(v) -> i|nil` to look up values.
- * use `sa:remove_value(v) -> v|nil` to find and remove a value.
-
-------------------------------------------------------------------------------
-
-### `glue.reverse(t, [i], [j]) -> t`
-
-Reverse an array in-place and return the input arg.
-
-__NOTE:__ Works on ffi arrays too if `i` and `j` are provided.
-
-------------------------------------------------------------------------------
-
-## Strings
-
-### `glue.gsplit(s,sep[,start[,plain]]) -> iter() -> e[,captures...]`
-
-### `glue.split(s,sep[,start[,plain]]) -> {s1,...}`
-
-Split a string by a separator pattern (or plain string) and iterate over
-the elements.
-
- * if sep is "" return the entire string in one iteration
- * if s is "" return s in one iteration
- * empty strings between separators are always returned,
- eg. `glue.gsplit(',', ',')` produces 2 empty strings
- * captures are allowed in sep and they are returned after the element,
- except for the last element for which they don't match (by definition).
-
-#### Examples
-
-```lua
-for s in glue.gsplit('Spam eggs spam spam and ham', '%s*spam%s*') do
- print('"'..s..'"')
-end
-
-> "Spam eggs"
-> ""
-> "and ham"
-```
-
-------------------------------------------------------------------------------
-
-### `glue.names('name1 ...') -> {'name1', ...}`
-
-Split a string by whitespace. Unlike `glue.split(s, '%s+')`, it ignores
-resulting empty elements. Also, non-string args pass through.
-
-------------------------------------------------------------------------------
-
-### `glue.capitalize(s) -> s`
-
-Capitalize the first letter of every word in string.
-
-------------------------------------------------------------------------------
-
-### `glue.lines(s, [opt], [init]) -> iter() -> s, i, j, k`
-
-Iterate the lines of a string. For each line it returns the line contents,
-the content-start, content-end and the next-content-start indices.
-
- * the lines are split at `\r\n`, `\r` and `\n` markers.
- * the line ending markers are included or excluded depending on the second
- arg, which can be `*L` (include line endings; default) or `*l` (exclude).
- * if the string is empty or doesn't contain a line ending marker, it is
- iterated once.
- * if the string ends with a line ending marker, one more empty string is
- iterated.
- * `init` tells it where to start parsing (default is 1).
-
-------------------------------------------------------------------------------
-
-### `glue.outdent(s, [indent]) -> s, indent`
-
-Remove spaces/tabs indentation of multi-line text based on the indentation
-of the first line. If a subsequent line is less indented than the first line,
-returns the original string. If `indent` given, it is prepended to each line.
-
-------------------------------------------------------------------------------
-
-### `glue.lineinfo(s, [i]) -> line, col`
-
-Given a byte position in a text, return the text position. If `i` is not
-given, returns a function `f(i)` that is faster on repeat calls.
-
-------------------------------------------------------------------------------
-
-### `glue.trim(s) -> s`
-
-Remove whitespace (defined as Lua pattern `"%s"`) from the beginning and end of a string.
-
-------------------------------------------------------------------------------
-
-### `glue.pad(s, n, [c], dir) -> s`
`glue.lpad(s, n, [c]) -> s`
`glue.rpad(s, n, [c]) -> s`
-
-Pad a string `s` to length `n` using char `c` (which defaults to `' '`)
-on its right (dir = 'r') or left (dir = 'l').
-
-------------------------------------------------------------------------------
-
-### `glue.esc(s[,mode]) -> pat`
-
-Escape magic characters of the string `s` so that it can be used as a pattern
-to string matching functions.
-
- * the optional argument `mode` can have the value `"*i"` (for case
- insensitive), in which case each alphabetical character in `s` will also be
- escaped as `"[aA]"` so that it matches both its lowercase and uppercase
- variants.
- * escapes embedded zeroes as the `%z` pattern.
-
-#### Uses
-
- * workaround for lack of pattern syntax for "this part of a match is an
- arbitrary string"
- * workaround for lack of a case-insensitive flag in pattern matching
- functions
-
-------------------------------------------------------------------------------
-
-### `glue.tohex(s|n[,upper]) -> s`
-
-Convert a binary string or a Lua number to its hex representation.
-
- * lowercase by default
- * uppercase if the arg `upper` is truthy
- * numbers must be in the unsigned 32 bit integer range
-
-------------------------------------------------------------------------------
-
-### `glue.fromhex(s[, isvalid]) -> s`
-
-Convert a hex string to its binary representation. Returns `nil` on invalid
-input unless `isvalid` is `true` which makes it raise on invalid input.
-
-------------------------------------------------------------------------------
-
-### `glue.starts(s, prefix) -> t|f`
-
-Find if string `s` starts with `prefix`. Implemented as `s:sub(1, #p) == p`
-which is 5x faster than `s:find'^...'` in LuaJIT 2.1 with JIT on (and about
-the same with jit off).
-
-------------------------------------------------------------------------------
-
-### `glue.ends(s, suffix) -> t|f`
-
-Find if string `s` ends with `suffix`.
-
-------------------------------------------------------------------------------
-
-### `glue.subst(s, t) -> s`
-
-Replace all `{foo}` occurences within `s` with `t.foo`.
-
-------------------------------------------------------------------------------
-
-### `glue.catargs(sep, ...) -> s`
-
-Concat args, skipping `nil` ones. Returns `nil` on zero non-nil args.
-
-------------------------------------------------------------------------------
-
-## Iterators
-
-### `glue.collect([i,]iterator) -> t`
-
-Iterate an iterator and collect its i'th return value of every step into an array.
-
- * i defaults to 1
-
-#### Examples
-
-Implementation of `keys()` and `values()` in terms of `collect()`
-
-```lua
-keys = function(t) return glue.collect(pairs(t)) end
-values = function(t) return glue.collect(2,pairs(t)) end
-```
-
-Collecting string matches:
-
-```lua
-s = 'a,b,c,'
-t = glue.collect(s:gmatch'(.-),')
-for i=1,#t do print(t[i]) end
-
-> a
-> b
-> c
-```
-
-------------------------------------------------------------------------------
-
-## Stubs
-
-### `glue.pass(...) -> ...`
-
-The identity function. Does nothing, returns back all arguments.
-
-#### Uses
-
-Default value for optional callback arguments:
-
-```lua
-function urlopen(url, callback, errback)
- callback = callback or glue.pass
- errback = errback or glue.pass
- ...
- callback()
-end
-```
-
-### `glue.noop()`
-
-Does nothing. Returns nothing.
-
-------------------------------------------------------------------------------
-
-## Caching
-
-### `glue.memoize(f, [narg], [weak]) -> f`
-
-### `glue.memoize_multiret(f, [narg], [weak]) -> f`
-
-Memoization for functions with any number of arguments. `memoize()` supports
-functions with _one return value_. `memoize_multiret()` supports any function.
-Both support `nil` and `NaN` args and retvals.
-
-Memoization guarantees to only call the original function _once_ for the same
-combination of arguments.
-
-Special attention is given to the vararg part of the function, if any. For
-instance, for a function `f(x, y, ...)`, calling `f(1)` is considered to be
-the same as calling `f(1, nil)`, but calling `f(1, nil)` is not the same as
-calling `f(1, nil, nil)`.
-
-The optional `narg` argument fixates the function to always take exactly
-`narg` args regardless of how the function was defined.
-
-The optional `weak` argument makes the cache of returned values weak and is
-useful for caching objects that are pinned elsewere without leaking memory.
-Using this flag requires that the function to be memoized returns heap
-objects only and always!
-
-### `glue.tuples([narg], [weak]) -> f(...) -> t`
-
-### `glue.weaktuples([narg]) -> f(...) -> t`
-
-Create a tuple space, which is a function that returns the same identity `t`
-for the same list of arguments. It is implemented as:
-
-```lua
-local tuple_mt = {__call = glue.unpack}
-function glue.tuples(...)
- return glue.memoize(function(...)
- return setmetatable(glue.pack(...), tuple_mt)
- end, ...)
-end
-```
-Tuples are immutable lists that can be used as table keys because they have
-value semantics since the tuple constructor returns the same identity for
-the exact same list of identities.
-
-The result tuple can be expanded back by calling it: `t() -> args...`.
-
-> __NOTE:__ Tuple elements are indexed internally with a hash tree.
-Creating a tuple thus takes N hash lookups and M table creations, where N+M
-is the number of elements in the tuple. Lookup time depends on how dense the
-tree is on the search path, which depends on how many existing tuples share
-a first sequence of elements with the tuple being created. In particular,
-creating tuples out of all permutations of a certain set of values hits the
-worst case for lookup time, but creates the minimum amount of tables relative
-to the number of tuples.
-
-### `glue.tuple([narg]) -> t`
-
-Create a tuple in a default global weak tuple space.
-
-------------------------------------------------------------------------------
-
-## Objects
-
-### `glue.inherit(t, parent) -> t`
`glue.inherit(t, nil) -> t`
-
-Set a table to inherit attributes from a parent table, or clear inheritance.
-
-If the table has no metatable and inheritance has to be set, not cleared,
-then make it one.
-
-#### Examples
-
-Logging mixin:
-
-```lua
-AbstractLogger = glue.inherit({}, function(t,k) error('abstract '..k) end)
-NullLogger = glue.inherit({log = function() end}, AbstractLogger)
-PrintLogger = glue.inherit({log = function(self,...) print(...) end}, AbstractLogger)
-
-HttpRequest = glue.inherit({
- perform = function(self, url)
- self:log('Requesting', url, '...')
- ...
- end
-}, NullLogger)
-
-LoggedRequest = glue.inherit({log = PrintLogger.log}, HttpRequest)
-
-LoggedRequest:perform'http://lua.org/'
-
-> Requesting http://lua.org/ ...
-```
-
-Defining a module in Lua 5.2
-
-```lua
-_ENV = glue.inherit({},_G)
-...
-```
-
-To get the effect of static (single or multiple) inheritance, use `glue.update`.
-
-When setting inheritance, you can pass in a function.
-
-Unlike `glue.object`, this doesn't add any keys to the object.
-
-------------------------------------------------------------------------------
-
-### `glue.object([super][, t], ...) -> t`
-
-Create a class or object from `t` (which defaults to `{}`) by setting `t`
-as its own metatable, setting `t.__index` to `super` and `t.__call` to
-`super.__call`. Extra args are passed to `glue.update(self, ...)`.
-This simple object model has the following qualities:
-
- * the implementation is only 4 LOC (14 LOC if extra args are used) and can
- thus be copy-pasted into any module to avoid a dependency on the glue library.
- * funcall-style instantiation with `t(...)` which calls `t:__call(...)`.
- * small memory footprint (3 table slots and no additional tables).
- * subclassing from instances is allowed (prototype-based inheritance).
- * `glue.object` can serve as a stub class/instance constructor:
- `t.__call = glue.object` (`t.new = glue.object` works too).
- * a separate constructor to be used only for subclassing can be made with
- the same pattern: `t.subclass = glue.object`.
- * virtual classes (aka dependency injection, aka nested inner classes
- whose fields and methods can be overridden by subclasses of the outer
- class): composite objects which need to instantiate other objects can be
- made extensible by exposing those objects' classes as fields of the
- container class with `container_class.inner_class = inner_class` and
- instantiating with `self.inner_class(...)` so that replacing `inner_class`
- in a sub-class of `container_class` is possible. Moreso, instantiation with
- `self:inner_class(...)` (so with a colon) passes the container object to
- `inner_class`'s constructor automatically which allows referencing the
- container object from the inner object.
- * overriding syntax sugar so that the super class need not be referenced
- explicitly when overriding can be incorporated into the base class with
- `base.override = glue.override`.
-
-------------------------------------------------------------------------------
-
-### `glue.before(class, method_name, f)`
-
-Modify a method such that it calls `f` at the beginning. `f` receives all
-the arguments passed to the method. `f`'s results are discarded.
-
-Usage:
-
-```lua
-glue.before(foo, 'bar', function(self, ...)
- ...
-end)
-```
-
-Alternatively,
-
-```lua
-foo.before = glue.before
-foo:before('bar', function(self, ...)
- ...
-end)
-```
-------------------------------------------------------------------------------
-
-### `glue.after(class, method_name, f)`
-
-Modify a method such that it calls `f` at the end. `f` receives all the
-arguments passed to the method. The modified method returns what `f` returns.
-
-Usage:
-
-```lua
-glue.after(foo, 'bar', function(self, ...)
- ...
-end)
-```
-
-Alternatively,
-
-```lua
-foo.after = glue.after
-foo:after('bar', function(self, ...)
- ...
-end)
-```
-------------------------------------------------------------------------------
-
-### `glue.override(class, method_name, f)`
-
-Override a method such that the new implementation only calls `f` as
-`f(inherited, self, ...)` where `inherited` is the old implementation.
-`f` receives all the method arguments and the method returns what `f` returns.
-
-Usage:
-
-```lua
-glue.override(foo, 'bar', function(inherited, self, ...)
- ...
- local ret = inherited(self, ...)
- ...
-end)
-```
-
-Alternatively,
-
-```lua
-foo.override = glue.override
-foo:override('bar', function(inherited, self, ...)
- ...
- local ret = inherited(self, ...)
- ...
-end)
-```
-------------------------------------------------------------------------------
-
-### `glue.gettersandsetters([getters], [setters], [super]) -> mt`
-
-Return a metatable that supports virtual properties with getters and setters.
-Can be used with setmetatable() and ffi.metatype(). `super` is for preserving
-the functionality of `__index` while `__index` is being used for getters.
-
-------------------------------------------------------------------------------
-
-## I/O
-
-### `glue.canopen(file[, mode]) -> filename | nil`
-
-Checks whether a file exists and it's available for reading or writing.
-The `mode` arg is the same as for [io.open] and defaults to 'rb'.
-
-------------------------------------------------------------------------------
-
-### `glue.readfile(filename[,format][,open]) -> s | nil, err`
-
-Read the contents of a file into a string.
-
- * `format` can be `"t"` in which case the file will be read in text mode
- (default is binary mode).
- * `open` is the file open function which defaults to `io.open`.
-
-------------------------------------------------------------------------------
-
-### `glue.readpipe(cmd[,format][,open]) -> s | nil, err`
-
-Read the output of a command into a string.
-The options are the same as for `glue.readfile`.
-
-------------------------------------------------------------------------------
-
-### `glue.replacefile(oldpath, newpath)`
-
-Move or rename a file. If `newpath` exists and it's a file, it is replaced
-by the old file atomically. The operation can still fail under many
-circumstances like if `newpath` is a directory or if the files are
-in different filesystems or if `oldpath` is missing or locked, etc.
-
-For consistent behavior across OSes, both paths should be absolute paths
-or just filenames.
-
-On LuaJIT, this is implemented based on `MoveFileExA` on Windows.
-
-------------------------------------------------------------------------------
-
-### `glue.writefile(filename,s|t|read,[format],[tmpfile]) -> ok, err`
-
-Write the contents of a string, table or iterator to a file.
-
- * the contents can be given as a string, an array of strings, or a function
- that returns a string or `nil` to signal end-of-stream.
- * `format` can be `"t"` in which case the file will be written in text mode
- (default is binary mode). It can also be `"a"` or `"at"` for appending.
- * `tmpfile` enables atomic saving via a temporary file (enabled by default)
- which is then renamed to `filename` and if writing or renaming fails the
- temp file is removed and `filename` is not touched (and if the program is
- killed while writing, you get a stale temp file but no data corruption).
- If `tmpfile` is false and writing fails then `filename` is removed (and if
- the program is killed while writing, you get a partially written file).
-
-------------------------------------------------------------------------------
-
-### `glue.printer(out[, format]) -> f`
-
-Create a `print()`-like function which uses the function `out` to output
-its values and uses the optional `format` to format each value. For instance
-`glue.printer(io.write, tostring)` returns a function which behaves like
-the standard `print()` function.
-
-------------------------------------------------------------------------------
-
-### `glue.time([utc, ][t]) -> ts`
`glue.time([utc, ][year, [month], [day], [hour], [min], [sec], [isdst]]) -> ts`
-
-Like `os.time()` but considers the arguments to be in UTC if either `utc`
-or `t.utc` is `true`.
-
-__NOTE:__ You should only use `os.date()` and `os.time()` and therefore
-`glue.time()` for current dates and use something else for historical dates
-because these functions don't work with negative timestamps because
-apparently time didn't exist before UNIX. At least they don't suffer from
-Y2038 so that's that.
-
-__NOTE:__ `os.time()` has second accuracy (so those timestamps are integers).
-For sub-second accuracy use the [time] module.
-
-------------------------------------------------------------------------------
-
-### `glue.utc_diff([t]) -> seconds`
-
-Difference between local time and UTC in seconds.
-
-------------------------------------------------------------------------------
-
-### `glue.day([utc, ][ts], [plus_days]) -> ts`
-
-Timestamp at day's beginning from `ts`, plus/minus some days.
-
-------------------------------------------------------------------------------
-
-### `glue.month([utc, ][ts], [plus_months]) -> ts`
-
-Timestamp at month's beginning from `ts`, plus/minus some months.
-
-------------------------------------------------------------------------------
-
-### `glue.year([utc, ][ts], [plus_years]) -> ts`
-
-Timestamp at year's beginning from `ts`, plus/minus some years.
-
-------------------------------------------------------------------------------
-
-### `glue.timeago(ts[, from_ts]) -> s`
-
-Format relative time, eg. `3 hours ago` or `in 2 weeks`.
-
-------------------------------------------------------------------------------
-
-## Errors
-
-### `glue.assert(v[,message[,format_args...]])`
-
-Like `assert` but supports formatting of the error message using
-`string.format()`.
-
-This is better than `assert(v, string.format(message, format_args...))`
-because it avoids creating the message string when the assertion is true.
-
-__CAVEAT__: Unlike standard `assert()`, this only returns its first argument
-even when no message is given, to avoid returning the error message and its
-args when a message is given and the assertion is true. So the pattern
-`a, b = glue.assert(f())` doesn't work.
-
-#### Example
-
-```lua
-glue.assert(depth <= maxdepth, 'maximum depth %d exceeded', maxdepth)
-```
-
-------------------------------------------------------------------------------
-
-### `glue.protect(func) -> protected_func`
-
-In Lua, API functions conventionally signal errors by returning nil and
-an error message instead of raising errors.
-In the implementation however, using assert() and error() is preferred
-to coding explicit conditional flows to cover exceptional cases.
-Use this function to convert error-raising functions to nil,err-returning
-functions:
-
-```lua
-protected_function = glue.protect(function()
- ...
- assert(...)
- ...
- error(...)
- ...
- return result_value
-end)
-
-local ret, err = protected_function()
-```
-
-------------------------------------------------------------------------------
-
-### `glue.pcall(f,...) -> true,... | false,traceback`
-
-With Lua's pcall() you lose the stack trace, and with usual uses of pcall()
-you don't want that. This variant appends the traceback to the error message.
-
-> __NOTE__: Lua 5.2 and LuaJIT only.
-
-------------------------------------------------------------------------------
-
-### `glue.fpcall(f,...) -> result | nil,traceback`
-
-### `glue.fcall(f,...) -> result`
-
-These constructs bring the try/finally/except idiom to Lua. The first variant
-returns nil,error when errors occur while the second re-raises the error.
-
-#### Example
-
-```lua
-local result = glue.fpcall(function(finally, except, ...)
- local temporary_resource = acquire_resource()
- finally(function() temporary_resource:free() end)
- ...
- local final_resource = acquire_resource()
- except(function() final_resource:free() end)
- ... code that might break ...
- return final_resource
-end, ...)
-```
-> __NOTE__: Lua 5.2 and LuaJIT only.
-
-------------------------------------------------------------------------------
-
-## Modules
-
-### `glue.module([name, ][parent]) -> M, P`
-
-### `glue.module([parent, ][name]) -> M, P`
-
-Create a module with a public and private namespace and set the environment
-of the calling function (not the global one!) to the module's private
-namespace and return the namespaces. Cross-references between the namespaces
-are also created at `M._P`, `P._M`, `P._P` and `M._M`, so both `_P` and `_M`
-can be accessed directly from the new environment.
-
-`parent` controls what the namespaces will inherit and it can be either
-another module, in which case `M` inherits `parent` and `P` inherits
-`parent._P`, or it can be a string in which case the module to inherit is
-first required. `parent` defaults to `_M` so that calling `glue.module()`
-creates a submodule of the current module. If there's no `_M` in the current
-environment then `P` inherits `_G` and `M` inherits nothing.
-
-Specifying a `name` for the module either returns `package.loaded[name]`
-if it is set or creates a module, sets `package.loaded[name]` to it and
-returns that. This is useful for creating and referencing shared namespaces
-without having to make a Lua file and require that.
-
-Naming the module also sets `P[name] = M` so that public symbols can be
-declared in `foo.bar` style instead of `_M.bar`.
-
-Setting `foo.module = glue.module` makes module `foo` directly extensible
-by calling `foo:module'bar'` or `require'foo':module'bar'`.
-
-NOTE: All that functionality is done in just 27 LOC, less than it takes
-to explain it, so read the code to get to another level of clarity.
-
-### `glue.autoload(t, submodules) -> t`
`glue.autoload(t, key, module|loader) -> t`
-
-Assign a metatable to `t` (or override an existing metatable's `__index`) such
-that when a missing key is accessed, the module said to contain that key is
-require'd automatically.
-
-The `submodules` argument is table of form `{key = module_name | load_function}`
-specifying the corresponding Lua module (or load function) that make each key
-available to `t`. The alternative syntax allows specifying the key - submodule
-associations one by one.
-
-#### Motivation
-
-Module autoloading allows splitting the implementation of a module in many
-submodules containing optional, self-contained functionality, without having
-to make this visible in the user API. This effectively disconnects how an API
-is modularized from how its implementation is modularized, allowing the
-implementation to be refactored at a later time without changing the API.
-
-#### Example
-
-**main module (foo.lua):**
-
-```lua
-local function bar() --function implemented in the main module
- ...
-end
-
---create and return the module table
-return glue.autoload({
- ...
- bar = bar,
-}, {
- baz = 'foo_extra', --autoloaded function, implemented in module foo_extra
-})
-```
-
-**submodule (foo_extra.lua):**
-
-```lua
-local foo = require'foo'
-
-function foo.baz(...)
- ...
-end
-```
-
-**in usage:**
-
-```lua
-local foo = require'foo'
-
-foo.baz(...) -- foo_extra was now loaded automatically
-```
-
-------------------------------------------------------------------------------
-
-### `glue.bin`
-
-Get the script's directory. This allows finding files in the script's
-directory regardless of the directory that Lua is started in.
-
-For executables created with [bundle], this is the executable's directory.
-
-#### Example
-
-```lua
-local foobar = glue.readfile(glue.bin .. '/' .. file_near_this_script)
-```
-
-#### Caveats
-
-This only works if glue itself can already be found and required
-(chicken/egg problem). Also, the path is relative to the current directory,
-so this stops working as soon as the current directory is changed.
-Also, depending on how the process was started, this information might be
-missing or wrong since it's set by the parent process. Better use
-[fs].exedir which has none of these problems.
-
-------------------------------------------------------------------------------
-
-### `glue.luapath(path[,index[,ext]])`
-
-Insert a Lua search pattern in `package.path` such that `require` will be able
-to load Lua modules from that path. The optional `index` arg specifies the
-insert position (default is 1, that is, before all existing paths; can be
-negative, to start counting from the end; can be the string 'after', which is
-the same as 0). The optional `ext` arg specifies the file extension to use
-(default is "lua").
-
-------------------------------------------------------------------------------
-
-### `glue.cpath(path[,index])`
-
-Insert a Lua search pattern in `package.cpath` such that `require` will be
-able to load Lua/C modules from that path. The `index` arg has the same
-meaning as with `glue.luapath`.
-
-#### Example
-
-```lua
-glue.luapath(glue.bin)
-glue.cpath(glue.bin)
-
-require'foo' --looking for `foo` in the same directory as the running script first
-```
-
-------------------------------------------------------------------------------
-
-## Allocation
-
-### `glue.freelist([create], [destroy]) -> alloc, free`
-
-Returns `alloc() -> e` and `free(e)` functions to allocate and deallocate
-Lua objects. The allocator returns the last freed object or calls `create()`
-to create a new one if the freelist is empty. `create` defaults to
-`function() return {} end`; `destroy` defaults to `glue.noop`.
-
-------------------------------------------------------------------------------
-
-### `glue.buffer(ctype) -> alloc(minlen|false) -> buf, capacity`
-
-(LuaJIT only) Return an allocation function that reuses or reallocates
-an internal buffer based on the `len` argument.
-
- * `ctype` must be a VLA: the returned buffer will have that type.
- this makes `glue.buffer(ctype)` compatible with `ffi.typeof(ctype)`.
- * the buffer only grows, it never shrinks and it only grows in
- powers of two steps.
- * the allocation function returns the buffer's current capacity which
- can be equal or greater than the requested length.
- * the returned buffer is anchored by the allocation function. calling
- `alloc(false)` unanchors the buffer.
- * the contents of the buffer _are not preserved_ between allocations
- but you _are allowed_ to access both buffers between two consecutive
- allocations in order to do that yourself.
-
-------------------------------------------------------------------------------
-
-### `glue.dynarray(ctype[, min_capacity]) -> alloc(minlen|false) -> buf, minlen`
-
-Like `glue.buffer()` but preserves data between reallocations, and always
-returns `minlen` instead of capacity.
-
-------------------------------------------------------------------------------
-
-### `glue.readall(read, self, ...) -> buf, len`
-
-Repeat read based on a `read(self, buf, len, ...) -> readlen` function.
-
-------------------------------------------------------------------------------
-
-### `glue.buffer_reader(buf,len | nil,err) -> read`
-
-Return a `read(buf, len) -> readlen` function that consumes data from the
-supplied buffer. The supplied `buf,len` can also be `nil,err` in which case
-the `read` function will always return just that. The buffer must be a
-`(u)int8_t` pointer or VLA.
-
-------------------------------------------------------------------------------
-
-## FFI
-
-### `glue.addr(ptr) -> number | string`
-
-Convert the address of a pointer into a Lua number (or possibly string
-on 64bit platforms). This is useful for:
-
- * hashing on pointer values (i.e. using pointers as table keys)
- * moving pointers in and out of Lua states when using [luastate]
-
-### `glue.ptr([ctype,]number|string) -> ptr`
-
-Convert an address value stored as a Lua number or string to a cdata pointer,
-optionally specifying a ctype for the pointer (defaults to `void*`).
-
-------------------------------------------------------------------------------
-
-### `glue.getbit(val, mask) -> true|false`
-
-Get the value of a single bit from an integer.
-
-### `glue.setbit(val, mask, bitval) -> val`
-
-Set the value of a single bit from an integer.
-
-### `glue.bor(flags, bits, [strict]) -> mask`
-
-`bit.bor()` that takes its arguments as a string of form `'opt1 opt2 ...'`,
-a list of form `{'opt1', 'opt2', ...}` or a map of form `{opt->true}`
-and performs `bit.bor()` on the numeric values of those arguments where
-the numeric values are given as the `bits` table of form `{opt->bitvalue}`.
-
-Useful for Luaizing C functions that take bitmask flags.
-
-Example: `glue.bor('a c', {a=1, b=2, c=4}) -> 5`.
-
-------------------------------------------------------------------------------
-
-## Tips
-
-String functions are also in the `glue.string` table.
-You can extend the Lua `string` namespace:
-
- `glue.update(string, glue.string)`
-
-so you can use them as string methods:
-
- `s:trim()`
-
-## Design
-
-[glue_design]
-
diff --git a/lib/glue_design.md b/lib/glue_design.md
deleted file mode 100644
index e7ec1dc..0000000
--- a/lib/glue_design.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-title: design of glue
-tagline: how and why
----
-
-## Scope
-
-A place to accumulate good implementations of common Lua idioms, mainly so
-that they can be copy-pasted in library code (a typical library only needs
-a few functions from glue) or used directly in app code (where another
-dependency is not a problem). In this context a good implementation is first
-of all small and its corner cases well documented (since they are usually not
-addressed in the implementation in order to keep the code small and fast).
-
-## Naming
-
-The idea is to find the most popular, familiar and _short_ names for _each
-and every_ function (no underscores and no capitals). Python gets this right,
-so does UNIX. A function with an unheard of name or alien semantics will be
-avoided. People rather recall known names/semantics rather than learn
-unfamiliar new names/semantics, even when those would be more clear.
-
-## Semantics
-
-They follow the general [api-design] rules.
-
-### Objects vs glue
-
-Don't provide data structures like list and set in a glue library, or a way
-to do OOP. Instead just provide the mechanisms as functions working on bare
-tables. Don't do both either: if your list type gets widely adopted, your
-programs will now be a mixture of bare tables (this is inevitable) and lists
-so now you have to decide which of your lists has a `sort()` method and which
-need to be wrapped first.
-
-### Write in Lua
-
-String lambdas, callable strings, list comprehensions are all fun, but they
-add syntax and a learning curve and should be generally avoided in contexts
-where their use is spare.
-
-### Sugar
-
-Don't add shortcut functions except when calling the shortcut function makes
-the intent clearer than when reading the equivalent Lua code.
-
-If something is an [idiom][lua-tricks], don't add a function for it, use it
-directly. Chances are its syntax will be more popular than its name. Eg. it's
-harder to recall and trust semantic equivalence of `isnan(x)` to the odd
-looking but mnemonic idiom `x ~= x` (eg. does `isnan` raise an error when `x`
-is not a number?). That doesn't mean `a < b and a or b` is a good idiom for
-`math.min(a, b)` though, `min()` itself is the idiom as we know it from math
-(`sign()`, `clamp()`, etc. are idioms too).
-
-Functional programming sugars like `compose` and `bind` makes code harder to
-read because brains are slow to switch between abstraction levels unless it's
-a self-contained DSL with radically different syntax and semantics than the
-surrounding code. Eg. it's easier to read a Lua string pattern or an embedded
-SQL string than it is to read expressions involving `bind` and `compose`
-which force you to simulate the equivalent Lua syntax in your head.
-
-Sugars like "message %s" % arg are the good ones: % is odd enough to put after
-a string constant that it has an idiomatic quality, and its semantics is
-self-evident by reading the format string literal, even for someone who never
-heard of python's `%` operator. Also, a prefix notation is generally more
-readable than a function call.
-
-## Implementation
-
-Keep the code readable and compact. Code changes that compromise these
-qualities for optimization should come with a benchmark to justify them.
-
-Document the limits of the algorithms involved with respect to input, like
-when does it have non-linear performance and if and how it is stack bound.
-Performance characteristics are not an implementation detail.
diff --git a/lib/glue_test.lua b/lib/glue_test.lua
deleted file mode 100644
index 0fd0a14..0000000
--- a/lib/glue_test.lua
+++ /dev/null
@@ -1,474 +0,0 @@
-local glue = require'glue'
-require'unit'
-
---math -----------------------------------------------------------------------
-
-test(glue.round(1.2), 1)
-test(glue.round(-1.2), -1)
-test(glue.round(1.5), 2) --half-up
-test(glue.round(-1.5), -1) --half-up
-test(glue.round(2^52+.49), 2^52) --largest number that works
-
-test(glue.snap(7, 5), 5)
-test(glue.snap(7.5, 5), 10) --half-up
-test(glue.snap(-7.5, 5), -5) --half-up
-
-test(glue.clamp(3, 2, 5), 3)
-test(glue.clamp(1, 2, 5), 2)
-test(glue.clamp(6, 2, 5), 5)
-
-test(#glue.random_string(1), 1)
-test(#glue.random_string(200), 200)
-
-assert(glue.uuid():gsub('[0-9a-f]', 'x') == 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')
-
---tables ---------------------------------------------------------------------
-
-test(glue.count({[0] = 1, 2, 3, a = 4}), 4)
-test(glue.count{}, 0)
-
-test(glue.indexof('b', {'a', 'b', 'c'}), 2)
-test(glue.indexof('b', {'x', 'y', 'z'}), nil)
-
-test(glue.index{a=5,b=7,c=3}, {[5]='a',[7]='b',[3]='c'})
-
-test(glue.keys({a=5,b=7,c=3}, true), {'a','b','c'})
-test(glue.keys({'a','b','c'}, true), {1,2,3})
-
-local t1, t2 = {}, {}
-for k,v in glue.sortedpairs{c=5,b=7,a=3} do
- table.insert(t1, k)
- table.insert(t2, v)
-end
-test(t1, {'a','b','c'})
-test(t2, {3,7,5})
-
-test(glue.update({a=1,b=2,c=3}, {d='add',b='overwrite'}, {b='over2'}), {a=1,b='over2',c=3,d='add'})
-
-test(glue.merge({a=1,b=2,c=3}, {d='add',b='overwrite'}, {b='over2'}), {a=1,b=2,c=3,d='add'})
-
-local t = {k0 = {v0 = 1}}
-test(glue.attr(t, 'k0').v0, 1) --existing key
-glue.attr(t, 'k').v = 1
-test(t.k, {v = 1}) --created key
-glue.attr(t, 'k2', 'v2')
-test(t.k2, 'v2') --custom value
-
---lists ----------------------------------------------------------------------
-
-test(glue.extend({5,6,8}, {1,2}, {'b','x'}), {5,6,8,1,2,'b','x'})
-
-test(glue.append({1,2,3}, 5,6), {1,2,3,5,6})
-
-local function insert(t,i,...)
- local n = select('#',...)
- glue.shift(t,i,n)
- for j=1,n do t[i+j-1] = select(j,...) end
- return t
-end
-test(insert({'a','b'}, 1, 'x','y'), {'x','y','a','b'}) --2 shifts
-test(insert({'a','b','c','d'}, 3, 'x', 'y'), {'a','b','x','y','c','d'}) --2 shifts
-test(insert({'a','b','c','d'}, 4, 'x', 'y'), {'a','b','c','x','y','d'}) --1 shift
-test(insert({'a','b','c','d'}, 5, 'x', 'y'), {'a','b','c','d','x','y'}) --0 shifts
-test(insert({'a','b','c','d'}, 6, 'x', 'y'), {'a','b','c','d',nil,'x','y'}) --out of bounds
-test(insert({'a','b','c','d'}, 1, 'x', 'y'), {'x','y','a','b','c','d'}) --first pos
-test(insert({}, 1, 'x', 'y'), {'x','y'}) --empty dest
-test(insert({}, 3, 'x', 'y'), {nil,nil,'x','y'}) --out of bounds
-
-local function remove(t,i,n) return glue.shift(t,i,-n) end
-test(remove({'a','b','c','d'}, 1, 3), {'d'})
-test(remove({'a','b','c','d'}, 2, 2), {'a', 'd'})
-test(remove({'a','b','c','d'}, 3, 2), {'a', 'b'})
-test(remove({'a','b','c','d'}, 1, 5), {}) --too many
-test(remove({'a','b','c','d'}, 4, 2), {'a', 'b', 'c'}) --too many
-test(remove({'a','b','c','d'}, 5, 5), {'a', 'b', 'c', 'd'}) --from too far
-test(remove({}, 5, 5), {}) --from too far
-
-test(glue.reverse({}), {})
-test(glue.reverse({5}), {5})
-test(glue.reverse({5, 2}), {2, 5})
-test(glue.reverse({5, 2, 1}), {1, 2, 5})
-test(glue.reverse({1, 3, 7, 5, 2}), {2, 5, 7, 3, 1})
-test(glue.reverse({1, 3, 7, 5, 2}, 3), {1, 3, 2, 5, 7})
-test(glue.reverse({1, 3, 7, 5, 2}, 2, 3), {1, 7, 3, 5, 2})
-
-test(glue.binsearch(10, {}), nil)
-test(glue.binsearch(10, {11}), 1)
-test(glue.binsearch(11, {11}), 1)
-test(glue.binsearch(12, {11}), nil)
-test(glue.binsearch(12, {11, 13}), 2)
-test(glue.binsearch(13, {11, 13}), 2)
-test(glue.binsearch(11, {11, 13}), 1)
-test(glue.binsearch(14, {11, 13}), nil)
-test(glue.binsearch(10, {11, 13}), 1)
-test(glue.binsearch(14, {11, 13, 15}), 3)
-test(glue.binsearch(12, {11, 13, 15}), 2)
-test(glue.binsearch(10, {11, 13, 15}), 1)
-test(glue.binsearch(16, {11, 13, 15}), nil)
-
---strings --------------------------------------------------------------------
-
-local function test1(s,sep,expect)
- local t={} for c in glue.gsplit(s,sep) do t[#t+1]=c end
- assert(#t == #expect)
- for i=1,#t do assert(t[i] == expect[i]) end
- test(t, expect)
-end
-test1('','',{''})
-test1('','asdf',{''})
-test1('asdf','',{'asdf'})
-test1('', ',', {''})
-test1(',', ',', {'',''})
-test1('a', ',', {'a'})
-test1('a,b', ',', {'a','b'})
-test1('a,b,', ',', {'a','b',''})
-test1(',a,b', ',', {'','a','b'})
-test1(',a,b,', ',', {'','a','b',''})
-test1(',a,,b,', ',', {'','a','','b',''})
-test1('a,,b', ',', {'a','','b'})
-test1('asd , fgh ,; qwe, rty. ,jkl', '%s*[,.;]%s*', {'asd','fgh','','qwe','rty','','jkl'})
-test1('Spam eggs spam spam and ham', 'spam', {'Spam eggs ',' ',' and ham'})
-t = {} for s,n in glue.gsplit('a 12,b 15x,c 20', '%s*(%d*),') do t[#t+1]={s,n} end
-test(t, {{'a','12'},{'b 15x',''},{'c 20',nil}})
---TODO: use case with () capture
-
-local i = 0
-local function assert_lines(s, t)
- i = i + 1
- local dt = {}
- for s in glue.lines(s, '*L') do
- table.insert(dt, s)
- end
- if #t ~= #dt then goto err end
- for i=1,#t do
- if t[i] ~= dt[i] then goto err end
- end
- do return end
- ::err::
- require'pp'('actual ', #dt, dt)
- require'pp'('expected', #t, t)
- error('test '..i..' failed')
-end
-assert_lines('', {''})
-assert_lines(' ', {' '})
-assert_lines('x\ny', {'x\n', 'y'})
-assert_lines('x\ny\n', {'x\n', 'y\n', ''})
-assert_lines('x\n\ny', {'x\n', '\n', 'y'})
-assert_lines('\n', {'\n', ''})
-assert_lines('\n\r\n', {'\n','\r\n',''})
-assert_lines('\r\n\n', {'\r\n','\n',''})
-assert_lines('\n\r', {'\n','\r',''})
-assert_lines('\n\r\n\r', {'\n','\r\n','\r',''})
-assert_lines('\n\n\r', {'\n','\n','\r',''})
-
-test(glue.trim(' a d '), 'a d')
-
-test({(pcall(glue.lineinfo, 'abc', 0))}, {false})
-test({(pcall(glue.lineinfo('abc'), 0))}, {false})
-test({(pcall(glue.lineinfo, 'abc', 5))}, {false})
-test({(pcall(glue.lineinfo('abc'), 5))}, {false})
-test({glue.lineinfo('abc', 1)}, {1, 1})
-test({glue.lineinfo('a\nb\nc', 4)}, {2, 2}) --on \n
-test({glue.lineinfo('a\nb\nc', 5)}, {3, 1})
-test({glue.lineinfo('a\nb\nc')(4)}, {2, 2}) --on \n
-test({glue.lineinfo('a\nb\nc')(5)}, {3, 1})
-
-test(glue.esc'^{(.-)}$', '%^{%(%.%-%)}%$')
-test(glue.esc'%\0%', '%%%z%%')
-
-if jit and jit.version:find'2%.1' then
- test(glue.tohex(0xdeadbeef01), 'deadbeef01') --LuaJIT 2.1+
- test(glue.tohex(0xdeadbeef02, true), 'DEADBEEF02') --LuaJIT 2.1+
-end
-test(glue.tohex'\xde\xad\xbe\xef\x01', 'deadbeef01')
-test(glue.tohex('\xde\xad\xbe\xef\x02', true), 'DEADBEEF02')
-test(glue.fromhex'deadbeef01', '\xde\xad\xbe\xef\x01')
-test(glue.fromhex'DEADBEEF02', '\xde\xad\xbe\xef\x02')
-test(glue.fromhex'5', '\5')
-test(glue.fromhex'5ff', '\5\xff')
-
-test(glue.starts('abc', 'ab'), true)
-test(glue.starts('aabc', 'ab'), false)
-test(glue.starts('', ''), true)
-test(glue.starts('abc', ''), true)
-test(glue.starts('', 'a'), false)
-
-test(glue.ends('', ''), true)
-test(glue.ends('x', ''), true)
-test(glue.ends('x', 'x'), true)
-test(glue.ends('', 'x'), false)
-test(glue.ends('x', 'y'), false)
-test(glue.ends('ax', 'x'), true)
-test(glue.ends('ax', 'a'), false)
-
---iterators ------------------------------------------------------------------
-
-test(glue.collect(('abc'):gmatch('.')), {'a','b','c'})
-test(glue.collect(2,ipairs{5,7,2}), {5,7,2})
-
---metamethods ----------------------------------------------------------------
-
-local t0 = {a = 1, b = 2}
-local t1 = glue.inherit({}, t0)
-local t2 = glue.inherit({}, t1)
-assert(t2.a == 1)
-assert(t2.b == 2)
-t0.b = 3
-assert(t2.b == 3)
-glue.inherit(t1)
-assert(not t2.a)
-
---i/o ------------------------------------------------------------------------
-
-assert(glue.canopen('glue.lua'))
-assert(glue.readfile(glue.bin..'/glue.lua'):match'glue', 'glue')
-assert(glue.readfile(glue.bin..'/glue.lua'):match'glue', 'glue')
-
-test(select(2,pcall(glue.assert,false,'bad %s','dog')), 'bad dog')
-test(select(2,pcall(glue.assert,false,'bad dog %s')), 'bad dog %s')
-test({pcall(glue.assert,1,2,3)}, {true, 1})
-test({pcall(glue.assert,false)}, {false, 'assertion failed!'})
-test({pcall(glue.assert,false,123)}, {false, '123'})
-test({pcall(glue.assert,false,123,456)}, {false, '123'})
-
-assert(glue.writefile('glue_test.tmp', 'abc', nil, 'glue_test.tmp.tmp'))
-assert(glue.readfile('glue_test.tmp') == 'abc')
-assert(glue.writefile('glue_test.tmp', 'def', nil, 'glue_test.tmp.tmp'))
-assert(glue.readfile('glue_test.tmp') == 'def')
-os.remove('glue_test.tmp')
-
---dates & timestamps ---------------------------------------------------------
-
---TODO: time, utc_diff, year, month, day
-
---no way to adjust TZ so these are commented out.
---assert(glue.utc_diff(glue.time(2000, 7, 1)) == 10800)
---assert(glue.utc_diff(glue.time(2000, 1, 1)) == 7200)
-
---errors ---------------------------------------------------------------------
-
---TODO: assert, protect, pcall, fpcall, fcall
-
---closures -------------------------------------------------------------------
-
-test(glue.pass(32), 32)
-
-local n = 0
-local f = glue.memoize(function() n = n + 1; return 6; end)
-test(f(), 6)
-test(f(), 6)
-test(n, 1)
-local n = 0
-local f = glue.memoize(function(x) n = n + 1; return x and 2*x; end)
-for i=1,100 do
- test(f(2), 4)
- test(f(3), 6)
- test(f(0/0), 0/0)
- test(f(), nil) --no distinction between 0 args and 1 nil arg!
- test(f(nil), nil)
-end
-test(n, 4)
-local n = 0
-local f = glue.memoize(function(x, y) n = n + 1; return x and y and x + y; end)
-for i=1,100 do
- test(f(3,2), 5)
- test(f(2,3), 5)
- test(f(nil,3), nil)
- test(f(3,nil), nil)
- test(f(nil,nil), nil)
- test(f(), nil) --no distinction between missing args and nil args!
- test(f(nil), nil) --same here, this doesn't increment the count!
- test(f(0/0), nil)
- test(f(nil, 0/0), nil)
- test(f(0/0, 1), 0/0)
- test(f(1, 0/0), 0/0)
- test(f(0/0, 0/0), 0/0)
-end
-test(n, 10)
-local n = 0
-local f = glue.memoize(function(x, ...)
- n = n + 1
- local z = x or -10
- for i=1,select('#',...) do
- z = z + (select(i,...) or -1)
- end
- return z
-end)
-for i=1,100 do
- test(f(10, 1, 1), 12) --1+2 args
- test(f(), -10) --1+0 args (no distinction between 0 args and 1 arg)
- test(f(nil), -10) --same here, this doesn't increment the count!
- test(f(nil, nil), -11) --but this does: 1+1 args
- test(f(0/0), 0/0) --1+0 args with NaN
-end
-test(n, 4)
-local n = 0
-local f = glue.memoize(function(x, y, z) n = n + 1; return x + y + z + n end)
-test(f(1, 1, 1), 4)
-test(f(1, 1, 1, 1), 4) --arg#4 ignored even though using memoize_vararg()
-
---tuples ---------------------------------------------------------------------
-
-local tuple = glue.tuple
-
-local function collectall()
- local after = collectgarbage'count'
- repeat
- local before = after
- collectgarbage()
- after = collectgarbage'count'
- until after >= before
-end
-
-do
---test: leaf index found but has no tuple.
-local t1 = tuple('a','b','c')
-local t2 = tuple('a','b')
-assert(t1 ~= t2)
-
---test: nil and nan values.
-local ab = 'a'..string.char(string.byte('b')) --because constants are not collected
-local e0 = tuple(ab) assert(e0() == ab)
-local e1 = tuple(ab,nil,1) assert(e1(2) == nil); assert(e1(3) == 1)
-local e2 = tuple(ab,nil,2) assert(e2(2) == nil); assert(e2(3) == 2)
-local e3 = tuple(ab,nil,2,nil) assert(select('#', e3()) == 4)
-local e4 = tuple(ab,0/0,2,nil) assert(e4(2) ~= e4(2))
-local a,b,c,d = e4()
-assert(a==ab and b~=b and c==2 and d==nil)
-
---test: anchoring of index tables (insufficient).
-ab = nil
-collectall()
-local ab = 'a'..'b'
-assert(e0 == tuple(ab))
-assert(e1 == tuple(ab,nil,1))
-assert(e2 == tuple(ab,nil,2))
-assert(e2 ~= tuple(ab,nil,2,nil))
-assert(e3 == tuple(ab,nil,2,nil))
-assert(e4 == tuple(ab,0/0,2,nil))
-
---test: tostring()
-assert(tostring(e0) == '(ab)')
-assert(tostring(tuple('b', 1, 'd')) == '(b, 1, d)')
-if jit then --only luajit has 'nan' for 0/0
- assert(tostring(e4) == '(ab, nan, 2, nil)')
-end
-
---test: anchoring of index tables.
-local t = {}
-for i=1,20 do
- for j = 1,20 do
- t[tuple(i, j)] = true
- end
-end
-collectall()
-for i=1,20 do
- for j = 1,20 do
- assert(t[tuple(i, j)])
- end
-end
-
---test: tuple spaces and wrapping.
-local tuple = glue.tuples(nil, true)
-local t1 = tuple(1, 2, 3)
-collectall()
-assert(tuple(1, 2, 3) == t1)
-
---test: weak tuple spaces don't leak.
-local function testleaks(weak, s)
- local tuple = glue.tuples(nil, weak)
- local before = collectgarbage'count'
- for i=1,10^5 do
- local a = math.floor(i / 53512) % 23
- local b = math.floor(i / 1439) % 17
- local c = math.floor(i / 197) % 16
- local d = math.floor(i / 16) % 19
- local e = i % 10
- tuple(a, b, c, d, e)
- end
- collectall()
- local after = collectgarbage'count'
- return (after - before) --the memory leak in KB
-end
-collectall()
-local leak = testleaks(true, 'weak'); assert(leak < 1000)
-local leak = testleaks(false, 'strong'); assert(leak > 10000)
-
-end
-
---modules --------------------------------------------------------------------
-
---module
-
-local function test_module()
- local foo_mod, foo_priv = glue.module'foo'
-
- assert(getfenv() == foo_priv)
- assert(foo_mod._P == foo_priv)
- assert(foo_mod ~= foo_priv)
- assert(_M == foo_mod)
- assert(_P == _M._P)
- assert(__index == _G)
- assert(_P._M == _M)
- a = 123
- assert(a == 123)
- assert(_P.a == 123)
- _M.a = 321
- assert(_M.a == 321) --P and M are diff namespaces
-
- foo.module = glue.module --make submodule api for foo
-
- local bar_mod = require'foo':module'bar' --submodule api
- local bar_mod2 = foo:module'bar' --submodule alt. api
- assert(bar_mod == bar_mod2) --using package.loaded works
- assert(__index == foo_mod._P) --inheriting works
- assert(bar_mod.print == nil) --public namespace not polluted
- b = 123
- assert(b == 123)
- assert(_P.b == 123)
- assert(bar_mod.a == 321) --inheriting the public namespace
-
-end
-test_module()
-assert(getfenv() == _G) --not chainging the global scope
-
---autoload
-
-local M = {}
-local x, y, z, p = 0, 0, 0, 0
-glue.autoload(M, 'x', function() x = x + 1 end)
-glue.autoload(M, 'y', function() y = y + 1 end)
-glue.autoload(M, {z = function() z = z + 1 end, p = function() p = p + 1 end})
-local _ = M.x, M.x, M.y, M.y, M.z, M.z, M.p, M.p
-assert(x == 1)
-assert(y == 1)
-assert(z == 1)
-assert(p == 1)
-
---ffi
-
-if jit then
- local ffi = require'ffi'
-
- assert(glue.addr(ffi.cast('void*', 0x55555555)) == 0x55555555)
- assert(glue.ptr('int*', 0x55555555) == ffi.cast('void*', 0x55555555))
-
- if ffi.abi'64bit' then
- assert(glue.addr(ffi.cast('void*', 0x5555555555)) == 0x5555555555)
- --going out of our way not to use the LL suffix so that Lua 5.1 can compile this.
- local huge = ffi.new('union { struct { uint32_t lo; uint32_t hi; }; struct{} *p; }',
- {lo = 0x12345678, hi = 0xdeadbeef})
- local huges = '\x78\x56\x34\x12\xef\xbe\xad\xde'
- assert(glue.addr(huge.p) == huges) --string comparison
- assert(glue.ptr('union{}*', huges) == huge.p) --pointer comparison
- end
-end
-
---list the namespace ---------------------------------------------------------
-
-for k,v in glue.sortedpairs(glue) do
- print(string.format('glue.%-20s %s', k, v))
-end
-
---TODO: freelist, buffer
-
diff --git a/lib/input.lua b/lib/input.lua
deleted file mode 100644
index 01af4de..0000000
--- a/lib/input.lua
+++ /dev/null
@@ -1,359 +0,0 @@
-local minhook = dofile("mods/evaisa.mp/lib/minhook.lua")("mods/evaisa.mp/bin")
-minhook.initialize()
-
-local SDL = dofile("mods/evaisa.mp/lib/sdl2_ffi.lua")
-local ffi = require("ffi")
-
-local game_controller = nil
-SDL.SDL_StartTextInput()
-
-
-local TryInitController = function()
- if game_controller == nil then
- local num_joysticks = SDL.SDL_NumJoysticks()
- local game_controller = nil
- for i = 0, num_joysticks - 1 do
- if SDL.SDL_IsGameController(i) ~= 0 then
- game_controller = SDL.SDL_GameControllerOpen(i)
- if game_controller ~= nil then
- break
- end
- end
- end
- end
-end
-
-TryInitController()
-
-local input = {
- pressed = {},
- inputs = {},
- released = {},
- held = {},
- chars = {},
- mouse = {
- x = 0,
- y = 0,
- held = {},
- pressed = {},
- released = {}
- },
- controller = {
- pressed = {},
- released = {},
- held = {},
- left_stick = {x = 0, y = 0},
- right_stick = {x = 0, y = 0},
- triggers = {left = 0, right = 0}
- },
- frame_finished = false
-}
-
-input.Reset = function(self)
- self.pressed = {}
- self.inputs = {}
- self.released = {}
- self.chars = {}
- self.mouse.pressed = {}
- self.mouse.released = {}
- self.controller.pressed = {}
- self.controller.released = {}
- self.controller.held = {}
- --[[self.controller.left_stick = {x = 0, y = 0}
- self.controller.right_stick = {x = 0, y = 0}
- self.controller.triggers = {left = 0, right = 0}]]
-end
-
-input.Clear = function (self)
- self.pressed = {}
- self.inputs = {}
- self.released = {}
- self.held = {}
- self.chars = {}
- self.mouse.pressed = {}
- self.mouse.released = {}
- self.mouse.held = {}
- self.mouse.x = 0
- self.mouse.y = 0
- self.controller.pressed = {}
- self.controller.released = {}
- self.controller.held = {}
- self.controller.left_stick = {x = 0, y = 0}
- self.controller.right_stick = {x = 0, y = 0}
- self.controller.triggers = {left = 0, right = 0}
-end
-
-
-local mouse_map = {
- "left",
- "middle",
- "right",
- "x1",
- "x2"
-}
-
-local controller_map = {
- "invalid",
- "a",
- "b",
- "x",
- "y",
- "back",
- "guide",
- "start",
- "left_stick",
- "right_stick",
- "left_shoulder",
- "right_shoulder",
- "up",
- "down",
- "left",
- "right",
- "misc",
- "paddle1",
- "paddle2",
- "paddle3",
- "paddle4",
- "max"
-}
-
-
-local SDL_PollEvent_hook
-SDL_PollEvent_hook = minhook.create_hook(SDL.SDL_PollEvent, function(event)
- local success, result = pcall(function()
- if(input.frame_finished)then
- input:Reset()
- input.frame_finished = false
- end
-
- local ret = SDL_PollEvent_hook.original(event)
-
- if ret == 0 then
- input.frame_finished = true
- return 0
- end
-
- if event.type == SDL.SDL_TEXTINPUT then
- local char = ffi.string(event.text.text)
- --print(char)
- table.insert(input.chars, char)
- elseif event.type == SDL.SDL_KEYDOWN then
- local key_name = ffi.string(SDL.SDL_GetKeyName(event.key.keysym.sym)):lower()
-
- --print(key_name)
-
- input.inputs[key_name] = GameGetFrameNum()
- if not input.held[key_name] then
- input.pressed[key_name] = GameGetFrameNum()
- --print(key_name)
- end
- input.held[key_name] = GameGetFrameNum()
- elseif event.type == SDL.SDL_KEYUP then
- local key_name = ffi.string(SDL.SDL_GetKeyName(event.key.keysym.sym)):lower()
- if(input.held[key_name])then
- input.released[key_name] = true
- input.held[key_name] = nil
- end
- elseif event.type == SDL.SDL_MOUSEMOTION then
- input.mouse.x = event.motion.x
- input.mouse.y = event.motion.y
- elseif event.type == SDL.SDL_MOUSEBUTTONDOWN then
- local map_button = mouse_map[event.button.button]
- input.mouse.held[map_button] = true
- input.mouse.pressed[map_button] = true
- elseif event.type == SDL.SDL_MOUSEBUTTONUP then
- local map_button = mouse_map[event.button.button]
- input.mouse.held[map_button] = nil
- input.mouse.released[map_button] = true
- elseif event.type == SDL.SDL_CONTROLLERBUTTONDOWN then
- local button_id = tonumber(event.cbutton.button) + 2
- local button = controller_map[button_id]
-
- mp_log:print(tostring(button))
- if not input.controller.held[button] then
- input.controller.pressed[button] = GameGetFrameNum()
- end
- input.controller.held[button] = GameGetFrameNum()
- elseif event.type == SDL.SDL_CONTROLLERBUTTONUP then
- local button_id = tonumber(event.cbutton.button) + 2
- local button = controller_map[button_id]
-
- if input.controller.held[button] then
- input.controller.released[button] = true
- input.controller.held[button] = nil
- end
- elseif event.type == SDL.SDL_CONTROLLERAXISMOTION then
- local axis = event.caxis.axis
- local value = event.caxis.value / 32767
- -- Depending on the axis, set the input for left or right thumbstick
- if axis == SDL.SDL_CONTROLLER_AXIS_LEFTX then
- input.controller.left_stick.x = value
- elseif axis == SDL.SDL_CONTROLLER_AXIS_LEFTY then
- input.controller.left_stick.y = value
- elseif axis == SDL.SDL_CONTROLLER_AXIS_RIGHTX then
- input.controller.right_stick.x = value
- elseif axis == SDL.SDL_CONTROLLER_AXIS_RIGHTY then
- input.controller.right_stick.y = value
- elseif axis == SDL.SDL_CONTROLLER_AXIS_TRIGGERLEFT then
- input.controller.triggers.left = value
- elseif axis == SDL.SDL_CONTROLLER_AXIS_TRIGGERRIGHT then
- input.controller.triggers.right = value
- end
- end
-
- return ret
- end)
-
- if success then
- return result
- end
-
- print("Input error: " .. result)
- return 0
-end)
-
-minhook.enable(SDL.SDL_PollEvent)
-
-input.WasKeyPressed = function(self, key)
- if(key == nil)then
- return false
- end
- return self.pressed[key] ~= nil
-end
-
-input.IsKeyDown = function(self, key)
- if(key == nil)then
- return false
- end
- return self.held[key] ~= nil
-end
-
-input.WasKeyReleased = function(self, key)
- if(key == nil)then
- return false
- end
- return self.released[key] ~= nil
-end
-
-input.WasMousePressed = function(self, button)
- if(button == nil)then
- return false
- end
- if(type(button) == "number")then
- button = mouse_map[button]
- end
- return self.mouse.pressed[button] ~= nil
-end
-
-input.IsMouseDown = function(self, button)
- if(button == nil)then
- return false
- end
- if(type(button) == "number")then
- button = mouse_map[button]
- end
- return self.mouse.held[button] ~= nil
-end
-
-input.WasMouseReleased = function(self, button)
- if(button == nil)then
- return false
- end
- if(type(button) == "number")then
- button = mouse_map[button]
- end
- return self.mouse.released[button] ~= nil
-end
-
-input.WasGamepadButtonPressed = function(self, button)
- TryInitController()
- if(button == nil)then
- return false
- end
- return self.controller.pressed[button] ~= nil
-end
-
-input.IsGamepadButtonDown = function(self, button)
- TryInitController()
- if(button == nil)then
- return false
- end
- return self.controller.held[button] ~= nil
-end
-
-input.WasGamepadButtonReleased = function(self, button)
- TryInitController()
- if(button == nil)then
- return false
- end
- return self.controller.released[button] ~= nil
-end
-
-input.GetGamepadAxis = function(self, axis)
- TryInitController()
- if(axis == nil)then
- return 0
- end
- if(axis == "left_stick")then
- return self.controller.left_stick.x, self.controller.left_stick.y
- elseif(axis == "right_stick")then
- return self.controller.right_stick.x, self.controller.right_stick.y
- elseif(axis == "left_trigger")then
- return self.controller.triggers.left
- elseif(axis == "right_trigger")then
- return self.controller.triggers.right
- end
-end
-
-input.GetMousePos = function(self)
- return self.mouse.x, self.mouse.y
-end
-
-input.GetUIMousePos = function(self, gui)
- local input_manager = EntityGetWithName("mp_input_manager")
- if(input_manager == nil or not EntityGetIsAlive(input_manager))then
- input_manager = EntityLoad("mods/evaisa.mp/files/entities/input_manager.xml")
- end
-
- local b_width = tonumber(game_config.get("internal_size_w")) or 1280
- local b_height = tonumber(game_config.get("internal_size_h")) or 720
-
- local controls_component = EntityGetFirstComponentIncludingDisabled(input_manager, "ControlsComponent")
- local screen_width, screen_height = GuiGetScreenDimensions(gui)
- local mouse_raw_x, mouse_raw_y = ComponentGetValue2(controls_component, "mMousePositionRaw")
- local mx, my = mouse_raw_x * screen_width / b_width, mouse_raw_y * screen_height / b_height
-
- return mx, my
-end
-
-input.GetInput = function(self, key)
- if(key == nil)then
- return false
- end
- return self.inputs[key]
-end
-
-input.GetChars = function(self)
- return self.chars
-end
-
-input.GetClipboardText = function(self)
- local char_ptr = SDL.SDL_GetClipboardText()
- if(char_ptr == nil)then
- return nil
- end
-
- local text = ffi.string(char_ptr)
- return text
-end
-
-input.SetClipboardText = function(self, text)
- -- convert to char*
- local char_ptr = ffi.new("char[?]", #text + 1)
- ffi.copy(char_ptr, text, #text)
- char_ptr[#text] = 0
-
- SDL.SDL_SetClipboardText(char_ptr)
-end
-
-return input
diff --git a/lib/inspect.lua b/lib/inspect.lua
deleted file mode 100644
index 9900a0b..0000000
--- a/lib/inspect.lua
+++ /dev/null
@@ -1,371 +0,0 @@
-local _tl_compat; if (tonumber((_VERSION or ''):match('[%d.]*$')) or 0) < 5.3 then local p, m = pcall(require, 'compat53.module'); if p then _tl_compat = m end end; local math = _tl_compat and _tl_compat.math or math; local string = _tl_compat and _tl_compat.string or string; local table = _tl_compat and _tl_compat.table or table
-local inspect = {Options = {}, }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-inspect._VERSION = 'inspect.lua 3.1.0'
-inspect._URL = 'http://github.com/kikito/inspect.lua'
-inspect._DESCRIPTION = 'human-readable representations of tables'
-inspect._LICENSE = [[
- MIT LICENSE
-
- Copyright (c) 2022 Enrique García Cota
-
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-]]
-inspect.KEY = setmetatable({}, { __tostring = function() return 'inspect.KEY' end })
-inspect.METATABLE = setmetatable({}, { __tostring = function() return 'inspect.METATABLE' end })
-
-local tostring = tostring
-local rep = string.rep
-local match = string.match
-local char = string.char
-local gsub = string.gsub
-local fmt = string.format
-
-local _rawget
-if rawget then
- _rawget = rawget
-else
- _rawget = function(t, k) return t[k] end
-end
-
-local function rawpairs(t)
- return next, t, nil
-end
-
-
-
-local function smartQuote(str)
- if match(str, '"') and not match(str, "'") then
- return "'" .. str .. "'"
- end
- return '"' .. gsub(str, '"', '\\"') .. '"'
-end
-
-
-local shortControlCharEscapes = {
- ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n",
- ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v", ["\127"] = "\\127",
-}
-local longControlCharEscapes = { ["\127"] = "\127" }
-for i = 0, 31 do
- local ch = char(i)
- if not shortControlCharEscapes[ch] then
- shortControlCharEscapes[ch] = "\\" .. i
- longControlCharEscapes[ch] = fmt("\\%03d", i)
- end
-end
-
-local function escape(str)
- return (gsub(gsub(gsub(str, "\\", "\\\\"),
- "(%c)%f[0-9]", longControlCharEscapes),
- "%c", shortControlCharEscapes))
-end
-
-local luaKeywords = {
- ['and'] = true,
- ['break'] = true,
- ['do'] = true,
- ['else'] = true,
- ['elseif'] = true,
- ['end'] = true,
- ['false'] = true,
- ['for'] = true,
- ['function'] = true,
- ['goto'] = true,
- ['if'] = true,
- ['in'] = true,
- ['local'] = true,
- ['nil'] = true,
- ['not'] = true,
- ['or'] = true,
- ['repeat'] = true,
- ['return'] = true,
- ['then'] = true,
- ['true'] = true,
- ['until'] = true,
- ['while'] = true,
-}
-
-local function isIdentifier(str)
- return type(str) == "string" and
- not not str:match("^[_%a][_%a%d]*$") and
- not luaKeywords[str]
-end
-
-local flr = math.floor
-local function isSequenceKey(k, sequenceLength)
- return type(k) == "number" and
- flr(k) == k and
- 1 <= (k) and
- k <= sequenceLength
-end
-
-local defaultTypeOrders = {
- ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4,
- ['function'] = 5, ['userdata'] = 6, ['thread'] = 7,
-}
-
-local function sortKeys(a, b)
- local ta, tb = type(a), type(b)
-
-
- if ta == tb and (ta == 'string' or ta == 'number') then
- return (a) < (b)
- end
-
- local dta = defaultTypeOrders[ta] or 100
- local dtb = defaultTypeOrders[tb] or 100
-
-
- return dta == dtb and ta < tb or dta < dtb
-end
-
-local function getKeys(t)
-
- local seqLen = 1
- while _rawget(t, seqLen) ~= nil do
- seqLen = seqLen + 1
- end
- seqLen = seqLen - 1
-
- local keys, keysLen = {}, 0
- for k in rawpairs(t) do
- if not isSequenceKey(k, seqLen) then
- keysLen = keysLen + 1
- keys[keysLen] = k
- end
- end
- table.sort(keys, sortKeys)
- return keys, keysLen, seqLen
-end
-
-local function countCycles(x, cycles)
- if type(x) == "table" then
- if cycles[x] then
- cycles[x] = cycles[x] + 1
- else
- cycles[x] = 1
- for k, v in rawpairs(x) do
- countCycles(k, cycles)
- countCycles(v, cycles)
- end
- countCycles(getmetatable(x), cycles)
- end
- end
-end
-
-local function makePath(path, a, b)
- local newPath = {}
- local len = #path
- for i = 1, len do newPath[i] = path[i] end
-
- newPath[len + 1] = a
- newPath[len + 2] = b
-
- return newPath
-end
-
-
-local function processRecursive(process,
- item,
- path,
- visited)
- if item == nil then return nil end
- if visited[item] then return visited[item] end
-
- local processed = process(item, path)
- if type(processed) == "table" then
- local processedCopy = {}
- visited[item] = processedCopy
- local processedKey
-
- for k, v in rawpairs(processed) do
- processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
- if processedKey ~= nil then
- processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
- end
- end
-
- local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
- if type(mt) ~= 'table' then mt = nil end
- setmetatable(processedCopy, mt)
- processed = processedCopy
- end
- return processed
-end
-
-local function puts(buf, str)
- buf.n = buf.n + 1
- buf[buf.n] = str
-end
-
-
-
-local Inspector = {}
-
-
-
-
-
-
-
-
-
-
-local Inspector_mt = { __index = Inspector }
-
-local function tabify(inspector)
- puts(inspector.buf, inspector.newline .. rep(inspector.indent, inspector.level))
-end
-
-function Inspector:getId(v)
- local id = self.ids[v]
- local ids = self.ids
- if not id then
- local tv = type(v)
- id = (ids[tv] or 0) + 1
- ids[v], ids[tv] = id, id
- end
- return tostring(id)
-end
-
-function Inspector:putValue(v)
- local buf = self.buf
- local tv = type(v)
- if tv == 'string' then
- puts(buf, smartQuote(escape(v)))
- elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
- tv == 'cdata' or tv == 'ctype' then
- puts(buf, tostring(v))
- elseif tv == 'table' and not self.ids[v] then
- local t = v
-
- if t == inspect.KEY or t == inspect.METATABLE then
- puts(buf, tostring(t))
- elseif self.level >= self.depth then
- puts(buf, '{...}')
- else
- if self.cycles[t] > 1 then puts(buf, fmt('<%d>', self:getId(t))) end
-
- local keys, keysLen, seqLen = getKeys(t)
-
- puts(buf, '{')
- self.level = self.level + 1
-
- for i = 1, seqLen + keysLen do
- if i > 1 then puts(buf, ',') end
- if i <= seqLen then
- puts(buf, ' ')
- self:putValue(t[i])
- else
- local k = keys[i - seqLen]
- tabify(self)
- if isIdentifier(k) then
- puts(buf, k)
- else
- puts(buf, "[")
- self:putValue(k)
- puts(buf, "]")
- end
- puts(buf, ' = ')
- self:putValue(t[k])
- end
- end
-
- local mt = getmetatable(t)
- if type(mt) == 'table' then
- if seqLen + keysLen > 0 then puts(buf, ',') end
- tabify(self)
- puts(buf, ' = ')
- self:putValue(mt)
- end
-
- self.level = self.level - 1
-
- if keysLen > 0 or type(mt) == 'table' then
- tabify(self)
- elseif seqLen > 0 then
- puts(buf, ' ')
- end
-
- puts(buf, '}')
- end
-
- else
- puts(buf, fmt('<%s %d>', tv, self:getId(v)))
- end
-end
-
-
-
-
-function inspect.inspect(root, options)
- options = options or {}
-
- local depth = options.depth or (math.huge)
- local newline = options.newline or '\n'
- local indent = options.indent or ' '
- local process = options.process
-
- if process then
- root = processRecursive(process, root, {}, {})
- end
-
- local cycles = {}
- countCycles(root, cycles)
-
- local inspector = setmetatable({
- buf = { n = 0 },
- ids = {},
- cycles = cycles,
- depth = depth,
- level = 0,
- newline = newline,
- indent = indent,
- }, Inspector_mt)
-
- inspector:putValue(root)
-
- return table.concat(inspector.buf)
-end
-
-setmetatable(inspect, {
- __call = function(_, root, options)
- return inspect.inspect(root, options)
- end,
-})
-
-return inspect
diff --git a/lib/json.lua b/lib/json.lua
deleted file mode 100644
index 1a4a47d..0000000
--- a/lib/json.lua
+++ /dev/null
@@ -1,196 +0,0 @@
---[[ json.lua
-
-A compact pure-Lua JSON library.
-The main functions are: json.stringify, json.parse.
-
-## json.stringify:
-
-This expects the following to be true of any tables being encoded:
- * They only have string or number keys. Number keys must be represented as
- strings in json; this is part of the json spec.
- * They are not recursive. Such a structure cannot be specified in json.
-
-A Lua table is considered to be an array if and only if its set of keys is a
-consecutive sequence of positive integers starting at 1. Arrays are encoded like
-so: `[2, 3, false, "hi"]`. Any other type of Lua table is encoded as a json
-object, encoded like so: `{"key1": 2, "key2": false}`.
-
-Because the Lua nil value cannot be a key, and as a table value is considerd
-equivalent to a missing key, there is no way to express the json "null" value in
-a Lua table. The only way this will output "null" is if your entire input obj is
-nil itself.
-
-An empty Lua table, {}, could be considered either a json object or array -
-it's an ambiguous edge case. We choose to treat this as an object as it is the
-more general type.
-
-To be clear, none of the above considerations is a limitation of this code.
-Rather, it is what we get when we completely observe the json specification for
-as arbitrary a Lua object as json is capable of expressing.
-
-## json.parse:
-
-This function parses json, with the exception that it does not pay attention to
-\u-escaped unicode code points in strings.
-
-It is difficult for Lua to return null as a value. In order to prevent the loss
-of keys with a null value in a json string, this function uses the one-off
-table value json.null (which is just an empty table) to indicate null values.
-This way you can check if a value is null with the conditional
-`val == json.null`.
-
-If you have control over the data and are using Lua, I would recommend just
-avoiding null values in your data to begin with.
-
---]]
-
-
-local json = {}
-
-
--- Internal functions.
-
-local function kind_of(obj)
- if type(obj) ~= 'table' then return type(obj) end
- local i = 1
- for _ in pairs(obj) do
- if obj[i] ~= nil then i = i + 1 else return 'table' end
- end
- if i == 1 then return 'table' else return 'array' end
-end
-
-local function escape_str(s)
- local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'}
- local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'}
- for i, c in ipairs(in_char) do
- s = s:gsub(c, '\\' .. out_char[i])
- end
- return s
-end
-
--- Returns pos, did_find; there are two cases:
--- 1. Delimiter found: pos = pos after leading space + delim; did_find = true.
--- 2. Delimiter not found: pos = pos after leading space; did_find = false.
--- This throws an error if err_if_missing is true and the delim is not found.
-local function skip_delim(str, pos, delim, err_if_missing)
- pos = pos + #str:match('^%s*', pos)
- if str:sub(pos, pos) ~= delim then
- if err_if_missing then
- error('Expected ' .. delim .. ' near position ' .. pos)
- end
- return pos, false
- end
- return pos + 1, true
-end
-
--- Expects the given pos to be the first character after the opening quote.
--- Returns val, pos; the returned pos is after the closing quote character.
-local function parse_str_val(str, pos, val)
- val = val or ''
- local early_end_error = 'End of input found while parsing string.'
- if pos > #str then error(early_end_error) end
- local c = str:sub(pos, pos)
- if c == '"' then return val, pos + 1 end
- if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end
- -- We must have a \ character.
- local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'}
- local nextc = str:sub(pos + 1, pos + 1)
- if not nextc then error(early_end_error) end
- return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc))
-end
-
--- Returns val, pos; the returned pos is after the number's final character.
-local function parse_num_val(str, pos)
- local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos)
- local val = tonumber(num_str)
- if not val then error('Error parsing number at position ' .. pos .. '.') end
- return val, pos + #num_str
-end
-
-
--- Public values and functions.
-
-function json.stringify(obj, as_key)
- local s = {} -- We'll build the string as an array of strings to be concatenated.
- local kind = kind_of(obj) -- This is 'array' if it's an array or type(obj) otherwise.
- if kind == 'array' then
- if as_key then error('Can\'t encode array as key.') end
- s[#s + 1] = '['
- for i, val in ipairs(obj) do
- if i > 1 then s[#s + 1] = ', ' end
- s[#s + 1] = json.stringify(val)
- end
- s[#s + 1] = ']'
- elseif kind == 'table' then
- if as_key then error('Can\'t encode table as key.') end
- s[#s + 1] = '{'
- for k, v in pairs(obj) do
- if #s > 1 then s[#s + 1] = ', ' end
- s[#s + 1] = json.stringify(k, true)
- s[#s + 1] = ':'
- s[#s + 1] = json.stringify(v)
- end
- s[#s + 1] = '}'
- elseif kind == 'string' then
- return '"' .. escape_str(obj) .. '"'
- elseif kind == 'number' then
- if as_key then return '"' .. tostring(obj) .. '"' end
- return tostring(obj)
- elseif kind == 'boolean' then
- return tostring(obj)
- elseif kind == 'nil' then
- return 'null'
- else
- --error('Unjsonifiable type: ' .. kind .. '.')
- return tostring(obj)
- end
- return table.concat(s)
-end
-
-json.null = {} -- This is a one-off table to represent the null value.
-
-function json.parse(str, pos, end_delim)
- pos = pos or 1
- if pos > #str then error('Reached unexpected end of input.') end
- local pos = pos + #str:match('^%s*', pos) -- Skip whitespace.
- local first = str:sub(pos, pos)
- if first == '{' then -- Parse an object.
- local obj, key, delim_found = {}, true, true
- pos = pos + 1
- while true do
- key, pos = json.parse(str, pos, '}')
- if key == nil then return obj, pos end
- if not delim_found then error('Comma missing between object items.') end
- pos = skip_delim(str, pos, ':', true) -- true -> error if missing.
- obj[key], pos = json.parse(str, pos)
- pos, delim_found = skip_delim(str, pos, ',')
- end
- elseif first == '[' then -- Parse an array.
- local arr, val, delim_found = {}, true, true
- pos = pos + 1
- while true do
- val, pos = json.parse(str, pos, ']')
- if val == nil then return arr, pos end
- if not delim_found then error('Comma missing between array items.') end
- arr[#arr + 1] = val
- pos, delim_found = skip_delim(str, pos, ',')
- end
- elseif first == '"' then -- Parse a string.
- return parse_str_val(str, pos + 1)
- elseif first == '-' or first:match('%d') then -- Parse a number.
- return parse_num_val(str, pos)
- elseif first == end_delim then -- End of an object or array.
- return nil, pos + 1
- else -- Parse true, false, or null.
- local literals = {['true'] = true, ['false'] = false, ['null'] = json.null}
- for lit_str, lit_val in pairs(literals) do
- local lit_end = pos + #lit_str - 1
- if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end
- end
- local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10)
- print('ERROR: Invalid json syntax starting at ' .. pos_info_str)
- return nil
- end
-end
-
-return json
diff --git a/lib/keybinds.lua b/lib/keybinds.lua
deleted file mode 100644
index 23cc10a..0000000
--- a/lib/keybinds.lua
+++ /dev/null
@@ -1,295 +0,0 @@
-local inputs = dofile_once("mods/evaisa.mp/lib/list_inputs.lua")
-
-local smallfolk = dofile_once("mods/evaisa.mp/lib/smallfolk.lua")
-
-local bindings = {
- _bindings = {},
- _binding_order = {},
- RegisterBinding = function(self, id, category, name, default, default_type, allow_mouse, allow_keyboard, allow_gamepad, allow_axis, allow_axis_button)
- if(allow_mouse == nil)then
- allow_mouse = true
- end
- if(allow_keyboard == nil)then
- allow_keyboard = true
- end
- if(allow_gamepad == nil)then
- allow_gamepad = true
- end
- if self._bindings[id] == nil then
- self._bindings[id] = {
- category = category,
- name = name,
- default = default,
- default_type = default_type,
- value = ModSettingGet("keybind."..category .. "." .. id) or default,
- being_set = false,
- allow_mouse = allow_mouse,
- allow_keyboard = allow_keyboard,
- allow_gamepad = allow_gamepad,
- allow_axis = allow_axis,
- allow_axis_button = allow_axis_button,
- type = ModSettingGet("keybind."..category .. "." .. id .. ".type") or default_type,
- was_down = false,
- }
- print("registering binding: " .. id)
- table.insert(self._binding_order, id)
- end
-
- GlobalsSetValue("evaisa.mp.keybinds", smallfolk.dumps(self._bindings))
- GlobalsSetValue("evaisa.mp.keybinds_order", smallfolk.dumps(self._binding_order))
- end,
- Load = function(self)
- local data = GlobalsGetValue("evaisa.mp.keybinds", "{}")
- print(data)
- local data = smallfolk.loads(data)
-
- self._bindings = data
-
- local order_s = GlobalsGetValue("evaisa.mp.keybinds_order", "{}")
- local order = smallfolk.loads(order_s)
- self._binding_order = order
-
- GameRemoveFlagRun("evaisa.mp.binding_being_set")
- end,
- IsJustDown = function(self, id)
- if(GameHasFlagRun("evaisa.mp.reload_bindings"))then
- GameRemoveFlagRun("evaisa.mp.reload_bindings")
- print("reloading binds!")
- self:Load()
- end
- local handlers = {
- mouse = function(name)
- return InputIsMouseButtonJustDown(inputs.mouse[name])
- end,
- key = function(name)
- return InputIsKeyJustDown(inputs.key[name])
- end,
- joy = function(name)
- return InputIsJoystickButtonJustDown(0, inputs.joy[name])
- end,
- }
-
- local binding = self._bindings[id]
- if binding ~= nil then
- local type = binding.type
- if type ~= nil and handlers[type] ~= nil then
- return handlers[type](binding.value)
- end
- end
- end,
- IsJustUp = function(self, id)
- if(GameHasFlagRun("evaisa.mp.reload_bindings"))then
- GameRemoveFlagRun("evaisa.mp.reload_bindings")
- self:Load()
- end
- local binding = self._bindings[id]
- if binding ~= nil then
- local handlers = {
- mouse = function(name)
- return InputIsMouseButtonJustUp(inputs.mouse[name])
- end,
- key = function(name)
- return InputIsKeyJustUp(inputs.key[name])
- end,
- joy = function(name)
- return InputIsJoystickButtonJustDown(0, inputs.joy[name]) and not binding.was_down
- end,
- }
-
-
- local type = binding.type
- if type ~= nil and handlers[type] ~= nil then
- return handlers[type](binding.value)
- end
- end
- end,
- IsDown = function(self, id)
- if(GameHasFlagRun("evaisa.mp.reload_bindings"))then
- GameRemoveFlagRun("evaisa.mp.reload_bindings")
- self:Load()
- end
- local binding = self._bindings[id]
- if binding ~= nil then
- local handlers = {
- mouse = function(name)
- return InputIsMouseButtonDown(inputs.mouse[name])
- end,
- key = function(name)
- return InputIsKeyDown(inputs.key[name])
- end,
- joy = function(name)
- return InputIsJoystickButtonDown(0, inputs.joy[name])
- end,
- }
-
- local type = binding.type
- if type ~= nil and handlers[type] ~= nil then
- return handlers[type](binding.value)
- end
- end
- end,
- GetAxis = function(self, id)
- if(GameHasFlagRun("evaisa.mp.reload_bindings"))then
- GameRemoveFlagRun("evaisa.mp.reload_bindings")
- self:Load()
- end
- local binding = self._bindings[id]
- if binding ~= nil then
- local handlers = {
- axis = function(name)
- local x, y = InputGetJoystickAnalogStick(0, inputs.stick[name])
- return x, y
- end,
- axis_button = function(name)
- return InputGetJoystickAnalogButton(0, inputs.trigger[name])
- end,
- }
-
- local type = binding.type
- if type ~= nil and handlers[type] ~= nil then
- local a, b = handlers[type](binding.value)
- return a, b
- end
- end
-
- return 0, 0
- end,
- Get = function(self, id)
- local binding = self._bindings[id]
- if binding ~= nil then
- return binding.value
- end
- return nil
- end,
- TrySet = function(self, id)
- local binding = self._bindings[id]
- if binding ~= nil and not GameHasFlagRun("evaisa.mp.binding_being_set") then
- GameAddFlagRun("evaisa.mp.binding_being_set")
- binding.being_set = true
- end
- end,
- Update = function(self)
-
- for bind_id, v in pairs(self._bindings)do
- local binding = v
- if binding ~= nil then
-
- if(v.type == "joy")then
- if(InputIsJoystickButtonDown(0, inputs.joy[binding.value]))then
- binding.was_down = true
- else
- if(binding.was_down)then
- binding.was_down = false
- end
- end
- end
-
- if binding.being_set then
-
- print("binding still being set!!")
-
- local set = false
- -- if backspace is pressed, unbind
- if(InputIsKeyJustDown(inputs.key.Key_BACKSPACE))then
- binding.value = ""
- binding.being_set = false
- GameRemoveFlagRun("evaisa.mp.binding_being_set")
- ModSettingSet("keybind."..binding.category .. "." .. bind_id, "")
- ModSettingSet("keybind."..binding.category .. "." .. bind_id .. ".type", "key")
- GameAddFlagRun("evaisa.mp.reload_bindings")
- end
-
- if(binding.allow_mouse)then
- if(not set)then
- for name, id in pairs(inputs.mouse)do
- if(InputIsMouseButtonJustDown(id))then
- binding.value = name
- binding.being_set = false
- GameRemoveFlagRun("evaisa.mp.binding_being_set")
- ModSettingSet("keybind."..binding.category .. "." .. bind_id, name)
- binding.type = "mouse"
- ModSettingSet("keybind."..binding.category .. "." .. bind_id .. ".type", "mouse")
- set = true
- break
- end
- end
- end
- end
- if(binding.allow_keyboard)then
- if not set then
- for name, id in pairs(inputs.key)do
- if(InputIsKeyJustDown(id))then
- binding.value = name
- binding.being_set = false
- GameRemoveFlagRun("evaisa.mp.binding_being_set")
- ModSettingSet("keybind."..binding.category .. "." .. bind_id, name)
- binding.type = "key"
- ModSettingSet("keybind."..binding.category .. "." .. bind_id .. ".type", "key")
- set = true
- break
- end
- end
- end
- end
- if(binding.allow_gamepad)then
- if not set then
- for name, id in pairs(inputs.joy)do
- if(InputIsJoystickButtonJustDown(0, id))then
- binding.value = name
- binding.being_set = false
- GameRemoveFlagRun("evaisa.mp.binding_being_set")
- ModSettingSet("keybind."..binding.category .. "." .. bind_id, name)
- binding.type = "joy"
- ModSettingSet("keybind."..binding.category .. "." .. bind_id .. ".type", "joy")
- set = true
- break
- end
- end
- end
- end
- if(binding.allow_axis)then
- if not set then
- for name, id in pairs(inputs.stick)do
- if(InputGetJoystickAnalogStick(0, id) > 0.9 or InputGetJoystickAnalogStick(0, id) < -0.9)then
- binding.value = name
- binding.being_set = false
- GameRemoveFlagRun("evaisa.mp.binding_being_set")
- ModSettingSet("keybind."..binding.category .. "." .. bind_id, name)
- binding.type = "axis"
- ModSettingSet("keybind."..binding.category .. "." .. bind_id .. ".type", "axis")
- set = true
- break
- end
- end
- end
- end
- if(binding.allow_axis_button)then
- if(not set)then
- for name, id in pairs(inputs.trigger)do
- if(InputGetJoystickAnalogButton(0, id) > 0.9)then
- binding.value = name
- binding.being_set = false
- GameRemoveFlagRun("evaisa.mp.binding_being_set")
- ModSettingSet("keybind."..binding.category .. "." .. bind_id, name)
- binding.type = "axis_button"
- ModSettingSet("keybind."..binding.category .. "." .. bind_id .. ".type", "axis_button")
- set = true
- break
- end
- end
- end
- end
-
- if(set)then
- GlobalsSetValue("evaisa.mp.keybinds", smallfolk.dumps(self._bindings))
- GameAddFlagRun("evaisa.mp.reload_bindings")
- end
- end
- end
- end
- end,
-}
-
-
-
-return bindings
\ No newline at end of file
diff --git a/lib/keyboard.lua b/lib/keyboard.lua
deleted file mode 100644
index 57c5d67..0000000
--- a/lib/keyboard.lua
+++ /dev/null
@@ -1,76 +0,0 @@
-if _hacky_keyboard_defined then
- return
-end
-
-_hacky_keyboard_defined = true
-
-if not require then
- mp_log:print("No require? Urgh.")
- return
-end
-
-local ffi = require('ffi')
-if not ffi then
- mp_log:print("No FFI? Well that's a pain.")
- return
-end
-
-_keyboard_present = true
-
-ffi.cdef([[
- const uint8_t* SDL_GetKeyboardState(int* numkeys);
- uint32_t SDL_GetKeyFromScancode(uint32_t scancode);
- char* SDL_GetScancodeName(uint32_t scancode);
- char* SDL_GetKeyName(uint32_t key);
-]])
-_SDL = ffi.load('SDL2.dll')
-
-local code_to_a = {}
-local shifts = {}
-
-for i = 0, 284 do
- local keycode = _SDL.SDL_GetKeyFromScancode(i)
- if keycode > 0 then
- local keyname = ffi.string(_SDL.SDL_GetKeyName(keycode))
- if keyname and #keyname > 0 then
- code_to_a[i] = keyname:lower()
- if keyname:lower():find("shift") then
- table.insert(shifts, i)
- end
- end
- end
-end
-
-local prev_state = {}
-for i = 0, 284 do
- prev_state[i] = 0
-end
-
-function hack_update_keys()
- local keys = _SDL.SDL_GetKeyboardState(nil)
- local pressed = {}
- local held = {}
- local released = {}
- -- start at scancode 1 because we don't care about "UNKNOWN"
- for scancode = 1, 284 do
- if keys[scancode] > 0 then
- if prev_state[scancode] <= 0 then
- pressed[#pressed+1] = code_to_a[scancode]
- end
- held[#held+1] = code_to_a[scancode]
- elseif prev_state[scancode] > 0 then
- released[#released+1] = code_to_a[scancode]
- end
- prev_state[scancode] = keys[scancode]
- end
-
- local shift_held = false
- for _, shiftcode in ipairs(shifts) do
- if keys[shiftcode] > 0 then
- shift_held = true
- break
- end
- end
-
- return pressed, held, released, shift_held
-end
diff --git a/lib/libspng.lua b/lib/libspng.lua
deleted file mode 100644
index e5efe0b..0000000
--- a/lib/libspng.lua
+++ /dev/null
@@ -1,443 +0,0 @@
-
---libspng LuaJIT binding.
---Written by Cosmin Apreutesei. Public Domain.
-
---if not ... then require'libspng_demo'; return end
-
-local bit = require'bit'
-local ffi = require'ffi'
-require'libspng_h'
-local C = ffi.load(package.searchpath('spng', package.cpath))
-
---given a row stride, return the next larger stride that is a multiple of 4.
-local function pad_stride(stride)
- return bit.band(stride + 3, bit.bnot(3))
-end
-
-local spng = {version = ffi.string(C.spng_version_string())}
-
-local formats = { --bpc:
- [C.SPNG_COLOR_TYPE_GRAYSCALE ] = 'g' , --1,2,4,8,16
- [C.SPNG_COLOR_TYPE_TRUECOLOR ] = 'rgb' , --8,16
- [C.SPNG_COLOR_TYPE_INDEXED ] = 'i' , --8 (with 1,2,4,8 indexes)
- [C.SPNG_COLOR_TYPE_GRAYSCALE_ALPHA] = 'ga' , --8,16
- [C.SPNG_COLOR_TYPE_TRUECOLOR_ALPHA] = 'rgba', --8,16
-}
-
---all conversions that libspng implements, in order of preference,
---with or without gamma conversion: {source = {dest1, ...}}.
-local rgb8 = {'rgba8', 'bgra8', 'rgb8', 'rgba16'}
-local rgba8 = {'rgba8', 'bgra8', 'rgba16', 'rgb8'}
-local rgb16 = {'rgba16', 'rgba8', 'bgra8', 'rgb8'}
-local rgba16 = {'rgba16', 'rgba8', 'bgra8', 'rgb8'}
-local g8 = {'ga8', 'rgba8', 'bgra8', 'rgba16', 'g8', 'rgb8'}
-local ga8 = {'ga8', 'rgba8', 'bgra8', 'rgba16', 'g8', 'rgb8'}
-local g16 = {'ga16', 'rgba16', 'rgba8', 'bgra8', 'rgb8'}
-local ga16 = {'ga16', 'rgba16', 'rgba8', 'bgra8', 'rgb8'}
-local conversions = {
- g1 = g8,
- g2 = g8,
- g4 = g8,
- g8 = g8,
- g16 = g16,
- ga8 = ga8,
- ga16 = ga16,
- rgb8 = rgb8,
- rgba8 = rgba8,
- rgb16 = rgb16,
- rgba16 = rgba16,
- i1 = rgb8,
- i2 = rgb8,
- i4 = rgb8,
- i8 = rgb8,
-}
-
-local dest_formats_no_gamma = {
- rgba8 = C.SPNG_FMT_RGBA8,
- bgra8 = C.SPNG_FMT_RGBA8,
- rgba16 = C.SPNG_FMT_RGBA16,
- rgb8 = C.SPNG_FMT_RGB8,
- g8 = C.SPNG_FMT_G8,
- ga16 = C.SPNG_FMT_GA16,
- ga8 = C.SPNG_FMT_GA8,
-}
-
-local dest_formats_gamma = {
- rgba8 = C.SPNG_FMT_RGBA8,
- bgra8 = C.SPNG_FMT_RGBA8,
- rgba16 = C.SPNG_FMT_RGBA16,
- rgb8 = C.SPNG_FMT_RGB8,
-}
-
-local function best_fmt(raw_fmt, accept, gamma)
- local dest_formats = gamma and dest_formats_gamma or dest_formats_no_gamma
- if accept and conversions[raw_fmt] then --source format convertible
- for _,bmp_fmt in ipairs(conversions[raw_fmt]) do
- if accept[bmp_fmt] then --found a dest format
- local spng_fmt = dest_formats[bmp_fmt]
- if spng_fmt then --dest format is available
- return bmp_fmt, spng_fmt
- end
- end
- end
- end
- return raw_fmt, C.SPNG_FMT_PNG
-end
-
-local function struct_getter(ct, get) --getter for a struct type
- local ct = ffi.typeof(ct)
- return function(ctx)
- local s = ct()
- return get(ctx, s) == 0 and s or nil
- end
-end
-local function prim_getter(ct, get) --getter for a primitive type
- local ct = ffi.typeof(ct)
- return function(ctx)
- local s = ct()
- return get(ctx, s) == 0 and s[0] or nil
- end
-end
-local function list_getter(ct, get) --getter for a list of structs
- local ct = ffi.typeof(ct)
- return function(ctx)
- local n = ffi.new'uint32_t[1]'
- if get(ctx, nil, n) ~= 0 then return nil end
- n = n[0]
- local s = ct(n)
- if get(ctx, s, n) ~= 0 then return nil end
- return s, n
- end
-end
-local chunk_decoders = {
- ihdr = struct_getter('struct spng_ihdr' , C.spng_get_ihdr),
- plte = struct_getter('struct spng_plte' , C.spng_get_plte),
- trns = struct_getter('struct spng_trns' , C.spng_get_trns),
- chrm = struct_getter('struct spng_chrm' , C.spng_get_chrm),
- chrm_int = struct_getter('struct spng_chrm_int', C.spng_get_chrm_int),
- gama = prim_getter('double[1]' , C.spng_get_gama),
- gama_int = prim_getter('uint32_t[1]' , C.spng_get_gama_int),
- iccp = struct_getter('struct spng_iccp' , C.spng_get_iccp),
- sbit = struct_getter('struct spng_sbit' , C.spng_get_sbit),
- srgb = prim_getter('uint8_t[1]' , C.spng_get_srgb),
- bkgd = struct_getter('struct spng_bkgd' , C.spng_get_bkgd),
- hist = struct_getter('struct spng_hist' , C.spng_get_hist),
- phys = struct_getter('struct spng_phys' , C.spng_get_phys),
- time = struct_getter('struct spng_time' , C.spng_get_time),
- text = list_getter('struct spng_text[?]' , C.spng_get_text),
- splt = list_getter('struct spng_splt[?]' , C.spng_get_splt),
- offs = struct_getter('struct spng_offs' , C.spng_get_offs),
- exif = struct_getter('struct spng_exif' , C.spng_get_exif),
- unknown = list_getter('struct spng_unknown_chunk', C.spng_get_unknown_chunks),
-}
-
-local u8a = ffi.typeof'uint8_t[?]'
-local u8p = ffi.typeof'uint8_t*'
-local rw_fn_ct = ffi.typeof'spng_rw_fn*'
---^^ very important to typeof this to avoid "table overflow" !
-
-local premultiply_funcs = {
- rgba8 = C.spng_premultiply_alpha_rgba8,
- bgra8 = C.spng_premultiply_alpha_rgba8,
- rgba16 = C.spng_premultiply_alpha_rgba16,
- ga8 = C.spng_premultiply_alpha_ga8,
- ga16 = C.spng_premultiply_alpha_ga16,
-}
-
-function spng.open(opt)
-
- local read
- if type(opt) == 'string' then
- local pos = 1
- read = function(buf, len)
- local part = opt:sub(pos, pos + len - 1)
- ffi.copy(buf, part, #part)
- pos = pos + #part
- return #part
- end
- elseif type(opt) == 'function' then
- opt = {read = opt}
- read = assert(opt.read, 'read expected')
- elseif type(opt) == 'table' then
- read = assert(opt.read, 'read expected')
- else
- error('Invalid argument type')
- end
-
- local ctx = C.spng_ctx_new(0)
- assert(ctx ~= nil)
-
- local read_cb
- local function free()
- if read_cb then read_cb:free(); read_cb = nil end
- if ctx then C.spng_ctx_free(ctx); ctx = nil end
- end
-
- local function check(ret)
- if ret == 0 then return true end
- free()
- return nil, ffi.string(C.spng_strerror(ret))
- end
-
- local read_err
- local function spng_read(ctx, _, buf, len)
- len = tonumber(len)
- ::again::
- local sz, err = read(buf, len)
- if not sz then read_err = err; return -2 end --SPNG_IO_ERROR
- if sz == 0 then return -1 end -- SPNG_IO_EOF
- if sz < len then --partial read
- len = len - sz
- buf = buf + sz
- goto again
- end
- return 0
- end
-
- read_cb = ffi.cast(rw_fn_ct, spng_read)
- local ok, err = check(C.spng_set_png_stream(ctx, read_cb, nil))
- if not ok then
- return nil, err
- end
- local ok, err = check(C.spng_decode_chunks(ctx))
- if not ok then
- return nil, read_err or err
- end
-
- local img = {free = free}
-
- function img:chunk(name)
- local decode = chunk_decoders[name]
- if not decode then
- return nil, 'unknown chunk name '..name
- end
- return decode(ctx)
- end
-
- local ihdr = img:chunk'ihdr'
- if not ihdr then
- free()
- return nil, 'invalid header'
- end
- img.w = ihdr.width
- img.h = ihdr.height
- local bpc = ihdr.bit_depth
- img.format = formats[ihdr.color_type]..bpc
- img.interlaced = ihdr.interlace_method ~= C.SPNG_INTERLACE_NONE or nil
- img.indexed = ihdr.color_type == C.SPNG_COLOR_TYPE_INDEXED or nil
- ihdr = nil
-
- function img:load(opt)
-
- local gamma = opt and opt.gamma
- local accept = opt and opt.accept
- local bmp_fmt, spng_fmt = best_fmt(img.format, accept, gamma)
-
- local nb = ffi.new'size_t[1]'
- local ok, err = check(C.spng_decoded_image_size(ctx, spng_fmt, nb))
- if not ok then
- return nil, err
- end
- local row_size = tonumber(nb[0]) / img.h
-
- local bmp = {w = img.w, h = img.h, format = bmp_fmt}
-
- bmp.stride = row_size
- if opt and opt.accept and opt.accept.stride_aligned then
- bmp.stride = pad_stride(bmp.stride)
- end
- bmp.size = bmp.stride * bmp.h
- bmp.data = ffi.new(u8a, bmp.size)
-
- local flags = bit.bor(
- C.SPNG_DECODE_TRNS,
- gamma and C.SPNG_DECODE_GAMMA or 0,
- C.SPNG_DECODE_PROGRESSIVE
- )
- C.spng_decode_image(ctx, nil, 0, spng_fmt, flags)
-
- local row_info = ffi.new'struct spng_row_info'
- local bottom_up = opt and opt.accept and opt.accept.bottom_up
- bmp.bottom_up = bottom_up
- local row_sz = bmp.size / bmp.h
-
- local function check_partial(ret)
- if ret == 0 then return end
- bmp.partial = true
- bmp.read_error = read_err or select(2, check(ret))
- return true
- end
- while true do
- if check_partial(C.spng_get_row_info(ctx, row_info)) then break end
- local i = row_info.row_num
- if bottom_up then i = img.h - i - 1 end
- local row = bmp.data + bmp.stride * i
- local ret = C.spng_decode_row(ctx, row, row_size)
- if ret == 75 then break end --SPNG_EOI
- if check_partial(ret) then break end
- end
-
- local premultiply_alpha =
- (not opt or opt.premultiply_alpha ~= false)
- and (img.format:find('a', 1, true) or img:chunk'trns')
- and premultiply_funcs[bmp.format]
- if premultiply_alpha then
- premultiply_alpha(bmp.data, bmp.size)
- end
-
- if bmp.format == 'bgra8' then --cairo's native format.
- C.spng_rgba8_to_bgra8(bmp.data, bmp.size)
- end
-
- return bmp
- end
- jit.off(img.load) --calls back into Lua through a ffi call.
-
- return img
-end
-
-jit.off(spng.open) --calls back into Lua through a ffi call.
-
-local function struct_setter(ct, set) --setter for a struct type
- local ct = ffi.typeof(ct)
- return function(ctx, v)
- local s = ct(v)
- return set(ctx, s) == 0
- end
-end
-local function prim_setter(ct, set) --setter for a primitive type
- local ct = ffi.typeof(ct)
- return function(ctx, v)
- local s = ct(v)
- return set(ctx, s) == 0
- end
-end
-local function list_setter(ct, set) --setter for a list of structs
- local ct = ffi.typeof(ct)
- return function(ctx, v)
- local t = ct(#v, v)
- return set(ctx, t, #v) == 0
- end
-end
-local chunk_encoders = {
- ihdr = struct_setter('struct spng_ihdr' , C.spng_set_ihdr),
- plte = struct_setter('struct spng_plte' , C.spng_set_plte),
- trns = struct_setter('struct spng_trns' , C.spng_set_trns),
- chrm = struct_setter('struct spng_chrm' , C.spng_set_chrm),
- chrm_int = struct_setter('struct spng_chrm_int', C.spng_set_chrm_int),
- gama = prim_setter('double[1]' , C.spng_set_gama),
- gama_int = prim_setter('uint32_t[1]' , C.spng_set_gama_int),
- iccp = struct_setter('struct spng_iccp' , C.spng_set_iccp),
- sbit = struct_setter('struct spng_sbit' , C.spng_set_sbit),
- srgb = prim_setter('uint8_t[1]' , C.spng_set_srgb),
- bkgd = struct_setter('struct spng_bkgd' , C.spng_set_bkgd),
- hist = struct_setter('struct spng_hist' , C.spng_set_hist),
- phys = struct_setter('struct spng_phys' , C.spng_set_phys),
- time = struct_setter('struct spng_time' , C.spng_set_time),
- text = list_setter('struct spng_text[?]' , C.spng_set_text),
- splt = list_setter('struct spng_splt[?]' , C.spng_set_splt),
- offs = struct_setter('struct spng_offs' , C.spng_set_offs),
- exif = struct_setter('struct spng_exif' , C.spng_set_exif),
- unknown = list_setter('struct spng_unknown_chunk', C.spng_set_unknown_chunks),
-}
-
-local color_types = {
- g1 = C.SPNG_COLOR_TYPE_GRAYSCALE,
- g2 = C.SPNG_COLOR_TYPE_GRAYSCALE,
- g4 = C.SPNG_COLOR_TYPE_GRAYSCALE,
- g8 = C.SPNG_COLOR_TYPE_GRAYSCALE,
- g16 = C.SPNG_COLOR_TYPE_GRAYSCALE,
- ga8 = C.SPNG_COLOR_TYPE_GRAYSCALE_ALPHA,
- ga16 = C.SPNG_COLOR_TYPE_GRAYSCALE_ALPHA,
- rgb8 = C.SPNG_COLOR_TYPE_TRUECOLOR,
- rgba8 = C.SPNG_COLOR_TYPE_TRUECOLOR_ALPHA,
- bgra8 = C.SPNG_COLOR_TYPE_TRUECOLOR_ALPHA,
- rgba16 = C.SPNG_COLOR_TYPE_TRUECOLOR_ALPHA,
- i1 = C.SPNG_COLOR_TYPE_INDEXED,
- i2 = C.SPNG_COLOR_TYPE_INDEXED,
- i4 = C.SPNG_COLOR_TYPE_INDEXED,
- i8 = C.SPNG_COLOR_TYPE_INDEXED,
-}
-
-function spng.save(opt)
-
- local bmp = assert(opt and opt.bitmap, 'bitmap expected')
- local write = assert(opt and opt.write, 'write expected')
- if bmp.bottom_up then
- return nil, 'bottom-up bitmap NYI'
- end
-
- local ctx = C.spng_ctx_new(C.SPNG_CTX_ENCODER)
- assert(ctx ~= nil)
-
- local write_cb
- local function free()
- if write_cb then write_cb:free(); write_cb = nil end
- if ctx then C.spng_ctx_free(ctx); ctx = nil end
- end
-
- local function check(ret)
- if ret == 0 then return true end
- free()
- return nil, ffi.string(C.spng_strerror(ret))
- end
-
- local write_err
- local function spng_write(ctx, _, buf, len)
- len = tonumber(len)
- local ok, err = write(buf, len)
- if not ok then write_err = err; return -2 end --SPNG_IO_ERROR
- return 0
- end
-
- --[[local]] write_cb = ffi.cast(rw_fn_ct, spng_write)
- local ok, err = check(C.spng_set_png_stream(ctx, write_cb, nil))
- if not ok then
- return nil, err
- end
-
- local color_type = color_types[bmp.format]
- local bpc = tonumber(bmp.format:match'%d+$')
- if not color_type or not bpc then
- return nil, 'invalid format '..bmp.format
- end
-
- assert(chunk_encoders.ihdr(ctx, {
- width = bmp.w,
- height = bmp.h,
- bit_depth = bpc,
- color_type = color_type,
- compression_method = 0,
- filter_method = 0,
- interlace_method = 0,
- }))
-
- if opt.chunks then
- for name, v in pairs(chunks) do
- local encode = assert(chunk_encoders[name], 'unknown chunk '..name)
- assert(encode(ctx, v), 'invalid chunk '..name)
- end
- end
-
- local data = bmp.data
- if bmp.format == 'bgra8' then
- data = ffi.new(u8a, bmp.size)
- ffi.copy(data, bmp.data, bmp.size)
- C.spng_rgba8_to_bgra8(data, bmp.size)
- end
-
- local fmt = C.SPNG_FMT_PNG
- local flags = C.SPNG_ENCODE_FINALIZE
- local ok, err = check(C.spng_encode_image(ctx, data, bmp.size, fmt, flags))
-
- free()
-
- if not ok then
- return nil, write_err or err
- end
-
- return true
-end
-jit.off(spng.save) --calls back into Lua through a ffi call.
-
-return spng
diff --git a/lib/libspng_demo.lua b/lib/libspng_demo.lua
deleted file mode 100644
index 2386379..0000000
--- a/lib/libspng_demo.lua
+++ /dev/null
@@ -1,87 +0,0 @@
-local spng = require'libspng'
-local testui = require'testui'
-local glue = require'glue'
-local fs = require'fs'
-local ffi = require'ffi'
-require'unit' --dir
-
-local filesets = {
- good_files = dir'media/png/good/*.png',
- bad_files = dir'media/png/bad/*.png',
-}
-local files = 'good_files'
-local bottom_up = false
-local stride_aligned = false
-local max_cut_size = 1024 * 6
-local cut_size = max_cut_size
-local pixel_formats = {bgra8 = true}
-local gamma = false
-
-function testui:repaint()
-
- self:checkerboard()
-
- self:pushgroup'right'
- local _
- _,files = self:choose('files', {'good_files', 'bad_files'}, files)
- _,bottom_up = self:button('bottom_up', bottom_up)
- _,stride_aligned = self:button('stride_aligned', stride_aligned)
- _,cut_size = self:slide('cut_size', cut_size, 0, max_cut_size, 1)
- _,pixel_formats = self:choose('format', {
- 'rgb8', 'rgba8', 'bgra8', 'rgba16', 'g8', 'ga8', 'ga16',
- }, pixel_formats)
- _,gamma = self:button('gamma', gamma)
- self:nextgroup()
-
- for i,path in ipairs(filesets[files]) do
-
- local f = assert(fs.open(path))
- local bufread = f:buffered_read()
- local left = cut_size
- local function read(buf, sz)
- if left == 0 then return 0 end
- local readsz, err = bufread(buf, math.min(left, sz))
- if not readsz then return nil, err end
- left = left - readsz
- return readsz
- end
-
- local img, bmp, err
- img, err = spng.open{read = read}
- if img then
- bmp, err = img:load{
- accept = glue.update({
- bottom_up = bottom_up,
- stride_aligned = stride_aligned,
- }, pixel_formats),
- gamma = gamma,
- }
- end
-
- if bmp and self.x + bmp.w >= self.window:client_size() then --wrap
- self:nextgroup()
- end
-
- if bmp then
-
- self:pushgroup'down'
- self:label(img.format)
- self:image(bmp)
- self:label(bmp.format)
- self:popgroup()
- self:rect(0, bmp.h * 2.5)
-
- else
- --self:rect(cx, cy, w, h, 'error_bg')
- --self:textbox(cx, cy, w, h,
- -- string.format('%s', err:match('^(.-)\n'):match(': ([^:]-)$')),
- -- 14, 'normal_fg', 'center', 'center')
- end
-
- if img then img:free() end
- end
-end
-
-testui:init()
-testui:continuous_repaint(1/0)
-testui:run()
diff --git a/lib/libspng_h.lua b/lib/libspng_h.lua
deleted file mode 100644
index 336afe9..0000000
--- a/lib/libspng_h.lua
+++ /dev/null
@@ -1,377 +0,0 @@
-require'ffi'.cdef[[
-
-enum spng_text_type
-{
- SPNG_TEXT = 1,
- SPNG_ZTXT = 2,
- SPNG_ITXT = 3
-};
-
-enum spng_color_type
-{
- SPNG_COLOR_TYPE_GRAYSCALE = 0,
- SPNG_COLOR_TYPE_TRUECOLOR = 2,
- SPNG_COLOR_TYPE_INDEXED = 3,
- SPNG_COLOR_TYPE_GRAYSCALE_ALPHA = 4,
- SPNG_COLOR_TYPE_TRUECOLOR_ALPHA = 6
-};
-
-enum spng_filter
-{
- SPNG_FILTER_NONE = 0,
- SPNG_FILTER_SUB = 1,
- SPNG_FILTER_UP = 2,
- SPNG_FILTER_AVERAGE = 3,
- SPNG_FILTER_PAETH = 4
-};
-
-enum spng_filter_choice
-{
- SPNG_DISABLE_FILTERING = 0,
- SPNG_FILTER_CHOICE_NONE = 8,
- SPNG_FILTER_CHOICE_SUB = 16,
- SPNG_FILTER_CHOICE_UP = 32,
- SPNG_FILTER_CHOICE_AVG = 64,
- SPNG_FILTER_CHOICE_PAETH = 128,
- SPNG_FILTER_CHOICE_ALL = (8|16|32|64|128)
-};
-
-enum spng_interlace_method
-{
- SPNG_INTERLACE_NONE = 0,
- SPNG_INTERLACE_ADAM7 = 1
-};
-
-/* Channels are always in byte-order */
-enum spng_format
-{
- SPNG_FMT_RGBA8 = 1,
- SPNG_FMT_RGBA16 = 2,
- SPNG_FMT_RGB8 = 4,
-
- /* Partially implemented, see documentation */
- SPNG_FMT_GA8 = 16,
- SPNG_FMT_GA16 = 32,
- SPNG_FMT_G8 = 64,
-
- /* No conversion or scaling */
- SPNG_FMT_PNG = 256, /* host-endian */
- SPNG_FMT_RAW = 512 /* big-endian */
-};
-
-enum spng_ctx_flags
-{
- SPNG_CTX_IGNORE_ADLER32 = 1, /* Ignore checksum in DEFLATE streams */
- SPNG_CTX_ENCODER = 2 /* Create an encoder context */
-};
-
-enum spng_decode_flags
-{
- SPNG_DECODE_USE_TRNS = 1, /* Deprecated */
- SPNG_DECODE_USE_GAMA = 2, /* Deprecated */
- SPNG_DECODE_USE_SBIT = 8, /* Undocumented */
-
- SPNG_DECODE_TRNS = 1, /* Apply transparency */
- SPNG_DECODE_GAMMA = 2, /* Apply gamma correction */
- SPNG_DECODE_PROGRESSIVE = 256 /* Initialize for progressive reads */
-};
-
-enum spng_crc_action
-{
- /* Default for critical chunks */
- SPNG_CRC_ERROR = 0,
-
- /* Discard chunk, invalid for critical chunks.
- Since v0.6.2: default for ancillary chunks */
- SPNG_CRC_DISCARD = 1,
-
- /* Ignore and don't calculate checksum.
- Since v0.6.2: also ignores checksums in DEFLATE streams */
- SPNG_CRC_USE = 2
-};
-
-enum spng_encode_flags
-{
- SPNG_ENCODE_PROGRESSIVE = 1, /* Initialize for progressive writes */
- SPNG_ENCODE_FINALIZE = 2, /* Finalize PNG after encoding image */
-};
-
-struct spng_ihdr
-{
- uint32_t width;
- uint32_t height;
- uint8_t bit_depth;
- uint8_t color_type;
- uint8_t compression_method;
- uint8_t filter_method;
- uint8_t interlace_method;
-};
-
-struct spng_plte_entry
-{
- uint8_t red;
- uint8_t green;
- uint8_t blue;
-
- uint8_t alpha; /* Reserved for internal use */
-};
-
-struct spng_plte
-{
- uint32_t n_entries;
- struct spng_plte_entry entries[256];
-};
-
-struct spng_trns
-{
- uint16_t gray;
-
- uint16_t red;
- uint16_t green;
- uint16_t blue;
-
- uint32_t n_type3_entries;
- uint8_t type3_alpha[256];
-};
-
-struct spng_chrm_int
-{
- uint32_t white_point_x;
- uint32_t white_point_y;
- uint32_t red_x;
- uint32_t red_y;
- uint32_t green_x;
- uint32_t green_y;
- uint32_t blue_x;
- uint32_t blue_y;
-};
-
-struct spng_chrm
-{
- double white_point_x;
- double white_point_y;
- double red_x;
- double red_y;
- double green_x;
- double green_y;
- double blue_x;
- double blue_y;
-};
-
-struct spng_iccp
-{
- char profile_name[80];
- size_t profile_len;
- char *profile;
-};
-
-struct spng_sbit
-{
- uint8_t grayscale_bits;
- uint8_t red_bits;
- uint8_t green_bits;
- uint8_t blue_bits;
- uint8_t alpha_bits;
-};
-
-struct spng_text
-{
- char keyword[80];
- int type;
-
- size_t length;
- char *text;
-
- uint8_t compression_flag; /* iTXt only */
- uint8_t compression_method; /* iTXt, ztXt only */
- char *language_tag; /* iTXt only */
- char *translated_keyword; /* iTXt only */
-};
-
-struct spng_bkgd
-{
- uint16_t gray; /* Only for gray/gray alpha */
- uint16_t red;
- uint16_t green;
- uint16_t blue;
- uint16_t plte_index; /* Only for indexed color */
-};
-
-struct spng_hist
-{
- uint16_t frequency[256];
-};
-
-struct spng_phys
-{
- uint32_t ppu_x, ppu_y;
- uint8_t unit_specifier;
-};
-
-struct spng_splt_entry
-{
- uint16_t red;
- uint16_t green;
- uint16_t blue;
- uint16_t alpha;
- uint16_t frequency;
-};
-
-struct spng_splt
-{
- char name[80];
- uint8_t sample_depth;
- uint32_t n_entries;
- struct spng_splt_entry *entries;
-};
-
-struct spng_time
-{
- uint16_t year;
- uint8_t month;
- uint8_t day;
- uint8_t hour;
- uint8_t minute;
- uint8_t second;
-};
-
-struct spng_offs
-{
- int32_t x, y;
- uint8_t unit_specifier;
-};
-
-struct spng_exif
-{
- size_t length;
- char *data;
-};
-
-struct spng_chunk
-{
- size_t offset;
- uint32_t length;
- uint8_t type[4];
- uint32_t crc;
-};
-
-enum spng_location
-{
- SPNG_AFTER_IHDR = 1,
- SPNG_AFTER_PLTE = 2,
- SPNG_AFTER_IDAT = 8,
-};
-
-struct spng_unknown_chunk
-{
- uint8_t type[4];
- size_t length;
- void *data;
- enum spng_location location;
-};
-
-enum spng_option
-{
- SPNG_KEEP_UNKNOWN_CHUNKS = 1,
-
- SPNG_IMG_COMPRESSION_LEVEL,
- SPNG_IMG_WINDOW_BITS,
- SPNG_IMG_MEM_LEVEL,
- SPNG_IMG_COMPRESSION_STRATEGY,
-
- SPNG_TEXT_COMPRESSION_LEVEL,
- SPNG_TEXT_WINDOW_BITS,
- SPNG_TEXT_MEM_LEVEL,
- SPNG_TEXT_COMPRESSION_STRATEGY,
-
- SPNG_FILTER_CHOICE,
- SPNG_CHUNK_COUNT_LIMIT,
- SPNG_ENCODE_TO_BUFFER,
-};
-
-struct spng_row_info
-{
- uint32_t scanline_idx;
- uint32_t row_num; /* deinterlaced row index */
- int pass;
- uint8_t filter;
-};
-
-const char *spng_strerror(int err);
-const char *spng_version_string(void);
-
-typedef struct spng_ctx spng_ctx;
-spng_ctx *spng_ctx_new(int flags);
-void spng_ctx_free(spng_ctx *ctx);
-
-typedef int spng_rw_fn(spng_ctx *ctx, void *user, uint8_t *dst_src, size_t length);
-int spng_set_png_stream(spng_ctx *ctx, spng_rw_fn *rw_func, void *user);
-
-int spng_set_image_limits(spng_ctx *ctx, uint32_t width, uint32_t height);
-int spng_get_image_limits(spng_ctx *ctx, uint32_t *width, uint32_t *height);
-int spng_set_chunk_limits(spng_ctx *ctx, size_t chunk_size, size_t cache_size);
-int spng_get_chunk_limits(spng_ctx *ctx, size_t *chunk_size, size_t *cache_size);
-int spng_set_crc_action(spng_ctx *ctx, int critical, int ancillary);
-int spng_set_option(spng_ctx *ctx, enum spng_option option, int value);
-int spng_get_option(spng_ctx *ctx, enum spng_option option, int *value);
-
-/* Decode */
-int spng_decoded_image_size(spng_ctx *ctx, int fmt, size_t *len);
-int spng_decode_image(spng_ctx *ctx, void *out, size_t len, int fmt, int flags);
-int spng_decode_row(spng_ctx *ctx, void *out, size_t len);
-int spng_decode_chunks(spng_ctx *ctx);
-
-/* Encode/decode */
-int spng_get_row_info(spng_ctx *ctx, struct spng_row_info *row_info);
-
-/* Encode */
-int spng_encode_image(spng_ctx *ctx, const void *img, size_t len, int fmt, int flags);
-int spng_encode_chunks(spng_ctx *ctx);
-
-int spng_get_ihdr(spng_ctx *ctx, struct spng_ihdr *ihdr);
-int spng_get_plte(spng_ctx *ctx, struct spng_plte *plte);
-int spng_get_trns(spng_ctx *ctx, struct spng_trns *trns);
-int spng_get_chrm(spng_ctx *ctx, struct spng_chrm *chrm);
-int spng_get_chrm_int(spng_ctx *ctx, struct spng_chrm_int *chrm_int);
-int spng_get_gama(spng_ctx *ctx, double *gamma);
-int spng_get_gama_int(spng_ctx *ctx, uint32_t *gama_int);
-int spng_get_iccp(spng_ctx *ctx, struct spng_iccp *iccp);
-int spng_get_sbit(spng_ctx *ctx, struct spng_sbit *sbit);
-int spng_get_srgb(spng_ctx *ctx, uint8_t *rendering_intent);
-int spng_get_text(spng_ctx *ctx, struct spng_text *text, uint32_t *n_text);
-int spng_get_bkgd(spng_ctx *ctx, struct spng_bkgd *bkgd);
-int spng_get_hist(spng_ctx *ctx, struct spng_hist *hist);
-int spng_get_phys(spng_ctx *ctx, struct spng_phys *phys);
-int spng_get_splt(spng_ctx *ctx, struct spng_splt *splt, uint32_t *n_splt);
-int spng_get_time(spng_ctx *ctx, struct spng_time *time);
-int spng_get_unknown_chunks(spng_ctx *ctx, struct spng_unknown_chunk *chunks, uint32_t *n_chunks);
-int spng_get_offs(spng_ctx *ctx, struct spng_offs *offs);
-int spng_get_exif(spng_ctx *ctx, struct spng_exif *exif);
-
-int spng_set_ihdr(spng_ctx *ctx, struct spng_ihdr *ihdr);
-int spng_set_plte(spng_ctx *ctx, struct spng_plte *plte);
-int spng_set_trns(spng_ctx *ctx, struct spng_trns *trns);
-int spng_set_chrm(spng_ctx *ctx, struct spng_chrm *chrm);
-int spng_set_chrm_int(spng_ctx *ctx, struct spng_chrm_int *chrm_int);
-int spng_set_gama(spng_ctx *ctx, double gamma);
-int spng_set_gama_int(spng_ctx *ctx, uint32_t gamma);
-int spng_set_iccp(spng_ctx *ctx, struct spng_iccp *iccp);
-int spng_set_sbit(spng_ctx *ctx, struct spng_sbit *sbit);
-int spng_set_srgb(spng_ctx *ctx, uint8_t rendering_intent);
-int spng_set_text(spng_ctx *ctx, struct spng_text *text, uint32_t n_text);
-int spng_set_bkgd(spng_ctx *ctx, struct spng_bkgd *bkgd);
-int spng_set_hist(spng_ctx *ctx, struct spng_hist *hist);
-int spng_set_phys(spng_ctx *ctx, struct spng_phys *phys);
-int spng_set_splt(spng_ctx *ctx, struct spng_splt *splt, uint32_t n_splt);
-int spng_set_time(spng_ctx *ctx, struct spng_time *time);
-int spng_set_unknown_chunks(spng_ctx *ctx, struct spng_unknown_chunk *chunks, uint32_t n_chunks);
-int spng_set_offs(spng_ctx *ctx, struct spng_offs *offs);
-int spng_set_exif(spng_ctx *ctx, struct spng_exif *exif);
-
-/* extensions for luapower ffi binding */
-void spng_rgba8_to_bgra8(void* p, uint32_t n);
-void spng_premultiply_alpha_rgba8(void* p, uint32_t n);
-void spng_premultiply_alpha_rgba16(void* p, uint32_t n);
-void spng_premultiply_alpha_ga8(void* p, uint32_t n);
-void spng_premultiply_alpha_ga16(void* p, uint32_t n);
-]]
diff --git a/lib/libspng_test.lua b/lib/libspng_test.lua
deleted file mode 100644
index affe655..0000000
--- a/lib/libspng_test.lua
+++ /dev/null
@@ -1,32 +0,0 @@
-local pp = require'pp'
-local fs = require'fs'
-local spng = require'libspng'
-
-local function load(file)
- local f = assert(fs.open(file))
- local img = assert(spng.open{read = f:buffered_read()})
- local bmp = assert(img:load{accept = {bgra8 = true}})
- assert(f:close())
- return img, bmp
-end
-
-local function save(bmp, file)
- local f = assert(fs.open(file, 'w'))
- assert(spng.save{
- bitmap = bmp,
- write = function(buf, sz)
- return f:write(buf, sz)
- end,
- })
- assert(f:close())
-end
-
-local img, bmp = load'media/png/good/z09n2c08.png'
-save(bmp, 'media/png/good/z09n2c08_1.png')
-local img2, bmp2 = pp(load'media/png/good/z09n2c08_1.png')
-assert(os.remove'media/png/good/z09n2c08_1.png')
-assert(bmp.size == bmp2.size)
-for i=0,bmp.size-1 do
- assert(bmp.data[i] == bmp2.data[i])
-end
-print'ok'
diff --git a/lib/list_inputs.lua b/lib/list_inputs.lua
deleted file mode 100644
index fa4067d..0000000
--- a/lib/list_inputs.lua
+++ /dev/null
@@ -1,312 +0,0 @@
-local mouse = {
- Mouse_left = 1,
- Mouse_right = 2,
- Mouse_middle = 3,
- Mouse_wheel_up = 4,
- Mouse_wheel_down = 5,
- Mouse_x1 = 6,
- Mouse_x2 = 7,
-}
-
-local key = {
- Key_a = 4,
- Key_b = 5,
- Key_c = 6,
- Key_d = 7,
- Key_e = 8,
- Key_f = 9,
- Key_g = 10,
- Key_h = 11,
- Key_i = 12,
- Key_j = 13,
- Key_k = 14,
- Key_l = 15,
- Key_m = 16,
- Key_n = 17,
- Key_o = 18,
- Key_p = 19,
- Key_q = 20,
- Key_r = 21,
- Key_s = 22,
- Key_t = 23,
- Key_u = 24,
- Key_v = 25,
- Key_w = 26,
- Key_x = 27,
- Key_y = 28,
- Key_z = 29,
- Key_1 = 30,
- Key_2 = 31,
- Key_3 = 32,
- Key_4 = 33,
- Key_5 = 34,
- Key_6 = 35,
- Key_7 = 36,
- Key_8 = 37,
- Key_9 = 38,
- Key_0 = 39,
- Key_RETURN = 40,
- Key_ESCAPE = 41,
- Key_BACKSPACE = 42,
- Key_TAB = 43,
- Key_SPACE = 44,
- Key_MINUS = 45,
- Key_EQUALS = 46,
- Key_LEFTBRACKET = 47,
- Key_RIGHTBRACKET = 48,
- Key_BACKSLASH = 49,
- Key_NONUSHASH = 50,
- Key_SEMICOLON = 51,
- Key_APOSTROPHE = 52,
- Key_GRAVE = 53,
- Key_COMMA = 54,
- Key_PERIOD = 55,
- Key_SLASH = 56,
- Key_CAPSLOCK = 57,
- Key_F1 = 58,
- Key_F2 = 59,
- Key_F3 = 60,
- Key_F4 = 61,
- Key_F5 = 62,
- Key_F6 = 63,
- Key_F7 = 64,
- Key_F8 = 65,
- Key_F9 = 66,
- Key_F10 = 67,
- Key_F11 = 68,
- Key_F12 = 69,
- Key_PRINTSCREEN = 70,
- Key_SCROLLLOCK = 71,
- Key_PAUSE = 72,
- Key_INSERT = 73,
- Key_HOME = 74,
- Key_PAGEUP = 75,
- Key_DELETE = 76,
- Key_END = 77,
- Key_PAGEDOWN = 78,
- Key_RIGHT = 79,
- Key_LEFT = 80,
- Key_DOWN = 81,
- Key_UP = 82,
- Key_NUMLOCKCLEAR = 83,
- Key_KP_DIVIDE = 84,
- Key_KP_MULTIPLY = 85,
- Key_KP_MINUS = 86,
- Key_KP_PLUS = 87,
- Key_KP_ENTER = 88,
- Key_KP_1 = 89,
- Key_KP_2 = 90,
- Key_KP_3 = 91,
- Key_KP_4 = 92,
- Key_KP_5 = 93,
- Key_KP_6 = 94,
- Key_KP_7 = 95,
- Key_KP_8 = 96,
- Key_KP_9 = 97,
- Key_KP_0 = 98,
- Key_KP_PERIOD = 99,
- Key_NONUSBACKSLASH = 100,
- Key_APPLICATION = 101,
- Key_POWER = 102,
- Key_KP_EQUALS = 103,
- Key_F13 = 104,
- Key_F14 = 105,
- Key_F15 = 106,
- Key_F16 = 107,
- Key_F17 = 108,
- Key_F18 = 109,
- Key_F19 = 110,
- Key_F20 = 111,
- Key_F21 = 112,
- Key_F22 = 113,
- Key_F23 = 114,
- Key_F24 = 115,
- Key_EXECUTE = 116,
- Key_HELP = 117,
- Key_MENU = 118,
- Key_SELECT = 119,
- Key_STOP = 120,
- Key_AGAIN = 121,
- Key_UNDO = 122,
- Key_CUT = 123,
- Key_COPY = 124,
- Key_PASTE = 125,
- Key_FIND = 126,
- Key_MUTE = 127,
- Key_VOLUMEUP = 128,
- Key_VOLUMEDOWN = 129,
- Key_KP_COMMA = 133,
- Key_KP_EQUALSAS400 = 134,
- Key_INTERNATIONAL1 = 135,
- Key_INTERNATIONAL2 = 136,
- Key_INTERNATIONAL3 = 137,
- Key_INTERNATIONAL4 = 138,
- Key_INTERNATIONAL5 = 139,
- Key_INTERNATIONAL6 = 140,
- Key_INTERNATIONAL7 = 141,
- Key_INTERNATIONAL8 = 142,
- Key_INTERNATIONAL9 = 143,
- Key_LANG1 = 144,
- Key_LANG2 = 145,
- Key_LANG3 = 146,
- Key_LANG4 = 147,
- Key_LANG5 = 148,
- Key_LANG6 = 149,
- Key_LANG7 = 150,
- Key_LANG8 = 151,
- Key_LANG9 = 152,
- Key_ALTERASE = 153,
- Key_SYSREQ = 154,
- Key_CANCEL = 155,
- Key_CLEAR = 156,
- Key_PRIOR = 157,
- Key_RETURN2 = 158,
- Key_SEPARATOR = 159,
- Key_OUT = 160,
- Key_OPER = 161,
- Key_CLEARAGAIN = 162,
- Key_CRSEL = 163,
- Key_EXSEL = 164,
- Key_KP_00 = 176,
- Key_KP_000 = 177,
- Key_THOUSANDSSEPARATOR = 178,
- Key_DECIMALSEPARATOR = 179,
- Key_CURRENCYUNIT = 180,
- Key_CURRENCYSUBUNIT = 181,
- Key_KP_LEFTPAREN = 182,
- Key_KP_RIGHTPAREN = 183,
- Key_KP_LEFTBRACE = 184,
- Key_KP_RIGHTBRACE = 185,
- Key_KP_TAB = 186,
- Key_KP_BACKSPACE = 187,
- Key_KP_A = 188,
- Key_KP_B = 189,
- Key_KP_C = 190,
- Key_KP_D = 191,
- Key_KP_E = 192,
- Key_KP_F = 193,
- Key_KP_XOR = 194,
- Key_KP_POWER = 195,
- Key_KP_PERCENT = 196,
- Key_KP_LESS = 197,
- Key_KP_GREATER = 198,
- Key_KP_AMPERSAND = 199,
- Key_KP_DBLAMPERSAND = 200,
- Key_KP_VERTICALBAR = 201,
- Key_KP_DBLVERTICALBAR = 202,
- Key_KP_COLON = 203,
- Key_KP_HASH = 204,
- Key_KP_SPACE = 205,
- Key_KP_AT = 206,
- Key_KP_EXCLAM = 207,
- Key_KP_MEMSTORE = 208,
- Key_KP_MEMRECALL = 209,
- Key_KP_MEMCLEAR = 210,
- Key_KP_MEMADD = 211,
- Key_KP_MEMSUBTRACT = 212,
- Key_KP_MEMMULTIPLY = 213,
- Key_KP_MEMDIVIDE = 214,
- Key_KP_PLUSMINUS = 215,
- Key_KP_CLEAR = 216,
- Key_KP_CLEARENTRY = 217,
- Key_KP_BINARY = 218,
- Key_KP_OCTAL = 219,
- Key_KP_DECIMAL = 220,
- Key_KP_HEXADECIMAL = 221,
- Key_LCTRL = 224,
- Key_LSHIFT = 225,
- Key_LALT = 226,
- Key_LGUI = 227,
- Key_RCTRL = 228,
- Key_RSHIFT = 229,
- Key_RALT = 230,
- Key_RGUI = 231,
- Key_MODE = 257,
- Key_AUDIONEXT = 258,
- Key_AUDIOPREV = 259,
- Key_AUDIOSTOP = 260,
- Key_AUDIOPLAY = 261,
- Key_AUDIOMUTE = 262,
- Key_MEDIASELECT = 263,
- Key_WWW = 264,
- Key_MAIL = 265,
- Key_CALCULATOR = 266,
- Key_COMPUTER = 267,
- Key_AC_SEARCH = 268,
- Key_AC_HOME = 269,
- Key_AC_BACK = 270,
- Key_AC_FORWARD = 271,
- Key_AC_STOP = 272,
- Key_AC_REFRESH = 273,
- Key_AC_BOOKMARKS = 274,
- Key_BRIGHTNESSDOWN = 275,
- Key_BRIGHTNESSUP = 276,
- Key_DISPLAYSWITCH = 277,
- Key_KBDILLUMTOGGLE = 278,
- Key_KBDILLUMDOWN = 279,
- Key_KBDILLUMUP = 280,
- Key_EJECT = 281,
- Key_SLEEP = 282,
- Key_APP1 = 283,
- Key_APP2 = 284,
- Key_SPECIAL_COUNT = 512,
-}
-
-local joy = {
- JOY_BUTTON_DPAD_UP = 11,
- JOY_BUTTON_DPAD_DOWN = 12,
- JOY_BUTTON_DPAD_LEFT = 13,
- JOY_BUTTON_DPAD_RIGHT = 14,
- JOY_BUTTON_START = 15,
- JOY_BUTTON_BACK = 16,
- JOY_BUTTON_LEFT_THUMB = 17,
- JOY_BUTTON_RIGHT_THUMB = 18,
- JOY_BUTTON_LEFT_SHOULDER = 19,
- JOY_BUTTON_RIGHT_SHOULDER = 20,
- JOY_BUTTON_0 = 23,
- JOY_BUTTON_1 = 24,
- JOY_BUTTON_2 = 25,
- JOY_BUTTON_3 = 26,
- JOY_BUTTON_4 = 27,
- JOY_BUTTON_5 = 28,
- JOY_BUTTON_6 = 29,
- JOY_BUTTON_7 = 30,
- JOY_BUTTON_8 = 31,
- JOY_BUTTON_9 = 32,
- JOY_BUTTON_10 = 33,
- JOY_BUTTON_11 = 34,
- JOY_BUTTON_12 = 35,
- JOY_BUTTON_13 = 36,
- JOY_BUTTON_14 = 37,
- JOY_BUTTON_15 = 38,
- JOY_BUTTON_LEFT_STICK_LEFT = 39,
- JOY_BUTTON_LEFT_STICK_RIGHT = 40,
- JOY_BUTTON_LEFT_STICK_UP = 41,
- JOY_BUTTON_LEFT_STICK_DOWN = 42,
- JOY_BUTTON_RIGHT_STICK_LEFT = 43,
- JOY_BUTTON_RIGHT_STICK_RIGHT = 44,
- JOY_BUTTON_RIGHT_STICK_UP = 45,
- JOY_BUTTON_RIGHT_STICK_DOWN = 46,
- JOY_BUTTON_A = 23,
- JOY_BUTTON_B = 24,
- JOY_BUTTON_X = 25,
- JOY_BUTTON_Y = 26,
-}
-
-local stick = {
- gamepad_left_stick = 0,
- gamepad_right_stick = 1
-}
-
-local trigger = {
- gamepad_left_trigger = 0,
- gamepad_right_trigger = 1
-}
-
-return {
- mouse = mouse,
- key = key,
- joy = joy,
- stick = stick,
- trigger = trigger
-}
\ No newline at end of file
diff --git a/lib/logger.lua b/lib/logger.lua
deleted file mode 100644
index c08c9d6..0000000
--- a/lib/logger.lua
+++ /dev/null
@@ -1,132 +0,0 @@
--- logger.lua
-local default_folder_path = "logger"
-
-local function create_logger(output_path, filename, overwrite, no_prefix, allow_repeats)
- -- ensure/create the directory for the logger files
- if not os.rename(output_path, output_path) then
- os.execute("mkdir \"" .. output_path .. "\" 2>nul")
- end
-
- local file_path = nil
-
- local new_logger = {
- log_file = nil,
- last_print = nil,
- last_was_duplicate = false,
- enabled = true
- }
-
- function new_logger.print(_, ...)
- if not new_logger.enabled then
- return
- end
-
- if(new_logger.last_print == nil)then
- file_path = output_path .. "/" .. filename
-
- if overwrite == nil or overwrite then
- local clear_file = io.open(file_path, "w")
- clear_file:close()
- end
- end
-
- if(not file_path)then
- error("Logger not initialized.")
- return
- end
-
- if not new_logger.log_file then
- -- reopen file
- new_logger.log_file = io.open(file_path, "a")
- return
- end
-
- local debug_info = debug.getinfo(2, "Sl")
-
- local args = {...}
- for i = 1, #args do
- args[i] = tostring(args[i])
- end
- local message = args[1]
- if(#args > 1)then
- for i = 2, #args do
- message = message .. " " .. args[i]
- end
- end
-
-
- -- Include timestamp in the log message
- local log_message = ""
-
- local log_without_prefix = ""
-
- if(no_prefix)then
- log_message = string.format("%s\n", message)
- log_without_prefix = log_message
- else
- -- Get the current timestamp
- local timestamp = os.date("%Y-%m-%d %H:%M:%S")
-
- log_without_prefix = string.format("%s\n", message)
-
- log_message = string.format("%s [%s:%d]: %s\n", timestamp, debug_info.source, debug_info.currentline, message)
- end
-
- -- if the message is the same as the last one, don't print it again
- if(not allow_repeats)then
- if new_logger.last_print == log_without_prefix then
- if(not new_logger.last_was_duplicate)then
- new_logger.log_file:write("\n[Multiple repeating prints detected, hiding..]\n")
- new_logger.log_file:flush()
- end
- new_logger.last_was_duplicate = true
- else
- new_logger.last_was_duplicate = false
- end
- else
- print("Allowing repeats")
- new_logger.last_was_duplicate = false
- end
-
- new_logger.last_print = log_without_prefix
-
- if(not new_logger.last_was_duplicate or allow_repeats)then
- new_logger.log_file:write(log_message)
- new_logger.log_file:flush()
- end
- end
-
- function new_logger.enabled(_, enabled)
- new_logger.enabled = enabled
- end
-
-
- function new_logger.close()
- if new_logger.log_file then
- new_logger.log_file:close()
- new_logger.log_file = nil
- end
- end
-
- return new_logger
-end
-
-local logger = {
- init = function(filename, overwrite, no_prefix, folder_overwrite, allow_repeats)
- return create_logger(folder_overwrite or default_folder_path, filename, overwrite, no_prefix, allow_repeats)
- end
-}
-
--- Metatable for logger table
-local logger_mt = {
- __call = function(_, folder_path)
- if folder_path then
- default_folder_path = folder_path
- end
- return logger
- end
-}
-
-setmetatable(logger, logger_mt)
-
-return logger
\ No newline at end of file
diff --git a/lib/minhook.lua b/lib/minhook.lua
deleted file mode 100644
index 156181e..0000000
--- a/lib/minhook.lua
+++ /dev/null
@@ -1,97 +0,0 @@
-function load_minhook(path)
- local minhook = {}
- local ffi = require("ffi")
-
- local dll_path = path .. "/luajit_minhook.dll"
-
- local lib = ffi.load(dll_path)
- minhook.lib = lib
- _G["__minhook_dont_unload"] = lib
-
- ffi.cdef([[
- bool mh_initialize();
- bool mh_uninitialize();
- void* mh_create_hook(void* function, void* detour);
- bool mh_remove_hook(void* function);
- bool mh_enable_hook(void* function);
- bool mh_disable_hook(void* function);
-
- void (*real_GameScreenshake)(struct CameraWorld*, struct vec2*);
- void GameScreenshake_hook_target(struct CameraWorld* camera, struct vec2* pos, float strength);
- void __thiscall GameScreenshake_xmm1_shim(struct CameraWorld* camera, struct vec2* pos);
-
- // std::string utility functions
- size_t std_string_size(const struct std_string* str);
- const char* std_string_c_str(const struct std_string* str);
- char* std_string_data(struct std_string* str);
-
- struct std_string* std_string_new(const char* cstr);
- struct std_string* std_string_new_n(const char* cstr, size_t n);
- void std_string_delete(struct std_string* str);
-
- void std_string_assign(struct std_string* str, const char* cstr);
- void std_string_assign_n(struct std_string* str, const char* cstr, size_t n);
-
- bool std_string_eq(const struct std_string* str, const char* cstr);
- int std_string_cmp(const struct std_string* str, const char* cstr);
- int std_string_cmp_n(const struct std_string* str, const char* cstr, size_t n);
- ]])
-
- minhook.initialize = lib.mh_initialize
- minhook.uninitialize = lib.mh_initialize
- minhook.remove = lib.mh_remove_hook
- minhook.enable = lib.mh_enable_hook
- minhook.disable = lib.mh_disable_hook
-
- function is_function_pointer(typ)
- return tostring(typ):find("(*)") ~= nil
- end
-
- -- Returns a function pointer type when the given type is a function or
- -- function pointer.
- function function_pointer_type(typ)
- if is_function_pointer(typ) then
- return typ
- end
-
- local new_type = ffi.typeof("$*", typ)
- if not is_function_pointer(new_type) then
- error("Given type is not a function or function pointer")
- end
-
- return new_type
- end
-
- function minhook.create_hook(func, hook)
- local func_type = function_pointer_type(ffi.typeof(func))
- local hook_func = ffi.cast(func_type, hook)
- local ret = lib.mh_create_hook(func, hook_func)
-
- if ret == nil then
- return nil
- end
-
- local original = ffi.cast(func_type, ret)
- return {
- func = func,
- hook_func = hook_func,
- original = original
- }
- end
-
- minhook.string_size = lib.std_string_size
- minhook.string_c_str = lib.std_string_c_str
- minhook.string_data = lib.std_string_data
- minhook.string_new = lib.std_string_new
- minhook.string_new_n = lib.std_string_new_n
- minhook.string_delete = lib.std_string_delete
- minhook.string_assign = lib.std_string_assign
- minhook.string_assign_n = lib.std_string_assign_n
- minhook.string_eq = lib.std_string_eq
- minhook.string_cmp = lib.std_string_cmp
- minhook.string_cmp_n = lib.std_string_cmp_n
-
- return minhook
-end
-
-return load_minhook
diff --git a/lib/msg.lua b/lib/msg.lua
deleted file mode 100644
index 3b20ca0..0000000
--- a/lib/msg.lua
+++ /dev/null
@@ -1,18 +0,0 @@
-local msg = {}
-
-msg.log = function (...)
- local arg = {...}
- local str = ""
- for i, v in ipairs(arg) do
- -- don't add comma to last argument
- if i ~= #arg then
- str = str .. tostring(v) .. ", "
- else
- str = str .. tostring(v)
- end
- end
- mp_log:print("[evaisa.mp] "..str)
- GamePrint("[evaisa.mp] "..str)
-end
-
-return msg
\ No newline at end of file
diff --git a/lib/nxml.lua b/lib/nxml.lua
deleted file mode 100644
index e349e82..0000000
--- a/lib/nxml.lua
+++ /dev/null
@@ -1,571 +0,0 @@
-local ffi = nil
-if require then
- pcall(function()
- ffi = require("ffi")
- end)
-end
-
-local str_sub
-local str_index
-local str_normalize
-
-if ffi then
- str_normalize = function(str)
- return ffi.cast("const char*", str)
- end
-
- str_sub = function(ptr, start_idx, len)
- return ffi.string(ptr + start_idx, len)
- end
-
- str_index = function(ptr, idx)
- return ptr[idx]
- end
-else
- str_normalize = function(str) return str end
-
- str_sub = function(str, start_idx, len)
- return str:sub(start_idx + 1, start_idx + len)
- end
-
- str_index = function(str, idx)
- return string.byte(str:sub(idx + 1, idx + 1))
- end
-end
-
---[[
- * The following is a Lua port of the NXML parser:
- * https://github.com/xwitchproject/nxml
- *
- * The NXML Parser is heavily based on code from poro
- * https://github.com/gummikana/poro
- *
- * The poro project is licensed under the Zlib license:
- *
- * --------------------------------------------------------------------------
- * Copyright (c) 2010-2019 Petri Purho, Dennis Belfrage
- * Contributors: Martin Jonasson, Olli Harjola
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- * --------------------------------------------------------------------------
-]]
-
-local nxml = {}
-
-local TOKENIZER_FUNCS = {}
-local TOKENIZER_MT = {
- __index = TOKENIZER_FUNCS,
- __tostring = function(self) return "natif.nxml.tokenizer" end
-}
-
-local function new_tokenizer(cstring, len)
- return setmetatable({
- data = cstring,
- cur_idx = 0,
- cur_row = 1,
- cur_col = 1,
- prev_row = 1,
- prev_col = 1,
- len = len
- }, TOKENIZER_MT)
-end
-
-local ws = {
- [string.byte(" ")] = true,
- [string.byte("\t")] = true,
- [string.byte("\n")] = true,
- [string.byte("\r")] = true
-}
-
-function TOKENIZER_FUNCS:is_whitespace(char)
- local n = tonumber(char)
- return ws[n] or false
-end
-
-local punct = {
- [string.byte("<")] = true,
- [string.byte(">")] = true,
- [string.byte("=")] = true,
- [string.byte("/")] = true,
-}
-
-function TOKENIZER_FUNCS:is_whitespace_or_punctuation(char)
- local n = tonumber(char)
- return self:is_whitespace(n) or punct[n] or false
-end
-
-function TOKENIZER_FUNCS:move(n)
- n = n or 1
- local prev_idx = self.cur_idx
- self.cur_idx = self.cur_idx + n
- if self.cur_idx >= self.len then
- self.cur_idx = self.len
- return
- end
- for i = prev_idx, self.cur_idx - 1 do
- if str_index(self.data, i) == string.byte("\n") then
- self.cur_row = self.cur_row + 1
- self.cur_col = 1
- else
- self.cur_col = self.cur_col + 1
- end
- end
-end
-
-function TOKENIZER_FUNCS:peek(n)
- n = n or 1
- local idx = self.cur_idx + n
- if idx >= self.len then return 0 end
-
- return str_index(self.data, idx)
-end
-
-function TOKENIZER_FUNCS:match_string(str)
- local len = #str
- str = str_normalize(str)
-
- for i = 0, len - 1 do
- if self:peek(i) ~= str_index(str, i) then return false end
- end
- return true
-end
-
-function TOKENIZER_FUNCS:eof()
- return self.cur_idx >= self.len
-end
-
-function TOKENIZER_FUNCS:cur_char()
- if self:eof() then return 0 end
- return tonumber(str_index(self.data, self.cur_idx))
-end
-
-function TOKENIZER_FUNCS:skip_whitespace()
- while not self:eof() do
- if self:is_whitespace(self:cur_char()) then
- self:move()
- elseif self:match_string("") do
- self:move()
- end
-
- if self:match_string("-->") then
- self:move(3)
- end
- elseif self:cur_char() == string.byte("<") and self:peek(1) == string.byte("!") then
- self:move(2)
- while not self:eof() and self:cur_char() ~= string.byte(">") do
- self:move()
- end
- if self:cur_char() == string.byte(">") then
- self:move()
- end
-
- elseif self:match_string("") then
- self:move(2)
- while not self:eof() and not self:match_string("?>") do
- self:move()
- end
- if self:match_string("?>") then
- self:move(2)
- end
- else
- break
- end
- end
-end
-
-function TOKENIZER_FUNCS:read_quoted_string()
- local start_idx = self.cur_idx
- local len = 0
-
- while not self:eof() and self:cur_char() ~= string.byte("\"") do
- len = len + 1
- self:move()
- end
-
- self:move() -- skip "
- return str_sub(self.data, start_idx, len)
-end
-
-function TOKENIZER_FUNCS:read_unquoted_string()
- local start_idx = self.cur_idx - 1 -- first char is move()d
- local len = 1
-
- while not self:eof() and not self:is_whitespace_or_punctuation(self:cur_char()) do
- len = len + 1
- self:move()
- end
-
- return str_sub(self.data, start_idx, len)
-end
-
-local C_NULL = 0
-local C_LT = string.byte("<")
-local C_GT = string.byte(">")
-local C_SLASH = string.byte("/")
-local C_EQ = string.byte("=")
-local C_QUOTE = string.byte("\"")
-
-function TOKENIZER_FUNCS:next_token()
- self:skip_whitespace()
-
- self.prev_row = self.cur_row
- self.prev_col = self.cur_col
-
- if self:eof() then return nil end
-
- local c = self:cur_char()
- self:move()
-
- if c == C_NULL then return nil
- elseif c == C_LT then return { type = "<" }
- elseif c == C_GT then return { type = ">" }
- elseif c == C_SLASH then return { type = "/" }
- elseif c == C_EQ then return { type = "=" }
- elseif c == C_QUOTE then return { type = "string", value = self:read_quoted_string() }
- else return { type = "string", value = self:read_unquoted_string() }
- end
-end
-
-local PARSER_FUNCS = {}
-local PARSER_MT = {
- __index = PARSER_FUNCS,
- __tostring = function(self) return "natif.nxml.parser" end
-}
-
-local function new_parser(tokenizer, error_reporter)
- return setmetatable({
- tok = tokenizer,
- errors = {},
- error_reporter = error_reporter or function(type, msg) print("parser error: [" .. type .. "] " .. msg) end
- }, PARSER_MT)
-end
-
-local XML_ELEMENT_FUNCS = {}
-local XML_ELEMENT_MT = {
- __index = XML_ELEMENT_FUNCS,
- __tostring = function(self)
- return nxml.tostring(self)
- end,
-}
-
-function PARSER_FUNCS:report_error(type, msg)
- self.error_reporter(type, msg)
- table.insert(self.errors, { type = type, msg = msg, row = self.tok.prev_row, col = self.tok.prev_col })
-end
-
-
-function PARSER_FUNCS:parse_attr(attr_table, name)
- local tok = self.tok:next_token()
- if tok.type == "=" then
- tok = self.tok:next_token()
-
- if tok.type == "string" then
- attr_table[name] = tok.value
- else
- self:report_error("missing_attribute_value", string.format("parsing attribute '%s' - expected a string after =, but did not find one"), name)
- end
- else
- self:report_error("missing_equals_sign", string.format("parsing attribute '%s' - did not find equals sign after attribute name", name))
- end
-end
-
-function PARSER_FUNCS:parse_element(skip_opening_tag)
- local tok
- if not skip_opening_tag then
- tok = self.tok:next_token()
- if tok.type ~= "<" then
- self:report_error("missing_tag_open", "couldn't find a '<' to start parsing with")
- end
- end
-
- tok = self.tok:next_token()
- if tok.type ~= "string" then
- self:report_error("missing_element_name", "expected an element name after '<'")
- end
-
- local elem_name = tok.value
- local elem = nxml.new_element(elem_name)
- local content_idx = 0
-
- local self_closing = false
-
- while true do
- tok = self.tok:next_token()
-
- if tok == nil then
- return elem
- elseif tok.type == "/" then
- if self.tok:cur_char() == C_GT then
- self.tok:move()
- self_closing = true
- end
- break
- elseif tok.type == ">" then
- break
- elseif tok.type == "string" then
- self:parse_attr(elem.attr, tok.value)
- end
- end
-
- if self_closing then return elem end
-
- while true do
- tok = self.tok:next_token()
-
- if tok == nil then
- return elem
- elseif tok.type == "<" then
- if self.tok:cur_char() == C_SLASH then
- self.tok:move()
-
- local end_name = self.tok:next_token()
- if end_name.type == "string" and end_name.value == elem_name then
- local close_greater = self.tok:next_token()
-
- if close_greater.type == ">" then
- return elem
- else
- self:report_error("missing_element_close", string.format("no closing '>' found for element '%s'", elem_name))
- end
- else
- self:report_error("mismatched_closing_tag", string.format("closing element is in wrong order - expected '%s>', but instead got '%s'", elem_name, tostring(end_name.value)))
- end
- return elem
- else
- local child = self:parse_element(elem, true)
- table.insert(elem.children, child)
- end
- else
- if not elem.content then
- elem.content = {}
- end
-
- content_idx = content_idx + 1
- elem.content[content_idx] = tok.value or tok.type
- end
- end
-end
-
-function PARSER_FUNCS:parse_elements()
- local tok = self.tok:next_token()
- local elems = {}
- local elems_i = 1
-
- while tok and tok.type == "<" do
- elems[elems_i] = self:parse_element(true)
- elems_i = elems_i + 1
-
- tok = self.tok:next_token()
- end
-
- return elems
-end
-
-local function is_punctuation(str)
- return str == "/" or str == "<" or str == ">" or str == "="
-end
-
-function XML_ELEMENT_FUNCS:text()
- local content_count = #self.content
-
- if self.content == nil or content_count == 0 then
- return ""
- end
-
- local text = self.content[1]
- for i = 2, content_count do
- local elem = self.content[i]
- local prev = self.content[i - 1]
-
- if is_punctuation(elem) or is_punctuation(prev) then
- text = text .. elem
- else
- text = text .. " " .. elem
- end
- end
-
- return text
-end
-
-function XML_ELEMENT_FUNCS:add_child(child)
- self.children[#self.children + 1] = child
-end
-
-function XML_ELEMENT_FUNCS:add_children(children)
- local children_i = #self.children + 1
- for i = 1, #children do
- self.children[children_i] = children[i]
- children_i = children_i + 1
- end
-end
-
-function XML_ELEMENT_FUNCS:remove_child(child)
- for i = 1, #self.children do
- if self.children[i] == child then
- table.remove(self.children, i)
- break
- end
- end
-end
-
-function XML_ELEMENT_FUNCS:remove_child_at(index)
- table.remove(self.children, index)
-end
-
-function XML_ELEMENT_FUNCS:clear_children()
- self.children = {}
-end
-
-function XML_ELEMENT_FUNCS:clear_attrs()
- self.attr = {}
-end
-
-function XML_ELEMENT_FUNCS:first_of(element_name)
- local i = 0
- local n = #self.children
-
- while i < n do
- i = i + 1
- local c = self.children[i]
-
- if c.name == element_name then return c end
- end
-
- return nil
-end
-
-function XML_ELEMENT_FUNCS:each_of(element_name)
- local i = 1
- local n = #self.children
-
- return function()
- while i <= n and self.children[i].name ~= element_name do
- i = i + 1
- end
- i = i + 1
- return self.children[i - 1]
- end
-end
-
-function XML_ELEMENT_FUNCS:all_of(element_name)
- local table = {}
- local i = 1
- for elem in self:each_of(element_name) do
- table[i] = elem
- i = i + 1
- end
- return table
-end
-
-function XML_ELEMENT_FUNCS:each_child()
- local i = 0
- local n = #self.children
-
- return function()
- while i <= n do
- i = i + 1
- return self.children[i]
- end
- end
-end
-
-function nxml.parse(data)
- local data_len = #data
- local tok = new_tokenizer(str_normalize(data), data_len)
- local parser = new_parser(tok)
-
- local elem = parser:parse_element(false)
-
- if not elem or (elem.errors and #elem.errors > 0) then
- error("parser encountered errors")
- end
-
- return elem
-end
-
-function nxml.parse_many(data)
- local data_len = #data
- local tok = new_tokenizer(str_normalize(data), data_len)
- local parser = new_parser(tok)
-
- local elems = parser:parse_elements(false)
-
- for i = 1, #elems do
- local elem = elems[i]
-
- if elem.errors and #elem.errors > 0 then
- error("parser encountered errors")
- end
- end
-
- return elems
-end
-
-function nxml.new_element(name, attrs)
- return setmetatable({
- name = name,
- attr = attrs or {},
- children = {},
- content = nil
- }, XML_ELEMENT_MT)
-end
-
-local function attr_value_to_str(value)
- local t = type(value)
- if t == "string" then return value end
- if t == "boolean" then return value and "1" or "0" end
-
- return tostring(value)
-end
-
-function nxml.tostring(elem, packed, indent_char, cur_indent)
- indent_char = indent_char or "\t"
- cur_indent = cur_indent or ""
- local s = "<" .. elem.name
- local self_closing = #elem.children == 0 and (not elem.content or #elem.content == 0)
-
- for k, v in pairs(elem.attr) do
- s = s .. " " .. k .. "=\"" .. attr_value_to_str(v) .. "\""
- end
-
- if self_closing then
- s = s .. " />"
- return s
- end
-
- s = s .. ">"
-
- local deeper_indent = cur_indent .. indent_char
-
- if elem.content and #elem.content ~= 0 then
- if not packed then s = s .. "\n" .. deeper_indent end
- s = s .. elem:text()
- end
-
- if not packed then s = s .. "\n" end
-
- for i, v in ipairs(elem.children) do
- if not packed then s = s .. deeper_indent end
- s = s .. nxml.tostring(v, packed, indent_char, deeper_indent)
- if not packed then s = s .. "\n" end
- end
-
- s = s .. cur_indent .. "" .. elem.name .. ">"
-
- return s
-end
-
-return nxml
diff --git a/lib/path.lua b/lib/path.lua
deleted file mode 100644
index b46cacb..0000000
--- a/lib/path.lua
+++ /dev/null
@@ -1,545 +0,0 @@
-
---Path manipulation for Windows and UNIX paths.
---Written by Cosmin Apreutesei. Public Domain.
-
-if not ... then require'path_test'; return end
-
-local path = {}
-setmetatable(path, path)
-
-path.platform = package.config:sub(1, 1) == '\\' and 'win' or 'unix'
-
-local function win(pl) --check if pl (or current platform) is Windows
- if pl == nil then pl = path.platform end
- assert(pl == 'unix' or pl == 'win', 'invalid platform')
- return pl == 'win'
-end
-
-function path.default_sep(pl)
- return win(pl) and '\\' or '/'
-end
-
---device aliases are file names that are found _in any directory_.
-local dev_aliases = {
- CON=1, PRN=1, AUX=1, NUL=1,
- COM1=1, COM2=1, COM3=1, COM4=1, COM5=1, COM6=1, COM7=1, COM8=1, COM9=1,
- LPT1=1, LPT2=1, LPT3=1, LPT4=1, LPT5=1, LPT6=1, LPT7=1, LPT8=1, LPT9=1,
-}
-
---check if a path refers to a device alias and return that alias.
-function path.dev_alias(s)
- s = s:match'[^\\/]+$' --basename (dev aliases are present in all dirs)
- s = s and s:match'^[^%.]+' --strip extension (they can have any extension)
- s = s and s:upper() --they're case-insensitive
- return s and dev_aliases[s] and s
-end
-
---get the path type which can be: 'abs', 'abs_long', 'abs_nodrive',
--- 'rel', 'rel_drive', 'unc', 'unc_long', 'global', 'dev', 'dev_alias'.
---NOTE: the empty path ('') comes off as type 'rel'.
-function path.type(s, pl)
- if win(pl) then
- if s:find'^\\\\' then
- if s:find'^\\\\%?\\' then
- if s:find'^\\\\%?\\%a:\\' then
- return 'abs_long'
- elseif s:find'^\\\\%?\\[uU][nN][cC]\\' then
- return 'unc_long'
- else
- return 'global'
- end
- elseif s:find'^\\\\%.\\' then
- return 'dev'
- else
- return 'unc'
- end
- elseif path.dev_alias(s) then
- return 'dev_alias'
- elseif s:find'^%a:' then
- return s:find'^..[\\/]' and 'abs' or 'rel_drive'
- else
- return s:find'^[\\/]' and 'abs_nodrive' or 'rel'
- end
- else
- return s:byte(1) == ('/'):byte(1) and 'abs' or 'rel'
- end
-end
-
---split a path into its local path component and, depending on the path
---type, the drive letter or server name.
---NOTE: UNC paths are not validated and can have and empty server or path.
-function path.parse(s, pl)
- local type = path.type(s, pl)
- if win(pl) then
- if type == 'rel' or type == 'abs_nodrive' then
- return type, s -- nothing to split
- elseif type == 'abs' or type == 'rel_drive' then
- return type, s:sub(3), s:sub(1,1) -- \path, drive
- elseif type == 'abs_long' then
- return type, s:sub(3+4), s:sub(1+4,1 +4) -- \path, drive
- elseif type == 'unc' then
- local server, path = s:match'^..([^\\]*)(.*)$'
- return type, path, server
- elseif type == 'unc_long' then
- local server, path = s:match'^........([^\\]*)(.*)$'
- return type, path, server
- elseif type == 'dev' then
- return type, s:sub(4) -- \path
- elseif type == 'dev_alias' then
- return type, s -- CON, NUL, ...
- elseif type == 'global' then
- return type, s:sub(4) -- \path
- end
- else
- return type, s --unix path: nothing to split
- end
-end
-
---put together a path from its broken-down components.
-function path.format(type, path, drive, pl)
- if win(pl) and type == 'abs' or type == 'rel_drive' then
- return drive .. ':' .. path
- elseif type == 'abs_long' then
- return '\\\\?\\' .. drive .. ':' .. path
- elseif type == 'unc' then
- return '\\\\' .. drive .. path
- elseif type == 'unc_long' then
- return '\\\\?\\UNC\\' .. drive .. path
- elseif type == 'dev' then
- return '\\\\.' .. path
- elseif type == 'global' then
- return '\\\\?' .. path
- else --abs/unix, rel, abs_nodrive, dev_alias
- return path
- end
-end
-
---check if a path is an absolute path or not, if it's empty or not,
---and if it's valid or not. NOTE: absolute paths for which their local path
---is '' are actually invalid (currently only UNC paths can be invalid and
---still parse); for those paths the third return value will be false.
-local function isabs(type, p, win)
- if type == 'rel' or type == 'rel_drive' or type == 'dev_alias' then
- return false, p == '', true
- elseif p == '' then
- return true, true, false --invalid absolute path
- else
- local isroot = p:find(win and '^[\\/]+$' or '^/+$') and true or false
- return true, isroot, true
- end
-end
-function path.isabs(s, pl)
- local type, p = path.parse(s, pl)
- return isabs(type, p, win(pl))
-end
-
---determine a path's separator if possible.
-local function detect_sep(p, win)
- if win then
- local fws = p:find'[^/]*/'
- local bks = p:find'[^\\/]*\\'
- if not fws == not bks then
- return nil --can't determine
- end
- return fws and '/' or '\\'
- else
- return '/'
- end
-end
-
---get/add/remove ending separator.
-local function set_endsep(type, p, win, sep, default_sep)
- local _, isempty = isabs(type, p, win)
- if isempty then --refuse to change empty paths
- return
- elseif sep == false or sep == '' then --remove it
- return p:gsub(win and '[\\/]+$' or '/+$', '')
- elseif p:find(win and '[\\/]$' or '/$') then --add it/already set
- return p
- else
- if sep == true then
- sep = detect_sep(p, win) or default_sep or (win and '\\' or '/')
- end
- assert(sep == '\\' or sep == '/', 'invalid separator')
- return p .. sep
- end
-end
-function path.endsep(s, pl, sep, default_sep)
- local win = win(pl)
- local type, p, drive = path.parse(s, pl)
- if sep == nil then
- return p:match(win and '[\\/]+$' or '/+$')
- else
- local p = set_endsep(type, p, win, sep, default_sep)
- return p and path.format(type, p, drive, pl) or s, p and true or false
- end
-end
-
---detect or set a path's separator (for Windows paths only).
---NOTE: setting '\' on a UNIX path may result in an invalid path because
---`\` is a valid character in UNIX filenames!
-local function set_sep(p, win, sep, default_sep, empty_names)
- local dsep = default_sep or (win and '\\' or '/')
- if sep == true then --set to default
- sep = dsep
- elseif sep == false then --set to default only if mixed
- sep = detect_sep(p, win) or dsep
- elseif sep == nil then --collapse only
- sep = '%1'
- else
- assert(sep == '\\' or sep == '/', 'invalid separator')
- end
- if empty_names then
- return p:gsub(win and '[\\/]' or '/', sep)
- else
- return p:gsub(win and '([\\/])[\\/]*' or '(/)/*', sep)
- end
-end
-function path.sep(s, pl, sep, default_sep, empty_names)
- local win = win(pl)
- local type, p, drive = path.parse(s, pl)
- if sep == nil and empty_names == nil then
- return detect_sep(p, win)
- else
- p = set_sep(p, win, sep, default_sep, empty_names)
- return path.format(type, p, drive, pl)
- end
-end
-
-function path.long(s, pl, long)
- local type, p, drive = path.parse(s, pl)
- local is_long = type == 'abs_long' or type == 'unc_long'
- local is_short = (win(pl) and type == 'abs') or type == 'unc'
- if long == nil then
- if is_long then
- return true
- elseif is_short then
- return false
- else
- return nil --does not apply
- end
- end
- if
- is_short and (long == true or (long == 'auto' and #s > 259))
- then
- p = p:gsub('/+', '\\') --NOTE: this might create a smaller path
- local long_type = type == 'abs' and 'abs_long' or 'unc_long'
- s = path.format(long_type, p, drive, pl)
- elseif
- is_long and (long == false or (long == 'auto' and #s <= 259 + 4))
- then
- local short_type = type == 'abs_long' and 'abs' or 'unc'
- s = path.format(short_type, p, drive, pl)
- end
- return s
-end
-
---get the last path component of a path.
---if the path ends in a separator then the empty string is returned.
-function path.file(s, pl)
- local _, p = path.parse(s, pl)
- return p:match(win(pl) and '[^\\/]*$' or '[^/]*$')
-end
-
---get the filename without extension and the extension from a path.
-function path.nameext(s, pl)
- local patt = win(pl) and '^(.-)%.([^%.\\/]*)$' or '^(.-)%.([^%./]*)$'
- local file = path.file(s, pl)
- local name, ext = file:match(patt)
- if not name or name == '' then -- 'dir' or '.bashrc'
- name, ext = file, nil
- end
- return name, ext
-end
-
-function path.ext(s, pl)
- return (select(2, path.nameext(s, pl)))
-end
-
---get a path without basename and separator. if the path ends with
---a separator then the whole path without the separator is returned.
-function path.dir(s, pl)
- local type, p, drive = path.parse(s, pl)
- if p == '' or p == '.' then --current dir has no dir
- return nil
- end
- local i1, i2, i3 = p:match(win(pl)
- and '()[\\/]*()[^\\/]*()$' or '()/*()[^/]*()$')
- if i1 == 1 and i3 == i2 then --root dir has no dir
- return nil
- end
- local i = i1 == 1 and i2 or i1
- local s = path.format(type, p:sub(1, i-1), drive, pl)
- return s == '' and '.' or s --fix '' as '.'
-end
-
---iterate over a path's components and separators.
-function path.gsplit(s, pl, full)
- local win = win(pl)
- local p = full and s or select(2, path.parse(s, pl))
- local root_sep = p:match(win and '^[\\/]+' or '^/+')
- local next_pc = p:gmatch(win and '([^\\/]+)([\\/]*)' or '([^/]+)(/*)')
- local started = not root_sep
- return function()
- if not started then
- started = true
- return '', root_sep
- elseif started then
- return next_pc()
- end
- end
-end
-
-local function iif(a, b, c)
- if a == b then
- return c
- else
- return a
- end
-end
-
--- remove `.` dirs (opt.dot_dirs)
--- remove unnecessary `..` dirs (opt.dot_dot_dirs)
--- normalize separator (opt.sep, opt.default_sep, opt.empty_names)
--- add/remove ending separator (opt.endsep)
--- convert between long and short Windows path encodings (opt.long)
-function path.normalize(s, pl, opt)
- opt = opt or {}
- local win = win(pl)
- local type, p, drive = path.parse(s, pl)
-
- local t = {} --{dir1, sep1, ...}
- local lastsep --last separator that was not added to the list
- for s, sep in path.gsplit(p, pl, true) do
- if s == '.' and not opt.dot_dirs then
- --skip adding the `.` dir and the separator following it
- lastsep = sep
- elseif s == '..' and not opt.dot_dot_dirs and #t > 0 then
- --find the last dir past any `.` dirs, in case opt.dot_dirs = true.
- local i = #t-1
- while t[i] == '.' do
- i = i - 2
- end
- --remove the last dir (and the separator following it)
- --that's not `..` and it's not the root element.
- if i > 0 and ((i > 1 or t[i] ~= '') and t[i] ~= '..') then
- table.remove(t, i)
- table.remove(t, i)
- lastsep = sep
- elseif #t == 2 and t[1] == '' then
- --skip any `..` after the root slash
- lastsep = sep
- else
- table.insert(t, s)
- table.insert(t, sep)
- end
- else
- table.insert(t, s)
- table.insert(t, sep)
- lastsep = nil
- end
- end
- if type == 'rel' and #t == 0 then
- --rel path '' is invalid. fix that.
- table.insert(t, '.')
- table.insert(t, lastsep)
- elseif lastsep == '' and (#t > 2 or t[1] ~= '') then
- --if there was no end separator originally before removing path
- --components, remove the left over end separator now.
- table.remove(t)
- end
- p = table.concat(t)
-
- if opt.sep ~= 'leave' then
- p = set_sep(p, win, iif(opt.sep, nil, false),
- opt.default_sep, opt.empty_names)
- end
-
- if opt.endsep ~= 'leave' then
- p = set_endsep(type, p, win, iif(opt.endsep, nil, false),
- opt.default_sep) or p
- end
-
- s = path.format(type, p, drive, pl)
-
- if win and opt.long ~= 'leave' then
- s = path.long(s, pl, iif(opt.long, nil, 'auto'))
- end
-
- return s
-end
-
---get the common base path (including the end separator if it's common)
---between two paths.
---BUG: the case-insensitive comparison doesn't work with utf8 paths!
-function path.commonpath(s1, s2, pl)
- local win = win(pl)
- local t1, p1, d1 = path.parse(s1, pl)
- local t2, p2, d2 = path.parse(s2, pl)
- local t, p, d
- if #p1 <= #p2 then --pick the smaller/first path when formatting
- t, p, d = t1, p1, d1
- else
- t, p, d = t2, p2, d2
- end
- if win then --make the search case-insensitive and normalize separators
- d1 = d1 and d1:lower()
- d2 = d2 and d2:lower()
- p1 = p1:lower():gsub('/', '\\')
- p2 = p2:lower():gsub('/', '\\')
- end
- if t1 ~= t2 or d1 ~= d2 then
- return nil
- elseif p1 == '' or p2 == '' then
- return path.format(t, p, d, pl)
- end
- local sep = (win and '\\' or '/'):byte(1)
- local si = 0 --index where the last common separator was found
- for i = 1, #p + 1 do
- local c1 = p1:byte(i)
- local c2 = p2:byte(i)
- local sep1 = c1 == nil or c1 == sep
- local sep2 = c2 == nil or c2 == sep
- if sep1 and sep2 then
- si = i
- elseif c1 ~= c2 then
- break
- end
- end
- p = p:sub(1, si)
- return path.format(t, p, d, pl)
-end
-
-local function depth(p, win)
- local n = 0
- for _ in p:gmatch(win and '()[^\\/]+' or '()[^/]+') do
- n = n + 1
- end
- return n
-end
-function path.depth(s, pl)
- local _, p = path.parse(s, pl)
- return depth(p, win(pl))
-end
-
---combine two paths if possible.
-local function combinable(type1, type2)
- if type2 == 'rel' then -- any + c/d -> any/c/d
- return type1 ~= 'dev_alias'
- elseif type2 == 'abs_nodrive' then -- C:a/b + /c/d -> C:/c/d/a/b
- return type1 == 'rel_drive'
- elseif type2 == 'rel_drive' then -- C:/a/b + C:c/d -> C:/a/b/c/d
- return type1 == 'abs' or type1 == 'abs_long'
- end
-end
-function path.combine(s1, s2, pl, sep, default_sep)
- local type1, p1, drive1 = path.parse(s1, pl)
- local type2, p2, drive2 = path.parse(s2, pl)
- if not combinable(type1, type2) then
- if combinable(type2, type1) then
- type1, type2, s1, s2, p1, p2, drive1, drive2 =
- type2, type1, s2, s1, p2, p1, drive2, drive1
- else
- return nil, ('cannot combine %s and %s paths'):format(type1, type2)
- end
- end
- if s2 == '' then -- any + '' -> any
- return s1
- elseif type2 == 'rel' or type2 == 'abs_nodrive' then
- local win = win(pl)
- local sep = sep or detect_sep(p1, win) or detect_sep(p2, win)
- or default_sep or (win and '\\' or '/')
- if type2 == 'rel' then -- any + c/d -> any/c/d
- p1 = set_endsep(type1, p1, win, sep) or p1
- return path.format(type1, p1 .. s2, drive1, pl)
- elseif type2 == 'abs_nodrive' then -- C:a/b + /d/e -> C:/d/e/a/b
- p2 = set_endsep(type2, p2, win, sep) or p2
- return path.format(type1, p2 .. p1, drive1, pl)
- end
- elseif type2 == 'rel_drive' then -- C:/a/b + C:d/e -> C:/a/b/d/e
- if drive1 ~= drive2 then
- return nil, 'path drives are different'
- end
- return path.combine(s1, p2, pl)
- end
-end
-
---transform a relative path into an absolute path given a base dir.
-path.abs = path.combine
-
---transform an absolute path into a relative path which is relative to `pwd`.
---the ending separator is preserved.
-function path.rel(s, pwd, pl, sep, default_sep)
- local prefix = path.commonpath(s, pwd, pl)
- if not prefix then return nil end
- local type, p, drive = path.parse(s, pl)
- local win = win(pl)
- local sep = sep or detect_sep(pwd, win) or detect_sep(p, win)
- or default_sep or (win and '\\' or '/')
- local endsep = p:match(win and '[\\/]*$' or '/*$')
- local pwd_suffix = pwd:sub(#prefix + 1)
- local n = depth(pwd_suffix, win)
- local p1 = ('..' .. sep):rep(n - 1) .. (n > 0 and '..' or '')
- local p2 = p:sub(#prefix + 1)
- local p2 = p2:gsub(win and '^[\\/]+' or '^/+', '')
- local p2 = p2:gsub(win and '[\\/]+$' or '/+$', '')
- local p2 = p1 == '' and p2 == '' and '.' or p2
- local p3 = p1 .. (p1 ~= '' and p2 ~= '' and sep or '') .. p2 .. endsep
- return path.format(type, p3, drive, pl)
-end
-
---validate/make-valid a filename
---NOTE: repl can be a function(match, err) -> repl_str.
---NOTE: if repl isn't itself escaped then duplicate filenames can result.
-function path.filename(s, pl, repl, break_on_err)
- local win = win(pl)
-
- local function check(err, msg)
- if not repl or err == break_on_err then
- return nil, msg, err
- end
- local s = repl(s, err)
- if not s then
- return nil, msg, err
- end
- return path.filename(s, pl, repl, err) --tail call
- end
-
- function subcheck(patt, err, msg)
- if repl then
- local user_repl = repl
- function repl(s, err)
- local s, repl_count = s:gsub(patt, function(c)
- return user_repl(c, err) --returning nil/false means no repl.
- end)
- return repl_count > 0 and s
- end
- end
- return check(err, msg)
- end
-
- local invalid_chars = win and '[%z\1-\31<>:"|%?%*\\/]' or '[%z/]'
- local empty
-
- if s == '' then
- return check(s, 'empty filename')
- elseif s == '.' or s == '..' then
- return check(s, 'filename is `.` or `..`')
- elseif win and path.dev_alias(s) then
- return check('dev_alias', 'filename is a Windows device alias')
- elseif win and s:find(invalid_chars) then
- return subcheck(invalid_chars, 'char', 'invalid characters in filename')
- elseif #s > 255 then --same maximum for Windows and Linux
- return check('length', 'filename too long')
- elseif s:find' +$' then
- return subcheck(' +$', 'evil', 'filename ends with spaces')
- elseif s:find'^ +' then
- return subcheck('^ +', 'evil', 'filename begins with spaces')
- elseif s:find'%.+$' then
- return subcheck('%.+$', 'evil', 'filename ends with a dot')
- end
- return s
-end
-
-return path
-
diff --git a/lib/path.md b/lib/path.md
deleted file mode 100644
index 5e7daa6..0000000
--- a/lib/path.md
+++ /dev/null
@@ -1,238 +0,0 @@
----
-tagline: path manipulation
----
-
-## `local path = require'path'`
-
-Path manipulation library for Windows and UNIX paths. Parses all Windows
-path formats including long paths (`\\?\`), device paths (`\\.\`)
-and UNC paths.
-
-## API
-
----------------------------------------------------- ------------------------------------------------
-`path.platform -> s` get the current platform
-`path.default_sep([pl]) -> s` get the default separator for a platform
-`path.dev_alias(s) -> s|nil` check if a path is a Windows device alias
-`path.type(s, [pl]) -> type` get the path type
-`path.parse(s, [pl]) -> type, path[, drv|srv]` break down a path to its basic parts
-`path.format(type, path, [drv|srv], pl) -> s` put together a path from parsed parts
-`path.isabs(s, [pl]) -> is_abs, is_empty` check if path is absolute, empty and valid
-`path.endsep(s, [pl], [sep], [dsep]) -> s, ok` get/add/remove the ending separator
-`path.sep(s, [pl], [sep], ...) -> s` detect/set the path separator
-`path.long(s, [pl], [long]) -> s|nil` get/set a Windows long absolute path
-`path.file(s, [pl]) -> s` get the last component of a path
-`path.nameext(s, [pl]) -> name, ext` split `path.file()` into name and extension
-`path.ext(s, [pl]) -> s` return only the extension from `path.nameext()`
-`path.dir(s, [pl]) -> s|nil` get the path without the last component
-`path.gsplit(s, [pl], [full]) ->iter() -> s, sep` iterate over path's components
-`path.normalize(s, [pl], [opt]) -> s` normalize a path in various ways
-`path.commonpath(s1, s2, [pl]) -> s|nil` get the common prefix of two paths
-`path.depth(s, [pl]) -> n` get the number of non-empty path components
-`path.combine(s1, s2, [pl], [sep], [dsep]) -> s|nil` combine two paths if possible
-`path.abs(dir, s, [pl], [sep], [dsep]) -> s|nil,err` convert relative path to absolute
-`path.rel(s, pwd, [pl], [sep], [dsep]) -> s|nil` convert absolute path to relative
-`path.filename(s, [pl], [repl]) -> s|nil,err,code` validate/make-valid filename
----------------------------------------------------- ------------------------------------------------
-
-In the table above, `pl` is for platform and can be `'win'` or `'unix'` and
-defaults to the current platform.
-
-### `path.platform -> s`
-
-Get the current platform which can be `'win'` or `'unix'`.
-
-### `path.default_sep([pl]) -> s`
-
-Get the default separator for a platform which can be `\` or `/`.
-
-### `path.dev_alias(s) -> s|nil`
-
-Check if a path is a Windows device alias and if it is, return that alias.
-
-### `path.type(s, [pl]) -> type`
-
-Get the path type which can be:
-
- * `'abs'` - `C:\path` (Windows) or `/path` (UNIX)
- * `'rel'` - `a/b` (Windows, UNIX)
- * `'abs_long'` - `\\?\C:\path` (Windows)
- * `'abs_nodrive'` - `\path` (Windows)
- * `'rel_drive'` - `C:a\b` (Windows)
- * `'unc'` - `\\server\share\path` (Windows)
- * `'unc_long'` - `\\?\UNC\server\share\path` (Windows)
- * `'global'` - `\\?\path` (Windows)
- * `'dev'` - `\\.\path` (Windows)
- * `'dev_alias'`: `CON`, `c:\path\nul.txt`, etc. (Windows)
-
-The empty path (`''`, which is technically invalid) comes off as type `'rel'`.
-
-The only paths that are portable between Windows and UNIX (Linux, OSX)
-without translation are type `'rel'` paths using forward slashes only which
-are no longer than 259 bytes and which don't contain any control characters
-(code 0-31) or the symbols `<>:"|%?*\`.
-
-### `path.parse(s, [pl]) -> type, path[, drive|server]`
-
-Split a path into its _local path_ component (i.e. the part containing only
-directories and files, eg. `\path` for `C:\path` or for `\\server\path`)
-and, depending on the path type, the drive letter or server name.
-
-UNC paths are not validated and can have an empty server or share path.
-
-### `path.format(type, path, [drive|server], [pl]) -> s`
-
-Put together a path from its broken-down components. No validation is done.
-
-### `path.isabs(s, [pl]) -> is_abs, is_empty, is_valid`
-
-Check if a path is an absolute path or not, if it's empty (i.e. root)
-or not, and if it's valid or not.
-
-Absolute paths for which their _local path_ is `''` are actually invalid
-(currently only incomplete UNC paths like `\\server` or `\\?` can be
-like that). For those paths `is_valid` is `false`.
-
-### `path.endsep(s, [pl], [sep], [dsep]) -> s, success`
-
-Get/add/remove an ending separator of a path. If `sep` is `nil` or missing,
-the ending separator is returned (`nil` is returned if the path has no ending
-separator). If `sep` is `true`, `'\\'`, `'/'`, the path is returned with an
-ending separator added (`true` means use path's own separator if it has one
-and failing that, use `dsep` or the default platform separator). If `sep` is
-`false` or `''` the path without its ending separator is returned. `success`
-is `false` if trying to add or remove the ending separator from an empty path
-(note that even when that happens, the path can still be concatenated
-directly to a relative path and result in a valid path).
-
-Multiple consecutive separators are treated as one in that they
-are returned together and are replaced together.
-
-### `path.sep(s, [pl], [sep], [default_sep], [empty_names]) -> s`
-
-Detect or set the a path's separator (for Windows paths only).
-
-The arg `sep` can be `nil` (detect), `true` (set to `default_sep`), `false`
-(set to `default_sep` but only if both `\` and `/` are found in the path,
-i.e. unify), `'\\'` or `'/'` (set specifically), or `nil` when `empty_names`
-is explicitly `false` (collapse duplicate separators only). `default_sep`
-defaults to the platform separator. Unless `empty_names` is `true`,
-consecutive separators are collapsed into the first one.
-
-__NOTE:__ Setting the separator as `\` on a UNIX path may result in an
-invalid path because `\` is a valid character in UNIX filenames.
-
-### `path.long(s, [pl], [long]) -> s|nil`
-
-Get/set a Windows long absolute path (one starting with `\\?\C:\`). If
-`long` is `nil`, returns whether the path is a long or short Windows absolute
-path (returns `nil` for all other kinds of paths). Otherwise it converts the
-path, in which case `long` can be `true` (convert to long path), `false`
-(convert to short path) or `'auto'` (convert to long style if too long,
-or to short style if short enough).
-
-### `path.file(s, [pl]) -> s`
-
-Get the last component of a path. Returns `''` if the path is empty or ends
-with a separator.
-
-### `path.nameext(s, [pl]) -> name, ext`
-
-Split a path's last component into the name and extension parts like so:
-
- * `a.txt'` -> `'a', 'txt'`
- * `'.bashrc'` -> `'.bashrc', nil`
- * `'a'` -> `'a', nil`
- * `'a.'` -> `'a', ''`
-
-### `path.ext(s, [pl]) -> s|nil`
-
-Return only the extension from `path.nameext()`.
-
-### `path.dir(s, [pl]) -> s`
-
-Get the path without the last component and separator. If the path ends with
-a separator then the whole path without the separator is returned. Multiple
-consecutive separators are treated as one. Returns `nil` for `''`, `'.'`,
-`'C:'`, `'/'`, `'C:\\'` and `\\server\`. Returns `'.'` for simple filenames.
-
-### `path.gsplit(s, [pl], [full]) -> iter() -> s, sep`
-
-Iterate over a path's _local components_ (that is excluding prefixes like
-`\\server` or `C:`). Pass `true` to the `full` arg to iterate over the
-whole unparsed path. For absolute paths, the first iteration is
-`'', `. Empty names are not iterated. Instead, consecutive
-separators are returned together. Concatenating all the iterated path
-components and separators always results in the exact original path.
-
-### `path.normalize(s, [pl], [opt]) -> s`
-
-Normalize a path by removing `.` dirs, removing unnecessary `..` dirs
-(careful: this changes where the path points to if there are symlinks on
-the path!), collapsing, normalizing or changing the separator
-(for Windows paths), converting between Windows long (`\\?\`, `\\?\UNC\`)
-and normal paths.
-
-The `opt` arg controls the normalization:
-
- * `dot_dirs` - use `true` to keep `.` dirs.
- * `dot_dot_dirs` - use `true` to keep the `..` dirs.
- * `sep`, `default_sep`, `empty_names` - args to pass to `path.sep()`
- (`sep` defaults to `false`, use `'leave'` to avoid normalizing the
- separators)
- * `endsep` - `sep` arg to pass to `path.endsep()` (defaults to `false`,
- use `'leave'` to avoid removing any end separator)
- * `long` - `long` arg to pass to `path.long()` (defaults to `'auto'`,
- use `'leave'` to avoid converting between short and long paths)
-
-__NOTE:__ If normalization results in the empty relative path `''`, then
-`'.'` is returned instead.
-
-### `path.commonpath(s1, s2, [pl]) -> s|nil`
-
-Get the common path prefix of two paths, including the end separator if both
-paths share it, or `nil` if the paths don't have anything in common.
-
-Note that `path.commonpath('C:', 'C:\\', 'win') == nil` because the paths are
-of different type even if they look like they share a common prefix.
-
-__BUG:__ The case-insensitive comparison for Windows doesn't work with
-paths with non-ASCII characters because it's made with `string.lower()`.
-Proper lowercase your paths before using this function, or patch
-`string.lower()` to support utf8 lowercasing. This is not an issue if both
-paths are in the original letter case (eg. they come from the same API).
-
-### `path.depth(s, [pl]) -> n`
-
-Get the number of non-empty path components, excluding prefixes like
-`C:\`, `\\server\`, etc.
-
-### `path.combine(s1, s2, [pl], [sep], [dsep]) -> s|nil,err`
-
-Combine two paths if possible (return `nil, err` if not). Supported
-combinations are between anything except `dev_alias` and `rel` paths,
-between `abs_nodrive` and `rel_drive`, and between `rel_drive` and `abs`
-or `abs_long`. When the paths can only be combined in one way, paths can be
-given in any order. The separator with which paths are combined is either
-`sep` or if `sep` is nil it's detected and if that fails `dsep` or the
-default separator is used.
-
-### `path.abs(dir, s, [pl], [sep], [dsep]) -> s|nil,err`
-
-Convert a relative path to an absolute path given a base dir
-(this is currently an alias of `path.combine()`).
-
-### `path.rel(s, pwd, [pl], [sep], [dsep]) -> s|nil`
-
-Convert an absolute path into a relative path which is relative to `pwd`.
-Returns `nil` if the paths are of different types or don't have a base path
-in common. The ending (back)slash is preserved if present.
-
-### `path.filename(s, [pl], [repl]) -> s|nil,err,errcode`
-
-Validate a filename or apply a replacement function on it in order to make it
-valid. The `repl` function receives the problematic match and an error code
-indicating the problem which can be one of '', '.', '..', 'dev_alias',
-'char', 'length', 'evil' and it should return a replacement string or
-`false/nil` if it cannot do the replacement (`'evil'` errors should generally
-be replaced with `''`).
diff --git a/lib/path_test.lua b/lib/path_test.lua
deleted file mode 100644
index d36604d..0000000
--- a/lib/path_test.lua
+++ /dev/null
@@ -1,449 +0,0 @@
-local path = require'path'
-
-assert(path.platform == 'win' or path.platform == 'unix')
-assert(path.default_sep'win' == '\\')
-assert(path.default_sep'unix' == '/')
-assert(path.default_sep() == path.default_sep(path.platform))
-
-assert(path.dev_alias'NUL' == 'NUL')
-assert(path.dev_alias'c:/a/b/con.txt' == 'CON')
-
---type -----------------------------------------------------------------------
-
-assert(path.type('c:\\', 'win') == 'abs')
-assert(path.type('c:/a/b', 'win') == 'abs')
-assert(path.type('/', 'unix') == 'abs')
-assert(path.type('/a/b', 'unix') == 'abs')
-assert(path.type('\\\\?\\C:\\', 'win') == 'abs_long')
-assert(path.type('/a/b', 'win') == 'abs_nodrive')
-assert(path.type('', 'win') == 'rel')
-assert(path.type('a', 'win') == 'rel')
-assert(path.type('a/b', 'win') == 'rel')
-assert(path.type('C:', 'win') == 'rel_drive')
-assert(path.type('C:a', 'win') == 'rel_drive')
-assert(path.type('\\\\', 'win') == 'unc')
-assert(path.type('\\\\server\\share', 'win') == 'unc')
-assert(path.type('\\\\?\\UNC\\', 'win') == 'unc_long')
-assert(path.type('\\\\?\\UNC\\server', 'win') == 'unc_long')
-assert(path.type('\\\\?\\UNC\\server\\share', 'win') == 'unc_long')
-assert(path.type('\\\\?\\', 'win') == 'global')
-assert(path.type('\\\\?\\a', 'win') == 'global')
-assert(path.type('\\\\.\\', 'win') == 'dev')
-assert(path.type('\\\\.\\a', 'win') == 'dev')
-assert(path.type('c:/nul', 'win') == 'dev_alias')
-
---isabs ----------------------------------------------------------------------
-
-local function test(s, pl, isabs2, isempty2, isvalid2)
- local isabs1, isempty1, isvalid1 = path.isabs(s, pl)
- print('isabs', s, pl, '->', isabs1, isempty1, isvalid1)
- assert(isabs1 == isabs2)
- assert(isempty1 == isempty2)
- assert(isvalid1 == isvalid2)
-end
-
-test('', 'win', false, true, true)
-test('/', 'win', true, true, true)
-test('\\//', 'win', true, true, true)
-test('C:', 'win', false, true, true)
-test('C:/', 'win', true, true, true)
-test('C:/a', 'win', true, false, true)
-test('a', 'win', false, false, true)
-
---device alias but appears abs
-test('C:/path/con.txt', 'win', false, false, true)
-
-test('\\\\', 'win', true, true, false) --invalid
-test('\\\\server', 'win', true, true, false) --invalid
-test('\\\\server\\', 'win', true, true, true) --still invalid but better :)
-test('\\\\server\\share', 'win', true, false, true) --valid
-
-test('/', 'unix', true, true, true)
-test('', 'unix', false, true, true)
-
---endsep ---------------------------------------------------------------------
-
-local function test(s, s2, success2, pl, sep, default_sep)
- local s1, success1 = path.endsep(s, pl, sep, default_sep)
- print('endsep', s, pl, sep, '->', s1, success1)
- assert(s1 == s2)
- assert(success1 == success2)
-end
-
---empty rel has no end sep
-test('', nil, nil, 'win', nil)
-test('C:', nil, nil, 'win', nil)
-
---abs root has end sep
-test('/', '/', nil, 'win', nil)
-test('/', '/', nil, 'unix', nil)
-test('C:\\', '\\', nil, 'win', nil)
-
---add
-test('a', 'a/', true, 'win', '/') --add specific
-test('a', 'a\\', true, 'unix', '\\') --add specific (invalid but allowed)
-test('a', 'a\\', true, 'win', true) --add default
-test('a/b', 'a/b/', true, 'win', true) --add detected
-
---remove
-test('a/', 'a', true, 'win', '') --remove
-test('a/', 'a', true, 'win', false) --remove
-
---already there, not adding
-test('a/', 'a/', true, 'win', '\\')
-
---refuse to remove from the empty abs path
-test('/', '/', false, 'win', '')
-test('C:/', 'C:/', false, 'win', '')
-
---refuse to add to the empty rel path
-test('', '', false, 'win', '/')
-test('C:', 'C:', false, 'win', '/')
-
---separator ------------------------------------------------------------------
-
-local function test(s, s2, pl, sep, default_sep, empty_names)
- local s1 = path.sep(s, pl, sep, default_sep, empty_names)
- print('sep', s, pl, sep, default_sep, empty_names, '->', s1)
- assert(s1 == s2)
-end
-
-test('', nil, 'win')
-test('a', nil, 'win')
-test('/', '/', 'win')
-test('\\', '\\', 'win')
-test('C:', nil, 'win')
-test('\\\\server', nil, 'win') --invalid UNC
-test('a/b\\c', nil, 'win')
-test('a/b\\c', '/', 'unix')
-
-test('', '', 'win', true)
-test('a/b', 'a\\b', 'win', true) --default
-test('a\\b', 'a/b', 'win', true, '/') --specific default
-test('a/b/c', 'a/b/c', 'win', false) --default if mixed
-test('a/b\\c', 'a\\b\\c', 'win', false) --default if mixed
-test('a/b\\c', 'a/b/c', 'win', false, '/') --specific default if mixed
-test('a/b\\c', 'a/b/c', 'win', '/') --specific
-test('a/b/c', 'a\\b\\c', 'win', '\\') --specific (invalid but allowed)
-
-test('a//b\\\\\\c', 'a/b\\c', 'win', nil, nil, false) --collapse only
---don't collapse, default if mixed, default
-test('a//b\\\\\\c', 'a\\\\b\\\\\\c', 'win', true, nil, true)
---don't collapse, default if mixed, specific
-test('a//b\\\\\\c', 'a//b///c', 'win', '/', nil, true)
---don't collapse, default if mixed
-test('a//b\\\\\\c', 'a\\\\b\\\\\\c', 'win', false, nil, true)
---don't collapse, default if mixed, specific default
-test('a//b\\\\\\c', 'a//b///c', 'win', false, '/', true)
-
---file -----------------------------------------------------------------------
-
-local function test(s, pl, s2)
- local s1 = path.file(s, pl)
- print('file', s, pl, '->', s1)
- assert(s1 == s2)
-end
-test('' , 'win', '')
-test('/' , 'win', '')
-test('a' , 'win', 'a')
-test('a/' , 'win', '')
-test('/a' , 'win', 'a')
-test('a/b' , 'win', 'b')
-test('a/b/', 'win', '')
-
-test('a\\b\\', 'unix', 'a\\b\\')
-test('a/b', 'unix', 'b')
-test('a/b/', 'unix', '')
-
---nameext --------------------------------------------------------------------
-
-local function test(s, pl, name2, ext2)
- local name1, ext1 = path.nameext(s, pl)
- print('nameext', s, pl, '->', name1, ext1)
- assert(name1 == name2)
- assert(ext1 == ext2)
-end
-
-test('', 'win', '', nil)
-test('/', 'win', '', nil)
-test('a/', 'win', '', nil)
-test('/a/b/a', 'win', 'a', nil)
-test('/a/b/a.', 'win', 'a', '') --invalid filename on Windows
-test('/a/b/a.txt', 'win', 'a', 'txt')
-test('/a/b/.bashrc', 'win', '.bashrc', nil)
-
---dir ------------------------------------------------------------------------
-
-local function test(s, pl, s2)
- local s1 = path.dir(s, pl)
- print('dir', s, pl, '->', s1)
- assert(s1 == s2)
-end
-
---empty rel path has no dir
-test('', 'win', nil)
-test('C:', 'win', nil)
-
---current dir has no dir
-test('.', 'win', nil)
-
---root has no dir
-test('C:/', 'win', nil)
-test('/', 'win', nil)
-test('\\', 'win', nil)
-
---dir is root
-test('/b', 'unix', '/')
-test('/aa', 'win', '/')
-test('C:/a', 'win', 'C:/')
-
---dir is the current dir
-test('a', 'win', '.')
-test('aa', 'win', '.')
-test('\\aa', 'unix', '.')
-test('C:a', 'win', 'C:')
-
---dir of empty filename
-test('a/', 'win', 'a')
-test('./', 'win', '.')
-
---dir of non-empty filename
-test('a/b', 'win', 'a')
-test('aa/bb', 'win', 'aa')
-test('C:/aa/bb', 'win', 'C:/aa')
-test('C:a', 'win', 'C:')
-test('a/b', 'unix', 'a')
-
---gsplit ---------------------------------------------------------------------
-
-function test(s, pl, full, t2)
- local t1 = {}
- for s, sep in path.gsplit(s, pl, full) do
- table.insert(t1, s)
- table.insert(t1, sep)
- end
- local _ = require'pp'.format
- print('gsplit', s, pl, full, '->', _(t1))
- assert(_(t1) == _(t2))
-end
-
-test('', 'win', nil, {})
-test('/', 'win', nil, {'', '/'})
-test('/a', 'win', nil, {'', '/', 'a', ''})
-test('/a/', 'win', nil, {'', '/', 'a', '/'})
-test('\\/a\\/', 'win', nil, {'', '\\/', 'a', '\\/'})
-test('C:', 'win', nil, {})
-test('C:\\a/b', 'win', nil, {'', '\\', 'a', '/', 'b', ''})
-test('a/b\\c', 'unix', nil, {'a', '/', 'b\\c', ''})
-
---normalize ------------------------------------------------------------------
-
-local function test(s, pl, opt, s2)
- local s1 = path.normalize(s, pl, opt)
- print('normal', s, pl, 'opt', '->', s1)
- assert(s1 == s2)
-end
-
---remove `.`
-local opt = {dot_dot_dirs = true, endsep = 'leave', sep = 'leave'}
-test('.', 'win', opt, '.')
-test('./', 'win', opt, './')
-test('C:.', 'win', opt, 'C:')
-test('C:./', 'win', opt, 'C:')
-test('.\\', 'win', opt, '.\\')
-test('./.', 'win', opt, '.')
-test('./.\\', 'win', opt, '.\\')
-test('/.', 'win', opt, '/')
-test('\\./', 'win', opt, '\\') --root slash kept
-test('/.\\.', 'win', opt, '/') --root slash kept
-test('/a/.', 'win', opt, '/a')
-test('/./a', 'win', opt, '/a')
-test('./a', 'win', opt, 'a')
-test('a/.', 'win', opt, 'a')
-test('a\\.', 'win', opt, 'a')
-test('a\\./', 'win', opt, 'a\\')
-test('a/b\\c', 'win', opt, 'a/b\\c')
-test('a\\././b///', 'win', opt, 'a\\b///')
-test('a/.\\.\\b\\\\', 'win', opt, 'a/b\\\\')
-
---remove `..`
-local opt = {dot_dirs = true, endsep = 'leave', sep = 'leave'}
-test('a/b/..', 'win', opt, 'a') --remove endsep from leftover
-test('a/b/c/..', 'win', opt, 'a/b') --remove endsep from leftover
-test('a/..', 'win', opt, '.') --no leftover to remove endsep from
-test('\\a/..', 'win', opt, '\\') --can't remove endsep from empty abs path
-test('\\a/../', 'win', opt, '\\') --keep endsep
-test('\\../', 'win', opt, '\\') --remove from root, keep endsep
-test('a\\b/../', 'win', opt, 'a\\') --keep endsep
-test('a/../', 'win', opt, './') --no leftover to see endsep
-test('C:/a/b/..', 'win', opt, 'C:/a')
-test('C:/a/b/c/../..', 'win', opt, 'C:/a')
---remove till empty
-test('a/..', 'win', opt, '.')
-test('a/b/../..', 'win', opt, '.')
-test('C:/a/..', 'win', opt, 'C:/') --keep endsep
-test('C:/a/b/../..', 'win', opt, 'C:/') --keep endsep
---one `..` too many from rel paths
-test('..', 'win', opt, '..')
-test('../', 'win', opt, '../')
-test('../..', 'win', opt, '../..')
-test('../..\\', 'win', opt, '../..\\')
-test('a/..\\', 'win', opt, '.\\')
-test('a/b/../../..', 'win', opt, '..')
---one `..` too many from abs paths
-test('/..', 'win', opt, '/')
-test('/..\\', 'win', opt, '/')
-test('/../..', 'win', opt, '/')
-test('/../..\\', 'win', opt, '/')
-test('C:/a/b/../../..', 'win', opt, 'C:/')
---skip `.` dirs when removing
-test('a/b/./././..', 'win', opt, 'a/././.')
-test('a/./././..', 'win', opt, '././.')
-test('./././..', 'win', opt, './././..')
-test('/./././..', 'win', opt, '/./././..')
-
---default options: remove `.` and `..` and end-slash, set-sep-if-mixed.
-test('C:///a/././b/x/../c\\d', 'win', nil, 'C:\\a\\b\\c\\d')
---default options: even when not mixed, separators are collapsed.
-test('C:///a/././b/x/../c/d', 'win', nil, 'C:/a/b/c/d')
---default options: remove endsep
-test('.\\', 'win', nil, '.')
-test('.\\././.\\', 'win', nil, '.')
-test('C:./', 'win', nil, 'C:')
-
---long paths
-local long = {long = 'auto', sep = 'leave', endsep = 'leave'}
-test('C:'..('/a/b'):rep(65), 'win', long, '\\\\?\\C:'..('\\a\\b'):rep(65))
-
---commonpath -----------------------------------------------------------------
-
-local function test(a, b, pl, c2)
- local c1 = path.commonpath(a, b, pl)
- print('commonp', a, b, pl, '->', c1)
- assert(c1 == c2)
-end
-
---same path
-test('', '', 'win', '')
-test('/', '/', 'win', '/')
-test('C:', 'C:', 'win', 'C:')
-test('C:a', 'C:a', 'win', 'C:a')
-
---diff type and/or drive
-test('C:/', 'C:', 'win', nil) --diff. type (common lexic prefix)
-test('C:a', 'C:/', 'win', nil) --diff. type
-test('C:/CON', 'C:/', 'win', nil) --diff. type
-test('C:', 'X:', 'win', nil) --diff. drive
-test('\\\\a\\', '\\\\b\\', 'win', nil) --diff. server
-
---same path diff. syntax, choose the first path
-test('c:/', 'C:/', 'win', 'c:/')
-test('C:/', 'C:\\', 'win', 'C:/')
-test('C:\\a/b', 'C:/a\\b', 'win', 'C:\\a/b')
-
---same path diff. syntax, choose the smallest path
-test('C:////////', 'c://', 'win', 'c://')
-test('c://', 'C:////////', 'win', 'c://')
-
-test('C:/a', 'C:/b', 'win', 'C:/')
-test('C:a', 'C:b', 'win', 'C:')
-test('C:/a/b', 'C:/a/c', 'win', 'C:/a/')
-test('C:/a/b', 'C:/a/b/', 'win', 'C:/a/b') --endsep not common
-test('C:/a/b/', 'C:/a/b/c', 'win', 'C:/a/b/') --endsep common and end
-test('C:/a/c/d', 'C:/a/b/f', 'win', 'C:/a/') --endsep common
-test('C:/a/b', 'C:/a/bc', 'win', 'C:/a/') --last sep, not last char
-test('C:/a//', 'C:/a//', 'win', 'C:/a//') --multiple endsep common
-
---case-sensitivity
-test('a/B', 'a/b', 'unix', 'a/')
-test('C:a/B', 'C:a/b', 'win', 'C:a/B') --pick first
-test('C:a/B/c', 'C:a/b/c/d', 'win', 'C:a/B/c') --pick smallest
-
---depth ----------------------------------------------------------------------
-
-assert(path.depth(''), 'win' == 0)
-assert(path.depth('/'), 'win' == 0)
-assert(path.depth('/\\///'), 'win' == 0)
-assert(path.depth('a/'), 'win' == 1)
-assert(path.depth('/a'), 'win' == 1)
-assert(path.depth('/a/'), 'win' == 1)
-assert(path.depth('a/b'), 'win' == 2)
-assert(path.depth('/a/b'), 'win' == 2)
-assert(path.depth('a/b/'), 'win' == 2)
-assert(path.depth('/a/b/'), 'win' == 2)
-assert(path.depth('a/b/c'), 'win' == 3)
-assert(path.depth('C:/a/b/c'), 'win' == 3)
-assert(path.depth('\\\\server\\share\\path'), 'win' == 2)
-
---combine (& implicitly abs) -------------------------------------------------
-
-local function test(s1, s2, pl, p2, err2)
- local p1, err1 = path.combine(s1, s2, pl)
- print('combine', s1, s2, pl, '->', p1, err1, err1)
- assert(p1 == p2)
- if err2 then
- assert(err1:find(err2, 1, true))
- end
-end
-
--- any + '' -> any
-test('C:a/b', '', 'win', 'C:a/b')
-
--- any + c/d -> any/c/d
-test('C:\\', 'c/d', 'win', 'C:\\c/d')
-
--- C:a/b + /d/e -> C:/d/e/a/b
-test('C:a/b', '\\d\\e', 'win', 'C:\\d\\e/a/b')
-
--- C:/a/b + C:d/e -> C:/a/b/d/e
-test('C:/a/b', 'C:d\\e', 'win', 'C:/a/b/d\\e')
-
--- errors
-test('/a', '/b', 'win', nil, 'cannot combine') --types
-test('C:', 'D:', 'win', nil, 'cannot combine') --drives
-
-
---rel ------------------------------------------------------------------------
-
-local function test(s, pwd, s2, pl, sep, default_sep)
- local s1 = path.rel(s, pwd, pl, sep, default_sep)
- print('rel', s, pwd, pl, '->', s1)
- assert(s1 == s2)
-end
-
-test('/a/c', '/a/b', '../c', 'win')
-test('/a/b/c', '/a/b', 'c', 'win')
-
-test('', '', '.', 'win')
-test('', 'a', '..', 'win')
-test('a', '', 'a', 'win')
-test('a/', '', 'a/', 'win')
-test('a', 'b', '../a', 'win', '/')
-test('a/', 'b', '../a/', 'win')
-test('a', 'b/', '../a', 'win')
-
-test('a/b', 'a/c', '../b', 'win') --1 updir + non-empty
-test('a/b/', 'a/c', '../b/', 'win') --1 updir + non-empty + endsep
-test('a/b', 'a/b/c', '..', 'win') --1 updir + empty
-test('a/b/', 'a/b/c', '../', 'win') --1 updir + empty + endsep
-test('a/b/c', 'a/b', 'c', 'win') --0 updirs + non-empty
-test('a/b', 'a/b', '.', 'win') --0 updirs + empty
-test('a/b/', 'a/b', './', 'win') --0 updirs + empty + endsep
-test('C:a/b/', 'C:a/b', 'C:./', 'win') --0 updirs + empty + endsep
-test('a/b', 'a/c/d', '../../b', 'win') --2 updirs + non-empty
-test('a/b/', 'a/c/d', '../../b/', 'win') --2 updirs + non-empty + endsep
-
---filename -------------------------------------------------------------------
-
-local function test(s, pl, repl, s2)
- local s1, err, errcode = path.filename(s, pl, repl)
- print('filename', s, pl, repl, '->', s1, err, errcode)
- assert(s1 == s2)
-end
-
-test('/a/..', 'unix', nil, nil)
-test('/a/..', 'unix', function() end, nil)
-test('/a/..', 'unix', function() return false end, nil)
-test('/a/..', 'unix', function(s, err) return '' end, '/a/')
---TODO
-
diff --git a/lib/pngencoder.lua b/lib/pngencoder.lua
deleted file mode 100644
index 4f89d91..0000000
--- a/lib/pngencoder.lua
+++ /dev/null
@@ -1,190 +0,0 @@
-local Png = {}
-Png.__index = Png
-
-local DEFLATE_MAX_BLOCK_SIZE = 65535
-
-local function putBigUint32(val, tbl, index)
- for i=0,3 do
- tbl[index + i] = bit.band(bit.rshift(val, (3 - i) * 8), 0xFF)
- end
-end
-
-function Png:writeBytes(data, index, len)
- index = index or 1
- len = len or #data
- for i=index,index+len-1 do
- table.insert(self.output, string.char(data[i]))
- end
-end
-
-function Png:write(pixels)
- local count = #pixels -- Byte count
- local pixelPointer = 1
- while count > 0 do
- if self.positionY >= self.height then
- error("All image pixels already written")
- end
-
- if self.deflateFilled == 0 then -- Start DEFLATE block
- local size = DEFLATE_MAX_BLOCK_SIZE;
- if (self.uncompRemain < size) then
- size = self.uncompRemain
- end
- local header = { -- 5 bytes long
- bit.band((self.uncompRemain <= DEFLATE_MAX_BLOCK_SIZE and 1 or 0), 0xFF),
- bit.band(bit.rshift(size, 0), 0xFF),
- bit.band(bit.rshift(size, 8), 0xFF),
- bit.band(bit.bxor(bit.rshift(size, 0), 0xFF), 0xFF),
- bit.band(bit.bxor(bit.rshift(size, 8), 0xFF), 0xFF),
- }
- self:writeBytes(header)
- self:crc32(header, 1, #header)
- end
- assert(self.positionX < self.lineSize and self.deflateFilled < DEFLATE_MAX_BLOCK_SIZE);
-
- if (self.positionX == 0) then -- Beginning of line - write filter method byte
- local b = {0}
- self:writeBytes(b)
- self:crc32(b, 1, 1)
- self:adler32(b, 1, 1)
- self.positionX = self.positionX + 1
- self.uncompRemain = self.uncompRemain - 1
- self.deflateFilled = self.deflateFilled + 1
- else -- Write some pixel bytes for current line
- local n = DEFLATE_MAX_BLOCK_SIZE - self.deflateFilled;
- if (self.lineSize - self.positionX < n) then
- n = self.lineSize - self.positionX
- end
- if (count < n) then
- n = count;
- end
- assert(n > 0);
-
- self:writeBytes(pixels, pixelPointer, n)
-
- -- Update checksums
- self:crc32(pixels, pixelPointer, n);
- self:adler32(pixels, pixelPointer, n);
-
- -- Increment positions
- count = count - n;
- pixelPointer = pixelPointer + n;
- self.positionX = self.positionX + n;
- self.uncompRemain = self.uncompRemain - n;
- self.deflateFilled = self.deflateFilled + n;
- end
-
- if (self.deflateFilled >= DEFLATE_MAX_BLOCK_SIZE) then
- self.deflateFilled = 0; -- End current block
- end
-
- if (self.positionX == self.lineSize) then -- Increment line
- self.positionX = 0;
- self.positionY = self.positionY + 1;
- if (self.positionY == self.height) then -- Reached end of pixels
- local footer = { -- 20 bytes long
- 0, 0, 0, 0, -- DEFLATE Adler-32 placeholder
- 0, 0, 0, 0, -- IDAT CRC-32 placeholder
- -- IEND chunk
- 0x00, 0x00, 0x00, 0x00,
- 0x49, 0x45, 0x4E, 0x44,
- 0xAE, 0x42, 0x60, 0x82,
- }
- putBigUint32(self.adler, footer, 1)
- self:crc32(footer, 1, 4)
- putBigUint32(self.crc, footer, 5)
- self:writeBytes(footer)
- self.done = true
- end
- end
- end
-end
-
-function Png:crc32(data, index, len)
- self.crc = bit.bnot(self.crc)
- for i=index,index+len-1 do
- local byte = data[i]
- for j=0,7 do -- Inefficient bitwise implementation, instead of table-based
- local nbit = bit.band(bit.bxor(self.crc, bit.rshift(byte, j)), 1);
- self.crc = bit.bxor(bit.rshift(self.crc, 1), bit.band((-nbit), 0xEDB88320));
- end
- end
- self.crc = bit.bnot(self.crc)
-end
-function Png:adler32(data, index, len)
- local s1 = bit.band(self.adler, 0xFFFF)
- local s2 = bit.rshift(self.adler, 16)
- for i=index,index+len-1 do
- s1 = (s1 + data[i]) % 65521
- s2 = (s2 + s1) % 65521
- end
- self.adler = bit.bor(bit.lshift(s2, 16), s1)
-end
-
-local function begin(width, height, colorMode)
- -- Default to rgb
- colorMode = colorMode or "rgb"
-
- -- Determine bytes per pixel and the PNG internal color type
- local bytesPerPixel, colorType
- if colorMode == "rgb" then
- bytesPerPixel, colorType = 3, 2
- elseif colorMode == "rgba" then
- bytesPerPixel, colorType = 4, 6
- else
- error("Invalid colorMode")
- end
-
- local state = setmetatable({ width = width, height = height, done = false, output = {} }, Png)
-
- -- Compute and check data siezs
- state.lineSize = width * bytesPerPixel + 1
- -- TODO: check if lineSize too big
-
- state.uncompRemain = state.lineSize * height
-
- local numBlocks = math.ceil(state.uncompRemain / DEFLATE_MAX_BLOCK_SIZE)
-
- -- 5 bytes per DEFLATE uncompressed block header, 2 bytes for zlib header, 4 bytes for zlib Adler-32 footer
- local idatSize = numBlocks * 5 + 6
- idatSize = idatSize + state.uncompRemain;
-
- -- TODO check if idatSize too big
-
- local header = { -- 43 bytes long
- -- PNG header
- 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
- -- IHDR chunk
- 0x00, 0x00, 0x00, 0x0D,
- 0x49, 0x48, 0x44, 0x52,
- 0, 0, 0, 0, -- 'width' placeholder
- 0, 0, 0, 0, -- 'height' placeholder
- 0x08, colorType, 0x00, 0x00, 0x00,
- 0, 0, 0, 0, -- IHDR CRC-32 placeholder
- -- IDAT chunk
- 0, 0, 0, 0, -- 'idatSize' placeholder
- 0x49, 0x44, 0x41, 0x54,
- -- DEFLATE data
- 0x08, 0x1D,
- }
- putBigUint32(width, header, 17)
- putBigUint32(height, header, 21)
- putBigUint32(idatSize, header, 34)
-
- state.crc = 0
- state:crc32(header, 13, 17)
- putBigUint32(state.crc, header, 30)
- state:writeBytes(header)
-
- state.crc = 0
- state:crc32(header, 38, 6); -- 0xD7245B6B
- state.adler = 1
-
- state.positionX = 0
- state.positionY = 0
- state.deflateFilled = 0
-
- return state
-end
-
-return begin
\ No newline at end of file
diff --git a/lib/pretty_print.lua b/lib/pretty_print.lua
deleted file mode 100644
index c7fc257..0000000
--- a/lib/pretty_print.lua
+++ /dev/null
@@ -1,85 +0,0 @@
-local pretty_print = {}
-pretty_print.table = function(node)
- -- to make output beautiful
- local function tab(amt)
- local str = ""
- for i=1,amt do
- str = str .. "\t"
- end
- return str
- end
-
- local cache, stack, output = {},{},{}
- local depth = 1
- local output_str = "{\n"
-
- while true do
- local size = 0
- for k,v in pairs(node) do
- size = size + 1
- end
-
- local cur_index = 1
- for k,v in pairs(node) do
- if (cache[node] == nil) or (cur_index >= cache[node]) then
-
- if (string.find(output_str,"}",output_str:len())) then
- output_str = output_str .. ",\n"
- elseif not (string.find(output_str,"\n",output_str:len())) then
- output_str = output_str .. "\n"
- end
-
- -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
- table.insert(output,output_str)
- output_str = ""
-
- local key
- if (type(k) == "number" or type(k) == "boolean") then
- key = "["..tostring(k).."]"
- else
- key = "['"..tostring(k).."']"
- end
-
- if (type(v) == "number" or type(v) == "boolean") then
- output_str = output_str .. tab(depth) .. key .. " = "..tostring(v)
- elseif (type(v) == "table") then
- output_str = output_str .. tab(depth) .. key .. " = {\n"
- table.insert(stack,node)
- table.insert(stack,v)
- cache[node] = cur_index+1
- break
- else
- output_str = output_str .. tab(depth) .. key .. " = '"..tostring(v).."'"
- end
-
- if (cur_index == size) then
- output_str = output_str .. "\n" .. tab(depth-1) .. "}"
- else
- output_str = output_str .. ","
- end
- else
- -- close the table
- if (cur_index == size) then
- output_str = output_str .. "\n" .. tab(depth-1) .. "}"
- end
- end
-
- cur_index = cur_index + 1
- end
-
- if (#stack > 0) then
- node = stack[#stack]
- stack[#stack] = nil
- depth = cache[node] == nil and depth + 1 or depth - 1
- else
- break
- end
- end
-
- -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
- table.insert(output,output_str)
- output_str = table.concat(output)
-
- return output_str
-end
-return pretty_print
\ No newline at end of file
diff --git a/lib/profile.lua b/lib/profile.lua
deleted file mode 100644
index 6d05785..0000000
--- a/lib/profile.lua
+++ /dev/null
@@ -1,288 +0,0 @@
-local clock = os.clock
-local profiler_gui = GuiCreate()
-
---- Simple profiler written in Lua.
--- @module profile
--- @alias profile
-local profile = {}
-
--- function labels
-local _labeled = {}
--- function definitions
-local _defined = {}
--- time of last call
-local _tcalled = {}
--- total execution time
-local _telapsed = {}
--- number of calls
-local _ncalls = {}
--- average execution time
-local _taverage = {}
--- list of internal profiler functions
-local _internal = {}
--- csv index
-local _csvindex = 0
-
-local last_run_frame = 0
-local hook_runs = 0
-
---- This is an internal function.
--- @tparam string event Event type
--- @tparam number line Line number
--- @tparam[opt] table info Debug info table
-function profile.hooker(event, line, info)
- --[[if GameGetFrameNum() == last_run_frame then
- hook_runs = hook_runs + 1
- else
- print("Ran hooker " .. hook_runs .. " times")
- hook_runs = 0
- last_run_frame = GameGetFrameNum()
- end]]
- info = info or debug.getinfo(2, 'fnS')
- local f = info.func
- -- ignore the profiler itself
- if _internal[f] or info.what ~= "Lua" then
- return
- end
- -- get the function name if available
- if info.name then
- _labeled[f] = info.name
- end
- -- find the line definition
- if not _defined[f] then
- _defined[f] = info.source..":"..info.linedefined
- _ncalls[f] = 0
- _telapsed[f] = 0
- _taverage[f] = 0
- end
- if _tcalled[f] then
- local dt = clock() - _tcalled[f]
- _telapsed[f] = _telapsed[f] + dt
- _taverage[f] = _telapsed[f] / (_ncalls[f] + 1)
- _tcalled[f] = nil
- end
- if event == "tail call" then
- local prev = debug.getinfo(3, 'fnS')
- profile.hooker("return", line, prev)
- profile.hooker("call", line, info)
- elseif event == 'call' then
- _tcalled[f] = clock()
- else
- _ncalls[f] = _ncalls[f] + 1
- end
-end
-
---- Sets a clock function to be used by the profiler.
--- @tparam function func Clock function that returns a number
-function profile.setclock(f)
- assert(type(f) == "function", "clock must be a function")
- clock = f
-end
-
---- Starts collecting data.
-function profile.start()
- --[[if rawget(_G, 'jit') then
- jit.off()
- jit.flush()
- end]]
- debug.sethook(profile.hooker, "cr")
-end
-
---- Stops collecting data.
-function profile.stop()
- debug.sethook()
- for f in pairs(_tcalled) do
- local dt = clock() - _tcalled[f]
- _telapsed[f] = _telapsed[f] + dt
- _taverage[f] = _telapsed[f] / math.max(_ncalls[f], 1)
- _tcalled[f] = nil
- end
- -- merge closures
- local lookup = {}
- for f, d in pairs(_defined) do
- local id = (_labeled[f] or '?')..d
- local f2 = lookup[id]
- if f2 then
- _ncalls[f2] = _ncalls[f2] + (_ncalls[f] or 0)
- _telapsed[f2] = _telapsed[f2] + (_telapsed[f] or 0)
- _taverage[f2] = _telapsed[f2] / math.max(_ncalls[f2], 1)
- _defined[f], _labeled[f] = nil, nil
- _ncalls[f], _telapsed[f] = nil, nil
- else
- lookup[id] = f
- end
- end
-
- --[[if rawget(_G, 'jit') then
- jit.on()
- jit.flush()
- end]]
- --collectgarbage('collect')
-end
-
---- Resets all collected data.
-function profile.reset()
- for f in pairs(_ncalls) do
- _ncalls[f] = 0
- end
- for f in pairs(_telapsed) do
- _telapsed[f] = 0
- end
- for f in pairs(_tcalled) do
- _tcalled[f] = nil
- end
- --_csvindex = 0
- --collectgarbage('collect')
-end
-
-function profile.clear()
- debug.sethook()
- for f in pairs(_ncalls) do
- _ncalls[f] = 0
- end
- for f in pairs(_telapsed) do
- _telapsed[f] = 0
- end
- for f in pairs(_tcalled) do
- _tcalled[f] = nil
- end
- _csvindex = 0
- collectgarbage('collect')
-end
-
---- This is an internal function.
--- @tparam function a First function
--- @tparam function b Second function
--- @treturn boolean True if "a" should rank higher than "b"
-function profile.comp(a, b)
- local dt = _telapsed[b] - _telapsed[a]
- if dt == 0 then
- return _ncalls[b] < _ncalls[a]
- end
- return dt < 0
-end
-
---- Generates a report of functions that have been called since the profile was started.
--- Returns the report as a numeric table of rows containing the rank, function label, number of calls, total execution time and source code line number.
--- @tparam[opt] number limit Maximum number of rows
--- @treturn table Table of rows
-function profile.query(limit)
- local t = {}
- for f, n in pairs(_ncalls) do
- if n > 0 then
- t[#t + 1] = f
- end
- end
- table.sort(t, profile.comp)
- if limit then
- while #t > limit do
- table.remove(t)
- end
- end
- for i, f in ipairs(t) do
- local dt = 0
- if _tcalled[f] then
- dt = clock() - _tcalled[f]
- end
- t[i] = { i, _labeled[f] or '?', _ncalls[f], _telapsed[f] + dt, _taverage[f], _defined[f] }
- end
- return t
-end
-
-local cols = { 3, 29, 11, 24, 24, 32 }
-
---- Generates a text report of functions that have been called since the profile was started.
--- Returns the report as a string that can be printed to the console.
--- @tparam[opt] number limit Maximum number of rows
--- @treturn string Text-based profiling report
-function profile.report(n)
- local out = {}
- local report = profile.query(n)
- for i, row in ipairs(report) do
- for j = 1, 5 do
- local s = row[j]
- local l2 = cols[j]
- s = tostring(s)
- local l1 = s:len()
- if l1 < l2 then
- s = s..(' '):rep(l2-l1)
- elseif l1 > l2 then
- s = s:sub(l1 - l2 + 1, l1)
- end
- row[j] = s
- end
- out[i] = table.concat(row, ' | ')
- end
-
- local row = " +-----+-------------------------------+-------------+--------------------------+--------------------------+----------------------------------+ \n"
- local col = " | # | Function | Calls | Time | Avg. Time | Code | \n"
- local sz = row..col..row
- if #out > 0 then
- sz = sz..' | '..table.concat(out, ' | \n | ')..' | \n'
- end
- return '\n'..sz..row
-end
-
---- Generates a csv report of functions that have been called since the profile was started.
--- Returns the report as a string.
--- @tparam[opt] number limit Maximum number of rows
--- @treturn string CSV-based profiling report
-function profile.csv(n)
- local out = {}
- local report = profile.query(n)
- for i, row in ipairs(report) do
- -- add csv index to the first column
-
- out[i] = tostring(_csvindex)..","..table.concat(row, ',')
-
- -- remove ending comma
- out[i] = out[i]:sub(1, -2)
- end
- _csvindex = _csvindex + 1
- return table.concat(out, '\n')
-end
-
---- Draws a graphical report of functions that have been called since the profile was started.
--- @tparam[opt] number limit Maximum number of rows
-function profile.draw(n)
- local out = {}
- local report = profile.query(n)
- for i, row in ipairs(report) do
- for j = 1, 5 do
- local s = row[j]
- local l2 = cols[j]
- s = tostring(s)
- local l1 = s:len()
- if l1 < l2 then
- s = s..(' '):rep(l2-l1)
- elseif l1 > l2 then
- s = s:sub(l1 - l2 + 1, l1)
- end
- row[j] = s
- end
- out[i] = table.concat(row, ' | ')
- end
-
- GuiStartFrame(profiler_gui)
- GuiLayoutBeginVertical(profiler_gui, 10, 10, true)
- GuiOptionsAdd(profiler_gui, 2)
-
- GuiText(profiler_gui, 0, 0, " | # | Function | Calls | Time | Avg. Time | Code |")
-
- if #out > 0 then
- for i, v in ipairs(out) do
- GuiText(profiler_gui, 0, 0, " | "..v.." |")
- end
- end
-
- GuiLayoutEnd(profiler_gui)
-end
-
--- store all internal profiler functions
-for _, v in pairs(profile) do
- if type(v) == "function" then
- _internal[v] = true
- end
-end
-
-return profile
\ No newline at end of file
diff --git a/lib/profiler_ui.lua b/lib/profiler_ui.lua
deleted file mode 100644
index 054915b..0000000
--- a/lib/profiler_ui.lua
+++ /dev/null
@@ -1,285 +0,0 @@
-local profile = dofile("mods/evaisa.mp/lib/profile.lua")
-
-local profile_next = false
-local profile_next_no_ui = false
-local get_profiler_rate = function()
- return math.floor(tonumber(ModSettingGet("evaisa.mp.profiler_rate")) or 1)
-end
-
-local profiler_rate = get_profiler_rate()
-
-local profiler_folder_name = "noita_online_logs/profiler"
-
--- create profiler folder
-if not os.rename(profiler_folder_name, profiler_folder_name) then
- os.execute("mkdir \"" .. profiler_folder_name .. "\"")
-end
-
-local profiler_result_file = nil
-local profiler_result_content = ""
-
-local profiler_ui = {}
-
-local did_frame = false
-local profiler_paused = false
-local profiler_frames = {}
-local profiler_data = {}
-local profiler_steps = 0
-
-local generate_profiler_data = function()
- profiler_data = {}
- local label_indices = {}
- local curr_frame = profiler_steps - #profiler_frames
-
- -- Precompute sums and organize data
- for i = 1, #(profiler_frames) do
- local v = profiler_frames[i]
- for j = 1, #v do
- local data = v[j]
- local label = data[1]
-
- if label_indices[label] == nil then
- label_indices[label] = {index = #profiler_data + 1, sum_calls = 0, sum_times = 0}
- profiler_data[label_indices[label].index] = {label, {{}, {}, {}}}
- end
-
- local entry = profiler_data[label_indices[label].index][2]
- table.insert(entry[1], curr_frame + i)
- table.insert(entry[2], data[2])
- table.insert(entry[3], data[3])
-
- -- Precompute sums
- label_indices[label].sum_times = label_indices[label].sum_times + data[2]
- label_indices[label].sum_calls = label_indices[label].sum_calls + data[3]
- end
- end
-
- -- Choose the index for sorting based on use_calls flag
- local sort_index = use_calls and "sum_calls" or "sum_times"
-
- -- Sort profiler_data based on precomputed sums
- table.sort(profiler_data, function(a, b)
- return label_indices[a[1]][sort_index] > label_indices[b[1]][sort_index]
- end)
-
- -- remove all but top 50
- if(#profiler_data > 50)then
- for i = 51, #profiler_data do
- profiler_data[i] = nil
- end
- end
-end
-
-profiler_ui.apply_profiler_rate = function()
- profiler_rate = get_profiler_rate()
-end
-
-profiler_ui.pre_update = function()
-
- if(not profiler_paused and (profile_next or profile_next_no_ui) and GameGetFrameNum() % profiler_rate == 0)then
- did_frame = true
- profile.start()
- --print("Profiling frame: "..GameGetFrameNum())
- else
- did_frame = false
- end
-
-
- if (input ~= nil and input:WasKeyPressed("f8")) then
- profile_next_no_ui = false
- profile_next = not profile_next
- if(profile_next)then
- profile.clear()
- profiler_result_file = io.open(profiler_folder_name.."/"..os.date("%Y-%m-%d_%H-%M-%S")..".csv", "w+")
- profiler_result_content = "Snapshot,Rank,Function,Calls,Time,Avg. Time,Code\n"
-
- profiler_frames = {}
- profiler_data = {}
- profiler_steps = 0
- print("Starting profiler")
- else
- profile.clear()
- if(profiler_result_file ~= nil)then
- profiler_result_file:write(profiler_result_content)
- profiler_result_file:close()
- profiler_result_file = nil
- end
- print("Stopping profiler")
- end
- end
-
- if (input ~= nil and input:WasKeyPressed("f7")) then
- profile_next = false
- profile_next_no_ui = not profile_next_no_ui
- if(profile_next_no_ui)then
- profile.clear()
- profiler_result_file = io.open(profiler_folder_name.."/"..os.date("%Y-%m-%d_%H-%M-%S")..".csv", "w+")
- profiler_result_content = "Snapshot,Rank,Function,Calls,Time,Avg. Time,Code\n"
-
- profiler_frames = {}
- profiler_data = {}
- profiler_steps = 0
- print("Starting profiler without UI")
- else
- profile.clear()
- if(profiler_result_file ~= nil)then
- profiler_result_file:write(profiler_result_content)
- profiler_result_file:close()
- profiler_result_file = nil
- end
- print("Stopping profiler without UI")
- end
-
- end
-end
-
-profiler_ui.end_profile = function()
- profile.stop()
-
- --local profiler_data = profile.csv(150)
-
- local frame = {}
-
- local report = profile.query(500)
-
- for i, row in ipairs(report) do
- local rank = row[1]
- local func = row[2]
- local calls = row[3]
- local time = row[4]
- local avg_time = row[5]
- local code = row[6]
-
- local untruncated_func = func
- local untruncated_code = code
-
- -- truncate func after first space
- func = string.match(func, "^[^ ]+")
- code = string.match(code, "^[^ ]+")
-
- local label = table.concat({code, " - ", func, "##", untruncated_func, untruncated_code}, "")
-
-
- -- add to profiler frames
-
-
- table.insert(frame, {label, time, calls})
-
- end
-
- table.insert(profiler_frames, frame)
-
- profiler_steps = profiler_steps + 1
-
- -- if profiler frames over 1000 then remove the first one
- if(#profiler_frames > 1000)then
- table.remove(profiler_frames, 1)
- end
-
-
- if(profiler_steps % 10 == 0)then
- generate_profiler_data()
- end
-
-
-
- profile.reset()
-end
-
-profiler_ui.draw = function()
- if imgui.Begin("Profiler") then
- -- add checkbox for auto scrolling
- -- add button for clearing data
-
- if imgui.Button("Clear data") then
- profile.clear()
- profiler_data = {}
- profiler_frames = {}
- profiler_steps = 0
- end
-
- imgui.SameLine()
-
- if(auto_scroll_profiler == nil)then
- auto_scroll_profiler = true
- end
-
- if(use_calls == nil)then
- use_calls = false
- end
-
- -- checkbox
- local _
- _, auto_scroll_profiler = imgui.Checkbox("Auto scroll", auto_scroll_profiler)
-
- imgui.SameLine()
- local old_use_calls = use_calls
- _, use_calls = imgui.Checkbox("Use calls", use_calls)
-
- if(old_use_calls ~= use_calls)then
- generate_profiler_data()
- end
-
-
- imgui.SameLine()
-
- if imgui.Button(profiler_paused and "Unpause" or "Pause") then
- profiler_paused = not profiler_paused
- end
-
-
- if implot.BeginPlot("Profiler") then
-
- local label_y = "time"
-
- if(use_calls)then
- label_y = "calls"
- end
-
- implot.SetupAxes("frame", label_y, auto_scroll_profiler and implot.PlotAxisFlags.Lock or implot.PlotAxisFlags.None, (auto_scroll_profiler and implot.PlotAxisFlags.AutoFit or implot.PlotAxisFlags.None));
-
-
-
- if(auto_scroll_profiler)then
- implot.SetupAxisLimits(implot.Axis.X1, math.max(profiler_steps - 100, 0), math.max(profiler_steps, 100), implot.PlotCond.Always)
- else
- implot.SetupAxisLimits(implot.Axis.X1, 0, 100)
- end
-
- implot.SetupLegend(implot.PlotLocation.East, implot.PlotLegendFlags.Outside)
-
- -- we need to defined them in time order
- local ind = 2
-
- if(use_calls)then
- ind = 3
- end
-
- for i = 1, #profiler_data do
- local p = profiler_data[i]
- local label = p[1]
- local data = p[2]
-
- implot.SetNextMarkerStyle(implot.PlotMarker.Circle, 1);
- implot.PlotLine(label, data[1], data[ind])
-
- end
-
- implot.EndPlot()
- end
-
- imgui.End()
- end
-end
-
-profiler_ui.post_update = function()
- if(did_frame)then
- profiler_ui.end_profile()
- end
-
- if(imgui ~= nil and profile_next)then
- profiler_ui.draw()
- end
-end
-
-return profiler_ui
\ No newline at end of file
diff --git a/lib/rng.lua b/lib/rng.lua
deleted file mode 100644
index cf4b02c..0000000
--- a/lib/rng.lua
+++ /dev/null
@@ -1,60 +0,0 @@
--- random number generator with seperated states
-
-local rng = {}
-
-function rng.new(seed)
- local self = {}
- self.seed = seed
- self.state = seed
- self.next = function()
- self.state = (self.state * 214013 + 2531011) % 4294967296
- return self.state
- end
- self.next_float = function()
- return self.next() / 4294967296
- end
- self.next_int = function(max)
- return math.floor(self.next_float() * max)
- end
- self.next_range = function(min, max)
- return min + self.next_float() * (max - min)
- end
- self.next_bool = function()
- return self.next() % 2 == 0
- end
- self.next_choice = function(choices)
- return choices[self.next_int(#choices) + 1]
- end
- self.next_shuffle = function(t)
- for i = #t, 2, -1 do
- local j = self.next_int(i) + 1
- t[i], t[j] = t[j], t[i]
- end
- end
- self.next_normal = function()
- local u1 = self.next_float()
- local u2 = self.next_float()
- local r = math.sqrt(-2 * math.log(u1))
- local theta = 2 * math.pi * u2
- return r * math.cos(theta)
- end
- self.next_normal_range = function(min, max)
- return min + (max - min) * (self.next_normal() + 3) / 6
- end
- self.next_normal_int = function(min, max)
- return math.floor(self.next_normal_range(min, max + 1))
- end
- self.range = function(min, max, debug)
- local out = self.next_range(min, max)
- if(debug)then
- print("Getting random number between "..tostring(min).." and "..tostring(max)..": "..tostring(math.floor(out)).." ("..out..")")
- end
- return math.floor(out)
- end
- self.float_range = function(min, max)
- return self.next_range(min, max)
- end
- return self
-end
-
-return rng
\ No newline at end of file
diff --git a/lib/sdl2_ffi.lua b/lib/sdl2_ffi.lua
deleted file mode 100644
index eed1462..0000000
--- a/lib/sdl2_ffi.lua
+++ /dev/null
@@ -1,3136 +0,0 @@
-local ffi = require"ffi"
-
---uncomment to debug cdef calls
---[[
-local ffi_cdef = ffi.cdef
-ffi.cdef = function(code)
- local ret,err = pcall(ffi_cdef,code)
- if not ret then
- local lineN = 1
- for line in code:gmatch("([^\n\r]*)\r?\n") do
- print(lineN, line)
- lineN = lineN + 1
- end
- print(err)
- error"bad cdef"
- end
-end
---]]
-ffi.cdef[[
-const char * SDL_GetPlatform (void);
-typedef enum
-{
- SDL_FALSE = 0,
- SDL_TRUE = 1
-} SDL_bool;
-typedef int8_t Sint8;
-typedef uint8_t Uint8;
-typedef int16_t Sint16;
-typedef uint16_t Uint16;
-typedef int32_t Sint32;
-typedef uint32_t Uint32;
-typedef int64_t Sint64;
-typedef uint64_t Uint64;
-typedef int SDL_compile_time_assert_uint8[(sizeof(Uint8) == 1) * 2 - 1];
-typedef int SDL_compile_time_assert_sint8[(sizeof(Sint8) == 1) * 2 - 1];
-typedef int SDL_compile_time_assert_uint16[(sizeof(Uint16) == 2) * 2 - 1];
-typedef int SDL_compile_time_assert_sint16[(sizeof(Sint16) == 2) * 2 - 1];
-typedef int SDL_compile_time_assert_uint32[(sizeof(Uint32) == 4) * 2 - 1];
-typedef int SDL_compile_time_assert_sint32[(sizeof(Sint32) == 4) * 2 - 1];
-typedef int SDL_compile_time_assert_uint64[(sizeof(Uint64) == 8) * 2 - 1];
-typedef int SDL_compile_time_assert_sint64[(sizeof(Sint64) == 8) * 2 - 1];
-typedef enum
-{
- DUMMY_ENUM_VALUE
-} SDL_DUMMY_ENUM;
-typedef int SDL_compile_time_assert_enum[(sizeof(SDL_DUMMY_ENUM) == sizeof(int)) * 2 - 1];
-void * SDL_malloc(size_t size);
-void * SDL_calloc(size_t nmemb, size_t size);
-void * SDL_realloc(void *mem, size_t size);
-void SDL_free(void *mem);
-typedef void *( *SDL_malloc_func)(size_t size);
-typedef void *( *SDL_calloc_func)(size_t nmemb, size_t size);
-typedef void *( *SDL_realloc_func)(void *mem, size_t size);
-typedef void ( *SDL_free_func)(void *mem);
-void SDL_GetMemoryFunctions(SDL_malloc_func *malloc_func,
- SDL_calloc_func *calloc_func,
- SDL_realloc_func *realloc_func,
- SDL_free_func *free_func);
-int SDL_SetMemoryFunctions(SDL_malloc_func malloc_func,
- SDL_calloc_func calloc_func,
- SDL_realloc_func realloc_func,
- SDL_free_func free_func);
-int SDL_GetNumAllocations(void);
-char * SDL_getenv(const char *name);
-int SDL_setenv(const char *name, const char *value, int overwrite);
-void SDL_qsort(void *base, size_t nmemb, size_t size, int (*compare) (const void *, const void *));
-int SDL_abs(int x);
-int SDL_isdigit(int x);
-int SDL_isspace(int x);
-int SDL_toupper(int x);
-int SDL_tolower(int x);
-void * SDL_memset( void *dst, int c, size_t len);
-void * SDL_memcpy( void *dst, const void *src, size_t len);
-void * SDL_memmove( void *dst, const void *src, size_t len);
-int SDL_memcmp(const void *s1, const void *s2, size_t len);
-wchar_t * SDL_wcsdup(const wchar_t *wstr);
-size_t SDL_wcslen(const wchar_t *wstr);
-size_t SDL_wcslcpy( wchar_t *dst, const wchar_t *src, size_t maxlen);
-size_t SDL_wcslcat( wchar_t *dst, const wchar_t *src, size_t maxlen);
-int SDL_wcscmp(const wchar_t *str1, const wchar_t *str2);
-size_t SDL_strlen(const char *str);
-size_t SDL_strlcpy( char *dst, const char *src, size_t maxlen);
-size_t SDL_utf8strlcpy( char *dst, const char *src, size_t dst_bytes);
-size_t SDL_strlcat( char *dst, const char *src, size_t maxlen);
-char * SDL_strdup(const char *str);
-char * SDL_strrev(char *str);
-char * SDL_strupr(char *str);
-char * SDL_strlwr(char *str);
-char * SDL_strchr(const char *str, int c);
-char * SDL_strrchr(const char *str, int c);
-char * SDL_strstr(const char *haystack, const char *needle);
-size_t SDL_utf8strlen(const char *str);
-char * SDL_itoa(int value, char *str, int radix);
-char * SDL_uitoa(unsigned int value, char *str, int radix);
-char * SDL_ltoa(long value, char *str, int radix);
-char * SDL_ultoa(unsigned long value, char *str, int radix);
-char * SDL_lltoa(Sint64 value, char *str, int radix);
-char * SDL_ulltoa(Uint64 value, char *str, int radix);
-int SDL_atoi(const char *str);
-double SDL_atof(const char *str);
-long SDL_strtol(const char *str, char **endp, int base);
-unsigned long SDL_strtoul(const char *str, char **endp, int base);
-Sint64 SDL_strtoll(const char *str, char **endp, int base);
-Uint64 SDL_strtoull(const char *str, char **endp, int base);
-double SDL_strtod(const char *str, char **endp);
-int SDL_strcmp(const char *str1, const char *str2);
-int SDL_strncmp(const char *str1, const char *str2, size_t maxlen);
-int SDL_strcasecmp(const char *str1, const char *str2);
-int SDL_strncasecmp(const char *str1, const char *str2, size_t len);
-int SDL_sscanf(const char *text, const char *fmt, ...) __attribute__ (( format( __scanf__, 2, 2 +1 )));
-int SDL_vsscanf(const char *text, const char *fmt, va_list ap);
-int SDL_snprintf( char *text, size_t maxlen, const char *fmt, ... ) __attribute__ (( format( __printf__, 3, 3 +1 )));
-int SDL_vsnprintf( char *text, size_t maxlen, const char *fmt, va_list ap);
-double SDL_acos(double x);
-float SDL_acosf(float x);
-double SDL_asin(double x);
-float SDL_asinf(float x);
-double SDL_atan(double x);
-float SDL_atanf(float x);
-double SDL_atan2(double x, double y);
-float SDL_atan2f(float x, float y);
-double SDL_ceil(double x);
-float SDL_ceilf(float x);
-double SDL_copysign(double x, double y);
-float SDL_copysignf(float x, float y);
-double SDL_cos(double x);
-float SDL_cosf(float x);
-double SDL_exp(double x);
-float SDL_expf(float x);
-double SDL_fabs(double x);
-float SDL_fabsf(float x);
-double SDL_floor(double x);
-float SDL_floorf(float x);
-double SDL_fmod(double x, double y);
-float SDL_fmodf(float x, float y);
-double SDL_log(double x);
-float SDL_logf(float x);
-double SDL_log10(double x);
-float SDL_log10f(float x);
-double SDL_pow(double x, double y);
-float SDL_powf(float x, float y);
-double SDL_scalbn(double x, int n);
-float SDL_scalbnf(float x, int n);
-double SDL_sin(double x);
-float SDL_sinf(float x);
-double SDL_sqrt(double x);
-float SDL_sqrtf(float x);
-double SDL_tan(double x);
-float SDL_tanf(float x);
-typedef struct _SDL_iconv_t *SDL_iconv_t;
-SDL_iconv_t SDL_iconv_open(const char *tocode,
- const char *fromcode);
-int SDL_iconv_close(SDL_iconv_t cd);
-size_t SDL_iconv(SDL_iconv_t cd, const char **inbuf,
- size_t * inbytesleft, char **outbuf,
- size_t * outbytesleft);
-char * SDL_iconv_string(const char *tocode,
- const char *fromcode,
- const char *inbuf,
- size_t inbytesleft);
-extern int SDL_main(int argc, char *argv[]);
-void SDL_SetMainReady(void);
-int SDL_RegisterApp(char *name, Uint32 style,
- void *hInst);
-void SDL_UnregisterApp(void);
-typedef enum
-{
- SDL_ASSERTION_RETRY,
- SDL_ASSERTION_BREAK,
- SDL_ASSERTION_ABORT,
- SDL_ASSERTION_IGNORE,
- SDL_ASSERTION_ALWAYS_IGNORE
-} SDL_AssertState;
-typedef struct SDL_AssertData
-{
- int always_ignore;
- unsigned int trigger_count;
- const char *condition;
- const char *filename;
- int linenum;
- const char *function;
- const struct SDL_AssertData *next;
-} SDL_AssertData;
-SDL_AssertState SDL_ReportAssertion(SDL_AssertData *,
- const char *,
- const char *, int)
-;
-typedef SDL_AssertState ( *SDL_AssertionHandler)(
- const SDL_AssertData* data, void* userdata);
-void SDL_SetAssertionHandler(
- SDL_AssertionHandler handler,
- void *userdata);
-SDL_AssertionHandler SDL_GetDefaultAssertionHandler(void);
-SDL_AssertionHandler SDL_GetAssertionHandler(void **puserdata);
-const SDL_AssertData * SDL_GetAssertionReport(void);
-void SDL_ResetAssertionReport(void);
-typedef int SDL_SpinLock;
-SDL_bool SDL_AtomicTryLock(SDL_SpinLock *lock);
-void SDL_AtomicLock(SDL_SpinLock *lock);
-void SDL_AtomicUnlock(SDL_SpinLock *lock);
-void SDL_MemoryBarrierReleaseFunction(void);
-void SDL_MemoryBarrierAcquireFunction(void);
-typedef struct { int value; } SDL_atomic_t;
-SDL_bool SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);
-int SDL_AtomicSet(SDL_atomic_t *a, int v);
-int SDL_AtomicGet(SDL_atomic_t *a);
-int SDL_AtomicAdd(SDL_atomic_t *a, int v);
-SDL_bool SDL_AtomicCASPtr(void **a, void *oldval, void *newval);
-void* SDL_AtomicSetPtr(void **a, void* v);
-void* SDL_AtomicGetPtr(void **a);
-int SDL_SetError( const char *fmt, ...) __attribute__ (( format( __printf__, 1, 1 +1 )));
-const char * SDL_GetError(void);
-void SDL_ClearError(void);
-typedef enum
-{
- SDL_ENOMEM,
- SDL_EFREAD,
- SDL_EFWRITE,
- SDL_EFSEEK,
- SDL_UNSUPPORTED,
- SDL_LASTERROR
-} SDL_errorcode;
-int SDL_Error(SDL_errorcode code);
-struct SDL_mutex;
-typedef struct SDL_mutex SDL_mutex;
-SDL_mutex * SDL_CreateMutex(void);
-int SDL_LockMutex(SDL_mutex * mutex);
-int SDL_TryLockMutex(SDL_mutex * mutex);
-int SDL_UnlockMutex(SDL_mutex * mutex);
-void SDL_DestroyMutex(SDL_mutex * mutex);
-struct SDL_semaphore;
-typedef struct SDL_semaphore SDL_sem;
-SDL_sem * SDL_CreateSemaphore(Uint32 initial_value);
-void SDL_DestroySemaphore(SDL_sem * sem);
-int SDL_SemWait(SDL_sem * sem);
-int SDL_SemTryWait(SDL_sem * sem);
-int SDL_SemWaitTimeout(SDL_sem * sem, Uint32 ms);
-int SDL_SemPost(SDL_sem * sem);
-Uint32 SDL_SemValue(SDL_sem * sem);
-struct SDL_cond;
-typedef struct SDL_cond SDL_cond;
-SDL_cond * SDL_CreateCond(void);
-void SDL_DestroyCond(SDL_cond * cond);
-int SDL_CondSignal(SDL_cond * cond);
-int SDL_CondBroadcast(SDL_cond * cond);
-int SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex);
-int SDL_CondWaitTimeout(SDL_cond * cond,
- SDL_mutex * mutex, Uint32 ms);
-struct SDL_Thread;
-typedef struct SDL_Thread SDL_Thread;
-typedef unsigned long SDL_threadID;
-typedef unsigned int SDL_TLSID;
-typedef enum {
- SDL_THREAD_PRIORITY_LOW,
- SDL_THREAD_PRIORITY_NORMAL,
- SDL_THREAD_PRIORITY_HIGH,
- SDL_THREAD_PRIORITY_TIME_CRITICAL
-} SDL_ThreadPriority;
-typedef int ( * SDL_ThreadFunction) (void *data);
-typedef uintptr_t(__attribute__((__cdecl__)) * pfnSDL_CurrentBeginThread)
- (void *, unsigned, unsigned (__attribute__((__stdcall__)) *func)(void *),
- void * , unsigned, unsigned * );
-typedef void (__attribute__((__cdecl__)) * pfnSDL_CurrentEndThread) (unsigned code);
-SDL_Thread *
-SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
- pfnSDL_CurrentBeginThread pfnBeginThread,
- pfnSDL_CurrentEndThread pfnEndThread);
-SDL_Thread *
-SDL_CreateThreadWithStackSize(int ( * fn) (void *),
- const char *name, const size_t stacksize, void *data,
- pfnSDL_CurrentBeginThread pfnBeginThread,
- pfnSDL_CurrentEndThread pfnEndThread);
-const char * SDL_GetThreadName(SDL_Thread *thread);
-SDL_threadID SDL_ThreadID(void);
-SDL_threadID SDL_GetThreadID(SDL_Thread * thread);
-int SDL_SetThreadPriority(SDL_ThreadPriority priority);
-void SDL_WaitThread(SDL_Thread * thread, int *status);
-void SDL_DetachThread(SDL_Thread * thread);
-SDL_TLSID SDL_TLSCreate(void);
-void * SDL_TLSGet(SDL_TLSID id);
-int SDL_TLSSet(SDL_TLSID id, const void *value, void ( *destructor)(void*));
-typedef struct SDL_RWops
-{
- Sint64 ( * size) (struct SDL_RWops * context);
- Sint64 ( * seek) (struct SDL_RWops * context, Sint64 offset,
- int whence);
- size_t ( * read) (struct SDL_RWops * context, void *ptr,
- size_t size, size_t maxnum);
- size_t ( * write) (struct SDL_RWops * context, const void *ptr,
- size_t size, size_t num);
- int ( * close) (struct SDL_RWops * context);
- Uint32 type;
- union
- {
- struct
- {
- SDL_bool append;
- void *h;
- struct
- {
- void *data;
- size_t size;
- size_t left;
- } buffer;
- } windowsio;
- struct
- {
- Uint8 *base;
- Uint8 *here;
- Uint8 *stop;
- } mem;
- struct
- {
- void *data1;
- void *data2;
- } unknown;
- } hidden;
-} SDL_RWops;
-SDL_RWops * SDL_RWFromFile(const char *file,
- const char *mode);
-SDL_RWops * SDL_RWFromFP(void * fp,
- SDL_bool autoclose);
-SDL_RWops * SDL_RWFromMem(void *mem, int size);
-SDL_RWops * SDL_RWFromConstMem(const void *mem,
- int size);
-SDL_RWops * SDL_AllocRW(void);
-void SDL_FreeRW(SDL_RWops * area);
-void * SDL_LoadFile_RW(SDL_RWops * src, size_t *datasize,
- int freesrc);
-Uint8 SDL_ReadU8(SDL_RWops * src);
-Uint16 SDL_ReadLE16(SDL_RWops * src);
-Uint16 SDL_ReadBE16(SDL_RWops * src);
-Uint32 SDL_ReadLE32(SDL_RWops * src);
-Uint32 SDL_ReadBE32(SDL_RWops * src);
-Uint64 SDL_ReadLE64(SDL_RWops * src);
-Uint64 SDL_ReadBE64(SDL_RWops * src);
-size_t SDL_WriteU8(SDL_RWops * dst, Uint8 value);
-size_t SDL_WriteLE16(SDL_RWops * dst, Uint16 value);
-size_t SDL_WriteBE16(SDL_RWops * dst, Uint16 value);
-size_t SDL_WriteLE32(SDL_RWops * dst, Uint32 value);
-size_t SDL_WriteBE32(SDL_RWops * dst, Uint32 value);
-size_t SDL_WriteLE64(SDL_RWops * dst, Uint64 value);
-size_t SDL_WriteBE64(SDL_RWops * dst, Uint64 value);
-typedef Uint16 SDL_AudioFormat;
-typedef void ( * SDL_AudioCallback) (void *userdata, Uint8 * stream,
- int len);
-typedef struct SDL_AudioSpec
-{
- int freq;
- SDL_AudioFormat format;
- Uint8 channels;
- Uint8 silence;
- Uint16 samples;
- Uint16 padding;
- Uint32 size;
- SDL_AudioCallback callback;
- void *userdata;
-} SDL_AudioSpec;
-struct SDL_AudioCVT;
-typedef void ( * SDL_AudioFilter) (struct SDL_AudioCVT * cvt,
- SDL_AudioFormat format);
-typedef struct SDL_AudioCVT
-{
- int needed;
- SDL_AudioFormat src_format;
- SDL_AudioFormat dst_format;
- double rate_incr;
- Uint8 *buf;
- int len;
- int len_cvt;
- int len_mult;
- double len_ratio;
- SDL_AudioFilter filters[9 + 1];
- int filter_index;
-} __attribute__((packed)) SDL_AudioCVT;
-int SDL_GetNumAudioDrivers(void);
-const char * SDL_GetAudioDriver(int index);
-int SDL_AudioInit(const char *driver_name);
-void SDL_AudioQuit(void);
-const char * SDL_GetCurrentAudioDriver(void);
-int SDL_OpenAudio(SDL_AudioSpec * desired,
- SDL_AudioSpec * obtained);
-typedef Uint32 SDL_AudioDeviceID;
-int SDL_GetNumAudioDevices(int iscapture);
-const char * SDL_GetAudioDeviceName(int index,
- int iscapture);
-SDL_AudioDeviceID SDL_OpenAudioDevice(const char
- *device,
- int iscapture,
- const
- SDL_AudioSpec *
- desired,
- SDL_AudioSpec *
- obtained,
- int
- allowed_changes);
-typedef enum
-{
- SDL_AUDIO_STOPPED = 0,
- SDL_AUDIO_PLAYING,
- SDL_AUDIO_PAUSED
-} SDL_AudioStatus;
-SDL_AudioStatus SDL_GetAudioStatus(void);
-SDL_AudioStatus
-SDL_GetAudioDeviceStatus(SDL_AudioDeviceID dev);
-void SDL_PauseAudio(int pause_on);
-void SDL_PauseAudioDevice(SDL_AudioDeviceID dev,
- int pause_on);
-SDL_AudioSpec * SDL_LoadWAV_RW(SDL_RWops * src,
- int freesrc,
- SDL_AudioSpec * spec,
- Uint8 ** audio_buf,
- Uint32 * audio_len);
-void SDL_FreeWAV(Uint8 * audio_buf);
-int SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
- SDL_AudioFormat src_format,
- Uint8 src_channels,
- int src_rate,
- SDL_AudioFormat dst_format,
- Uint8 dst_channels,
- int dst_rate);
-int SDL_ConvertAudio(SDL_AudioCVT * cvt);
-struct _SDL_AudioStream;
-typedef struct _SDL_AudioStream SDL_AudioStream;
-SDL_AudioStream * SDL_NewAudioStream(const SDL_AudioFormat src_format,
- const Uint8 src_channels,
- const int src_rate,
- const SDL_AudioFormat dst_format,
- const Uint8 dst_channels,
- const int dst_rate);
-int SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len);
-int SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len);
-int SDL_AudioStreamAvailable(SDL_AudioStream *stream);
-int SDL_AudioStreamFlush(SDL_AudioStream *stream);
-void SDL_AudioStreamClear(SDL_AudioStream *stream);
-void SDL_FreeAudioStream(SDL_AudioStream *stream);
-void SDL_MixAudio(Uint8 * dst, const Uint8 * src,
- Uint32 len, int volume);
-void SDL_MixAudioFormat(Uint8 * dst,
- const Uint8 * src,
- SDL_AudioFormat format,
- Uint32 len, int volume);
-int SDL_QueueAudio(SDL_AudioDeviceID dev, const void *data, Uint32 len);
-Uint32 SDL_DequeueAudio(SDL_AudioDeviceID dev, void *data, Uint32 len);
-Uint32 SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev);
-void SDL_ClearQueuedAudio(SDL_AudioDeviceID dev);
-void SDL_LockAudio(void);
-void SDL_LockAudioDevice(SDL_AudioDeviceID dev);
-void SDL_UnlockAudio(void);
-void SDL_UnlockAudioDevice(SDL_AudioDeviceID dev);
-void SDL_CloseAudio(void);
-void SDL_CloseAudioDevice(SDL_AudioDeviceID dev);
-int SDL_SetClipboardText(const char *text);
-char * SDL_GetClipboardText(void);
-SDL_bool SDL_HasClipboardText(void);
-int SDL_GetCPUCount(void);
-int SDL_GetCPUCacheLineSize(void);
-SDL_bool SDL_HasRDTSC(void);
-SDL_bool SDL_HasAltiVec(void);
-SDL_bool SDL_HasMMX(void);
-SDL_bool SDL_Has3DNow(void);
-SDL_bool SDL_HasSSE(void);
-SDL_bool SDL_HasSSE2(void);
-SDL_bool SDL_HasSSE3(void);
-SDL_bool SDL_HasSSE41(void);
-SDL_bool SDL_HasSSE42(void);
-SDL_bool SDL_HasAVX(void);
-SDL_bool SDL_HasAVX2(void);
-SDL_bool SDL_HasAVX512F(void);
-SDL_bool SDL_HasNEON(void);
-int SDL_GetSystemRAM(void);
-enum
-{
- SDL_PIXELTYPE_UNKNOWN,
- SDL_PIXELTYPE_INDEX1,
- SDL_PIXELTYPE_INDEX4,
- SDL_PIXELTYPE_INDEX8,
- SDL_PIXELTYPE_PACKED8,
- SDL_PIXELTYPE_PACKED16,
- SDL_PIXELTYPE_PACKED32,
- SDL_PIXELTYPE_ARRAYU8,
- SDL_PIXELTYPE_ARRAYU16,
- SDL_PIXELTYPE_ARRAYU32,
- SDL_PIXELTYPE_ARRAYF16,
- SDL_PIXELTYPE_ARRAYF32
-};
-enum
-{
- SDL_BITMAPORDER_NONE,
- SDL_BITMAPORDER_4321,
- SDL_BITMAPORDER_1234
-};
-enum
-{
- SDL_PACKEDORDER_NONE,
- SDL_PACKEDORDER_XRGB,
- SDL_PACKEDORDER_RGBX,
- SDL_PACKEDORDER_ARGB,
- SDL_PACKEDORDER_RGBA,
- SDL_PACKEDORDER_XBGR,
- SDL_PACKEDORDER_BGRX,
- SDL_PACKEDORDER_ABGR,
- SDL_PACKEDORDER_BGRA
-};
-enum
-{
- SDL_ARRAYORDER_NONE,
- SDL_ARRAYORDER_RGB,
- SDL_ARRAYORDER_RGBA,
- SDL_ARRAYORDER_ARGB,
- SDL_ARRAYORDER_BGR,
- SDL_ARRAYORDER_BGRA,
- SDL_ARRAYORDER_ABGR
-};
-enum
-{
- SDL_PACKEDLAYOUT_NONE,
- SDL_PACKEDLAYOUT_332,
- SDL_PACKEDLAYOUT_4444,
- SDL_PACKEDLAYOUT_1555,
- SDL_PACKEDLAYOUT_5551,
- SDL_PACKEDLAYOUT_565,
- SDL_PACKEDLAYOUT_8888,
- SDL_PACKEDLAYOUT_2101010,
- SDL_PACKEDLAYOUT_1010102
-};
-typedef enum
-{
- SDL_PIXELFORMAT_UNKNOWN,
- SDL_PIXELFORMAT_INDEX1LSB =
- ((1 << 28) | ((SDL_PIXELTYPE_INDEX1) << 24) | ((SDL_BITMAPORDER_4321) << 20) | ((0) << 16) | ((1) << 8) | ((0) << 0))
- ,
- SDL_PIXELFORMAT_INDEX1MSB =
- ((1 << 28) | ((SDL_PIXELTYPE_INDEX1) << 24) | ((SDL_BITMAPORDER_1234) << 20) | ((0) << 16) | ((1) << 8) | ((0) << 0))
- ,
- SDL_PIXELFORMAT_INDEX4LSB =
- ((1 << 28) | ((SDL_PIXELTYPE_INDEX4) << 24) | ((SDL_BITMAPORDER_4321) << 20) | ((0) << 16) | ((4) << 8) | ((0) << 0))
- ,
- SDL_PIXELFORMAT_INDEX4MSB =
- ((1 << 28) | ((SDL_PIXELTYPE_INDEX4) << 24) | ((SDL_BITMAPORDER_1234) << 20) | ((0) << 16) | ((4) << 8) | ((0) << 0))
- ,
- SDL_PIXELFORMAT_INDEX8 =
- ((1 << 28) | ((SDL_PIXELTYPE_INDEX8) << 24) | ((0) << 20) | ((0) << 16) | ((8) << 8) | ((1) << 0)),
- SDL_PIXELFORMAT_RGB332 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED8) << 24) | ((SDL_PACKEDORDER_XRGB) << 20) | ((SDL_PACKEDLAYOUT_332) << 16) | ((8) << 8) | ((1) << 0))
- ,
- SDL_PIXELFORMAT_RGB444 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_XRGB) << 20) | ((SDL_PACKEDLAYOUT_4444) << 16) | ((12) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_RGB555 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_XRGB) << 20) | ((SDL_PACKEDLAYOUT_1555) << 16) | ((15) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_BGR555 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_XBGR) << 20) | ((SDL_PACKEDLAYOUT_1555) << 16) | ((15) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_ARGB4444 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_ARGB) << 20) | ((SDL_PACKEDLAYOUT_4444) << 16) | ((16) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_RGBA4444 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_RGBA) << 20) | ((SDL_PACKEDLAYOUT_4444) << 16) | ((16) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_ABGR4444 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_ABGR) << 20) | ((SDL_PACKEDLAYOUT_4444) << 16) | ((16) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_BGRA4444 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_BGRA) << 20) | ((SDL_PACKEDLAYOUT_4444) << 16) | ((16) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_ARGB1555 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_ARGB) << 20) | ((SDL_PACKEDLAYOUT_1555) << 16) | ((16) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_RGBA5551 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_RGBA) << 20) | ((SDL_PACKEDLAYOUT_5551) << 16) | ((16) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_ABGR1555 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_ABGR) << 20) | ((SDL_PACKEDLAYOUT_1555) << 16) | ((16) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_BGRA5551 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_BGRA) << 20) | ((SDL_PACKEDLAYOUT_5551) << 16) | ((16) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_RGB565 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_XRGB) << 20) | ((SDL_PACKEDLAYOUT_565) << 16) | ((16) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_BGR565 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED16) << 24) | ((SDL_PACKEDORDER_XBGR) << 20) | ((SDL_PACKEDLAYOUT_565) << 16) | ((16) << 8) | ((2) << 0))
- ,
- SDL_PIXELFORMAT_RGB24 =
- ((1 << 28) | ((SDL_PIXELTYPE_ARRAYU8) << 24) | ((SDL_ARRAYORDER_RGB) << 20) | ((0) << 16) | ((24) << 8) | ((3) << 0))
- ,
- SDL_PIXELFORMAT_BGR24 =
- ((1 << 28) | ((SDL_PIXELTYPE_ARRAYU8) << 24) | ((SDL_ARRAYORDER_BGR) << 20) | ((0) << 16) | ((24) << 8) | ((3) << 0))
- ,
- SDL_PIXELFORMAT_RGB888 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED32) << 24) | ((SDL_PACKEDORDER_XRGB) << 20) | ((SDL_PACKEDLAYOUT_8888) << 16) | ((24) << 8) | ((4) << 0))
- ,
- SDL_PIXELFORMAT_RGBX8888 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED32) << 24) | ((SDL_PACKEDORDER_RGBX) << 20) | ((SDL_PACKEDLAYOUT_8888) << 16) | ((24) << 8) | ((4) << 0))
- ,
- SDL_PIXELFORMAT_BGR888 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED32) << 24) | ((SDL_PACKEDORDER_XBGR) << 20) | ((SDL_PACKEDLAYOUT_8888) << 16) | ((24) << 8) | ((4) << 0))
- ,
- SDL_PIXELFORMAT_BGRX8888 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED32) << 24) | ((SDL_PACKEDORDER_BGRX) << 20) | ((SDL_PACKEDLAYOUT_8888) << 16) | ((24) << 8) | ((4) << 0))
- ,
- SDL_PIXELFORMAT_ARGB8888 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED32) << 24) | ((SDL_PACKEDORDER_ARGB) << 20) | ((SDL_PACKEDLAYOUT_8888) << 16) | ((32) << 8) | ((4) << 0))
- ,
- SDL_PIXELFORMAT_RGBA8888 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED32) << 24) | ((SDL_PACKEDORDER_RGBA) << 20) | ((SDL_PACKEDLAYOUT_8888) << 16) | ((32) << 8) | ((4) << 0))
- ,
- SDL_PIXELFORMAT_ABGR8888 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED32) << 24) | ((SDL_PACKEDORDER_ABGR) << 20) | ((SDL_PACKEDLAYOUT_8888) << 16) | ((32) << 8) | ((4) << 0))
- ,
- SDL_PIXELFORMAT_BGRA8888 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED32) << 24) | ((SDL_PACKEDORDER_BGRA) << 20) | ((SDL_PACKEDLAYOUT_8888) << 16) | ((32) << 8) | ((4) << 0))
- ,
- SDL_PIXELFORMAT_ARGB2101010 =
- ((1 << 28) | ((SDL_PIXELTYPE_PACKED32) << 24) | ((SDL_PACKEDORDER_ARGB) << 20) | ((SDL_PACKEDLAYOUT_2101010) << 16) | ((32) << 8) | ((4) << 0))
- ,
- SDL_PIXELFORMAT_RGBA32 = SDL_PIXELFORMAT_ABGR8888,
- SDL_PIXELFORMAT_ARGB32 = SDL_PIXELFORMAT_BGRA8888,
- SDL_PIXELFORMAT_BGRA32 = SDL_PIXELFORMAT_ARGB8888,
- SDL_PIXELFORMAT_ABGR32 = SDL_PIXELFORMAT_RGBA8888,
- SDL_PIXELFORMAT_YV12 =
- ((((Uint32)(((Uint8)(('Y'))))) << 0) | (((Uint32)(((Uint8)(('V'))))) << 8) | (((Uint32)(((Uint8)(('1'))))) << 16) | (((Uint32)(((Uint8)(('2'))))) << 24)),
- SDL_PIXELFORMAT_IYUV =
- ((((Uint32)(((Uint8)(('I'))))) << 0) | (((Uint32)(((Uint8)(('Y'))))) << 8) | (((Uint32)(((Uint8)(('U'))))) << 16) | (((Uint32)(((Uint8)(('V'))))) << 24)),
- SDL_PIXELFORMAT_YUY2 =
- ((((Uint32)(((Uint8)(('Y'))))) << 0) | (((Uint32)(((Uint8)(('U'))))) << 8) | (((Uint32)(((Uint8)(('Y'))))) << 16) | (((Uint32)(((Uint8)(('2'))))) << 24)),
- SDL_PIXELFORMAT_UYVY =
- ((((Uint32)(((Uint8)(('U'))))) << 0) | (((Uint32)(((Uint8)(('Y'))))) << 8) | (((Uint32)(((Uint8)(('V'))))) << 16) | (((Uint32)(((Uint8)(('Y'))))) << 24)),
- SDL_PIXELFORMAT_YVYU =
- ((((Uint32)(((Uint8)(('Y'))))) << 0) | (((Uint32)(((Uint8)(('V'))))) << 8) | (((Uint32)(((Uint8)(('Y'))))) << 16) | (((Uint32)(((Uint8)(('U'))))) << 24)),
- SDL_PIXELFORMAT_NV12 =
- ((((Uint32)(((Uint8)(('N'))))) << 0) | (((Uint32)(((Uint8)(('V'))))) << 8) | (((Uint32)(((Uint8)(('1'))))) << 16) | (((Uint32)(((Uint8)(('2'))))) << 24)),
- SDL_PIXELFORMAT_NV21 =
- ((((Uint32)(((Uint8)(('N'))))) << 0) | (((Uint32)(((Uint8)(('V'))))) << 8) | (((Uint32)(((Uint8)(('2'))))) << 16) | (((Uint32)(((Uint8)(('1'))))) << 24)),
- SDL_PIXELFORMAT_EXTERNAL_OES =
- ((((Uint32)(((Uint8)(('O'))))) << 0) | (((Uint32)(((Uint8)(('E'))))) << 8) | (((Uint32)(((Uint8)(('S'))))) << 16) | (((Uint32)(((Uint8)((' '))))) << 24))
-} SDL_PixelFormatEnum;
-typedef struct SDL_Color
-{
- Uint8 r;
- Uint8 g;
- Uint8 b;
- Uint8 a;
-} SDL_Color;
-typedef struct SDL_Palette
-{
- int ncolors;
- SDL_Color *colors;
- Uint32 version;
- int refcount;
-} SDL_Palette;
-typedef struct SDL_PixelFormat
-{
- Uint32 format;
- SDL_Palette *palette;
- Uint8 BitsPerPixel;
- Uint8 BytesPerPixel;
- Uint8 padding[2];
- Uint32 Rmask;
- Uint32 Gmask;
- Uint32 Bmask;
- Uint32 Amask;
- Uint8 Rloss;
- Uint8 Gloss;
- Uint8 Bloss;
- Uint8 Aloss;
- Uint8 Rshift;
- Uint8 Gshift;
- Uint8 Bshift;
- Uint8 Ashift;
- int refcount;
- struct SDL_PixelFormat *next;
-} SDL_PixelFormat;
-const char* SDL_GetPixelFormatName(Uint32 format);
-SDL_bool SDL_PixelFormatEnumToMasks(Uint32 format,
- int *bpp,
- Uint32 * Rmask,
- Uint32 * Gmask,
- Uint32 * Bmask,
- Uint32 * Amask);
-Uint32 SDL_MasksToPixelFormatEnum(int bpp,
- Uint32 Rmask,
- Uint32 Gmask,
- Uint32 Bmask,
- Uint32 Amask);
-SDL_PixelFormat * SDL_AllocFormat(Uint32 pixel_format);
-void SDL_FreeFormat(SDL_PixelFormat *format);
-SDL_Palette * SDL_AllocPalette(int ncolors);
-int SDL_SetPixelFormatPalette(SDL_PixelFormat * format,
- SDL_Palette *palette);
-int SDL_SetPaletteColors(SDL_Palette * palette,
- const SDL_Color * colors,
- int firstcolor, int ncolors);
-void SDL_FreePalette(SDL_Palette * palette);
-Uint32 SDL_MapRGB(const SDL_PixelFormat * format,
- Uint8 r, Uint8 g, Uint8 b);
-Uint32 SDL_MapRGBA(const SDL_PixelFormat * format,
- Uint8 r, Uint8 g, Uint8 b,
- Uint8 a);
-void SDL_GetRGB(Uint32 pixel,
- const SDL_PixelFormat * format,
- Uint8 * r, Uint8 * g, Uint8 * b);
-void SDL_GetRGBA(Uint32 pixel,
- const SDL_PixelFormat * format,
- Uint8 * r, Uint8 * g, Uint8 * b,
- Uint8 * a);
-void SDL_CalculateGammaRamp(float gamma, Uint16 * ramp);
-typedef struct SDL_Point
-{
- int x;
- int y;
-} SDL_Point;
-typedef struct SDL_FPoint
-{
- float x;
- float y;
-} SDL_FPoint;
-typedef struct SDL_Rect
-{
- int x, y;
- int w, h;
-} SDL_Rect;
-typedef struct SDL_FRect
-{
- float x;
- float y;
- float w;
- float h;
-} SDL_FRect;
-SDL_bool SDL_HasIntersection(const SDL_Rect * A,
- const SDL_Rect * B);
-SDL_bool SDL_IntersectRect(const SDL_Rect * A,
- const SDL_Rect * B,
- SDL_Rect * result);
-void SDL_UnionRect(const SDL_Rect * A,
- const SDL_Rect * B,
- SDL_Rect * result);
-SDL_bool SDL_EnclosePoints(const SDL_Point * points,
- int count,
- const SDL_Rect * clip,
- SDL_Rect * result);
-SDL_bool SDL_IntersectRectAndLine(const SDL_Rect *
- rect, int *X1,
- int *Y1, int *X2,
- int *Y2);
-typedef enum
-{
- SDL_BLENDMODE_NONE = 0x00000000,
- SDL_BLENDMODE_BLEND = 0x00000001,
- SDL_BLENDMODE_ADD = 0x00000002,
- SDL_BLENDMODE_MOD = 0x00000004,
- SDL_BLENDMODE_INVALID = 0x7FFFFFFF
-} SDL_BlendMode;
-typedef enum
-{
- SDL_BLENDOPERATION_ADD = 0x1,
- SDL_BLENDOPERATION_SUBTRACT = 0x2,
- SDL_BLENDOPERATION_REV_SUBTRACT = 0x3,
- SDL_BLENDOPERATION_MINIMUM = 0x4,
- SDL_BLENDOPERATION_MAXIMUM = 0x5
-} SDL_BlendOperation;
-typedef enum
-{
- SDL_BLENDFACTOR_ZERO = 0x1,
- SDL_BLENDFACTOR_ONE = 0x2,
- SDL_BLENDFACTOR_SRC_COLOR = 0x3,
- SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR = 0x4,
- SDL_BLENDFACTOR_SRC_ALPHA = 0x5,
- SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA = 0x6,
- SDL_BLENDFACTOR_DST_COLOR = 0x7,
- SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR = 0x8,
- SDL_BLENDFACTOR_DST_ALPHA = 0x9,
- SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA = 0xA
-} SDL_BlendFactor;
-SDL_BlendMode SDL_ComposeCustomBlendMode(SDL_BlendFactor srcColorFactor,
- SDL_BlendFactor dstColorFactor,
- SDL_BlendOperation colorOperation,
- SDL_BlendFactor srcAlphaFactor,
- SDL_BlendFactor dstAlphaFactor,
- SDL_BlendOperation alphaOperation);
-typedef struct SDL_Surface
-{
- Uint32 flags;
- SDL_PixelFormat *format;
- int w, h;
- int pitch;
- void *pixels;
- void *userdata;
- int locked;
- void *lock_data;
- SDL_Rect clip_rect;
- struct SDL_BlitMap *map;
- int refcount;
-} SDL_Surface;
-typedef int ( *SDL_blit) (struct SDL_Surface * src, SDL_Rect * srcrect,
- struct SDL_Surface * dst, SDL_Rect * dstrect);
-typedef enum
-{
- SDL_YUV_CONVERSION_JPEG,
- SDL_YUV_CONVERSION_BT601,
- SDL_YUV_CONVERSION_BT709,
- SDL_YUV_CONVERSION_AUTOMATIC
-} SDL_YUV_CONVERSION_MODE;
-SDL_Surface * SDL_CreateRGBSurface
- (Uint32 flags, int width, int height, int depth,
- Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
-SDL_Surface * SDL_CreateRGBSurfaceWithFormat
- (Uint32 flags, int width, int height, int depth, Uint32 format);
-SDL_Surface * SDL_CreateRGBSurfaceFrom(void *pixels,
- int width,
- int height,
- int depth,
- int pitch,
- Uint32 Rmask,
- Uint32 Gmask,
- Uint32 Bmask,
- Uint32 Amask);
-SDL_Surface * SDL_CreateRGBSurfaceWithFormatFrom
- (void *pixels, int width, int height, int depth, int pitch, Uint32 format);
-void SDL_FreeSurface(SDL_Surface * surface);
-int SDL_SetSurfacePalette(SDL_Surface * surface,
- SDL_Palette * palette);
-int SDL_LockSurface(SDL_Surface * surface);
-void SDL_UnlockSurface(SDL_Surface * surface);
-SDL_Surface * SDL_LoadBMP_RW(SDL_RWops * src,
- int freesrc);
-int SDL_SaveBMP_RW
- (SDL_Surface * surface, SDL_RWops * dst, int freedst);
-int SDL_SetSurfaceRLE(SDL_Surface * surface,
- int flag);
-int SDL_SetColorKey(SDL_Surface * surface,
- int flag, Uint32 key);
-SDL_bool SDL_HasColorKey(SDL_Surface * surface);
-int SDL_GetColorKey(SDL_Surface * surface,
- Uint32 * key);
-int SDL_SetSurfaceColorMod(SDL_Surface * surface,
- Uint8 r, Uint8 g, Uint8 b);
-int SDL_GetSurfaceColorMod(SDL_Surface * surface,
- Uint8 * r, Uint8 * g,
- Uint8 * b);
-int SDL_SetSurfaceAlphaMod(SDL_Surface * surface,
- Uint8 alpha);
-int SDL_GetSurfaceAlphaMod(SDL_Surface * surface,
- Uint8 * alpha);
-int SDL_SetSurfaceBlendMode(SDL_Surface * surface,
- SDL_BlendMode blendMode);
-int SDL_GetSurfaceBlendMode(SDL_Surface * surface,
- SDL_BlendMode *blendMode);
-SDL_bool SDL_SetClipRect(SDL_Surface * surface,
- const SDL_Rect * rect);
-void SDL_GetClipRect(SDL_Surface * surface,
- SDL_Rect * rect);
-SDL_Surface * SDL_DuplicateSurface(SDL_Surface * surface);
-SDL_Surface * SDL_ConvertSurface
- (SDL_Surface * src, const SDL_PixelFormat * fmt, Uint32 flags);
-SDL_Surface * SDL_ConvertSurfaceFormat
- (SDL_Surface * src, Uint32 pixel_format, Uint32 flags);
-int SDL_ConvertPixels(int width, int height,
- Uint32 src_format,
- const void * src, int src_pitch,
- Uint32 dst_format,
- void * dst, int dst_pitch);
-int SDL_FillRect
- (SDL_Surface * dst, const SDL_Rect * rect, Uint32 color);
-int SDL_FillRects
- (SDL_Surface * dst, const SDL_Rect * rects, int count, Uint32 color);
-int SDL_UpperBlit
- (SDL_Surface * src, const SDL_Rect * srcrect,
- SDL_Surface * dst, SDL_Rect * dstrect);
-int SDL_LowerBlit
- (SDL_Surface * src, SDL_Rect * srcrect,
- SDL_Surface * dst, SDL_Rect * dstrect);
-int SDL_SoftStretch(SDL_Surface * src,
- const SDL_Rect * srcrect,
- SDL_Surface * dst,
- const SDL_Rect * dstrect);
-int SDL_UpperBlitScaled
- (SDL_Surface * src, const SDL_Rect * srcrect,
- SDL_Surface * dst, SDL_Rect * dstrect);
-int SDL_LowerBlitScaled
- (SDL_Surface * src, SDL_Rect * srcrect,
- SDL_Surface * dst, SDL_Rect * dstrect);
-void SDL_SetYUVConversionMode(SDL_YUV_CONVERSION_MODE mode);
-SDL_YUV_CONVERSION_MODE SDL_GetYUVConversionMode(void);
-SDL_YUV_CONVERSION_MODE SDL_GetYUVConversionModeForResolution(int width, int height);
-typedef struct
-{
- Uint32 format;
- int w;
- int h;
- int refresh_rate;
- void *driverdata;
-} SDL_DisplayMode;
-typedef struct SDL_Window SDL_Window;
-typedef enum
-{
- SDL_WINDOW_FULLSCREEN = 0x00000001,
- SDL_WINDOW_OPENGL = 0x00000002,
- SDL_WINDOW_SHOWN = 0x00000004,
- SDL_WINDOW_HIDDEN = 0x00000008,
- SDL_WINDOW_BORDERLESS = 0x00000010,
- SDL_WINDOW_RESIZABLE = 0x00000020,
- SDL_WINDOW_MINIMIZED = 0x00000040,
- SDL_WINDOW_MAXIMIZED = 0x00000080,
- SDL_WINDOW_INPUT_GRABBED = 0x00000100,
- SDL_WINDOW_INPUT_FOCUS = 0x00000200,
- SDL_WINDOW_MOUSE_FOCUS = 0x00000400,
- SDL_WINDOW_FULLSCREEN_DESKTOP = ( SDL_WINDOW_FULLSCREEN | 0x00001000 ),
- SDL_WINDOW_FOREIGN = 0x00000800,
- SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000,
- SDL_WINDOW_MOUSE_CAPTURE = 0x00004000,
- SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000,
- SDL_WINDOW_SKIP_TASKBAR = 0x00010000,
- SDL_WINDOW_UTILITY = 0x00020000,
- SDL_WINDOW_TOOLTIP = 0x00040000,
- SDL_WINDOW_POPUP_MENU = 0x00080000,
- SDL_WINDOW_VULKAN = 0x10000000
-} SDL_WindowFlags;
-typedef enum
-{
- SDL_WINDOWEVENT_NONE,
- SDL_WINDOWEVENT_SHOWN,
- SDL_WINDOWEVENT_HIDDEN,
- SDL_WINDOWEVENT_EXPOSED,
- SDL_WINDOWEVENT_MOVED,
- SDL_WINDOWEVENT_RESIZED,
- SDL_WINDOWEVENT_SIZE_CHANGED,
- SDL_WINDOWEVENT_MINIMIZED,
- SDL_WINDOWEVENT_MAXIMIZED,
- SDL_WINDOWEVENT_RESTORED,
- SDL_WINDOWEVENT_ENTER,
- SDL_WINDOWEVENT_LEAVE,
- SDL_WINDOWEVENT_FOCUS_GAINED,
- SDL_WINDOWEVENT_FOCUS_LOST,
- SDL_WINDOWEVENT_CLOSE,
- SDL_WINDOWEVENT_TAKE_FOCUS,
- SDL_WINDOWEVENT_HIT_TEST
-} SDL_WindowEventID;
-typedef enum
-{
- SDL_DISPLAYEVENT_NONE,
- SDL_DISPLAYEVENT_ORIENTATION
-} SDL_DisplayEventID;
-typedef enum
-{
- SDL_ORIENTATION_UNKNOWN,
- SDL_ORIENTATION_LANDSCAPE,
- SDL_ORIENTATION_LANDSCAPE_FLIPPED,
- SDL_ORIENTATION_PORTRAIT,
- SDL_ORIENTATION_PORTRAIT_FLIPPED
-} SDL_DisplayOrientation;
-typedef void *SDL_GLContext;
-typedef enum
-{
- SDL_GL_RED_SIZE,
- SDL_GL_GREEN_SIZE,
- SDL_GL_BLUE_SIZE,
- SDL_GL_ALPHA_SIZE,
- SDL_GL_BUFFER_SIZE,
- SDL_GL_DOUBLEBUFFER,
- SDL_GL_DEPTH_SIZE,
- SDL_GL_STENCIL_SIZE,
- SDL_GL_ACCUM_RED_SIZE,
- SDL_GL_ACCUM_GREEN_SIZE,
- SDL_GL_ACCUM_BLUE_SIZE,
- SDL_GL_ACCUM_ALPHA_SIZE,
- SDL_GL_STEREO,
- SDL_GL_MULTISAMPLEBUFFERS,
- SDL_GL_MULTISAMPLESAMPLES,
- SDL_GL_ACCELERATED_VISUAL,
- SDL_GL_RETAINED_BACKING,
- SDL_GL_CONTEXT_MAJOR_VERSION,
- SDL_GL_CONTEXT_MINOR_VERSION,
- SDL_GL_CONTEXT_EGL,
- SDL_GL_CONTEXT_FLAGS,
- SDL_GL_CONTEXT_PROFILE_MASK,
- SDL_GL_SHARE_WITH_CURRENT_CONTEXT,
- SDL_GL_FRAMEBUFFER_SRGB_CAPABLE,
- SDL_GL_CONTEXT_RELEASE_BEHAVIOR,
- SDL_GL_CONTEXT_RESET_NOTIFICATION,
- SDL_GL_CONTEXT_NO_ERROR
-} SDL_GLattr;
-typedef enum
-{
- SDL_GL_CONTEXT_PROFILE_CORE = 0x0001,
- SDL_GL_CONTEXT_PROFILE_COMPATIBILITY = 0x0002,
- SDL_GL_CONTEXT_PROFILE_ES = 0x0004
-} SDL_GLprofile;
-typedef enum
-{
- SDL_GL_CONTEXT_DEBUG_FLAG = 0x0001,
- SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG = 0x0002,
- SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG = 0x0004,
- SDL_GL_CONTEXT_RESET_ISOLATION_FLAG = 0x0008
-} SDL_GLcontextFlag;
-typedef enum
-{
- SDL_GL_CONTEXT_RELEASE_BEHAVIOR_NONE = 0x0000,
- SDL_GL_CONTEXT_RELEASE_BEHAVIOR_FLUSH = 0x0001
-} SDL_GLcontextReleaseFlag;
-typedef enum
-{
- SDL_GL_CONTEXT_RESET_NO_NOTIFICATION = 0x0000,
- SDL_GL_CONTEXT_RESET_LOSE_CONTEXT = 0x0001
-} SDL_GLContextResetNotification;
-int SDL_GetNumVideoDrivers(void);
-const char * SDL_GetVideoDriver(int index);
-int SDL_VideoInit(const char *driver_name);
-void SDL_VideoQuit(void);
-const char * SDL_GetCurrentVideoDriver(void);
-int SDL_GetNumVideoDisplays(void);
-const char * SDL_GetDisplayName(int displayIndex);
-int SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect);
-int SDL_GetDisplayUsableBounds(int displayIndex, SDL_Rect * rect);
-int SDL_GetDisplayDPI(int displayIndex, float * ddpi, float * hdpi, float * vdpi);
-SDL_DisplayOrientation SDL_GetDisplayOrientation(int displayIndex);
-int SDL_GetNumDisplayModes(int displayIndex);
-int SDL_GetDisplayMode(int displayIndex, int modeIndex,
- SDL_DisplayMode * mode);
-int SDL_GetDesktopDisplayMode(int displayIndex, SDL_DisplayMode * mode);
-int SDL_GetCurrentDisplayMode(int displayIndex, SDL_DisplayMode * mode);
-SDL_DisplayMode * SDL_GetClosestDisplayMode(int displayIndex, const SDL_DisplayMode * mode, SDL_DisplayMode * closest);
-int SDL_GetWindowDisplayIndex(SDL_Window * window);
-int SDL_SetWindowDisplayMode(SDL_Window * window,
- const SDL_DisplayMode
- * mode);
-int SDL_GetWindowDisplayMode(SDL_Window * window,
- SDL_DisplayMode * mode);
-Uint32 SDL_GetWindowPixelFormat(SDL_Window * window);
-SDL_Window * SDL_CreateWindow(const char *title,
- int x, int y, int w,
- int h, Uint32 flags);
-SDL_Window * SDL_CreateWindowFrom(const void *data);
-Uint32 SDL_GetWindowID(SDL_Window * window);
-SDL_Window * SDL_GetWindowFromID(Uint32 id);
-Uint32 SDL_GetWindowFlags(SDL_Window * window);
-void SDL_SetWindowTitle(SDL_Window * window,
- const char *title);
-const char * SDL_GetWindowTitle(SDL_Window * window);
-void SDL_SetWindowIcon(SDL_Window * window,
- SDL_Surface * icon);
-void* SDL_SetWindowData(SDL_Window * window,
- const char *name,
- void *userdata);
-void * SDL_GetWindowData(SDL_Window * window,
- const char *name);
-void SDL_SetWindowPosition(SDL_Window * window,
- int x, int y);
-void SDL_GetWindowPosition(SDL_Window * window,
- int *x, int *y);
-void SDL_SetWindowSize(SDL_Window * window, int w,
- int h);
-void SDL_GetWindowSize(SDL_Window * window, int *w,
- int *h);
-int SDL_GetWindowBordersSize(SDL_Window * window,
- int *top, int *left,
- int *bottom, int *right);
-void SDL_SetWindowMinimumSize(SDL_Window * window,
- int min_w, int min_h);
-void SDL_GetWindowMinimumSize(SDL_Window * window,
- int *w, int *h);
-void SDL_SetWindowMaximumSize(SDL_Window * window,
- int max_w, int max_h);
-void SDL_GetWindowMaximumSize(SDL_Window * window,
- int *w, int *h);
-void SDL_SetWindowBordered(SDL_Window * window,
- SDL_bool bordered);
-void SDL_SetWindowResizable(SDL_Window * window,
- SDL_bool resizable);
-void SDL_ShowWindow(SDL_Window * window);
-void SDL_HideWindow(SDL_Window * window);
-void SDL_RaiseWindow(SDL_Window * window);
-void SDL_MaximizeWindow(SDL_Window * window);
-void SDL_MinimizeWindow(SDL_Window * window);
-void SDL_RestoreWindow(SDL_Window * window);
-int SDL_SetWindowFullscreen(SDL_Window * window,
- Uint32 flags);
-SDL_Surface * SDL_GetWindowSurface(SDL_Window * window);
-int SDL_UpdateWindowSurface(SDL_Window * window);
-int SDL_UpdateWindowSurfaceRects(SDL_Window * window,
- const SDL_Rect * rects,
- int numrects);
-void SDL_SetWindowGrab(SDL_Window * window,
- SDL_bool grabbed);
-SDL_bool SDL_GetWindowGrab(SDL_Window * window);
-SDL_Window * SDL_GetGrabbedWindow(void);
-int SDL_SetWindowBrightness(SDL_Window * window, float brightness);
-float SDL_GetWindowBrightness(SDL_Window * window);
-int SDL_SetWindowOpacity(SDL_Window * window, float opacity);
-int SDL_GetWindowOpacity(SDL_Window * window, float * out_opacity);
-int SDL_SetWindowModalFor(SDL_Window * modal_window, SDL_Window * parent_window);
-int SDL_SetWindowInputFocus(SDL_Window * window);
-int SDL_SetWindowGammaRamp(SDL_Window * window,
- const Uint16 * red,
- const Uint16 * green,
- const Uint16 * blue);
-int SDL_GetWindowGammaRamp(SDL_Window * window,
- Uint16 * red,
- Uint16 * green,
- Uint16 * blue);
-typedef enum
-{
- SDL_HITTEST_NORMAL,
- SDL_HITTEST_DRAGGABLE,
- SDL_HITTEST_RESIZE_TOPLEFT,
- SDL_HITTEST_RESIZE_TOP,
- SDL_HITTEST_RESIZE_TOPRIGHT,
- SDL_HITTEST_RESIZE_RIGHT,
- SDL_HITTEST_RESIZE_BOTTOMRIGHT,
- SDL_HITTEST_RESIZE_BOTTOM,
- SDL_HITTEST_RESIZE_BOTTOMLEFT,
- SDL_HITTEST_RESIZE_LEFT
-} SDL_HitTestResult;
-typedef SDL_HitTestResult ( *SDL_HitTest)(SDL_Window *win,
- const SDL_Point *area,
- void *data);
-int SDL_SetWindowHitTest(SDL_Window * window,
- SDL_HitTest callback,
- void *callback_data);
-void SDL_DestroyWindow(SDL_Window * window);
-SDL_bool SDL_IsScreenSaverEnabled(void);
-void SDL_EnableScreenSaver(void);
-void SDL_DisableScreenSaver(void);
-int SDL_GL_LoadLibrary(const char *path);
-void * SDL_GL_GetProcAddress(const char *proc);
-void SDL_GL_UnloadLibrary(void);
-SDL_bool SDL_GL_ExtensionSupported(const char
- *extension);
-void SDL_GL_ResetAttributes(void);
-int SDL_GL_SetAttribute(SDL_GLattr attr, int value);
-int SDL_GL_GetAttribute(SDL_GLattr attr, int *value);
-SDL_GLContext SDL_GL_CreateContext(SDL_Window *
- window);
-int SDL_GL_MakeCurrent(SDL_Window * window,
- SDL_GLContext context);
-SDL_Window* SDL_GL_GetCurrentWindow(void);
-SDL_GLContext SDL_GL_GetCurrentContext(void);
-void SDL_GL_GetDrawableSize(SDL_Window * window, int *w,
- int *h);
-int SDL_GL_SetSwapInterval(int interval);
-int SDL_GL_GetSwapInterval(void);
-void SDL_GL_SwapWindow(SDL_Window * window);
-void SDL_GL_DeleteContext(SDL_GLContext context);
-typedef enum
-{
- SDL_SCANCODE_UNKNOWN = 0,
- SDL_SCANCODE_A = 4,
- SDL_SCANCODE_B = 5,
- SDL_SCANCODE_C = 6,
- SDL_SCANCODE_D = 7,
- SDL_SCANCODE_E = 8,
- SDL_SCANCODE_F = 9,
- SDL_SCANCODE_G = 10,
- SDL_SCANCODE_H = 11,
- SDL_SCANCODE_I = 12,
- SDL_SCANCODE_J = 13,
- SDL_SCANCODE_K = 14,
- SDL_SCANCODE_L = 15,
- SDL_SCANCODE_M = 16,
- SDL_SCANCODE_N = 17,
- SDL_SCANCODE_O = 18,
- SDL_SCANCODE_P = 19,
- SDL_SCANCODE_Q = 20,
- SDL_SCANCODE_R = 21,
- SDL_SCANCODE_S = 22,
- SDL_SCANCODE_T = 23,
- SDL_SCANCODE_U = 24,
- SDL_SCANCODE_V = 25,
- SDL_SCANCODE_W = 26,
- SDL_SCANCODE_X = 27,
- SDL_SCANCODE_Y = 28,
- SDL_SCANCODE_Z = 29,
- SDL_SCANCODE_1 = 30,
- SDL_SCANCODE_2 = 31,
- SDL_SCANCODE_3 = 32,
- SDL_SCANCODE_4 = 33,
- SDL_SCANCODE_5 = 34,
- SDL_SCANCODE_6 = 35,
- SDL_SCANCODE_7 = 36,
- SDL_SCANCODE_8 = 37,
- SDL_SCANCODE_9 = 38,
- SDL_SCANCODE_0 = 39,
- SDL_SCANCODE_RETURN = 40,
- SDL_SCANCODE_ESCAPE = 41,
- SDL_SCANCODE_BACKSPACE = 42,
- SDL_SCANCODE_TAB = 43,
- SDL_SCANCODE_SPACE = 44,
- SDL_SCANCODE_MINUS = 45,
- SDL_SCANCODE_EQUALS = 46,
- SDL_SCANCODE_LEFTBRACKET = 47,
- SDL_SCANCODE_RIGHTBRACKET = 48,
- SDL_SCANCODE_BACKSLASH = 49,
- SDL_SCANCODE_NONUSHASH = 50,
- SDL_SCANCODE_SEMICOLON = 51,
- SDL_SCANCODE_APOSTROPHE = 52,
- SDL_SCANCODE_GRAVE = 53,
- SDL_SCANCODE_COMMA = 54,
- SDL_SCANCODE_PERIOD = 55,
- SDL_SCANCODE_SLASH = 56,
- SDL_SCANCODE_CAPSLOCK = 57,
- SDL_SCANCODE_F1 = 58,
- SDL_SCANCODE_F2 = 59,
- SDL_SCANCODE_F3 = 60,
- SDL_SCANCODE_F4 = 61,
- SDL_SCANCODE_F5 = 62,
- SDL_SCANCODE_F6 = 63,
- SDL_SCANCODE_F7 = 64,
- SDL_SCANCODE_F8 = 65,
- SDL_SCANCODE_F9 = 66,
- SDL_SCANCODE_F10 = 67,
- SDL_SCANCODE_F11 = 68,
- SDL_SCANCODE_F12 = 69,
- SDL_SCANCODE_PRINTSCREEN = 70,
- SDL_SCANCODE_SCROLLLOCK = 71,
- SDL_SCANCODE_PAUSE = 72,
- SDL_SCANCODE_INSERT = 73,
- SDL_SCANCODE_HOME = 74,
- SDL_SCANCODE_PAGEUP = 75,
- SDL_SCANCODE_DELETE = 76,
- SDL_SCANCODE_END = 77,
- SDL_SCANCODE_PAGEDOWN = 78,
- SDL_SCANCODE_RIGHT = 79,
- SDL_SCANCODE_LEFT = 80,
- SDL_SCANCODE_DOWN = 81,
- SDL_SCANCODE_UP = 82,
- SDL_SCANCODE_NUMLOCKCLEAR = 83,
- SDL_SCANCODE_KP_DIVIDE = 84,
- SDL_SCANCODE_KP_MULTIPLY = 85,
- SDL_SCANCODE_KP_MINUS = 86,
- SDL_SCANCODE_KP_PLUS = 87,
- SDL_SCANCODE_KP_ENTER = 88,
- SDL_SCANCODE_KP_1 = 89,
- SDL_SCANCODE_KP_2 = 90,
- SDL_SCANCODE_KP_3 = 91,
- SDL_SCANCODE_KP_4 = 92,
- SDL_SCANCODE_KP_5 = 93,
- SDL_SCANCODE_KP_6 = 94,
- SDL_SCANCODE_KP_7 = 95,
- SDL_SCANCODE_KP_8 = 96,
- SDL_SCANCODE_KP_9 = 97,
- SDL_SCANCODE_KP_0 = 98,
- SDL_SCANCODE_KP_PERIOD = 99,
- SDL_SCANCODE_NONUSBACKSLASH = 100,
- SDL_SCANCODE_APPLICATION = 101,
- SDL_SCANCODE_POWER = 102,
- SDL_SCANCODE_KP_EQUALS = 103,
- SDL_SCANCODE_F13 = 104,
- SDL_SCANCODE_F14 = 105,
- SDL_SCANCODE_F15 = 106,
- SDL_SCANCODE_F16 = 107,
- SDL_SCANCODE_F17 = 108,
- SDL_SCANCODE_F18 = 109,
- SDL_SCANCODE_F19 = 110,
- SDL_SCANCODE_F20 = 111,
- SDL_SCANCODE_F21 = 112,
- SDL_SCANCODE_F22 = 113,
- SDL_SCANCODE_F23 = 114,
- SDL_SCANCODE_F24 = 115,
- SDL_SCANCODE_EXECUTE = 116,
- SDL_SCANCODE_HELP = 117,
- SDL_SCANCODE_MENU = 118,
- SDL_SCANCODE_SELECT = 119,
- SDL_SCANCODE_STOP = 120,
- SDL_SCANCODE_AGAIN = 121,
- SDL_SCANCODE_UNDO = 122,
- SDL_SCANCODE_CUT = 123,
- SDL_SCANCODE_COPY = 124,
- SDL_SCANCODE_PASTE = 125,
- SDL_SCANCODE_FIND = 126,
- SDL_SCANCODE_MUTE = 127,
- SDL_SCANCODE_VOLUMEUP = 128,
- SDL_SCANCODE_VOLUMEDOWN = 129,
- SDL_SCANCODE_KP_COMMA = 133,
- SDL_SCANCODE_KP_EQUALSAS400 = 134,
- SDL_SCANCODE_INTERNATIONAL1 = 135,
- SDL_SCANCODE_INTERNATIONAL2 = 136,
- SDL_SCANCODE_INTERNATIONAL3 = 137,
- SDL_SCANCODE_INTERNATIONAL4 = 138,
- SDL_SCANCODE_INTERNATIONAL5 = 139,
- SDL_SCANCODE_INTERNATIONAL6 = 140,
- SDL_SCANCODE_INTERNATIONAL7 = 141,
- SDL_SCANCODE_INTERNATIONAL8 = 142,
- SDL_SCANCODE_INTERNATIONAL9 = 143,
- SDL_SCANCODE_LANG1 = 144,
- SDL_SCANCODE_LANG2 = 145,
- SDL_SCANCODE_LANG3 = 146,
- SDL_SCANCODE_LANG4 = 147,
- SDL_SCANCODE_LANG5 = 148,
- SDL_SCANCODE_LANG6 = 149,
- SDL_SCANCODE_LANG7 = 150,
- SDL_SCANCODE_LANG8 = 151,
- SDL_SCANCODE_LANG9 = 152,
- SDL_SCANCODE_ALTERASE = 153,
- SDL_SCANCODE_SYSREQ = 154,
- SDL_SCANCODE_CANCEL = 155,
- SDL_SCANCODE_CLEAR = 156,
- SDL_SCANCODE_PRIOR = 157,
- SDL_SCANCODE_RETURN2 = 158,
- SDL_SCANCODE_SEPARATOR = 159,
- SDL_SCANCODE_OUT = 160,
- SDL_SCANCODE_OPER = 161,
- SDL_SCANCODE_CLEARAGAIN = 162,
- SDL_SCANCODE_CRSEL = 163,
- SDL_SCANCODE_EXSEL = 164,
- SDL_SCANCODE_KP_00 = 176,
- SDL_SCANCODE_KP_000 = 177,
- SDL_SCANCODE_THOUSANDSSEPARATOR = 178,
- SDL_SCANCODE_DECIMALSEPARATOR = 179,
- SDL_SCANCODE_CURRENCYUNIT = 180,
- SDL_SCANCODE_CURRENCYSUBUNIT = 181,
- SDL_SCANCODE_KP_LEFTPAREN = 182,
- SDL_SCANCODE_KP_RIGHTPAREN = 183,
- SDL_SCANCODE_KP_LEFTBRACE = 184,
- SDL_SCANCODE_KP_RIGHTBRACE = 185,
- SDL_SCANCODE_KP_TAB = 186,
- SDL_SCANCODE_KP_BACKSPACE = 187,
- SDL_SCANCODE_KP_A = 188,
- SDL_SCANCODE_KP_B = 189,
- SDL_SCANCODE_KP_C = 190,
- SDL_SCANCODE_KP_D = 191,
- SDL_SCANCODE_KP_E = 192,
- SDL_SCANCODE_KP_F = 193,
- SDL_SCANCODE_KP_XOR = 194,
- SDL_SCANCODE_KP_POWER = 195,
- SDL_SCANCODE_KP_PERCENT = 196,
- SDL_SCANCODE_KP_LESS = 197,
- SDL_SCANCODE_KP_GREATER = 198,
- SDL_SCANCODE_KP_AMPERSAND = 199,
- SDL_SCANCODE_KP_DBLAMPERSAND = 200,
- SDL_SCANCODE_KP_VERTICALBAR = 201,
- SDL_SCANCODE_KP_DBLVERTICALBAR = 202,
- SDL_SCANCODE_KP_COLON = 203,
- SDL_SCANCODE_KP_HASH = 204,
- SDL_SCANCODE_KP_SPACE = 205,
- SDL_SCANCODE_KP_AT = 206,
- SDL_SCANCODE_KP_EXCLAM = 207,
- SDL_SCANCODE_KP_MEMSTORE = 208,
- SDL_SCANCODE_KP_MEMRECALL = 209,
- SDL_SCANCODE_KP_MEMCLEAR = 210,
- SDL_SCANCODE_KP_MEMADD = 211,
- SDL_SCANCODE_KP_MEMSUBTRACT = 212,
- SDL_SCANCODE_KP_MEMMULTIPLY = 213,
- SDL_SCANCODE_KP_MEMDIVIDE = 214,
- SDL_SCANCODE_KP_PLUSMINUS = 215,
- SDL_SCANCODE_KP_CLEAR = 216,
- SDL_SCANCODE_KP_CLEARENTRY = 217,
- SDL_SCANCODE_KP_BINARY = 218,
- SDL_SCANCODE_KP_OCTAL = 219,
- SDL_SCANCODE_KP_DECIMAL = 220,
- SDL_SCANCODE_KP_HEXADECIMAL = 221,
- SDL_SCANCODE_LCTRL = 224,
- SDL_SCANCODE_LSHIFT = 225,
- SDL_SCANCODE_LALT = 226,
- SDL_SCANCODE_LGUI = 227,
- SDL_SCANCODE_RCTRL = 228,
- SDL_SCANCODE_RSHIFT = 229,
- SDL_SCANCODE_RALT = 230,
- SDL_SCANCODE_RGUI = 231,
- SDL_SCANCODE_MODE = 257,
- SDL_SCANCODE_AUDIONEXT = 258,
- SDL_SCANCODE_AUDIOPREV = 259,
- SDL_SCANCODE_AUDIOSTOP = 260,
- SDL_SCANCODE_AUDIOPLAY = 261,
- SDL_SCANCODE_AUDIOMUTE = 262,
- SDL_SCANCODE_MEDIASELECT = 263,
- SDL_SCANCODE_WWW = 264,
- SDL_SCANCODE_MAIL = 265,
- SDL_SCANCODE_CALCULATOR = 266,
- SDL_SCANCODE_COMPUTER = 267,
- SDL_SCANCODE_AC_SEARCH = 268,
- SDL_SCANCODE_AC_HOME = 269,
- SDL_SCANCODE_AC_BACK = 270,
- SDL_SCANCODE_AC_FORWARD = 271,
- SDL_SCANCODE_AC_STOP = 272,
- SDL_SCANCODE_AC_REFRESH = 273,
- SDL_SCANCODE_AC_BOOKMARKS = 274,
- SDL_SCANCODE_BRIGHTNESSDOWN = 275,
- SDL_SCANCODE_BRIGHTNESSUP = 276,
- SDL_SCANCODE_DISPLAYSWITCH = 277,
- SDL_SCANCODE_KBDILLUMTOGGLE = 278,
- SDL_SCANCODE_KBDILLUMDOWN = 279,
- SDL_SCANCODE_KBDILLUMUP = 280,
- SDL_SCANCODE_EJECT = 281,
- SDL_SCANCODE_SLEEP = 282,
- SDL_SCANCODE_APP1 = 283,
- SDL_SCANCODE_APP2 = 284,
- SDL_SCANCODE_AUDIOREWIND = 285,
- SDL_SCANCODE_AUDIOFASTFORWARD = 286,
- SDL_NUM_SCANCODES = 512
-} SDL_Scancode;
-typedef Sint32 SDL_Keycode;
-enum
-{
- SDLK_UNKNOWN = 0,
- SDLK_RETURN = '\r',
- SDLK_ESCAPE = '\033',
- SDLK_BACKSPACE = '\b',
- SDLK_TAB = '\t',
- SDLK_SPACE = ' ',
- SDLK_EXCLAIM = '!',
- SDLK_QUOTEDBL = '"',
- SDLK_HASH = '#',
- SDLK_PERCENT = '%',
- SDLK_DOLLAR = '$',
- SDLK_AMPERSAND = '&',
- SDLK_QUOTE = '\'',
- SDLK_LEFTPAREN = '(',
- SDLK_RIGHTPAREN = ')',
- SDLK_ASTERISK = '*',
- SDLK_PLUS = '+',
- SDLK_COMMA = ',',
- SDLK_MINUS = '-',
- SDLK_PERIOD = '.',
- SDLK_SLASH = '/',
- SDLK_0 = '0',
- SDLK_1 = '1',
- SDLK_2 = '2',
- SDLK_3 = '3',
- SDLK_4 = '4',
- SDLK_5 = '5',
- SDLK_6 = '6',
- SDLK_7 = '7',
- SDLK_8 = '8',
- SDLK_9 = '9',
- SDLK_COLON = ':',
- SDLK_SEMICOLON = ';',
- SDLK_LESS = '<',
- SDLK_EQUALS = '=',
- SDLK_GREATER = '>',
- SDLK_QUESTION = '?',
- SDLK_AT = '@',
- SDLK_LEFTBRACKET = '[',
- SDLK_BACKSLASH = '\\',
- SDLK_RIGHTBRACKET = ']',
- SDLK_CARET = '^',
- SDLK_UNDERSCORE = '_',
- SDLK_BACKQUOTE = '`',
- SDLK_a = 'a',
- SDLK_b = 'b',
- SDLK_c = 'c',
- SDLK_d = 'd',
- SDLK_e = 'e',
- SDLK_f = 'f',
- SDLK_g = 'g',
- SDLK_h = 'h',
- SDLK_i = 'i',
- SDLK_j = 'j',
- SDLK_k = 'k',
- SDLK_l = 'l',
- SDLK_m = 'm',
- SDLK_n = 'n',
- SDLK_o = 'o',
- SDLK_p = 'p',
- SDLK_q = 'q',
- SDLK_r = 'r',
- SDLK_s = 's',
- SDLK_t = 't',
- SDLK_u = 'u',
- SDLK_v = 'v',
- SDLK_w = 'w',
- SDLK_x = 'x',
- SDLK_y = 'y',
- SDLK_z = 'z',
- SDLK_CAPSLOCK = (SDL_SCANCODE_CAPSLOCK | (1<<30)),
- SDLK_F1 = (SDL_SCANCODE_F1 | (1<<30)),
- SDLK_F2 = (SDL_SCANCODE_F2 | (1<<30)),
- SDLK_F3 = (SDL_SCANCODE_F3 | (1<<30)),
- SDLK_F4 = (SDL_SCANCODE_F4 | (1<<30)),
- SDLK_F5 = (SDL_SCANCODE_F5 | (1<<30)),
- SDLK_F6 = (SDL_SCANCODE_F6 | (1<<30)),
- SDLK_F7 = (SDL_SCANCODE_F7 | (1<<30)),
- SDLK_F8 = (SDL_SCANCODE_F8 | (1<<30)),
- SDLK_F9 = (SDL_SCANCODE_F9 | (1<<30)),
- SDLK_F10 = (SDL_SCANCODE_F10 | (1<<30)),
- SDLK_F11 = (SDL_SCANCODE_F11 | (1<<30)),
- SDLK_F12 = (SDL_SCANCODE_F12 | (1<<30)),
- SDLK_PRINTSCREEN = (SDL_SCANCODE_PRINTSCREEN | (1<<30)),
- SDLK_SCROLLLOCK = (SDL_SCANCODE_SCROLLLOCK | (1<<30)),
- SDLK_PAUSE = (SDL_SCANCODE_PAUSE | (1<<30)),
- SDLK_INSERT = (SDL_SCANCODE_INSERT | (1<<30)),
- SDLK_HOME = (SDL_SCANCODE_HOME | (1<<30)),
- SDLK_PAGEUP = (SDL_SCANCODE_PAGEUP | (1<<30)),
- SDLK_DELETE = '\177',
- SDLK_END = (SDL_SCANCODE_END | (1<<30)),
- SDLK_PAGEDOWN = (SDL_SCANCODE_PAGEDOWN | (1<<30)),
- SDLK_RIGHT = (SDL_SCANCODE_RIGHT | (1<<30)),
- SDLK_LEFT = (SDL_SCANCODE_LEFT | (1<<30)),
- SDLK_DOWN = (SDL_SCANCODE_DOWN | (1<<30)),
- SDLK_UP = (SDL_SCANCODE_UP | (1<<30)),
- SDLK_NUMLOCKCLEAR = (SDL_SCANCODE_NUMLOCKCLEAR | (1<<30)),
- SDLK_KP_DIVIDE = (SDL_SCANCODE_KP_DIVIDE | (1<<30)),
- SDLK_KP_MULTIPLY = (SDL_SCANCODE_KP_MULTIPLY | (1<<30)),
- SDLK_KP_MINUS = (SDL_SCANCODE_KP_MINUS | (1<<30)),
- SDLK_KP_PLUS = (SDL_SCANCODE_KP_PLUS | (1<<30)),
- SDLK_KP_ENTER = (SDL_SCANCODE_KP_ENTER | (1<<30)),
- SDLK_KP_1 = (SDL_SCANCODE_KP_1 | (1<<30)),
- SDLK_KP_2 = (SDL_SCANCODE_KP_2 | (1<<30)),
- SDLK_KP_3 = (SDL_SCANCODE_KP_3 | (1<<30)),
- SDLK_KP_4 = (SDL_SCANCODE_KP_4 | (1<<30)),
- SDLK_KP_5 = (SDL_SCANCODE_KP_5 | (1<<30)),
- SDLK_KP_6 = (SDL_SCANCODE_KP_6 | (1<<30)),
- SDLK_KP_7 = (SDL_SCANCODE_KP_7 | (1<<30)),
- SDLK_KP_8 = (SDL_SCANCODE_KP_8 | (1<<30)),
- SDLK_KP_9 = (SDL_SCANCODE_KP_9 | (1<<30)),
- SDLK_KP_0 = (SDL_SCANCODE_KP_0 | (1<<30)),
- SDLK_KP_PERIOD = (SDL_SCANCODE_KP_PERIOD | (1<<30)),
- SDLK_APPLICATION = (SDL_SCANCODE_APPLICATION | (1<<30)),
- SDLK_POWER = (SDL_SCANCODE_POWER | (1<<30)),
- SDLK_KP_EQUALS = (SDL_SCANCODE_KP_EQUALS | (1<<30)),
- SDLK_F13 = (SDL_SCANCODE_F13 | (1<<30)),
- SDLK_F14 = (SDL_SCANCODE_F14 | (1<<30)),
- SDLK_F15 = (SDL_SCANCODE_F15 | (1<<30)),
- SDLK_F16 = (SDL_SCANCODE_F16 | (1<<30)),
- SDLK_F17 = (SDL_SCANCODE_F17 | (1<<30)),
- SDLK_F18 = (SDL_SCANCODE_F18 | (1<<30)),
- SDLK_F19 = (SDL_SCANCODE_F19 | (1<<30)),
- SDLK_F20 = (SDL_SCANCODE_F20 | (1<<30)),
- SDLK_F21 = (SDL_SCANCODE_F21 | (1<<30)),
- SDLK_F22 = (SDL_SCANCODE_F22 | (1<<30)),
- SDLK_F23 = (SDL_SCANCODE_F23 | (1<<30)),
- SDLK_F24 = (SDL_SCANCODE_F24 | (1<<30)),
- SDLK_EXECUTE = (SDL_SCANCODE_EXECUTE | (1<<30)),
- SDLK_HELP = (SDL_SCANCODE_HELP | (1<<30)),
- SDLK_MENU = (SDL_SCANCODE_MENU | (1<<30)),
- SDLK_SELECT = (SDL_SCANCODE_SELECT | (1<<30)),
- SDLK_STOP = (SDL_SCANCODE_STOP | (1<<30)),
- SDLK_AGAIN = (SDL_SCANCODE_AGAIN | (1<<30)),
- SDLK_UNDO = (SDL_SCANCODE_UNDO | (1<<30)),
- SDLK_CUT = (SDL_SCANCODE_CUT | (1<<30)),
- SDLK_COPY = (SDL_SCANCODE_COPY | (1<<30)),
- SDLK_PASTE = (SDL_SCANCODE_PASTE | (1<<30)),
- SDLK_FIND = (SDL_SCANCODE_FIND | (1<<30)),
- SDLK_MUTE = (SDL_SCANCODE_MUTE | (1<<30)),
- SDLK_VOLUMEUP = (SDL_SCANCODE_VOLUMEUP | (1<<30)),
- SDLK_VOLUMEDOWN = (SDL_SCANCODE_VOLUMEDOWN | (1<<30)),
- SDLK_KP_COMMA = (SDL_SCANCODE_KP_COMMA | (1<<30)),
- SDLK_KP_EQUALSAS400 =
- (SDL_SCANCODE_KP_EQUALSAS400 | (1<<30)),
- SDLK_ALTERASE = (SDL_SCANCODE_ALTERASE | (1<<30)),
- SDLK_SYSREQ = (SDL_SCANCODE_SYSREQ | (1<<30)),
- SDLK_CANCEL = (SDL_SCANCODE_CANCEL | (1<<30)),
- SDLK_CLEAR = (SDL_SCANCODE_CLEAR | (1<<30)),
- SDLK_PRIOR = (SDL_SCANCODE_PRIOR | (1<<30)),
- SDLK_RETURN2 = (SDL_SCANCODE_RETURN2 | (1<<30)),
- SDLK_SEPARATOR = (SDL_SCANCODE_SEPARATOR | (1<<30)),
- SDLK_OUT = (SDL_SCANCODE_OUT | (1<<30)),
- SDLK_OPER = (SDL_SCANCODE_OPER | (1<<30)),
- SDLK_CLEARAGAIN = (SDL_SCANCODE_CLEARAGAIN | (1<<30)),
- SDLK_CRSEL = (SDL_SCANCODE_CRSEL | (1<<30)),
- SDLK_EXSEL = (SDL_SCANCODE_EXSEL | (1<<30)),
- SDLK_KP_00 = (SDL_SCANCODE_KP_00 | (1<<30)),
- SDLK_KP_000 = (SDL_SCANCODE_KP_000 | (1<<30)),
- SDLK_THOUSANDSSEPARATOR =
- (SDL_SCANCODE_THOUSANDSSEPARATOR | (1<<30)),
- SDLK_DECIMALSEPARATOR =
- (SDL_SCANCODE_DECIMALSEPARATOR | (1<<30)),
- SDLK_CURRENCYUNIT = (SDL_SCANCODE_CURRENCYUNIT | (1<<30)),
- SDLK_CURRENCYSUBUNIT =
- (SDL_SCANCODE_CURRENCYSUBUNIT | (1<<30)),
- SDLK_KP_LEFTPAREN = (SDL_SCANCODE_KP_LEFTPAREN | (1<<30)),
- SDLK_KP_RIGHTPAREN = (SDL_SCANCODE_KP_RIGHTPAREN | (1<<30)),
- SDLK_KP_LEFTBRACE = (SDL_SCANCODE_KP_LEFTBRACE | (1<<30)),
- SDLK_KP_RIGHTBRACE = (SDL_SCANCODE_KP_RIGHTBRACE | (1<<30)),
- SDLK_KP_TAB = (SDL_SCANCODE_KP_TAB | (1<<30)),
- SDLK_KP_BACKSPACE = (SDL_SCANCODE_KP_BACKSPACE | (1<<30)),
- SDLK_KP_A = (SDL_SCANCODE_KP_A | (1<<30)),
- SDLK_KP_B = (SDL_SCANCODE_KP_B | (1<<30)),
- SDLK_KP_C = (SDL_SCANCODE_KP_C | (1<<30)),
- SDLK_KP_D = (SDL_SCANCODE_KP_D | (1<<30)),
- SDLK_KP_E = (SDL_SCANCODE_KP_E | (1<<30)),
- SDLK_KP_F = (SDL_SCANCODE_KP_F | (1<<30)),
- SDLK_KP_XOR = (SDL_SCANCODE_KP_XOR | (1<<30)),
- SDLK_KP_POWER = (SDL_SCANCODE_KP_POWER | (1<<30)),
- SDLK_KP_PERCENT = (SDL_SCANCODE_KP_PERCENT | (1<<30)),
- SDLK_KP_LESS = (SDL_SCANCODE_KP_LESS | (1<<30)),
- SDLK_KP_GREATER = (SDL_SCANCODE_KP_GREATER | (1<<30)),
- SDLK_KP_AMPERSAND = (SDL_SCANCODE_KP_AMPERSAND | (1<<30)),
- SDLK_KP_DBLAMPERSAND =
- (SDL_SCANCODE_KP_DBLAMPERSAND | (1<<30)),
- SDLK_KP_VERTICALBAR =
- (SDL_SCANCODE_KP_VERTICALBAR | (1<<30)),
- SDLK_KP_DBLVERTICALBAR =
- (SDL_SCANCODE_KP_DBLVERTICALBAR | (1<<30)),
- SDLK_KP_COLON = (SDL_SCANCODE_KP_COLON | (1<<30)),
- SDLK_KP_HASH = (SDL_SCANCODE_KP_HASH | (1<<30)),
- SDLK_KP_SPACE = (SDL_SCANCODE_KP_SPACE | (1<<30)),
- SDLK_KP_AT = (SDL_SCANCODE_KP_AT | (1<<30)),
- SDLK_KP_EXCLAM = (SDL_SCANCODE_KP_EXCLAM | (1<<30)),
- SDLK_KP_MEMSTORE = (SDL_SCANCODE_KP_MEMSTORE | (1<<30)),
- SDLK_KP_MEMRECALL = (SDL_SCANCODE_KP_MEMRECALL | (1<<30)),
- SDLK_KP_MEMCLEAR = (SDL_SCANCODE_KP_MEMCLEAR | (1<<30)),
- SDLK_KP_MEMADD = (SDL_SCANCODE_KP_MEMADD | (1<<30)),
- SDLK_KP_MEMSUBTRACT =
- (SDL_SCANCODE_KP_MEMSUBTRACT | (1<<30)),
- SDLK_KP_MEMMULTIPLY =
- (SDL_SCANCODE_KP_MEMMULTIPLY | (1<<30)),
- SDLK_KP_MEMDIVIDE = (SDL_SCANCODE_KP_MEMDIVIDE | (1<<30)),
- SDLK_KP_PLUSMINUS = (SDL_SCANCODE_KP_PLUSMINUS | (1<<30)),
- SDLK_KP_CLEAR = (SDL_SCANCODE_KP_CLEAR | (1<<30)),
- SDLK_KP_CLEARENTRY = (SDL_SCANCODE_KP_CLEARENTRY | (1<<30)),
- SDLK_KP_BINARY = (SDL_SCANCODE_KP_BINARY | (1<<30)),
- SDLK_KP_OCTAL = (SDL_SCANCODE_KP_OCTAL | (1<<30)),
- SDLK_KP_DECIMAL = (SDL_SCANCODE_KP_DECIMAL | (1<<30)),
- SDLK_KP_HEXADECIMAL =
- (SDL_SCANCODE_KP_HEXADECIMAL | (1<<30)),
- SDLK_LCTRL = (SDL_SCANCODE_LCTRL | (1<<30)),
- SDLK_LSHIFT = (SDL_SCANCODE_LSHIFT | (1<<30)),
- SDLK_LALT = (SDL_SCANCODE_LALT | (1<<30)),
- SDLK_LGUI = (SDL_SCANCODE_LGUI | (1<<30)),
- SDLK_RCTRL = (SDL_SCANCODE_RCTRL | (1<<30)),
- SDLK_RSHIFT = (SDL_SCANCODE_RSHIFT | (1<<30)),
- SDLK_RALT = (SDL_SCANCODE_RALT | (1<<30)),
- SDLK_RGUI = (SDL_SCANCODE_RGUI | (1<<30)),
- SDLK_MODE = (SDL_SCANCODE_MODE | (1<<30)),
- SDLK_AUDIONEXT = (SDL_SCANCODE_AUDIONEXT | (1<<30)),
- SDLK_AUDIOPREV = (SDL_SCANCODE_AUDIOPREV | (1<<30)),
- SDLK_AUDIOSTOP = (SDL_SCANCODE_AUDIOSTOP | (1<<30)),
- SDLK_AUDIOPLAY = (SDL_SCANCODE_AUDIOPLAY | (1<<30)),
- SDLK_AUDIOMUTE = (SDL_SCANCODE_AUDIOMUTE | (1<<30)),
- SDLK_MEDIASELECT = (SDL_SCANCODE_MEDIASELECT | (1<<30)),
- SDLK_WWW = (SDL_SCANCODE_WWW | (1<<30)),
- SDLK_MAIL = (SDL_SCANCODE_MAIL | (1<<30)),
- SDLK_CALCULATOR = (SDL_SCANCODE_CALCULATOR | (1<<30)),
- SDLK_COMPUTER = (SDL_SCANCODE_COMPUTER | (1<<30)),
- SDLK_AC_SEARCH = (SDL_SCANCODE_AC_SEARCH | (1<<30)),
- SDLK_AC_HOME = (SDL_SCANCODE_AC_HOME | (1<<30)),
- SDLK_AC_BACK = (SDL_SCANCODE_AC_BACK | (1<<30)),
- SDLK_AC_FORWARD = (SDL_SCANCODE_AC_FORWARD | (1<<30)),
- SDLK_AC_STOP = (SDL_SCANCODE_AC_STOP | (1<<30)),
- SDLK_AC_REFRESH = (SDL_SCANCODE_AC_REFRESH | (1<<30)),
- SDLK_AC_BOOKMARKS = (SDL_SCANCODE_AC_BOOKMARKS | (1<<30)),
- SDLK_BRIGHTNESSDOWN =
- (SDL_SCANCODE_BRIGHTNESSDOWN | (1<<30)),
- SDLK_BRIGHTNESSUP = (SDL_SCANCODE_BRIGHTNESSUP | (1<<30)),
- SDLK_DISPLAYSWITCH = (SDL_SCANCODE_DISPLAYSWITCH | (1<<30)),
- SDLK_KBDILLUMTOGGLE =
- (SDL_SCANCODE_KBDILLUMTOGGLE | (1<<30)),
- SDLK_KBDILLUMDOWN = (SDL_SCANCODE_KBDILLUMDOWN | (1<<30)),
- SDLK_KBDILLUMUP = (SDL_SCANCODE_KBDILLUMUP | (1<<30)),
- SDLK_EJECT = (SDL_SCANCODE_EJECT | (1<<30)),
- SDLK_SLEEP = (SDL_SCANCODE_SLEEP | (1<<30)),
- SDLK_APP1 = (SDL_SCANCODE_APP1 | (1<<30)),
- SDLK_APP2 = (SDL_SCANCODE_APP2 | (1<<30)),
- SDLK_AUDIOREWIND = (SDL_SCANCODE_AUDIOREWIND | (1<<30)),
- SDLK_AUDIOFASTFORWARD = (SDL_SCANCODE_AUDIOFASTFORWARD | (1<<30))
-};
-typedef enum
-{
- KMOD_NONE = 0x0000,
- KMOD_LSHIFT = 0x0001,
- KMOD_RSHIFT = 0x0002,
- KMOD_LCTRL = 0x0040,
- KMOD_RCTRL = 0x0080,
- KMOD_LALT = 0x0100,
- KMOD_RALT = 0x0200,
- KMOD_LGUI = 0x0400,
- KMOD_RGUI = 0x0800,
- KMOD_NUM = 0x1000,
- KMOD_CAPS = 0x2000,
- KMOD_MODE = 0x4000,
- KMOD_RESERVED = 0x8000
-} SDL_Keymod;
-typedef struct SDL_Keysym
-{
- SDL_Scancode scancode;
- SDL_Keycode sym;
- Uint16 mod;
- Uint32 unused;
-} SDL_Keysym;
-SDL_Window * SDL_GetKeyboardFocus(void);
-const Uint8 * SDL_GetKeyboardState(int *numkeys);
-SDL_Keymod SDL_GetModState(void);
-void SDL_SetModState(SDL_Keymod modstate);
-SDL_Keycode SDL_GetKeyFromScancode(SDL_Scancode scancode);
-SDL_Scancode SDL_GetScancodeFromKey(SDL_Keycode key);
-const char * SDL_GetScancodeName(SDL_Scancode scancode);
-SDL_Scancode SDL_GetScancodeFromName(const char *name);
-const char * SDL_GetKeyName(SDL_Keycode key);
-SDL_Keycode SDL_GetKeyFromName(const char *name);
-void SDL_StartTextInput(void);
-SDL_bool SDL_IsTextInputActive(void);
-void SDL_StopTextInput(void);
-void SDL_SetTextInputRect(SDL_Rect *rect);
-SDL_bool SDL_HasScreenKeyboardSupport(void);
-SDL_bool SDL_IsScreenKeyboardShown(SDL_Window *window);
-typedef struct SDL_Cursor SDL_Cursor;
-typedef enum
-{
- SDL_SYSTEM_CURSOR_ARROW,
- SDL_SYSTEM_CURSOR_IBEAM,
- SDL_SYSTEM_CURSOR_WAIT,
- SDL_SYSTEM_CURSOR_CROSSHAIR,
- SDL_SYSTEM_CURSOR_WAITARROW,
- SDL_SYSTEM_CURSOR_SIZENWSE,
- SDL_SYSTEM_CURSOR_SIZENESW,
- SDL_SYSTEM_CURSOR_SIZEWE,
- SDL_SYSTEM_CURSOR_SIZENS,
- SDL_SYSTEM_CURSOR_SIZEALL,
- SDL_SYSTEM_CURSOR_NO,
- SDL_SYSTEM_CURSOR_HAND,
- SDL_NUM_SYSTEM_CURSORS
-} SDL_SystemCursor;
-typedef enum
-{
- SDL_MOUSEWHEEL_NORMAL,
- SDL_MOUSEWHEEL_FLIPPED
-} SDL_MouseWheelDirection;
-SDL_Window * SDL_GetMouseFocus(void);
-Uint32 SDL_GetMouseState(int *x, int *y);
-Uint32 SDL_GetGlobalMouseState(int *x, int *y);
-Uint32 SDL_GetRelativeMouseState(int *x, int *y);
-void SDL_WarpMouseInWindow(SDL_Window * window,
- int x, int y);
-int SDL_WarpMouseGlobal(int x, int y);
-int SDL_SetRelativeMouseMode(SDL_bool enabled);
-int SDL_CaptureMouse(SDL_bool enabled);
-SDL_bool SDL_GetRelativeMouseMode(void);
-SDL_Cursor * SDL_CreateCursor(const Uint8 * data,
- const Uint8 * mask,
- int w, int h, int hot_x,
- int hot_y);
-SDL_Cursor * SDL_CreateColorCursor(SDL_Surface *surface,
- int hot_x,
- int hot_y);
-SDL_Cursor * SDL_CreateSystemCursor(SDL_SystemCursor id);
-void SDL_SetCursor(SDL_Cursor * cursor);
-SDL_Cursor * SDL_GetCursor(void);
-SDL_Cursor * SDL_GetDefaultCursor(void);
-void SDL_FreeCursor(SDL_Cursor * cursor);
-int SDL_ShowCursor(int toggle);
-struct _SDL_Joystick;
-typedef struct _SDL_Joystick SDL_Joystick;
-typedef struct {
- Uint8 data[16];
-} SDL_JoystickGUID;
-typedef Sint32 SDL_JoystickID;
-typedef enum
-{
- SDL_JOYSTICK_TYPE_UNKNOWN,
- SDL_JOYSTICK_TYPE_GAMECONTROLLER,
- SDL_JOYSTICK_TYPE_WHEEL,
- SDL_JOYSTICK_TYPE_ARCADE_STICK,
- SDL_JOYSTICK_TYPE_FLIGHT_STICK,
- SDL_JOYSTICK_TYPE_DANCE_PAD,
- SDL_JOYSTICK_TYPE_GUITAR,
- SDL_JOYSTICK_TYPE_DRUM_KIT,
- SDL_JOYSTICK_TYPE_ARCADE_PAD,
- SDL_JOYSTICK_TYPE_THROTTLE
-} SDL_JoystickType;
-typedef enum
-{
- SDL_JOYSTICK_POWER_UNKNOWN = -1,
- SDL_JOYSTICK_POWER_EMPTY,
- SDL_JOYSTICK_POWER_LOW,
- SDL_JOYSTICK_POWER_MEDIUM,
- SDL_JOYSTICK_POWER_FULL,
- SDL_JOYSTICK_POWER_WIRED,
- SDL_JOYSTICK_POWER_MAX
-} SDL_JoystickPowerLevel;
-void SDL_LockJoysticks(void);
-void SDL_UnlockJoysticks(void);
-int SDL_NumJoysticks(void);
-const char * SDL_JoystickNameForIndex(int device_index);
-int SDL_JoystickGetDevicePlayerIndex(int device_index);
-SDL_JoystickGUID SDL_JoystickGetDeviceGUID(int device_index);
-Uint16 SDL_JoystickGetDeviceVendor(int device_index);
-Uint16 SDL_JoystickGetDeviceProduct(int device_index);
-Uint16 SDL_JoystickGetDeviceProductVersion(int device_index);
-SDL_JoystickType SDL_JoystickGetDeviceType(int device_index);
-SDL_JoystickID SDL_JoystickGetDeviceInstanceID(int device_index);
-SDL_Joystick * SDL_JoystickOpen(int device_index);
-SDL_Joystick * SDL_JoystickFromInstanceID(SDL_JoystickID joyid);
-const char * SDL_JoystickName(SDL_Joystick * joystick);
-int SDL_JoystickGetPlayerIndex(SDL_Joystick * joystick);
-SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick);
-Uint16 SDL_JoystickGetVendor(SDL_Joystick * joystick);
-Uint16 SDL_JoystickGetProduct(SDL_Joystick * joystick);
-Uint16 SDL_JoystickGetProductVersion(SDL_Joystick * joystick);
-SDL_JoystickType SDL_JoystickGetType(SDL_Joystick * joystick);
-void SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID);
-SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID);
-SDL_bool SDL_JoystickGetAttached(SDL_Joystick * joystick);
-SDL_JoystickID SDL_JoystickInstanceID(SDL_Joystick * joystick);
-int SDL_JoystickNumAxes(SDL_Joystick * joystick);
-int SDL_JoystickNumBalls(SDL_Joystick * joystick);
-int SDL_JoystickNumHats(SDL_Joystick * joystick);
-int SDL_JoystickNumButtons(SDL_Joystick * joystick);
-void SDL_JoystickUpdate(void);
-int SDL_JoystickEventState(int state);
-Sint16 SDL_JoystickGetAxis(SDL_Joystick * joystick,
- int axis);
-SDL_bool SDL_JoystickGetAxisInitialState(SDL_Joystick * joystick,
- int axis, Sint16 *state);
-Uint8 SDL_JoystickGetHat(SDL_Joystick * joystick,
- int hat);
-int SDL_JoystickGetBall(SDL_Joystick * joystick,
- int ball, int *dx, int *dy);
-Uint8 SDL_JoystickGetButton(SDL_Joystick * joystick,
- int button);
-int SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
-void SDL_JoystickClose(SDL_Joystick * joystick);
-SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick);
-struct _SDL_GameController;
-typedef struct _SDL_GameController SDL_GameController;
-typedef enum
-{
- SDL_CONTROLLER_BINDTYPE_NONE = 0,
- SDL_CONTROLLER_BINDTYPE_BUTTON,
- SDL_CONTROLLER_BINDTYPE_AXIS,
- SDL_CONTROLLER_BINDTYPE_HAT
-} SDL_GameControllerBindType;
-typedef struct SDL_GameControllerButtonBind
-{
- SDL_GameControllerBindType bindType;
- union
- {
- int button;
- int axis;
- struct {
- int hat;
- int hat_mask;
- } hat;
- } value;
-} SDL_GameControllerButtonBind;
-int SDL_GameControllerAddMappingsFromRW(SDL_RWops * rw, int freerw);
-int SDL_GameControllerAddMapping(const char* mappingString);
-int SDL_GameControllerNumMappings(void);
-char * SDL_GameControllerMappingForIndex(int mapping_index);
-char * SDL_GameControllerMappingForGUID(SDL_JoystickGUID guid);
-char * SDL_GameControllerMapping(SDL_GameController * gamecontroller);
-SDL_bool SDL_IsGameController(int joystick_index);
-const char * SDL_GameControllerNameForIndex(int joystick_index);
-char * SDL_GameControllerMappingForDeviceIndex(int joystick_index);
-SDL_GameController * SDL_GameControllerOpen(int joystick_index);
-SDL_GameController * SDL_GameControllerFromInstanceID(SDL_JoystickID joyid);
-const char * SDL_GameControllerName(SDL_GameController *gamecontroller);
-int SDL_GameControllerGetPlayerIndex(SDL_GameController *gamecontroller);
-Uint16 SDL_GameControllerGetVendor(SDL_GameController * gamecontroller);
-Uint16 SDL_GameControllerGetProduct(SDL_GameController * gamecontroller);
-Uint16 SDL_GameControllerGetProductVersion(SDL_GameController * gamecontroller);
-SDL_bool SDL_GameControllerGetAttached(SDL_GameController *gamecontroller);
-SDL_Joystick * SDL_GameControllerGetJoystick(SDL_GameController *gamecontroller);
-int SDL_GameControllerEventState(int state);
-void SDL_GameControllerUpdate(void);
-typedef enum
-{
- SDL_CONTROLLER_AXIS_INVALID = -1,
- SDL_CONTROLLER_AXIS_LEFTX,
- SDL_CONTROLLER_AXIS_LEFTY,
- SDL_CONTROLLER_AXIS_RIGHTX,
- SDL_CONTROLLER_AXIS_RIGHTY,
- SDL_CONTROLLER_AXIS_TRIGGERLEFT,
- SDL_CONTROLLER_AXIS_TRIGGERRIGHT,
- SDL_CONTROLLER_AXIS_MAX
-} SDL_GameControllerAxis;
-SDL_GameControllerAxis SDL_GameControllerGetAxisFromString(const char *pchString);
-const char* SDL_GameControllerGetStringForAxis(SDL_GameControllerAxis axis);
-SDL_GameControllerButtonBind
-SDL_GameControllerGetBindForAxis(SDL_GameController *gamecontroller,
- SDL_GameControllerAxis axis);
-Sint16
-SDL_GameControllerGetAxis(SDL_GameController *gamecontroller,
- SDL_GameControllerAxis axis);
-typedef enum
-{
- SDL_CONTROLLER_BUTTON_INVALID = -1,
- SDL_CONTROLLER_BUTTON_A,
- SDL_CONTROLLER_BUTTON_B,
- SDL_CONTROLLER_BUTTON_X,
- SDL_CONTROLLER_BUTTON_Y,
- SDL_CONTROLLER_BUTTON_BACK,
- SDL_CONTROLLER_BUTTON_GUIDE,
- SDL_CONTROLLER_BUTTON_START,
- SDL_CONTROLLER_BUTTON_LEFTSTICK,
- SDL_CONTROLLER_BUTTON_RIGHTSTICK,
- SDL_CONTROLLER_BUTTON_LEFTSHOULDER,
- SDL_CONTROLLER_BUTTON_RIGHTSHOULDER,
- SDL_CONTROLLER_BUTTON_DPAD_UP,
- SDL_CONTROLLER_BUTTON_DPAD_DOWN,
- SDL_CONTROLLER_BUTTON_DPAD_LEFT,
- SDL_CONTROLLER_BUTTON_DPAD_RIGHT,
- SDL_CONTROLLER_BUTTON_MAX
-} SDL_GameControllerButton;
-SDL_GameControllerButton SDL_GameControllerGetButtonFromString(const char *pchString);
-const char* SDL_GameControllerGetStringForButton(SDL_GameControllerButton button);
-SDL_GameControllerButtonBind
-SDL_GameControllerGetBindForButton(SDL_GameController *gamecontroller,
- SDL_GameControllerButton button);
-Uint8 SDL_GameControllerGetButton(SDL_GameController *gamecontroller,
- SDL_GameControllerButton button);
-int SDL_GameControllerRumble(SDL_GameController *gamecontroller, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms);
-void SDL_GameControllerClose(SDL_GameController *gamecontroller);
-typedef Sint64 SDL_TouchID;
-typedef Sint64 SDL_FingerID;
-typedef enum
-{
- SDL_TOUCH_DEVICE_INVALID = -1,
- SDL_TOUCH_DEVICE_DIRECT,
- SDL_TOUCH_DEVICE_INDIRECT_ABSOLUTE,
- SDL_TOUCH_DEVICE_INDIRECT_RELATIVE,
-} SDL_TouchDeviceType;
-typedef struct SDL_Finger
-{
- SDL_FingerID id;
- float x;
- float y;
- float pressure;
-} SDL_Finger;
-int SDL_GetNumTouchDevices(void);
-SDL_TouchID SDL_GetTouchDevice(int index);
-SDL_TouchDeviceType SDL_GetTouchDeviceType(SDL_TouchID touchID);
-int SDL_GetNumTouchFingers(SDL_TouchID touchID);
-SDL_Finger * SDL_GetTouchFinger(SDL_TouchID touchID, int index);
-typedef Sint64 SDL_GestureID;
-int SDL_RecordGesture(SDL_TouchID touchId);
-int SDL_SaveAllDollarTemplates(SDL_RWops *dst);
-int SDL_SaveDollarTemplate(SDL_GestureID gestureId,SDL_RWops *dst);
-int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src);
-typedef enum
-{
- SDL_FIRSTEVENT = 0,
- SDL_QUIT = 0x100,
- SDL_APP_TERMINATING,
- SDL_APP_LOWMEMORY,
- SDL_APP_WILLENTERBACKGROUND,
- SDL_APP_DIDENTERBACKGROUND,
- SDL_APP_WILLENTERFOREGROUND,
- SDL_APP_DIDENTERFOREGROUND,
- SDL_DISPLAYEVENT = 0x150,
- SDL_WINDOWEVENT = 0x200,
- SDL_SYSWMEVENT,
- SDL_KEYDOWN = 0x300,
- SDL_KEYUP,
- SDL_TEXTEDITING,
- SDL_TEXTINPUT,
- SDL_KEYMAPCHANGED,
- SDL_MOUSEMOTION = 0x400,
- SDL_MOUSEBUTTONDOWN,
- SDL_MOUSEBUTTONUP,
- SDL_MOUSEWHEEL,
- SDL_JOYAXISMOTION = 0x600,
- SDL_JOYBALLMOTION,
- SDL_JOYHATMOTION,
- SDL_JOYBUTTONDOWN,
- SDL_JOYBUTTONUP,
- SDL_JOYDEVICEADDED,
- SDL_JOYDEVICEREMOVED,
- SDL_CONTROLLERAXISMOTION = 0x650,
- SDL_CONTROLLERBUTTONDOWN,
- SDL_CONTROLLERBUTTONUP,
- SDL_CONTROLLERDEVICEADDED,
- SDL_CONTROLLERDEVICEREMOVED,
- SDL_CONTROLLERDEVICEREMAPPED,
- SDL_FINGERDOWN = 0x700,
- SDL_FINGERUP,
- SDL_FINGERMOTION,
- SDL_DOLLARGESTURE = 0x800,
- SDL_DOLLARRECORD,
- SDL_MULTIGESTURE,
- SDL_CLIPBOARDUPDATE = 0x900,
- SDL_DROPFILE = 0x1000,
- SDL_DROPTEXT,
- SDL_DROPBEGIN,
- SDL_DROPCOMPLETE,
- SDL_AUDIODEVICEADDED = 0x1100,
- SDL_AUDIODEVICEREMOVED,
- SDL_SENSORUPDATE = 0x1200,
- SDL_RENDER_TARGETS_RESET = 0x2000,
- SDL_RENDER_DEVICE_RESET,
- SDL_USEREVENT = 0x8000,
- SDL_LASTEVENT = 0xFFFF
-} SDL_EventType;
-typedef struct SDL_CommonEvent
-{
- Uint32 type;
- Uint32 timestamp;
-} SDL_CommonEvent;
-typedef struct SDL_DisplayEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Uint32 display;
- Uint8 event;
- Uint8 padding1;
- Uint8 padding2;
- Uint8 padding3;
- Sint32 data1;
-} SDL_DisplayEvent;
-typedef struct SDL_WindowEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Uint32 windowID;
- Uint8 event;
- Uint8 padding1;
- Uint8 padding2;
- Uint8 padding3;
- Sint32 data1;
- Sint32 data2;
-} SDL_WindowEvent;
-typedef struct SDL_KeyboardEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Uint32 windowID;
- Uint8 state;
- Uint8 repeat;
- Uint8 padding2;
- Uint8 padding3;
- SDL_Keysym keysym;
-} SDL_KeyboardEvent;
-typedef struct SDL_TextEditingEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Uint32 windowID;
- char text[(32)];
- Sint32 start;
- Sint32 length;
-} SDL_TextEditingEvent;
-typedef struct SDL_TextInputEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Uint32 windowID;
- char text[(32)];
-} SDL_TextInputEvent;
-typedef struct SDL_MouseMotionEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Uint32 windowID;
- Uint32 which;
- Uint32 state;
- Sint32 x;
- Sint32 y;
- Sint32 xrel;
- Sint32 yrel;
-} SDL_MouseMotionEvent;
-typedef struct SDL_MouseButtonEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Uint32 windowID;
- Uint32 which;
- Uint8 button;
- Uint8 state;
- Uint8 clicks;
- Uint8 padding1;
- Sint32 x;
- Sint32 y;
-} SDL_MouseButtonEvent;
-typedef struct SDL_MouseWheelEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Uint32 windowID;
- Uint32 which;
- Sint32 x;
- Sint32 y;
- Uint32 direction;
-} SDL_MouseWheelEvent;
-typedef struct SDL_JoyAxisEvent
-{
- Uint32 type;
- Uint32 timestamp;
- SDL_JoystickID which;
- Uint8 axis;
- Uint8 padding1;
- Uint8 padding2;
- Uint8 padding3;
- Sint16 value;
- Uint16 padding4;
-} SDL_JoyAxisEvent;
-typedef struct SDL_JoyBallEvent
-{
- Uint32 type;
- Uint32 timestamp;
- SDL_JoystickID which;
- Uint8 ball;
- Uint8 padding1;
- Uint8 padding2;
- Uint8 padding3;
- Sint16 xrel;
- Sint16 yrel;
-} SDL_JoyBallEvent;
-typedef struct SDL_JoyHatEvent
-{
- Uint32 type;
- Uint32 timestamp;
- SDL_JoystickID which;
- Uint8 hat;
- Uint8 value;
- Uint8 padding1;
- Uint8 padding2;
-} SDL_JoyHatEvent;
-typedef struct SDL_JoyButtonEvent
-{
- Uint32 type;
- Uint32 timestamp;
- SDL_JoystickID which;
- Uint8 button;
- Uint8 state;
- Uint8 padding1;
- Uint8 padding2;
-} SDL_JoyButtonEvent;
-typedef struct SDL_JoyDeviceEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Sint32 which;
-} SDL_JoyDeviceEvent;
-typedef struct SDL_ControllerAxisEvent
-{
- Uint32 type;
- Uint32 timestamp;
- SDL_JoystickID which;
- Uint8 axis;
- Uint8 padding1;
- Uint8 padding2;
- Uint8 padding3;
- Sint16 value;
- Uint16 padding4;
-} SDL_ControllerAxisEvent;
-typedef struct SDL_ControllerButtonEvent
-{
- Uint32 type;
- Uint32 timestamp;
- SDL_JoystickID which;
- Uint8 button;
- Uint8 state;
- Uint8 padding1;
- Uint8 padding2;
-} SDL_ControllerButtonEvent;
-typedef struct SDL_ControllerDeviceEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Sint32 which;
-} SDL_ControllerDeviceEvent;
-typedef struct SDL_AudioDeviceEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Uint32 which;
- Uint8 iscapture;
- Uint8 padding1;
- Uint8 padding2;
- Uint8 padding3;
-} SDL_AudioDeviceEvent;
-typedef struct SDL_TouchFingerEvent
-{
- Uint32 type;
- Uint32 timestamp;
- SDL_TouchID touchId;
- SDL_FingerID fingerId;
- float x;
- float y;
- float dx;
- float dy;
- float pressure;
-} SDL_TouchFingerEvent;
-typedef struct SDL_MultiGestureEvent
-{
- Uint32 type;
- Uint32 timestamp;
- SDL_TouchID touchId;
- float dTheta;
- float dDist;
- float x;
- float y;
- Uint16 numFingers;
- Uint16 padding;
-} SDL_MultiGestureEvent;
-typedef struct SDL_DollarGestureEvent
-{
- Uint32 type;
- Uint32 timestamp;
- SDL_TouchID touchId;
- SDL_GestureID gestureId;
- Uint32 numFingers;
- float error;
- float x;
- float y;
-} SDL_DollarGestureEvent;
-typedef struct SDL_DropEvent
-{
- Uint32 type;
- Uint32 timestamp;
- char *file;
- Uint32 windowID;
-} SDL_DropEvent;
-typedef struct SDL_SensorEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Sint32 which;
- float data[6];
-} SDL_SensorEvent;
-typedef struct SDL_QuitEvent
-{
- Uint32 type;
- Uint32 timestamp;
-} SDL_QuitEvent;
-typedef struct SDL_OSEvent
-{
- Uint32 type;
- Uint32 timestamp;
-} SDL_OSEvent;
-typedef struct SDL_UserEvent
-{
- Uint32 type;
- Uint32 timestamp;
- Uint32 windowID;
- Sint32 code;
- void *data1;
- void *data2;
-} SDL_UserEvent;
-struct SDL_SysWMmsg;
-typedef struct SDL_SysWMmsg SDL_SysWMmsg;
-typedef struct SDL_SysWMEvent
-{
- Uint32 type;
- Uint32 timestamp;
- SDL_SysWMmsg *msg;
-} SDL_SysWMEvent;
-typedef union SDL_Event
-{
- Uint32 type;
- SDL_CommonEvent common;
- SDL_DisplayEvent display;
- SDL_WindowEvent window;
- SDL_KeyboardEvent key;
- SDL_TextEditingEvent edit;
- SDL_TextInputEvent text;
- SDL_MouseMotionEvent motion;
- SDL_MouseButtonEvent button;
- SDL_MouseWheelEvent wheel;
- SDL_JoyAxisEvent jaxis;
- SDL_JoyBallEvent jball;
- SDL_JoyHatEvent jhat;
- SDL_JoyButtonEvent jbutton;
- SDL_JoyDeviceEvent jdevice;
- SDL_ControllerAxisEvent caxis;
- SDL_ControllerButtonEvent cbutton;
- SDL_ControllerDeviceEvent cdevice;
- SDL_AudioDeviceEvent adevice;
- SDL_SensorEvent sensor;
- SDL_QuitEvent quit;
- SDL_UserEvent user;
- SDL_SysWMEvent syswm;
- SDL_TouchFingerEvent tfinger;
- SDL_MultiGestureEvent mgesture;
- SDL_DollarGestureEvent dgesture;
- SDL_DropEvent drop;
- Uint8 padding[56];
-} SDL_Event;
-void SDL_PumpEvents(void);
-typedef enum
-{
- SDL_ADDEVENT,
- SDL_PEEKEVENT,
- SDL_GETEVENT
-} SDL_eventaction;
-int SDL_PeepEvents(SDL_Event * events, int numevents,
- SDL_eventaction action,
- Uint32 minType, Uint32 maxType);
-SDL_bool SDL_HasEvent(Uint32 type);
-SDL_bool SDL_HasEvents(Uint32 minType, Uint32 maxType);
-void SDL_FlushEvent(Uint32 type);
-void SDL_FlushEvents(Uint32 minType, Uint32 maxType);
-int SDL_PollEvent(SDL_Event * event);
-int SDL_WaitEvent(SDL_Event * event);
-int SDL_WaitEventTimeout(SDL_Event * event,
- int timeout);
-int SDL_PushEvent(SDL_Event * event);
-typedef int ( * SDL_EventFilter) (void *userdata, SDL_Event * event);
-void SDL_SetEventFilter(SDL_EventFilter filter,
- void *userdata);
-SDL_bool SDL_GetEventFilter(SDL_EventFilter * filter,
- void **userdata);
-void SDL_AddEventWatch(SDL_EventFilter filter,
- void *userdata);
-void SDL_DelEventWatch(SDL_EventFilter filter,
- void *userdata);
-void SDL_FilterEvents(SDL_EventFilter filter,
- void *userdata);
-Uint8 SDL_EventState(Uint32 type, int state);
-Uint32 SDL_RegisterEvents(int numevents);
-char * SDL_GetBasePath(void);
-char * SDL_GetPrefPath(const char *org, const char *app);
-struct _SDL_Haptic;
-typedef struct _SDL_Haptic SDL_Haptic;
-typedef struct SDL_HapticDirection
-{
- Uint8 type;
- Sint32 dir[3];
-} SDL_HapticDirection;
-typedef struct SDL_HapticConstant
-{
- Uint16 type;
- SDL_HapticDirection direction;
- Uint32 length;
- Uint16 delay;
- Uint16 button;
- Uint16 interval;
- Sint16 level;
- Uint16 attack_length;
- Uint16 attack_level;
- Uint16 fade_length;
- Uint16 fade_level;
-} SDL_HapticConstant;
-typedef struct SDL_HapticPeriodic
-{
- Uint16 type;
- SDL_HapticDirection direction;
- Uint32 length;
- Uint16 delay;
- Uint16 button;
- Uint16 interval;
- Uint16 period;
- Sint16 magnitude;
- Sint16 offset;
- Uint16 phase;
- Uint16 attack_length;
- Uint16 attack_level;
- Uint16 fade_length;
- Uint16 fade_level;
-} SDL_HapticPeriodic;
-typedef struct SDL_HapticCondition
-{
- Uint16 type;
- SDL_HapticDirection direction;
- Uint32 length;
- Uint16 delay;
- Uint16 button;
- Uint16 interval;
- Uint16 right_sat[3];
- Uint16 left_sat[3];
- Sint16 right_coeff[3];
- Sint16 left_coeff[3];
- Uint16 deadband[3];
- Sint16 center[3];
-} SDL_HapticCondition;
-typedef struct SDL_HapticRamp
-{
- Uint16 type;
- SDL_HapticDirection direction;
- Uint32 length;
- Uint16 delay;
- Uint16 button;
- Uint16 interval;
- Sint16 start;
- Sint16 end;
- Uint16 attack_length;
- Uint16 attack_level;
- Uint16 fade_length;
- Uint16 fade_level;
-} SDL_HapticRamp;
-typedef struct SDL_HapticLeftRight
-{
- Uint16 type;
- Uint32 length;
- Uint16 large_magnitude;
- Uint16 small_magnitude;
-} SDL_HapticLeftRight;
-typedef struct SDL_HapticCustom
-{
- Uint16 type;
- SDL_HapticDirection direction;
- Uint32 length;
- Uint16 delay;
- Uint16 button;
- Uint16 interval;
- Uint8 channels;
- Uint16 period;
- Uint16 samples;
- Uint16 *data;
- Uint16 attack_length;
- Uint16 attack_level;
- Uint16 fade_length;
- Uint16 fade_level;
-} SDL_HapticCustom;
-typedef union SDL_HapticEffect
-{
- Uint16 type;
- SDL_HapticConstant constant;
- SDL_HapticPeriodic periodic;
- SDL_HapticCondition condition;
- SDL_HapticRamp ramp;
- SDL_HapticLeftRight leftright;
- SDL_HapticCustom custom;
-} SDL_HapticEffect;
-int SDL_NumHaptics(void);
-const char * SDL_HapticName(int device_index);
-SDL_Haptic * SDL_HapticOpen(int device_index);
-int SDL_HapticOpened(int device_index);
-int SDL_HapticIndex(SDL_Haptic * haptic);
-int SDL_MouseIsHaptic(void);
-SDL_Haptic * SDL_HapticOpenFromMouse(void);
-int SDL_JoystickIsHaptic(SDL_Joystick * joystick);
-SDL_Haptic * SDL_HapticOpenFromJoystick(SDL_Joystick *
- joystick);
-void SDL_HapticClose(SDL_Haptic * haptic);
-int SDL_HapticNumEffects(SDL_Haptic * haptic);
-int SDL_HapticNumEffectsPlaying(SDL_Haptic * haptic);
-unsigned int SDL_HapticQuery(SDL_Haptic * haptic);
-int SDL_HapticNumAxes(SDL_Haptic * haptic);
-int SDL_HapticEffectSupported(SDL_Haptic * haptic,
- SDL_HapticEffect *
- effect);
-int SDL_HapticNewEffect(SDL_Haptic * haptic,
- SDL_HapticEffect * effect);
-int SDL_HapticUpdateEffect(SDL_Haptic * haptic,
- int effect,
- SDL_HapticEffect * data);
-int SDL_HapticRunEffect(SDL_Haptic * haptic,
- int effect,
- Uint32 iterations);
-int SDL_HapticStopEffect(SDL_Haptic * haptic,
- int effect);
-void SDL_HapticDestroyEffect(SDL_Haptic * haptic,
- int effect);
-int SDL_HapticGetEffectStatus(SDL_Haptic * haptic,
- int effect);
-int SDL_HapticSetGain(SDL_Haptic * haptic, int gain);
-int SDL_HapticSetAutocenter(SDL_Haptic * haptic,
- int autocenter);
-int SDL_HapticPause(SDL_Haptic * haptic);
-int SDL_HapticUnpause(SDL_Haptic * haptic);
-int SDL_HapticStopAll(SDL_Haptic * haptic);
-int SDL_HapticRumbleSupported(SDL_Haptic * haptic);
-int SDL_HapticRumbleInit(SDL_Haptic * haptic);
-int SDL_HapticRumblePlay(SDL_Haptic * haptic, float strength, Uint32 length );
-int SDL_HapticRumbleStop(SDL_Haptic * haptic);
-typedef enum
-{
- SDL_HINT_DEFAULT,
- SDL_HINT_NORMAL,
- SDL_HINT_OVERRIDE
-} SDL_HintPriority;
-SDL_bool SDL_SetHintWithPriority(const char *name,
- const char *value,
- SDL_HintPriority priority);
-SDL_bool SDL_SetHint(const char *name,
- const char *value);
-const char * SDL_GetHint(const char *name);
-SDL_bool SDL_GetHintBoolean(const char *name, SDL_bool default_value);
-typedef void ( *SDL_HintCallback)(void *userdata, const char *name, const char *oldValue, const char *newValue);
-void SDL_AddHintCallback(const char *name,
- SDL_HintCallback callback,
- void *userdata);
-void SDL_DelHintCallback(const char *name,
- SDL_HintCallback callback,
- void *userdata);
-void SDL_ClearHints(void);
-void * SDL_LoadObject(const char *sofile);
-void * SDL_LoadFunction(void *handle,
- const char *name);
-void SDL_UnloadObject(void *handle);
-enum
-{
- SDL_LOG_CATEGORY_APPLICATION,
- SDL_LOG_CATEGORY_ERROR,
- SDL_LOG_CATEGORY_ASSERT,
- SDL_LOG_CATEGORY_SYSTEM,
- SDL_LOG_CATEGORY_AUDIO,
- SDL_LOG_CATEGORY_VIDEO,
- SDL_LOG_CATEGORY_RENDER,
- SDL_LOG_CATEGORY_INPUT,
- SDL_LOG_CATEGORY_TEST,
- SDL_LOG_CATEGORY_RESERVED1,
- SDL_LOG_CATEGORY_RESERVED2,
- SDL_LOG_CATEGORY_RESERVED3,
- SDL_LOG_CATEGORY_RESERVED4,
- SDL_LOG_CATEGORY_RESERVED5,
- SDL_LOG_CATEGORY_RESERVED6,
- SDL_LOG_CATEGORY_RESERVED7,
- SDL_LOG_CATEGORY_RESERVED8,
- SDL_LOG_CATEGORY_RESERVED9,
- SDL_LOG_CATEGORY_RESERVED10,
- SDL_LOG_CATEGORY_CUSTOM
-};
-typedef enum
-{
- SDL_LOG_PRIORITY_VERBOSE = 1,
- SDL_LOG_PRIORITY_DEBUG,
- SDL_LOG_PRIORITY_INFO,
- SDL_LOG_PRIORITY_WARN,
- SDL_LOG_PRIORITY_ERROR,
- SDL_LOG_PRIORITY_CRITICAL,
- SDL_NUM_LOG_PRIORITIES
-} SDL_LogPriority;
-void SDL_LogSetAllPriority(SDL_LogPriority priority);
-void SDL_LogSetPriority(int category,
- SDL_LogPriority priority);
-SDL_LogPriority SDL_LogGetPriority(int category);
-void SDL_LogResetPriorities(void);
-void SDL_Log( const char *fmt, ...) __attribute__ (( format( __printf__, 1, 1 +1 )));
-void SDL_LogVerbose(int category, const char *fmt, ...) __attribute__ (( format( __printf__, 2, 2 +1 )));
-void SDL_LogDebug(int category, const char *fmt, ...) __attribute__ (( format( __printf__, 2, 2 +1 )));
-void SDL_LogInfo(int category, const char *fmt, ...) __attribute__ (( format( __printf__, 2, 2 +1 )));
-void SDL_LogWarn(int category, const char *fmt, ...) __attribute__ (( format( __printf__, 2, 2 +1 )));
-void SDL_LogError(int category, const char *fmt, ...) __attribute__ (( format( __printf__, 2, 2 +1 )));
-void SDL_LogCritical(int category, const char *fmt, ...) __attribute__ (( format( __printf__, 2, 2 +1 )));
-void SDL_LogMessage(int category,
- SDL_LogPriority priority,
- const char *fmt, ...) __attribute__ (( format( __printf__, 3, 3 +1 )));
-void SDL_LogMessageV(int category,
- SDL_LogPriority priority,
- const char *fmt, va_list ap);
-typedef void ( *SDL_LogOutputFunction)(void *userdata, int category, SDL_LogPriority priority, const char *message);
-void SDL_LogGetOutputFunction(SDL_LogOutputFunction *callback, void **userdata);
-void SDL_LogSetOutputFunction(SDL_LogOutputFunction callback, void *userdata);
-typedef enum
-{
- SDL_MESSAGEBOX_ERROR = 0x00000010,
- SDL_MESSAGEBOX_WARNING = 0x00000020,
- SDL_MESSAGEBOX_INFORMATION = 0x00000040
-} SDL_MessageBoxFlags;
-typedef enum
-{
- SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT = 0x00000001,
- SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT = 0x00000002
-} SDL_MessageBoxButtonFlags;
-typedef struct
-{
- Uint32 flags;
- int buttonid;
- const char * text;
-} SDL_MessageBoxButtonData;
-typedef struct
-{
- Uint8 r, g, b;
-} SDL_MessageBoxColor;
-typedef enum
-{
- SDL_MESSAGEBOX_COLOR_BACKGROUND,
- SDL_MESSAGEBOX_COLOR_TEXT,
- SDL_MESSAGEBOX_COLOR_BUTTON_BORDER,
- SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND,
- SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED,
- SDL_MESSAGEBOX_COLOR_MAX
-} SDL_MessageBoxColorType;
-typedef struct
-{
- SDL_MessageBoxColor colors[SDL_MESSAGEBOX_COLOR_MAX];
-} SDL_MessageBoxColorScheme;
-typedef struct
-{
- Uint32 flags;
- SDL_Window *window;
- const char *title;
- const char *message;
- int numbuttons;
- const SDL_MessageBoxButtonData *buttons;
- const SDL_MessageBoxColorScheme *colorScheme;
-} SDL_MessageBoxData;
-int SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
-int SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window);
-typedef enum
-{
- SDL_POWERSTATE_UNKNOWN,
- SDL_POWERSTATE_ON_BATTERY,
- SDL_POWERSTATE_NO_BATTERY,
- SDL_POWERSTATE_CHARGING,
- SDL_POWERSTATE_CHARGED
-} SDL_PowerState;
-SDL_PowerState SDL_GetPowerInfo(int *secs, int *pct);
-typedef enum
-{
- SDL_RENDERER_SOFTWARE = 0x00000001,
- SDL_RENDERER_ACCELERATED = 0x00000002,
- SDL_RENDERER_PRESENTVSYNC = 0x00000004,
- SDL_RENDERER_TARGETTEXTURE = 0x00000008
-} SDL_RendererFlags;
-typedef struct SDL_RendererInfo
-{
- const char *name;
- Uint32 flags;
- Uint32 num_texture_formats;
- Uint32 texture_formats[16];
- int max_texture_width;
- int max_texture_height;
-} SDL_RendererInfo;
-typedef enum
-{
- SDL_TEXTUREACCESS_STATIC,
- SDL_TEXTUREACCESS_STREAMING,
- SDL_TEXTUREACCESS_TARGET
-} SDL_TextureAccess;
-typedef enum
-{
- SDL_TEXTUREMODULATE_NONE = 0x00000000,
- SDL_TEXTUREMODULATE_COLOR = 0x00000001,
- SDL_TEXTUREMODULATE_ALPHA = 0x00000002
-} SDL_TextureModulate;
-typedef enum
-{
- SDL_FLIP_NONE = 0x00000000,
- SDL_FLIP_HORIZONTAL = 0x00000001,
- SDL_FLIP_VERTICAL = 0x00000002
-} SDL_RendererFlip;
-struct SDL_Renderer;
-typedef struct SDL_Renderer SDL_Renderer;
-struct SDL_Texture;
-typedef struct SDL_Texture SDL_Texture;
-int SDL_GetNumRenderDrivers(void);
-int SDL_GetRenderDriverInfo(int index,
- SDL_RendererInfo * info);
-int SDL_CreateWindowAndRenderer(
- int width, int height, Uint32 window_flags,
- SDL_Window **window, SDL_Renderer **renderer);
-SDL_Renderer * SDL_CreateRenderer(SDL_Window * window,
- int index, Uint32 flags);
-SDL_Renderer * SDL_CreateSoftwareRenderer(SDL_Surface * surface);
-SDL_Renderer * SDL_GetRenderer(SDL_Window * window);
-int SDL_GetRendererInfo(SDL_Renderer * renderer,
- SDL_RendererInfo * info);
-int SDL_GetRendererOutputSize(SDL_Renderer * renderer,
- int *w, int *h);
-SDL_Texture * SDL_CreateTexture(SDL_Renderer * renderer,
- Uint32 format,
- int access, int w,
- int h);
-SDL_Texture * SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface);
-int SDL_QueryTexture(SDL_Texture * texture,
- Uint32 * format, int *access,
- int *w, int *h);
-int SDL_SetTextureColorMod(SDL_Texture * texture,
- Uint8 r, Uint8 g, Uint8 b);
-int SDL_GetTextureColorMod(SDL_Texture * texture,
- Uint8 * r, Uint8 * g,
- Uint8 * b);
-int SDL_SetTextureAlphaMod(SDL_Texture * texture,
- Uint8 alpha);
-int SDL_GetTextureAlphaMod(SDL_Texture * texture,
- Uint8 * alpha);
-int SDL_SetTextureBlendMode(SDL_Texture * texture,
- SDL_BlendMode blendMode);
-int SDL_GetTextureBlendMode(SDL_Texture * texture,
- SDL_BlendMode *blendMode);
-int SDL_UpdateTexture(SDL_Texture * texture,
- const SDL_Rect * rect,
- const void *pixels, int pitch);
-int SDL_UpdateYUVTexture(SDL_Texture * texture,
- const SDL_Rect * rect,
- const Uint8 *Yplane, int Ypitch,
- const Uint8 *Uplane, int Upitch,
- const Uint8 *Vplane, int Vpitch);
-int SDL_LockTexture(SDL_Texture * texture,
- const SDL_Rect * rect,
- void **pixels, int *pitch);
-void SDL_UnlockTexture(SDL_Texture * texture);
-SDL_bool SDL_RenderTargetSupported(SDL_Renderer *renderer);
-int SDL_SetRenderTarget(SDL_Renderer *renderer,
- SDL_Texture *texture);
-SDL_Texture * SDL_GetRenderTarget(SDL_Renderer *renderer);
-int SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h);
-void SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h);
-int SDL_RenderSetIntegerScale(SDL_Renderer * renderer,
- SDL_bool enable);
-SDL_bool SDL_RenderGetIntegerScale(SDL_Renderer * renderer);
-int SDL_RenderSetViewport(SDL_Renderer * renderer,
- const SDL_Rect * rect);
-void SDL_RenderGetViewport(SDL_Renderer * renderer,
- SDL_Rect * rect);
-int SDL_RenderSetClipRect(SDL_Renderer * renderer,
- const SDL_Rect * rect);
-void SDL_RenderGetClipRect(SDL_Renderer * renderer,
- SDL_Rect * rect);
-SDL_bool SDL_RenderIsClipEnabled(SDL_Renderer * renderer);
-int SDL_RenderSetScale(SDL_Renderer * renderer,
- float scaleX, float scaleY);
-void SDL_RenderGetScale(SDL_Renderer * renderer,
- float *scaleX, float *scaleY);
-int SDL_SetRenderDrawColor(SDL_Renderer * renderer,
- Uint8 r, Uint8 g, Uint8 b,
- Uint8 a);
-int SDL_GetRenderDrawColor(SDL_Renderer * renderer,
- Uint8 * r, Uint8 * g, Uint8 * b,
- Uint8 * a);
-int SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer,
- SDL_BlendMode blendMode);
-int SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer,
- SDL_BlendMode *blendMode);
-int SDL_RenderClear(SDL_Renderer * renderer);
-int SDL_RenderDrawPoint(SDL_Renderer * renderer,
- int x, int y);
-int SDL_RenderDrawPoints(SDL_Renderer * renderer,
- const SDL_Point * points,
- int count);
-int SDL_RenderDrawLine(SDL_Renderer * renderer,
- int x1, int y1, int x2, int y2);
-int SDL_RenderDrawLines(SDL_Renderer * renderer,
- const SDL_Point * points,
- int count);
-int SDL_RenderDrawRect(SDL_Renderer * renderer,
- const SDL_Rect * rect);
-int SDL_RenderDrawRects(SDL_Renderer * renderer,
- const SDL_Rect * rects,
- int count);
-int SDL_RenderFillRect(SDL_Renderer * renderer,
- const SDL_Rect * rect);
-int SDL_RenderFillRects(SDL_Renderer * renderer,
- const SDL_Rect * rects,
- int count);
-int SDL_RenderCopy(SDL_Renderer * renderer,
- SDL_Texture * texture,
- const SDL_Rect * srcrect,
- const SDL_Rect * dstrect);
-int SDL_RenderCopyEx(SDL_Renderer * renderer,
- SDL_Texture * texture,
- const SDL_Rect * srcrect,
- const SDL_Rect * dstrect,
- const double angle,
- const SDL_Point *center,
- const SDL_RendererFlip flip);
-int SDL_RenderDrawPointF(SDL_Renderer * renderer,
- float x, float y);
-int SDL_RenderDrawPointsF(SDL_Renderer * renderer,
- const SDL_FPoint * points,
- int count);
-int SDL_RenderDrawLineF(SDL_Renderer * renderer,
- float x1, float y1, float x2, float y2);
-int SDL_RenderDrawLinesF(SDL_Renderer * renderer,
- const SDL_FPoint * points,
- int count);
-int SDL_RenderDrawRectF(SDL_Renderer * renderer,
- const SDL_FRect * rect);
-int SDL_RenderDrawRectsF(SDL_Renderer * renderer,
- const SDL_FRect * rects,
- int count);
-int SDL_RenderFillRectF(SDL_Renderer * renderer,
- const SDL_FRect * rect);
-int SDL_RenderFillRectsF(SDL_Renderer * renderer,
- const SDL_FRect * rects,
- int count);
-int SDL_RenderCopyF(SDL_Renderer * renderer,
- SDL_Texture * texture,
- const SDL_Rect * srcrect,
- const SDL_FRect * dstrect);
-int SDL_RenderCopyExF(SDL_Renderer * renderer,
- SDL_Texture * texture,
- const SDL_Rect * srcrect,
- const SDL_FRect * dstrect,
- const double angle,
- const SDL_FPoint *center,
- const SDL_RendererFlip flip);
-int SDL_RenderReadPixels(SDL_Renderer * renderer,
- const SDL_Rect * rect,
- Uint32 format,
- void *pixels, int pitch);
-void SDL_RenderPresent(SDL_Renderer * renderer);
-void SDL_DestroyTexture(SDL_Texture * texture);
-void SDL_DestroyRenderer(SDL_Renderer * renderer);
-int SDL_RenderFlush(SDL_Renderer * renderer);
-int SDL_GL_BindTexture(SDL_Texture *texture, float *texw, float *texh);
-int SDL_GL_UnbindTexture(SDL_Texture *texture);
-void * SDL_RenderGetMetalLayer(SDL_Renderer * renderer);
-void * SDL_RenderGetMetalCommandEncoder(SDL_Renderer * renderer);
-struct _SDL_Sensor;
-typedef struct _SDL_Sensor SDL_Sensor;
-typedef Sint32 SDL_SensorID;
-typedef enum
-{
- SDL_SENSOR_INVALID = -1,
- SDL_SENSOR_UNKNOWN,
- SDL_SENSOR_ACCEL,
- SDL_SENSOR_GYRO
-} SDL_SensorType;
-int SDL_NumSensors(void);
-const char * SDL_SensorGetDeviceName(int device_index);
-SDL_SensorType SDL_SensorGetDeviceType(int device_index);
-int SDL_SensorGetDeviceNonPortableType(int device_index);
-SDL_SensorID SDL_SensorGetDeviceInstanceID(int device_index);
-SDL_Sensor * SDL_SensorOpen(int device_index);
-SDL_Sensor * SDL_SensorFromInstanceID(SDL_SensorID instance_id);
-const char * SDL_SensorGetName(SDL_Sensor *sensor);
-SDL_SensorType SDL_SensorGetType(SDL_Sensor *sensor);
-int SDL_SensorGetNonPortableType(SDL_Sensor *sensor);
-SDL_SensorID SDL_SensorGetInstanceID(SDL_Sensor *sensor);
-int SDL_SensorGetData(SDL_Sensor * sensor, float *data, int num_values);
-void SDL_SensorClose(SDL_Sensor * sensor);
-void SDL_SensorUpdate(void);
-SDL_Window * SDL_CreateShapedWindow(const char *title,unsigned int x,unsigned int y,unsigned int w,unsigned int h,Uint32 flags);
-SDL_bool SDL_IsShapedWindow(const SDL_Window *window);
-typedef enum {
- ShapeModeDefault,
- ShapeModeBinarizeAlpha,
- ShapeModeReverseBinarizeAlpha,
- ShapeModeColorKey
-} WindowShapeMode;
-typedef union {
- Uint8 binarizationCutoff;
- SDL_Color colorKey;
-} SDL_WindowShapeParams;
-typedef struct SDL_WindowShapeMode {
- WindowShapeMode mode;
- SDL_WindowShapeParams parameters;
-} SDL_WindowShapeMode;
-int SDL_SetWindowShape(SDL_Window *window,SDL_Surface *shape,SDL_WindowShapeMode *shape_mode);
-int SDL_GetShapedWindowMode(SDL_Window *window,SDL_WindowShapeMode *shape_mode);
-typedef void ( * SDL_WindowsMessageHook)(void *userdata, void *hWnd, unsigned int message, Uint64 wParam, Sint64 lParam);
-void SDL_SetWindowsMessageHook(SDL_WindowsMessageHook callback, void *userdata);
-int SDL_Direct3D9GetAdapterIndex( int displayIndex );
-typedef struct IDirect3DDevice9 IDirect3DDevice9;
-IDirect3DDevice9* SDL_RenderGetD3D9Device(SDL_Renderer * renderer);
-SDL_bool SDL_DXGIGetOutputInfo( int displayIndex, int *adapterIndex, int *outputIndex );
-SDL_bool SDL_IsTablet(void);
-Uint32 SDL_GetTicks(void);
-Uint64 SDL_GetPerformanceCounter(void);
-Uint64 SDL_GetPerformanceFrequency(void);
-void SDL_Delay(Uint32 ms);
-typedef Uint32 ( * SDL_TimerCallback) (Uint32 interval, void *param);
-typedef int SDL_TimerID;
-SDL_TimerID SDL_AddTimer(Uint32 interval,
- SDL_TimerCallback callback,
- void *param);
-SDL_bool SDL_RemoveTimer(SDL_TimerID id);
-typedef struct SDL_version
-{
- Uint8 major;
- Uint8 minor;
- Uint8 patch;
-} SDL_version;
-void SDL_GetVersion(SDL_version * ver);
-const char * SDL_GetRevision(void);
-int SDL_GetRevisionNumber(void);
-int SDL_Init(Uint32 flags);
-int SDL_InitSubSystem(Uint32 flags);
-void SDL_QuitSubSystem(Uint32 flags);
-Uint32 SDL_WasInit(Uint32 flags);
-void SDL_Quit(void);]]
-ffi.cdef[[static const int SDL_AUDIO_DRIVER_WASAPI = 1;
-static const int SDL_AUDIO_DRIVER_DSOUND = 1;
-static const int SDL_AUDIO_DRIVER_WINMM = 1;
-static const int SDL_AUDIO_DRIVER_DISK = 1;
-static const int SDL_AUDIO_DRIVER_DUMMY = 1;
-static const int SDL_JOYSTICK_DINPUT = 1;
-static const int SDL_JOYSTICK_XINPUT = 1;
-static const int SDL_JOYSTICK_HIDAPI = 1;
-static const int SDL_HAPTIC_DINPUT = 1;
-static const int SDL_HAPTIC_XINPUT = 1;
-static const int SDL_SENSOR_DUMMY = 1;
-static const int SDL_LOADSO_WINDOWS = 1;
-static const int SDL_THREAD_WINDOWS = 1;
-static const int SDL_TIMER_WINDOWS = 1;
-static const int SDL_VIDEO_DRIVER_DUMMY = 1;
-static const int SDL_VIDEO_DRIVER_WINDOWS = 1;
-static const int SDL_VIDEO_RENDER_D3D = 1;
-static const int SDL_VIDEO_RENDER_D3D11 = 0;
-static const int SDL_VIDEO_OPENGL = 1;
-static const int SDL_VIDEO_OPENGL_WGL = 1;
-static const int SDL_VIDEO_RENDER_OGL = 1;
-static const int SDL_VIDEO_RENDER_OGL_ES2 = 1;
-static const int SDL_VIDEO_OPENGL_ES2 = 1;
-static const int SDL_VIDEO_OPENGL_EGL = 1;
-static const int SDL_VIDEO_VULKAN = 1;
-static const int SDL_POWER_WINDOWS = 1;
-static const int SDL_FILESYSTEM_WINDOWS = 1;
-static const int SDL_ASSEMBLY_ROUTINES = 1;
-static const int SDL_MAX_SINT8 = ((Sint8)0x7F);
-static const int SDL_MIN_SINT8 = ((Sint8)(~0x7F));
-static const int SDL_MAX_UINT8 = ((Uint8)0xFF);
-static const int SDL_MIN_UINT8 = ((Uint8)0x00);
-static const int SDL_MAX_SINT16 = ((Sint16)0x7FFF);
-static const int SDL_MIN_SINT16 = ((Sint16)(~0x7FFF));
-static const int SDL_MAX_UINT16 = ((Uint16)0xFFFF);
-static const int SDL_MIN_UINT16 = ((Uint16)0x0000);
-static const int SDL_MAX_SINT32 = ((Sint32)0x7FFFFFFF);
-static const int SDL_MIN_SINT32 = ((Sint32)(~0x7FFFFFFF));
-static const int SDL_MAX_UINT32 = ((Uint32)0xFFFFFFFFu);
-static const int SDL_MIN_UINT32 = ((Uint32)0x00000000);
-static const int SDL_PRIs64 = "I64d";
-static const int SDL_PRIu64 = "I64u";
-static const int SDL_PRIx64 = "I64x";
-static const int SDL_PRIX64 = "I64X";
-static const int SDL_ICONV_ERROR = (size_t)-1;
-static const int SDL_ICONV_E2BIG = (size_t)-2;
-static const int SDL_ICONV_EILSEQ = (size_t)-3;
-static const int SDL_ICONV_EINVAL = (size_t)-4;
-static const int SDL_ASSERT_LEVEL = 2;
-static const int SDL_NULL_WHILE_LOOP_CONDITION = (0);
-static const int SDL_LIL_ENDIAN = 1234;
-static const int SDL_BIG_ENDIAN = 4321;
-static const int SDL_BYTEORDER = SDL_LIL_ENDIAN;
-static const int SDL_MUTEX_TIMEDOUT = 1;
-static const int SDL_MUTEX_MAXWAIT = (~(Uint32)0);
-static const int SDL_RWOPS_UNKNOWN = 0U;
-static const int SDL_RWOPS_WINFILE = 1U;
-static const int SDL_RWOPS_STDFILE = 2U;
-static const int SDL_RWOPS_JNIFILE = 3U;
-static const int SDL_RWOPS_MEMORY = 4U;
-static const int SDL_RWOPS_MEMORY_RO = 5U;
-static const int RW_SEEK_SET = 0;
-static const int RW_SEEK_CUR = 1;
-static const int RW_SEEK_END = 2;
-static const int SDL_AUDIO_MASK_BITSIZE = (0xFF);
-static const int SDL_AUDIO_MASK_DATATYPE = (1<<8);
-static const int SDL_AUDIO_MASK_ENDIAN = (1<<12);
-static const int SDL_AUDIO_MASK_SIGNED = (1<<15);
-static const int AUDIO_U8 = 0x0008;
-static const int AUDIO_S8 = 0x8008;
-static const int AUDIO_U16LSB = 0x0010;
-static const int AUDIO_S16LSB = 0x8010;
-static const int AUDIO_U16MSB = 0x1010;
-static const int AUDIO_S16MSB = 0x9010;
-static const int AUDIO_U16 = AUDIO_U16LSB;
-static const int AUDIO_S16 = AUDIO_S16LSB;
-static const int AUDIO_S32LSB = 0x8020;
-static const int AUDIO_S32MSB = 0x9020;
-static const int AUDIO_S32 = AUDIO_S32LSB;
-static const int AUDIO_F32LSB = 0x8120;
-static const int AUDIO_F32MSB = 0x9120;
-static const int AUDIO_F32 = AUDIO_F32LSB;
-static const int AUDIO_U16SYS = AUDIO_U16LSB;
-static const int AUDIO_S16SYS = AUDIO_S16LSB;
-static const int AUDIO_S32SYS = AUDIO_S32LSB;
-static const int AUDIO_F32SYS = AUDIO_F32LSB;
-static const int SDL_AUDIO_ALLOW_FREQUENCY_CHANGE = 0x00000001;
-static const int SDL_AUDIO_ALLOW_FORMAT_CHANGE = 0x00000002;
-static const int SDL_AUDIO_ALLOW_CHANNELS_CHANGE = 0x00000004;
-static const int SDL_AUDIO_ALLOW_SAMPLES_CHANGE = 0x00000008;
-static const int SDL_AUDIO_ALLOW_ANY_CHANGE = (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_CHANNELS_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE);
-static const int SDL_AUDIOCVT_MAX_FILTERS = 9;
-static const int SDL_MIX_MAXVOLUME = 128;
-static const int SDL_CACHELINE_SIZE = 128;
-static const int SDL_ALPHA_OPAQUE = 255;
-static const int SDL_ALPHA_TRANSPARENT = 0;
-static const int SDL_SWSURFACE = 0;
-static const int SDL_PREALLOC = 0x00000001;
-static const int SDL_RLEACCEL = 0x00000002;
-static const int SDL_DONTFREE = 0x00000004;
-static const int SDL_BlitSurface = SDL_UpperBlit;
-static const int SDL_BlitScaled = SDL_UpperBlitScaled;
-static const int SDL_WINDOWPOS_UNDEFINED_MASK = 0x1FFF0000u;
-static const int SDL_WINDOWPOS_CENTERED_MASK = 0x2FFF0000u;
-static const int SDLK_SCANCODE_MASK = (1<<30);
-static const int KMOD_CTRL = (KMOD_LCTRL|KMOD_RCTRL);
-static const int KMOD_SHIFT = (KMOD_LSHIFT|KMOD_RSHIFT);
-static const int KMOD_ALT = (KMOD_LALT|KMOD_RALT);
-static const int KMOD_GUI = (KMOD_LGUI|KMOD_RGUI);
-static const int SDL_BUTTON_LEFT = 1;
-static const int SDL_BUTTON_MIDDLE = 2;
-static const int SDL_BUTTON_RIGHT = 3;
-static const int SDL_BUTTON_X1 = 4;
-static const int SDL_BUTTON_X2 = 5;
-static const int SDL_JOYSTICK_AXIS_MAX = 32767;
-static const int SDL_JOYSTICK_AXIS_MIN = -32768;
-static const int SDL_HAT_CENTERED = 0x00;
-static const int SDL_HAT_UP = 0x01;
-static const int SDL_HAT_RIGHT = 0x02;
-static const int SDL_HAT_DOWN = 0x04;
-static const int SDL_HAT_LEFT = 0x08;
-static const int SDL_HAT_RIGHTUP = (SDL_HAT_RIGHT|SDL_HAT_UP);
-static const int SDL_HAT_RIGHTDOWN = (SDL_HAT_RIGHT|SDL_HAT_DOWN);
-static const int SDL_HAT_LEFTUP = (SDL_HAT_LEFT|SDL_HAT_UP);
-static const int SDL_HAT_LEFTDOWN = (SDL_HAT_LEFT|SDL_HAT_DOWN);
-static const int SDL_TOUCH_MOUSEID = ((Uint32)-1);
-static const int SDL_RELEASED = 0;
-static const int SDL_PRESSED = 1;
-static const int SDL_TEXTEDITINGEVENT_TEXT_SIZE = (32);
-static const int SDL_TEXTINPUTEVENT_TEXT_SIZE = (32);
-static const int SDL_QUERY = -1;
-static const int SDL_IGNORE = 0;
-static const int SDL_DISABLE = 0;
-static const int SDL_ENABLE = 1;
-static const int SDL_HAPTIC_CONSTANT = (1u<<0);
-static const int SDL_HAPTIC_SINE = (1u<<1);
-static const int SDL_HAPTIC_LEFTRIGHT = (1u<<2);
-static const int SDL_HAPTIC_TRIANGLE = (1u<<3);
-static const int SDL_HAPTIC_SAWTOOTHUP = (1u<<4);
-static const int SDL_HAPTIC_SAWTOOTHDOWN = (1u<<5);
-static const int SDL_HAPTIC_RAMP = (1u<<6);
-static const int SDL_HAPTIC_SPRING = (1u<<7);
-static const int SDL_HAPTIC_DAMPER = (1u<<8);
-static const int SDL_HAPTIC_INERTIA = (1u<<9);
-static const int SDL_HAPTIC_FRICTION = (1u<<10);
-static const int SDL_HAPTIC_CUSTOM = (1u<<11);
-static const int SDL_HAPTIC_GAIN = (1u<<12);
-static const int SDL_HAPTIC_AUTOCENTER = (1u<<13);
-static const int SDL_HAPTIC_STATUS = (1u<<14);
-static const int SDL_HAPTIC_PAUSE = (1u<<15);
-static const int SDL_HAPTIC_POLAR = 0;
-static const int SDL_HAPTIC_CARTESIAN = 1;
-static const int SDL_HAPTIC_SPHERICAL = 2;
-static const int SDL_HAPTIC_INFINITY = 4294967295U;
-static const int SDL_HINT_FRAMEBUFFER_ACCELERATION = "SDL_FRAMEBUFFER_ACCELERATION";
-static const int SDL_HINT_RENDER_DRIVER = "SDL_RENDER_DRIVER";
-static const int SDL_HINT_RENDER_OPENGL_SHADERS = "SDL_RENDER_OPENGL_SHADERS";
-static const int SDL_HINT_RENDER_DIRECT3D_THREADSAFE = "SDL_RENDER_DIRECT3D_THREADSAFE";
-static const int SDL_HINT_RENDER_DIRECT3D11_DEBUG = "SDL_RENDER_DIRECT3D11_DEBUG";
-static const int SDL_HINT_RENDER_LOGICAL_SIZE_MODE = "SDL_RENDER_LOGICAL_SIZE_MODE";
-static const int SDL_HINT_RENDER_SCALE_QUALITY = "SDL_RENDER_SCALE_QUALITY";
-static const int SDL_HINT_RENDER_VSYNC = "SDL_RENDER_VSYNC";
-static const int SDL_HINT_VIDEO_ALLOW_SCREENSAVER = "SDL_VIDEO_ALLOW_SCREENSAVER";
-static const int SDL_HINT_VIDEO_X11_XVIDMODE = "SDL_VIDEO_X11_XVIDMODE";
-static const int SDL_HINT_VIDEO_X11_XINERAMA = "SDL_VIDEO_X11_XINERAMA";
-static const int SDL_HINT_VIDEO_X11_XRANDR = "SDL_VIDEO_X11_XRANDR";
-static const int SDL_HINT_VIDEO_X11_NET_WM_PING = "SDL_VIDEO_X11_NET_WM_PING";
-static const int SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR = "SDL_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR";
-static const int SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN = "SDL_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN";
-static const int SDL_HINT_WINDOWS_INTRESOURCE_ICON = "SDL_WINDOWS_INTRESOURCE_ICON";
-static const int SDL_HINT_WINDOWS_INTRESOURCE_ICON_SMALL = "SDL_WINDOWS_INTRESOURCE_ICON_SMALL";
-static const int SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP = "SDL_WINDOWS_ENABLE_MESSAGELOOP";
-static const int SDL_HINT_GRAB_KEYBOARD = "SDL_GRAB_KEYBOARD";
-static const int SDL_HINT_MOUSE_DOUBLE_CLICK_TIME = "SDL_MOUSE_DOUBLE_CLICK_TIME";
-static const int SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS = "SDL_MOUSE_DOUBLE_CLICK_RADIUS";
-static const int SDL_HINT_MOUSE_NORMAL_SPEED_SCALE = "SDL_MOUSE_NORMAL_SPEED_SCALE";
-static const int SDL_HINT_MOUSE_RELATIVE_SPEED_SCALE = "SDL_MOUSE_RELATIVE_SPEED_SCALE";
-static const int SDL_HINT_MOUSE_RELATIVE_MODE_WARP = "SDL_MOUSE_RELATIVE_MODE_WARP";
-static const int SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH = "SDL_MOUSE_FOCUS_CLICKTHROUGH";
-static const int SDL_HINT_TOUCH_MOUSE_EVENTS = "SDL_TOUCH_MOUSE_EVENTS";
-static const int SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS = "SDL_VIDEO_MINIMIZE_ON_FOCUS_LOSS";
-static const int SDL_HINT_IDLE_TIMER_DISABLED = "SDL_IOS_IDLE_TIMER_DISABLED";
-static const int SDL_HINT_ORIENTATIONS = "SDL_IOS_ORIENTATIONS";
-static const int SDL_HINT_APPLE_TV_CONTROLLER_UI_EVENTS = "SDL_APPLE_TV_CONTROLLER_UI_EVENTS";
-static const int SDL_HINT_APPLE_TV_REMOTE_ALLOW_ROTATION = "SDL_APPLE_TV_REMOTE_ALLOW_ROTATION";
-static const int SDL_HINT_IOS_HIDE_HOME_INDICATOR = "SDL_IOS_HIDE_HOME_INDICATOR";
-static const int SDL_HINT_ACCELEROMETER_AS_JOYSTICK = "SDL_ACCELEROMETER_AS_JOYSTICK";
-static const int SDL_HINT_TV_REMOTE_AS_JOYSTICK = "SDL_TV_REMOTE_AS_JOYSTICK";
-static const int SDL_HINT_XINPUT_ENABLED = "SDL_XINPUT_ENABLED";
-static const int SDL_HINT_XINPUT_USE_OLD_JOYSTICK_MAPPING = "SDL_XINPUT_USE_OLD_JOYSTICK_MAPPING";
-static const int SDL_HINT_GAMECONTROLLERCONFIG = "SDL_GAMECONTROLLERCONFIG";
-static const int SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES = "SDL_GAMECONTROLLER_IGNORE_DEVICES";
-static const int SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT = "SDL_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT";
-static const int SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS = "SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS";
-static const int SDL_HINT_JOYSTICK_HIDAPI = "SDL_JOYSTICK_HIDAPI";
-static const int SDL_HINT_JOYSTICK_HIDAPI_PS4 = "SDL_JOYSTICK_HIDAPI_PS4";
-static const int SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE = "SDL_JOYSTICK_HIDAPI_PS4_RUMBLE";
-static const int SDL_HINT_JOYSTICK_HIDAPI_STEAM = "SDL_JOYSTICK_HIDAPI_STEAM";
-static const int SDL_HINT_JOYSTICK_HIDAPI_SWITCH = "SDL_JOYSTICK_HIDAPI_SWITCH";
-static const int SDL_HINT_JOYSTICK_HIDAPI_XBOX = "SDL_JOYSTICK_HIDAPI_XBOX";
-static const int SDL_HINT_ENABLE_STEAM_CONTROLLERS = "SDL_ENABLE_STEAM_CONTROLLERS";
-static const int SDL_HINT_ALLOW_TOPMOST = "SDL_ALLOW_TOPMOST";
-static const int SDL_HINT_TIMER_RESOLUTION = "SDL_TIMER_RESOLUTION";
-static const int SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION = "SDL_QTWAYLAND_CONTENT_ORIENTATION";
-static const int SDL_HINT_QTWAYLAND_WINDOW_FLAGS = "SDL_QTWAYLAND_WINDOW_FLAGS";
-static const int SDL_HINT_THREAD_STACK_SIZE = "SDL_THREAD_STACK_SIZE";
-static const int SDL_HINT_VIDEO_HIGHDPI_DISABLED = "SDL_VIDEO_HIGHDPI_DISABLED";
-static const int SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK = "SDL_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK";
-static const int SDL_HINT_VIDEO_WIN_D3DCOMPILER = "SDL_VIDEO_WIN_D3DCOMPILER";
-static const int SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT = "SDL_VIDEO_WINDOW_SHARE_PIXEL_FORMAT";
-static const int SDL_HINT_WINRT_PRIVACY_POLICY_URL = "SDL_WINRT_PRIVACY_POLICY_URL";
-static const int SDL_HINT_WINRT_PRIVACY_POLICY_LABEL = "SDL_WINRT_PRIVACY_POLICY_LABEL";
-static const int SDL_HINT_WINRT_HANDLE_BACK_BUTTON = "SDL_WINRT_HANDLE_BACK_BUTTON";
-static const int SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES = "SDL_VIDEO_MAC_FULLSCREEN_SPACES";
-static const int SDL_HINT_MAC_BACKGROUND_APP = "SDL_MAC_BACKGROUND_APP";
-static const int SDL_HINT_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION = "SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION";
-static const int SDL_HINT_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION = "SDL_ANDROID_APK_EXPANSION_PATCH_FILE_VERSION";
-static const int SDL_HINT_IME_INTERNAL_EDITING = "SDL_IME_INTERNAL_EDITING";
-static const int SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH = "SDL_ANDROID_SEPARATE_MOUSE_AND_TOUCH";
-static const int SDL_HINT_ANDROID_TRAP_BACK_BUTTON = "SDL_ANDROID_TRAP_BACK_BUTTON";
-static const int SDL_HINT_RETURN_KEY_HIDES_IME = "SDL_RETURN_KEY_HIDES_IME";
-static const int SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT = "SDL_EMSCRIPTEN_KEYBOARD_ELEMENT";
-static const int SDL_HINT_NO_SIGNAL_HANDLERS = "SDL_NO_SIGNAL_HANDLERS";
-static const int SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4 = "SDL_WINDOWS_NO_CLOSE_ON_ALT_F4";
-static const int SDL_HINT_BMP_SAVE_LEGACY_FORMAT = "SDL_BMP_SAVE_LEGACY_FORMAT";
-static const int SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING = "SDL_WINDOWS_DISABLE_THREAD_NAMING";
-static const int SDL_HINT_RPI_VIDEO_LAYER = "SDL_RPI_VIDEO_LAYER";
-static const int SDL_HINT_VIDEO_DOUBLE_BUFFER = "SDL_VIDEO_DOUBLE_BUFFER";
-static const int SDL_HINT_OPENGL_ES_DRIVER = "SDL_OPENGL_ES_DRIVER";
-static const int SDL_HINT_AUDIO_RESAMPLING_MODE = "SDL_AUDIO_RESAMPLING_MODE";
-static const int SDL_HINT_AUDIO_CATEGORY = "SDL_AUDIO_CATEGORY";
-static const int SDL_HINT_RENDER_BATCHING = "SDL_RENDER_BATCHING";
-static const int SDL_MAX_LOG_MESSAGE = 4096;
-static const int SDL_NONSHAPEABLE_WINDOW = -1;
-static const int SDL_INVALID_SHAPE_ARGUMENT = -2;
-static const int SDL_WINDOW_LACKS_SHAPE = -3;
-static const int SDL_MAJOR_VERSION = 2;
-static const int SDL_MINOR_VERSION = 0;
-static const int SDL_PATCHLEVEL = 9;
-static const int SDL_INIT_TIMER = 0x00000001u;
-static const int SDL_INIT_AUDIO = 0x00000010u;
-static const int SDL_INIT_VIDEO = 0x00000020u;
-static const int SDL_INIT_JOYSTICK = 0x00000200u;
-static const int SDL_INIT_HAPTIC = 0x00001000u;
-static const int SDL_INIT_GAMECONTROLLER = 0x00002000u;
-static const int SDL_INIT_EVENTS = 0x00004000u;
-static const int SDL_INIT_SENSOR = 0x00008000u;
-static const int SDL_INIT_NOPARACHUTE = 0x00100000u;]]
-ffi.cdef[[static const int SDL_WINDOWPOS_CENTERED = SDL_WINDOWPOS_CENTERED_MASK
-]]
-local lib = ffi.load"SDL2"
-
-local M = {C=lib}
-
-function M.loadBMP(file)
- return M.loadBMP_RW(M.RWFromFile(file, 'rb'), 1)
-end
-function M.loadWAV(file, spec, audio_buf, audio_len)
- return M.loadWAV_RW(M.RWFromFile(file, "rb"), 1, spec, audio_buf, audio_len)
-end
-function M.saveBMP(surface, file)
- return M.saveBMP_RW(surface, M.RWFromFile(file, 'wb'), 1)
-end
-
-local callback_t
-local callbacks_anchor = {}
-function M.MakeAudioCallback(func)
- if not callback_t then
- local CallbackFactory = require "lj-async.callback"
- callback_t = CallbackFactory("void(*)(void*,uint8_t*,int)") --"SDL_AudioCallback"
- end
- local cb = callback_t(func)
- table.insert(callbacks_anchor,cb)
- return cb:funcptr()
-end
-local threadfunc_t
-function M.MakeThreadFunc(func)
- if not threadfunc_t then
- local CallbackFactory = require "lj-async.callback"
- threadfunc_t = CallbackFactory("int(*)(void*)")
- end
- local cb = threadfunc_t(func)
- table.insert(callbacks_anchor,cb)
- return cb:funcptr()
-end
-
-setmetatable(M,{
-__index = function(t,k)
- local str2 = "SDL_"..string.upper(k:sub(1,1))..k:sub(2)
- local ok,ptr = pcall(function(str) return lib[str] end,str2)
- if not ok then ok,ptr = pcall(function(str) return lib[str] end,k) end
- if not ok then error(k.." not found") end
- rawset(M, k, ptr)
- return ptr
-end
-})
-
-
-
-return M
\ No newline at end of file
diff --git a/lib/sha1/bit32_ops.lua b/lib/sha1/bit32_ops.lua
deleted file mode 100644
index 344b0f3..0000000
--- a/lib/sha1/bit32_ops.lua
+++ /dev/null
@@ -1,24 +0,0 @@
-local bit32 = require "bit32"
-
-local ops = {}
-
-local band = bit32.band
-local bor = bit32.bor
-local bxor = bit32.bxor
-
-ops.uint32_lrot = bit32.lrotate
-ops.byte_xor = bxor
-ops.uint32_xor_3 = bxor
-ops.uint32_xor_4 = bxor
-
-function ops.uint32_ternary(a, b, c)
- -- c ~ (a & (b ~ c)) has less bitwise operations than (a & b) | (~a & c).
- return bxor(c, band(a, bxor(b, c)))
-end
-
-function ops.uint32_majority(a, b, c)
- -- (a & (b | c)) | (b & c) has less bitwise operations than (a & b) | (a & c) | (b & c).
- return bor(band(a, bor(b, c)), band(b, c))
-end
-
-return ops
diff --git a/lib/sha1/bit_ops.lua b/lib/sha1/bit_ops.lua
deleted file mode 100644
index 5fbaf05..0000000
--- a/lib/sha1/bit_ops.lua
+++ /dev/null
@@ -1,24 +0,0 @@
-local bit = require "bit"
-
-local ops = {}
-
-local band = bit.band
-local bor = bit.bor
-local bxor = bit.bxor
-
-ops.uint32_lrot = bit.rol
-ops.byte_xor = bxor
-ops.uint32_xor_3 = bxor
-ops.uint32_xor_4 = bxor
-
-function ops.uint32_ternary(a, b, c)
- -- c ~ (a & (b ~ c)) has less bitwise operations than (a & b) | (~a & c).
- return bxor(c, band(a, bxor(b, c)))
-end
-
-function ops.uint32_majority(a, b, c)
- -- (a & (b | c)) | (b & c) has less bitwise operations than (a & b) | (a & c) | (b & c).
- return bor(band(a, bor(b, c)), band(b, c))
-end
-
-return ops
diff --git a/lib/sha1/common.lua b/lib/sha1/common.lua
deleted file mode 100644
index c31ffef..0000000
--- a/lib/sha1/common.lua
+++ /dev/null
@@ -1,20 +0,0 @@
-local common = {}
-
--- Merges four bytes into a uint32 number.
-function common.bytes_to_uint32(a, b, c, d)
- return a * 0x1000000 + b * 0x10000 + c * 0x100 + d
-end
-
--- Splits a uint32 number into four bytes.
-function common.uint32_to_bytes(a)
- local a4 = a % 256
- a = (a - a4) / 256
- local a3 = a % 256
- a = (a - a3) / 256
- local a2 = a % 256
- local a1 = (a - a2) / 256
- return a1, a2, a3, a4
-end
-
-
-return common
diff --git a/lib/sha1/init.lua b/lib/sha1/init.lua
deleted file mode 100644
index 57839de..0000000
--- a/lib/sha1/init.lua
+++ /dev/null
@@ -1,195 +0,0 @@
-local common = require "sha1.common"
-
-local sha1 = {
- -- Meta fields retained for compatibility.
- _VERSION = "sha.lua 0.6.0",
- _URL = "https://github.com/mpeterv/sha1",
- _DESCRIPTION = [[
-SHA-1 secure hash and HMAC-SHA1 signature computation in Lua,
-using bit and bit32 modules and Lua 5.3 operators when available
-and falling back to a pure Lua implementation on Lua 5.1.
-Based on code orignally by Jeffrey Friedl and modified by
-Eike Decker and Enrique García Cota.]],
- _LICENSE = [[
-MIT LICENSE
-
-Copyright (c) 2013 Enrique García Cota, Eike Decker, Jeffrey Friedl
-Copyright (c) 2018 Peter Melnichenko
-
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.]]
-}
-
-sha1.version = "0.6.0"
-
-local function choose_ops()
- if _VERSION:find("5%.3") then
- return "lua53_ops"
- elseif pcall(require, "bit") then
- return "bit_ops"
- elseif pcall(require, "bit32") then
- return "bit32_ops"
- else
- return "pure_lua_ops"
- end
-end
-
-local ops = require("sha1." .. choose_ops())
-local uint32_lrot = ops.uint32_lrot
-local byte_xor = ops.byte_xor
-local uint32_xor_3 = ops.uint32_xor_3
-local uint32_xor_4 = ops.uint32_xor_4
-local uint32_ternary = ops.uint32_ternary
-local uint32_majority = ops.uint32_majority
-
-local bytes_to_uint32 = common.bytes_to_uint32
-local uint32_to_bytes = common.uint32_to_bytes
-
-local sbyte = string.byte
-local schar = string.char
-local sformat = string.format
-local srep = string.rep
-
-local function hex_to_binary(hex)
- return (hex:gsub("..", function(hexval)
- return schar(tonumber(hexval, 16))
- end))
-end
-
--- Calculates SHA1 for a string, returns it encoded as 40 hexadecimal digits.
-function sha1.sha1(str)
- -- Input preprocessing.
- -- First, append a `1` bit and seven `0` bits.
- local first_append = schar(0x80)
-
- -- Next, append some zero bytes to make the length of the final message a multiple of 64.
- -- Eight more bytes will be added next.
- local non_zero_message_bytes = #str + 1 + 8
- local second_append = srep(schar(0), -non_zero_message_bytes % 64)
-
- -- Finally, append the length of the original message in bits as a 64-bit number.
- -- Assume that it fits into the lower 32 bits.
- local third_append = schar(0, 0, 0, 0, uint32_to_bytes(#str * 8))
-
- str = str .. first_append .. second_append .. third_append
- assert(#str % 64 == 0)
-
- -- Initialize hash value.
- local h0 = 0x67452301
- local h1 = 0xEFCDAB89
- local h2 = 0x98BADCFE
- local h3 = 0x10325476
- local h4 = 0xC3D2E1F0
-
- local w = {}
-
- -- Process the input in successive 64-byte chunks.
- for chunk_start = 1, #str, 64 do
- -- Load the chunk into W[0..15] as uint32 numbers.
- local uint32_start = chunk_start
-
- for i = 0, 15 do
- w[i] = bytes_to_uint32(sbyte(str, uint32_start, uint32_start + 3))
- uint32_start = uint32_start + 4
- end
-
- -- Extend the input vector.
- for i = 16, 79 do
- w[i] = uint32_lrot(uint32_xor_4(w[i - 3], w[i - 8], w[i - 14], w[i - 16]), 1)
- end
-
- -- Initialize hash value for this chunk.
- local a = h0
- local b = h1
- local c = h2
- local d = h3
- local e = h4
-
- -- Main loop.
- for i = 0, 79 do
- local f
- local k
-
- if i <= 19 then
- f = uint32_ternary(b, c, d)
- k = 0x5A827999
- elseif i <= 39 then
- f = uint32_xor_3(b, c, d)
- k = 0x6ED9EBA1
- elseif i <= 59 then
- f = uint32_majority(b, c, d)
- k = 0x8F1BBCDC
- else
- f = uint32_xor_3(b, c, d)
- k = 0xCA62C1D6
- end
-
- local temp = (uint32_lrot(a, 5) + f + e + k + w[i]) % 4294967296
- e = d
- d = c
- c = uint32_lrot(b, 30)
- b = a
- a = temp
- end
-
- -- Add this chunk's hash to result so far.
- h0 = (h0 + a) % 4294967296
- h1 = (h1 + b) % 4294967296
- h2 = (h2 + c) % 4294967296
- h3 = (h3 + d) % 4294967296
- h4 = (h4 + e) % 4294967296
- end
-
- return sformat("%08x%08x%08x%08x%08x", h0, h1, h2, h3, h4)
-end
-
-function sha1.binary(str)
- return hex_to_binary(sha1.sha1(str))
-end
-
--- Precalculate replacement tables.
-local xor_with_0x5c = {}
-local xor_with_0x36 = {}
-
-for i = 0, 0xff do
- xor_with_0x5c[schar(i)] = schar(byte_xor(0x5c, i))
- xor_with_0x36[schar(i)] = schar(byte_xor(0x36, i))
-end
-
--- 512 bits.
-local BLOCK_SIZE = 64
-
-function sha1.hmac(key, text)
- if #key > BLOCK_SIZE then
- key = sha1.binary(key)
- end
-
- local key_xord_with_0x36 = key:gsub('.', xor_with_0x36) .. srep(schar(0x36), BLOCK_SIZE - #key)
- local key_xord_with_0x5c = key:gsub('.', xor_with_0x5c) .. srep(schar(0x5c), BLOCK_SIZE - #key)
-
- return sha1.sha1(key_xord_with_0x5c .. sha1.binary(key_xord_with_0x36 .. text))
-end
-
-function sha1.hmac_binary(key, text)
- return hex_to_binary(sha1.hmac(key, text))
-end
-
-setmetatable(sha1, {__call = function(_, str) return sha1.sha1(str) end})
-
-return sha1
diff --git a/lib/sha1/lua53_ops.lua b/lib/sha1/lua53_ops.lua
deleted file mode 100644
index d5312e6..0000000
--- a/lib/sha1/lua53_ops.lua
+++ /dev/null
@@ -1,29 +0,0 @@
-local ops = {}
-
-function ops.uint32_lrot(a, bits)
- return ((a << bits) & 0xFFFFFFFF) | (a >> (32 - bits))
-end
-
-function ops.byte_xor(a, b)
- return a ~ b
-end
-
-function ops.uint32_xor_3(a, b, c)
- return a ~ b ~ c
-end
-
-function ops.uint32_xor_4(a, b, c, d)
- return a ~ b ~ c ~ d
-end
-
-function ops.uint32_ternary(a, b, c)
- -- c ~ (a & (b ~ c)) has less bitwise operations than (a & b) | (~a & c).
- return c ~ (a & (b ~ c))
-end
-
-function ops.uint32_majority(a, b, c)
- -- (a & (b | c)) | (b & c) has less bitwise operations than (a & b) | (a & c) | (b & c).
- return (a & (b | c)) | (b & c)
-end
-
-return ops
diff --git a/lib/sha1/pure_lua_ops.lua b/lib/sha1/pure_lua_ops.lua
deleted file mode 100644
index 7a645d0..0000000
--- a/lib/sha1/pure_lua_ops.lua
+++ /dev/null
@@ -1,144 +0,0 @@
-local common = require "sha1.common"
-
-local ops = {}
-
-local bytes_to_uint32 = common.bytes_to_uint32
-local uint32_to_bytes = common.uint32_to_bytes
-
-function ops.uint32_lrot(a, bits)
- local power = 2 ^ bits
- local inv_power = 4294967296 / power
- local lower_bits = a % inv_power
- return (lower_bits * power) + ((a - lower_bits) / inv_power)
-end
-
--- Build caches for bitwise `and` and `xor` over bytes to speed up uint32 operations.
--- Building the cache by simply applying these operators over all pairs is too slow and
--- duplicates a lot of work over different bits of inputs.
--- Instead, when building a cache over bytes, for each pair of bytes split both arguments
--- into two 4-bit numbers, calculate values over these two halves, then join the results into a byte again.
--- While there are 256 * 256 = 65536 pairs of bytes, there are only 16 * 16 = 256 pairs
--- of 4-bit numbers, so that building an 8-bit cache given a 4-bit cache is rather efficient.
--- The same logic is applied recursively to make a 4-bit cache from a 2-bit cache and a 2-bit
--- cache from a 1-bit cache, which is calculated given the 1-bit version of the operator.
-
--- Returns a cache containing all values of a bitwise operator over numbers with given number of bits,
--- given an operator over single bits.
--- Value of `op(a, b)` is stored in `cache[a * (2 ^ bits) + b]`.
-local function make_op_cache(bit_op, bits)
- if bits == 1 then
- return {[0] = bit_op(0, 0), bit_op(0, 1), bit_op(1, 0), bit_op(1, 1)}
- end
-
- local half_bits = bits / 2
- local size = 2 ^ bits
- local half_size = 2 ^ half_bits
- local half_cache = make_op_cache(bit_op, half_bits)
-
- local cache = {}
-
- -- The implementation used is an optimized version of the following reference one,
- -- with intermediate calculations reused and moved to the outermost loop possible.
- -- It's possible to reorder the loops and move the calculation of one of the
- -- half-results one level up, but then the cache is not filled in a proper array order
- -- and its access performance suffers.
-
- -- for a1 = 0, half_size - 1 do
- -- for a2 = 0, half_size - 1 do
- -- for b1 = 0, half_size - 1 do
- -- for b2 = 0, half_size - 1 do
- -- local a = a1 * half_size + a2
- -- local b = b1 * half_size + b2
- -- local v1 = half_cache[a1 * half_size + b1]
- -- local v2 = half_cache[a2 * half_size + b2]
- -- local v = v1 * half_size + v2
- -- cache[a * size + b] = v
- -- end
- -- end
- -- end
- -- end
-
- for a1 = 0, half_size - 1 do
- local a1_half_size = a1 * half_size
-
- for a2 = 0, half_size - 1 do
- local a2_size = a2 * half_size
- local a_size = (a1_half_size + a2) * size
-
- for b1 = 0, half_size - 1 do
- local a_size_plus_b1_half_size = a_size + b1 * half_size
- local v1_half_size = half_cache[a1_half_size + b1] * half_size
-
- for b2 = 0, half_size - 1 do
- cache[a_size_plus_b1_half_size + b2] = v1_half_size + half_cache[a2_size + b2]
- end
- end
- end
- end
-
- return cache
-end
-
-local byte_and_cache = make_op_cache(function(a, b) return a * b end, 8)
-local byte_xor_cache = make_op_cache(function(a, b) return a == b and 0 or 1 end, 8)
-
-function ops.byte_xor(a, b)
- return byte_xor_cache[a * 256 + b]
-end
-
-function ops.uint32_xor_3(a, b, c)
- local a1, a2, a3, a4 = uint32_to_bytes(a)
- local b1, b2, b3, b4 = uint32_to_bytes(b)
- local c1, c2, c3, c4 = uint32_to_bytes(c)
-
- return bytes_to_uint32(
- byte_xor_cache[a1 * 256 + byte_xor_cache[b1 * 256 + c1]],
- byte_xor_cache[a2 * 256 + byte_xor_cache[b2 * 256 + c2]],
- byte_xor_cache[a3 * 256 + byte_xor_cache[b3 * 256 + c3]],
- byte_xor_cache[a4 * 256 + byte_xor_cache[b4 * 256 + c4]]
- )
-end
-
-function ops.uint32_xor_4(a, b, c, d)
- local a1, a2, a3, a4 = uint32_to_bytes(a)
- local b1, b2, b3, b4 = uint32_to_bytes(b)
- local c1, c2, c3, c4 = uint32_to_bytes(c)
- local d1, d2, d3, d4 = uint32_to_bytes(d)
-
- return bytes_to_uint32(
- byte_xor_cache[a1 * 256 + byte_xor_cache[b1 * 256 + byte_xor_cache[c1 * 256 + d1]]],
- byte_xor_cache[a2 * 256 + byte_xor_cache[b2 * 256 + byte_xor_cache[c2 * 256 + d2]]],
- byte_xor_cache[a3 * 256 + byte_xor_cache[b3 * 256 + byte_xor_cache[c3 * 256 + d3]]],
- byte_xor_cache[a4 * 256 + byte_xor_cache[b4 * 256 + byte_xor_cache[c4 * 256 + d4]]]
- )
-end
-
-function ops.uint32_ternary(a, b, c)
- local a1, a2, a3, a4 = uint32_to_bytes(a)
- local b1, b2, b3, b4 = uint32_to_bytes(b)
- local c1, c2, c3, c4 = uint32_to_bytes(c)
-
- -- (a & b) + (~a & c) has less bitwise operations than (a & b) | (~a & c).
- return bytes_to_uint32(
- byte_and_cache[b1 * 256 + a1] + byte_and_cache[c1 * 256 + 255 - a1],
- byte_and_cache[b2 * 256 + a2] + byte_and_cache[c2 * 256 + 255 - a2],
- byte_and_cache[b3 * 256 + a3] + byte_and_cache[c3 * 256 + 255 - a3],
- byte_and_cache[b4 * 256 + a4] + byte_and_cache[c4 * 256 + 255 - a4]
- )
-end
-
-function ops.uint32_majority(a, b, c)
- local a1, a2, a3, a4 = uint32_to_bytes(a)
- local b1, b2, b3, b4 = uint32_to_bytes(b)
- local c1, c2, c3, c4 = uint32_to_bytes(c)
-
- -- (a & b) + (c & (a ~ b)) has less bitwise operations than (a & b) | (a & c) | (b & c).
- return bytes_to_uint32(
- byte_and_cache[a1 * 256 + b1] + byte_and_cache[c1 * 256 + byte_xor_cache[a1 * 256 + b1]],
- byte_and_cache[a2 * 256 + b2] + byte_and_cache[c2 * 256 + byte_xor_cache[a2 * 256 + b2]],
- byte_and_cache[a3 * 256 + b3] + byte_and_cache[c3 * 256 + byte_xor_cache[a3 * 256 + b3]],
- byte_and_cache[a4 * 256 + b4] + byte_and_cache[c4 * 256 + byte_xor_cache[a4 * 256 + b4]]
- )
-end
-
-return ops
diff --git a/lib/smallfolk.lua b/lib/smallfolk.lua
deleted file mode 100644
index acdc332..0000000
--- a/lib/smallfolk.lua
+++ /dev/null
@@ -1,213 +0,0 @@
-local M = {}
-local expect_object, dump_object
-local error, tostring, pairs, type, floor, huge, concat = error, tostring, pairs, type, math.floor, math.huge, table.concat
-
-local dump_type = {}
-
-function dump_type:string(nmemo, memo, acc)
- local nacc = #acc
- acc[nacc + 1] = "'"
- acc[nacc + 2] = self:gsub("'", "''")
- acc[nacc + 3] = "'"
- return nmemo
-end
-
-function dump_type:number(nmemo, memo, acc)
- acc[#acc + 1] = ("%.17g"):format(self)
- return nmemo
-end
-
-function dump_type:table(nmemo, memo, acc)
- if memo[self] then
- acc[#acc + 1] = '@'
- acc[#acc + 1] = tostring(memo[self])
- return nmemo
- end
- nmemo = nmemo + 1
- memo[self] = nmemo
- acc[#acc + 1] = '{'
- local nself = #self
- for i = 1, nself do -- don't use ipairs here, we need the gaps
- nmemo = dump_object(self[i], nmemo, memo, acc)
- acc[#acc + 1] = ','
- end
- for k, v in pairs(self) do
- if type(k) ~= 'number' or floor(k) ~= k or k < 1 or k > nself then
- nmemo = dump_object(k, nmemo, memo, acc)
- acc[#acc + 1] = ':'
- nmemo = dump_object(v, nmemo, memo, acc)
- acc[#acc + 1] = ','
- end
- end
- acc[#acc] = acc[#acc] == '{' and '{}' or '}'
- return nmemo
-end
-
-function dump_object(object, nmemo, memo, acc)
- if object == true then
- acc[#acc + 1] = 't'
- elseif object == false then
- acc[#acc + 1] = 'f'
- elseif object == nil then
- acc[#acc + 1] = 'n'
- elseif object ~= object then
- if (''..object):sub(1,1) == '-' then
- acc[#acc + 1] = 'N'
- else
- acc[#acc + 1] = 'Q'
- end
- elseif object == huge then
- acc[#acc + 1] = 'I'
- elseif object == -huge then
- acc[#acc + 1] = 'i'
- else
- local t = type(object)
- if not dump_type[t] then
- error('cannot dump type ' .. t)
- end
- return dump_type[t](object, nmemo, memo, acc)
- end
- return nmemo
-end
-
-function M.dumps(object)
- local nmemo = 0
- local memo = {}
- local acc = {}
- dump_object(object, nmemo, memo, acc)
- return concat(acc)
-end
-
-local function invalid(i)
- error('invalid input at position ' .. i)
-end
-
-local nonzero_digit = {['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true}
-local is_digit = {['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true}
-local function expect_number(string, start)
- local i = start
- local head = string:sub(i, i)
- if head == '-' then
- i = i + 1
- head = string:sub(i, i)
- end
- if nonzero_digit[head] then
- repeat
- i = i + 1
- head = string:sub(i, i)
- until not is_digit[head]
- elseif head == '0' then
- i = i + 1
- head = string:sub(i, i)
- else
- invalid(i)
- end
- if head == '.' then
- local oldi = i
- repeat
- i = i + 1
- head = string:sub(i, i)
- until not is_digit[head]
- if i == oldi + 1 then
- invalid(i)
- end
- end
- if head == 'e' or head == 'E' then
- i = i + 1
- head = string:sub(i, i)
- if head == '+' or head == '-' then
- i = i + 1
- head = string:sub(i, i)
- end
- if not is_digit[head] then
- invalid(i)
- end
- repeat
- i = i + 1
- head = string:sub(i, i)
- until not is_digit[head]
- end
- return tonumber(string:sub(start, i - 1)), i
-end
-
-local expect_object_head = {
- t = function(string, i) return true, i end,
- f = function(string, i) return false, i end,
- n = function(string, i) return nil, i end,
- Q = function(string, i) return -(0/0), i end,
- N = function(string, i) return 0/0, i end,
- I = function(string, i) return 1/0, i end,
- i = function(string, i) return -1/0, i end,
- ["'"] = function(string, i)
- local nexti = i - 1
- repeat
- nexti = string:find("'", nexti + 1, true) + 1
- until string:sub(nexti, nexti) ~= "'"
- return string:sub(i, nexti - 2):gsub("''", "'"), nexti
- end,
- ['0'] = function(string, i)
- return expect_number(string, i - 1)
- end,
- ['{'] = function(string, i, tables)
- local nt, k, v = {}
- local j = 1
- tables[#tables + 1] = nt
- if string:sub(i, i) == '}' then
- return nt, i + 1
- end
- while true do
- k, i = expect_object(string, i, tables)
- if string:sub(i, i) == ':' then
- v, i = expect_object(string, i + 1, tables)
- nt[k] = v
- else
- nt[j] = k
- j = j + 1
- end
- local head = string:sub(i, i)
- if head == ',' then
- i = i + 1
- elseif head == '}' then
- return nt, i + 1
- else
- invalid(i)
- end
- end
- end,
- ['@'] = function(string, i, tables)
- local match = string:match('^%d+', i)
- local ref = tonumber(match)
- if tables[ref] then
- return tables[ref], i + #match
- end
- invalid(i)
- end,
-}
-expect_object_head['1'] = expect_object_head['0']
-expect_object_head['2'] = expect_object_head['0']
-expect_object_head['3'] = expect_object_head['0']
-expect_object_head['4'] = expect_object_head['0']
-expect_object_head['5'] = expect_object_head['0']
-expect_object_head['6'] = expect_object_head['0']
-expect_object_head['7'] = expect_object_head['0']
-expect_object_head['8'] = expect_object_head['0']
-expect_object_head['9'] = expect_object_head['0']
-expect_object_head['-'] = expect_object_head['0']
-expect_object_head['.'] = expect_object_head['0']
-
-expect_object = function(string, i, tables)
- local head = string:sub(i, i)
- if expect_object_head[head] then
- return expect_object_head[head](string, i + 1, tables)
- end
- invalid(i)
-end
-
-function M.loads(string, maxsize)
- if #string > (maxsize or 10000) then
- error 'input too large'
- end
- return (expect_object(string, 1, {}))
-end
-
-return M
diff --git a/lib/steamutils.lua b/lib/steamutils.lua
deleted file mode 100644
index c20a2e2..0000000
--- a/lib/steamutils.lua
+++ /dev/null
@@ -1,1010 +0,0 @@
-steam_utils = {}
-
-unidecode = require('unicorndecode')
-
-username_cache = {}
-
-last_language = nil
-
-steam_utils.truncateNameStreaming = function(name, id)
- local name = name:sub(1, 1) .. "..."
-
- if lobby_code ~= nil and id ~= nil then
- local members = steam_utils.getLobbyMembersIDs(lobby_code, true)
- for i = 1, #members do
- if members[i] == id then
- name = "(" .. tostring(i) .. ")" .. name
- break
- end
- end
- end
-
- return name
-end
-
-
-steam_utils.getTranslatedPersonaName = function(steam_id, no_streamer_mode)
-
- if(steam_id == nil)then
- no_streamer_mode = true
- end
-
- local name = "Unknown"
- if(steam_id ~= nil and tonumber(tostring(steam_id)) ~= nil)then
-
- local language = GameTextGetTranslatedOrNot("$current_language")
-
- if (last_language ~= language) then
- username_cache = {}
- last_language = language
- end
-
- if(username_cache[steam_id] ~= nil)then
- name = username_cache[steam_id]
- goto continue
- end
-
- name = steam.friends.getFriendPersonaName(steam_id)
-
- local supported = check_string(name)
-
- if(not supported)then
- name = unidecode.decode(name)
- end
-
-
- if (name == nil or name == "") then
- name = "Unknown"
- goto continue
- end
-
- -- cache name
- username_cache[steam_id] = name
-
- ::continue::
- end
-
- -- truncate name after first letter if streamer mode is enabled
- if(ModSettingGet("evaisa.mp.streamer_mode") and not no_streamer_mode)then
- name = steam_utils.truncateNameStreaming(name, steam_id)
- end
-
-
-
- return name
-end
-
-steam_utils.getSteamFriends = function()
- local list = {}
- for i = 1, steam.friends.getFriendCount(0x04) do
- local h = steam.friends.getFriendByIndex(i - 1, 0x04)
-
- if(tonumber(tostring(h)) == nil)then
- goto continue
- end
-
- table.insert(list, { id = h, name = steam_utils.getTranslatedPersonaName(h) })
- ::continue::
- end
- return list
-end
-
-function color_split(abgr_int)
- local r = bit.band(abgr_int, 0x000000FF)
- local g = bit.band(abgr_int, 0x0000FF00)
- local b = bit.band(abgr_int, 0x00FF0000)
- local a = bit.band(abgr_int, 0xFF000000)
-
- g = bit.rshift(g, 8)
- b = bit.rshift(b, 16)
- a = bit.rshift(a, 24)
-
- return r,g,b,a
-end
-
-function color_merge(r,g,b,a)
- local abgr_int = 0
- abgr_int = bit.bor(abgr_int, r)
- abgr_int = bit.bor(abgr_int, bit.lshift(g, 8))
- abgr_int = bit.bor(abgr_int, bit.lshift(b, 16))
- abgr_int = bit.bor(abgr_int, bit.lshift(a, 24))
-
- return abgr_int
-end
-
-local steam_id = nil
-steam_utils.getSteamID = function()
- if (steam_id == nil) then
- steam_id = steam.user.getSteamID()
- end
- return steam_id
-end
-
-steam_utils.getNumLobbyMembers = function()
- return total_lobby_members
-end
-
---local lfs = require("lfs")
-local fs = require("fs")
-
--- clear avatar cache directory
-function clear_avatar_cache()
- local cache_folder = "data/evaisa.mp/cache/avatars/"
- -- create folder if it doesn't exist
- local path = ""
- for folder_name in cache_folder:gmatch("([^/]+)")do
- path = path .. folder_name
- fs.mkdir(path, true)
- path = path .. "/"
- end
-
- for file in fs.dir(cache_folder) do
- if(not file) then
- break
- end
- if (file ~= "." and file ~= "..") then
- print("Removing file: " .. file)
- local f = cache_folder .. file
- os.remove(f)
- end
- end
-end
-
-cached_avatars = cached_avatars or {}
-
-steam_utils.getUserAvatar = function(user_id)
-
- if(user_id == nil or ModSettingGet("evaisa.mp.streamer_mode"))then
- return "mods/evaisa.mp/files/gfx/ui/no_avatar.png"
- end
-
- if(cached_avatars[user_id] ~= nil)then
- return cached_avatars[user_id]
- end
-
- steam.friends.requestUserInformation(user_id, false)
-
- local handle = steam.friends.getSmallFriendAvatar(user_id)
- if(handle == nil)then
- cached_avatars[user_id] = "mods/evaisa.mp/files/gfx/ui/no_avatar.png"
- end
-
- local cache_folder = "data/evaisa.mp/cache/avatars/"
-
- local path = ""
- for folder_name in cache_folder:gmatch("([^/]+)")do
- path = path .. folder_name
- fs.mkdir(path, true)
- path = path .. "/"
- end
-
- local image_data = steam.utils.getImageData(handle)
- local width, height = steam.utils.getImageSize(handle)
-
- if(image_data == nil)then
- cached_avatars[user_id] = "mods/evaisa.mp/files/gfx/ui/no_avatar.png"
- return "mods/evaisa.mp/files/gfx/ui/no_avatar.png"
- end
-
- local path = cache_folder .. tostring(user_id) .. ".png"
-
- local png = pngencoder(width, height)
-
- for y = 1, height do
- for x = 1, width do
- local index = (y - 1) * width + x
- local pixel = image_data[index]
- local r, g, b, a = color_split(pixel)
-
- png:write { r, g, b }
- end
- end
-
- local data = table.concat(png.output)
-
- local file = io.open(path, "wb")
- file:write(data)
- file:close()
-
- cached_avatars[user_id] = path
-
- return path
-end
-
-lobby_members = lobby_members or {}
-lobby_members_no_spectators = lobby_members_no_spectators or {}
-was_streamer_mode = was_streamer_mode or false
-
-steam_utils.getLobbyMembers = function(lobby_id, include_spectators, update_cache)
- -- implement cache
-
- if(was_streamer_mode and not ModSettingGet("evaisa.mp.streamer_mode"))then
- update_cache = true
- was_streamer_mode = false
- elseif(not was_streamer_mode and ModSettingGet("evaisa.mp.streamer_mode"))then
- update_cache = true
- was_streamer_mode = true
- end
-
-
- if(not update_cache)then
- if(include_spectators and lobby_members[tostring(lobby_id)])then
- --print("Returning cached lobby members")
- return lobby_members[tostring(lobby_id)]
- elseif(not include_spectators and lobby_members_no_spectators[tostring(lobby_id)])then
- --print("Returning cached lobby members without spectators")
- return lobby_members_no_spectators[tostring(lobby_id)]
- end
- end
-
- lobby_members[tostring(lobby_id)] = {}
- lobby_members_no_spectators[tostring(lobby_id)] = {}
-
- for i = 1, steam.matchmaking.getNumLobbyMembers(lobby_id) do
- local h = steam.matchmaking.getLobbyMemberByIndex(lobby_id, i - 1)
-
- -- if spectator
- local is_spectator = steam.matchmaking.getLobbyData(lobby_id, tostring(h) .. "_spectator") == "true"
-
- if(steam.matchmaking.getLobbyMemberData(lobby_code, h, "in_game") == "false")then
- is_spectator = true
- end
-
- if(not is_spectator)then
- table.insert(lobby_members_no_spectators[tostring(lobby_id)], {
- id = h,
- name = steam_utils.getTranslatedPersonaName(h, h == steam_utils.getSteamID()),
- is_spectator = is_spectator
- })
- end
-
- table.insert(lobby_members[tostring(lobby_id)], {
- id = h,
- name = steam_utils.getTranslatedPersonaName(h, h == steam_utils.getSteamID()),
- is_spectator = is_spectator
- })
- end
-
- if(include_spectators)then
- return lobby_members[tostring(lobby_id)]
- else
- return lobby_members_no_spectators[tostring(lobby_id)]
- end
-
-end
-
-steam_utils.updateCacheSpectators = function(lobby_id)
- if(lobby_members[tostring(lobby_id)] == nil)then
- return
- end
- for i = 1, #lobby_members[tostring(lobby_id)] do
- local member = lobby_members[tostring(lobby_id)][i]
- member.is_spectator = steam.matchmaking.getLobbyData(lobby_id, tostring(member.id) .. "_spectator") == "true"
- end
-end
-
-lobby_members_ids = lobby_members_ids or {}
-
-steam_utils.getLobbyMembersIDs = function(lobby_id, include_spectators, update_cache)
- -- implement cache
- if(not update_cache and lobby_members_ids[tostring(lobby_id)])then
- goto return_list
- end
-
- lobby_members_ids[tostring(lobby_id)] = {}
-
- for i = 1, steam.matchmaking.getNumLobbyMembers(lobby_id) do
- local h = steam.matchmaking.getLobbyMemberByIndex(lobby_id, i - 1)
-
- table.insert(lobby_members_ids[tostring(lobby_id)], h)
- end
-
- ::return_list::
-
- local out = {}
-
- for i = 1, #lobby_members_ids[tostring(lobby_id)] do
- local member = lobby_members_ids[tostring(lobby_id)][i]
- table.insert(out, member)
- end
-
- return out
-
-end
-
-steam_utils.getPlayerCount = function(lobby, include_spectators, update_cache)
- local members = steamutils.getLobbyMembers(lobby, include_spectators, update_cache)
- return #members
-end
-
-steam_utils.IsOwner = function(user)
- if(user ~= nil)then
- return steam_utils.getLobbyOwner() == user
- end
- return steam_utils.getLobbyOwner() == steam_utils.getSteamID()
-end
-
-steam_utils.getLobbyOwner = function()
- if(lobby_code == nil)then
- return nil
- end
- if(lobby_owner == nil)then
- lobby_owner = steam.matchmaking.getLobbyOwner(lobby_code)
- end
- return lobby_owner
-end
-
-steam_utils.IsSpectator = function(lobby_id, player_id)
- local spectating = steam.matchmaking.getLobbyData(lobby_id, tostring(player_id and player_id or steam_utils.getSteamID()) .. "_spectator") ==
- "true"
- return spectating
-end
-
-steam_utils.isInLobby = function(lobby_id, steam_id)
- local list = steam_utils.getLobbyMembers(lobby_id, true)
- for i = 1, #list do
- if (list[i].id == steam_id) then
- return true
- end
- end
- return false
-end
-
--- BUG: does not work for private lobbies.
-steam_utils.doesLobbyExist = function(lobby_id, callback)
- steam.matchmaking.addRequestLobbyListDistanceFilter(distance.worldwide)
-
- steam.matchmaking.requestLobbyList(function(data)
- lobby_count = data.count
- if (lobby_count > 0) then
- for i = 0, lobby_count - 1 do
- local lobby = steam.matchmaking.getLobbyByIndex(i)
- if (lobby.lobbyID ~= nil) then
- if (lobby.lobbyID == lobby_id) then
- callback(true)
- return
- end
- end
- end
- end
- callback(false)
- end)
-end
-
-
-steam_utils.Leave = function(lobby_id)
-
- local active_mode = FindGamemode(steam.matchmaking.getLobbyData(lobby_id, "gamemode"))
- if (active_mode) then
- active_mode.leave(lobby_id)
- end
-
- cached_lobby_data = {}
- cached_lobby_user_data = {}
- initial_refreshes = 10
- delay.reset()
- is_awaiting_spectate = false
- gui_closed = false
- gamemode_settings = {}
- steam.matchmaking.leaveLobby(lobby_id)
- invite_menu_open = false
- show_lobby_code = false
- lobby_code = nil
- banned_members = {}
-end
-
-
-local datastore = dofile("mods/evaisa.mp/lib/data_store.lua")
-local data_store = datastore.new(os.getenv('APPDATA'):gsub("\\Roaming", "").."\\LocalLow\\Nolla_Games_Noita\\save00\\evaisa.mp_data")
-local persistent_bans = datastore.new(os.getenv('APPDATA'):gsub("\\Roaming", "").."\\LocalLow\\Nolla_Games_Noita\\save00\\evaisa.mp_bans")
-
-steam_utils.IsPlayerBlacklisted = function(steam_id)
- local value = persistent_bans.Get(tostring(steam_id))
- if (value == nil) then
- return false
- end
- return true
-end
-
-steam_utils.BlacklistPlayer = function(steam_id)
- persistent_bans.Set(tostring(steam_id), steam.utils.compressSteamID(steam_id))
-end
-
-steam_utils.UnblacklistPlayer = function(steam_id)
- persistent_bans.Remove(tostring(steam_id))
-end
-
-steam_utils.GetBlacklistedPlayers = function()
- local keys = persistent_bans.Keys()
- local out = {}
- for k, v in pairs(keys) do
- local value = persistent_bans.Get(v)
- if (value ~= nil) then
- table.insert(out, steam.utils.decompressSteamID(value))
- end
- end
- return out
-end
-
-steam_utils.AddLobbyFlag = function(lobby, flag)
- local flags = steam.matchmaking.getLobbyData(lobby, "flags")
- if (flags == nil or flags == "") then
- flags = flag
- else
- flags = flags .. "," .. flag
- end
-
- print("Added flag: " .. flag)
-
- steam_utils.TrySetLobbyData(lobby, "flags", flags)
-end
-
-steam_utils.RemoveLobbyFlag = function(lobby, flag)
- local flags = steam.matchmaking.getLobbyData(lobby, "flags")
- if (flags == nil or flags == "") then
- return
- end
- local flag_table = {}
- for f in flags:gmatch("([^,]+)") do
- if (f ~= flag) then
- table.insert(flag_table, f)
- end
- end
- local new_flags = table.concat(flag_table, ",")
-
- print("Removed flag: " .. flag)
-
- steam_utils.TrySetLobbyData(lobby, "flags", new_flags)
-end
-
-steam_utils.GetLobbyFlags = function(lobby)
- local flags = steam.matchmaking.getLobbyData(lobby, "flags")
- if (flags == nil or flags == "") then
- return {}
- end
- local out = {}
- for f in flags:gmatch("([^,]+)") do
- table.insert(out, f)
- end
- return out
-end
-
-steam_utils.HasLobbyFlag = function(lobby, flag)
- local flags = steam.matchmaking.getLobbyData(lobby, "flags")
- local has_flag = false
- if (flags ~= nil and flags ~= "") then
-
- for f in flags:gmatch("([^,]+)") do
- if (f == flag) then
- has_flag = true
- break
- end
- end
- end
-
- print("Has flag: " .. tostring(has_flag))
- return has_flag
-end
-
-steam_utils.GetLobbyData = function(key)
- if(lobby_code == nil)then
- return nil
- end
- local value = cached_lobby_data[key]
- try(function()
- if (value == nil or value == "") then
- -- run getLobbyData to make sure
- local code = lobby_code
- value = steam.matchmaking.getLobbyData(code, key)
-
- cached_lobby_data[key] = value
-
- return value
- end
- end).catch(function(err)
- mp_log:print("Failed to get lobby data: " .. key)
- mp_log:print(err)
- end)
- return value
-end
-
-
-steam_utils.TrySetLobbyData = function(lobby, key, value)
- if(cached_lobby_data[key] == value)then
- return
- end
- try(function()
- local result = steam.matchmaking.setLobbyData(lobby, key, value)
- -- if retult is boolean and true
- if (type(result) == "boolean" and result) then
- cached_lobby_data[key] = value
- end
- end).catch(function(err)
- mp_log:print("Failed to set lobby data: " .. key .. " = " .. value)
- mp_log:print(err)
- end)
-end
-
-steam_utils.DeleteLobbyData = function(lobby, key)
- if(cached_lobby_data[key] == nil)then
- return
- end
- try(function()
- steam.matchmaking.deleteLobbyData(lobby, key)
- cached_lobby_data[key] = nil
- end).catch(function(err)
- mp_log:print("Failed to delete lobby data: " .. key)
- mp_log:print(err)
- end)
-end
-
-steam_utils.CleanLobbyData = function(callback)
- print("Cleaning lobby data")
- if(lobby_code == nil)then
- return nil
- end
-
- print("Cleaning lobby data for lobby: " .. tostring(lobby_code))
-
- if(callback == nil)then
- callback = function(key, value)
- return true
- end
- end
-
- print("Callback found")
-
- try(function()
- -- loop through all keys and remove them
- local lobby_data_count = steam.matchmaking.getLobbyDataCount(lobby_code)
- local keys_to_remove = {}
- print("Data count: " .. lobby_data_count)
- for i = 1, lobby_data_count do
- local data = steam.matchmaking.getLobbyDataByIndex(lobby_code, i -1 )
- local key = data.key
- local value = data.value
-
- local result = callback(key, value)
-
- if(result)then
- table.insert(keys_to_remove, key)
- end
- end
-
- for i = 1, #keys_to_remove do
- local key = keys_to_remove[i]
- steam_utils.DeleteLobbyData(lobby_code, key)
- print("Removed lobby data: " .. key)
- end
-
-
- end).catch(function(err)
- mp_log:print("Failed to clear lobby data")
- mp_log:print(err)
- end)
-
-end
-
-steam_utils.SetLocalLobbyData = function(lobby, key, value)
- if (key == "time_updated") then
- mp_log:print("Illegal lobby key: time_updated")
- return
- end
-
- -- Compress the lobby ID
- lobby = steam.utils.compressSteamID(lobby)
-
- -- Create a key to store the data in data_store
- local data_key = tostring(lobby) .. "_" .. key
-
- -- Store the value with the data_key in data_store
- data_store.Set(data_key, value)
-
- -- Get the saved list of "all_keys" from data_store
- local key_string = data_store.Get("all_keys")
- local keys = (key_string ~= nil and key_string ~= "") and bitser.loads(key_string) or {}
-
- if(type(keys) ~= "table")then
- keys = {}
- end
-
- -- Check if there's not an entry for the lobby in keys table
- if (keys[tostring(lobby)] == nil) then
- -- Create an entry for lobby in keys table and set the key as true
- keys[tostring(lobby)] = {
- [key] = true,
- ["time_updated"] = os.time(),
- }
- else
- -- If the lobby already exists in keys, set the key as true
- keys[tostring(lobby)][key] = true
- keys[tostring(lobby)]["time_updated"] = os.time()
- end
-
- local key_string = bitser.dumps(keys)
-
- data_store.Set("all_keys", key_string)
-end
-
-steam_utils.GetLocalLobbyData = function(lobby, key)
- -- Compress the lobby ID
- lobby = steam.utils.compressSteamID(lobby)
-
- -- Create a key to get the data from data_store
- local data_key = tostring(lobby) .. "_" .. key
-
- -- Retrieve the value for the data_key
- local value = data_store.Get(data_key)
-
- -- Return the value
- return value
-end
-
-lobby_data_cache = lobby_data_cache or {}
-
-steam_utils.CheckLocalLobbyData = function()
- -- Get saved list of "all_keys" from data_store
- local key_string = data_store.Get("all_keys")
- local keys = (key_string ~= nil and key_string ~= "") and bitser.loads(key_string)
-
- -- if keys is nil, remove all data from data_store
- if (keys == nil) then
- if(RepairDataFolder ~= nil)then
- RepairDataFolder()
- end
- return
- end
-
- if(type(keys) ~= "table")then
- return
- end
-
- -- Print current lobby data for debugging purposes
- --mp_log:print("Checking lobby data: " .. pretty.table(keys))
-
- -- Set a variable to represent 12 hours in seconds
- local twelve_hours_sec = 12 * 60 * 60
-
- -- Iterate through all the saved lobbies
- for lobby, lobby_keys in pairs(keys) do
- -- Check if the lobby data is older than 12 hours
- if os.time() - lobby_keys["time_updated"] > twelve_hours_sec then
- -- If lobby data is older than 12 hours, remove the lobby entry from keys table
- keys[lobby] = nil
-
- -- Also remove the stored data for that lobby
- for key, _ in pairs(lobby_keys) do
- if key ~= "time_updated" then
- -- Remove the data with key "{lobby}_{key}" from data_store
- data_store.Remove(tostring(lobby) .. "_" .. key)
- mp_log:print("Removed old lobby data: " .. tostring(lobby) .. "_" .. key)
- end
- end
- end
- end
-
- -- Update the "all_keys" entry in data_store with the current keys table
- local updated_key_string = bitser.dumps(keys)
- data_store.Set("all_keys", updated_key_string)
-end
-
-steam_utils.RemoveLocalLobbyData = function(lobby, key)
- -- Compress the lobby ID
- lobby = steam.utils.compressSteamID(lobby)
- local key_string = data_store.Get("all_keys")
- local keys = (key_string ~= nil and key_string ~= "") and bitser.loads(key_string) or {}
-
- data_store.Remove(tostring(lobby) .. "_" .. key)
-
- for lob, lobby_keys in pairs(keys) do
- if (lob == lobby) then
- for k, _ in pairs(lobby_keys) do
- if (k == key) then
- keys[lob][key] = nil
- data_store.Set("all_keys", bitser.dumps(keys))
- return
- end
- end
- end
- end
-end
-
-steam_utils.messageTypes = {
- AllPlayers = 0,
- OtherPlayers = 1,
- Clients = 2,
- Host = 3,
- Spectators = 4,
-}
-
-message_handlers = {
- [steam_utils.messageTypes.AllPlayers] = function(data, lobby, reliable, include_spectators, event, channel)
- local members = steamutils.getLobbyMembers(lobby, include_spectators)
- for k, member in pairs(members) do
- --networking_log:print("Sending message ["..bitser.loads(data)[1].."] to " .. member.name)
-
- local success, size = 0, 0
-
- if(member.id == steam_utils.getSteamID())then
- HandleMessage({msg_size = 0, user = steam_utils.getSteamID(), data = data})
- goto continue
- end
-
- if (reliable) then
- success, size = steam.networking.sendString(member.id, data, channel)
- else
- success, size = steam.networking.sendStringUnreliable(member.id, data, channel)
- end
-
- success = tonumber(tostring(success))
- --GamePrint("Sent message of size " .. tostring(size) .. " to " .. member.name .. " (" .. tostring(success) .. ")")
- if (success ~= 1) then
- GamePrint("Failed to send message ["..event.."] to " .. member.name .. " (" .. tostring(success) .. ")")
- pretty.table(steam.networking.getConnectionInfo(member.id))
- else
- local id = event
- if(id ~= nil and type(id) == "string")then
- if(bytes_sent_per_type[id] == nil)then
- bytes_sent_per_type[id] = 0
- end
- bytes_sent_per_type[id] = bytes_sent_per_type[id] + size
- end
- bytes_sent = bytes_sent + size
- end
-
- ::continue::
- end
- end,
- [steam_utils.messageTypes.OtherPlayers] = function(data, lobby, reliable, include_spectators, event, channel)
- local members = steamutils.getLobbyMembers(lobby, include_spectators)
- for k, member in pairs(members) do
- if (member.id ~= steam_utils.getSteamID()) then
- --networking_log:print("Sending message ["..bitser.loads(data)[1].."] to " .. member.name)
- --print("Sending to " .. member.name)
-
- local success, size = 0, 0
-
- if (reliable) then
- success, size = steam.networking.sendString(member.id, data, channel)
- else
- success, size = steam.networking.sendStringUnreliable(member.id, data, channel)
- end
-
- success = tonumber(tostring(success))
- --GamePrint("Sent message of size " .. tostring(size) .. " to " .. member.name .. " (" .. tostring(success) .. ")")
- if (success ~= 1) then
- GamePrint("Failed to send message ["..event.."] to " .. member.name .. " (" .. tostring(success) .. ")")
- else
- local id = event
- if(id ~= nil and type(id) == "string")then
- if(bytes_sent_per_type[id] == nil)then
- bytes_sent_per_type[id] = 0
- end
- bytes_sent_per_type[id] = bytes_sent_per_type[id] + size
- end
- bytes_sent = bytes_sent + size
- end
- end
- end
- end,
- [steam_utils.messageTypes.Clients] = function(data, lobby, reliable, include_spectators, event, channel)
- local members = steamutils.getLobbyMembers(lobby, include_spectators)
- for k, member in pairs(members) do
- if (member.id ~= steam_utils.getSteamID() and member.id ~= steam.matchmaking.getLobbyOwner(lobby)) then
- --networking_log:print("Sending message ["..bitser.loads(data)[1].."] to " .. member.name)
- local success, size = 0, 0
-
- if (reliable) then
- success, size = steam.networking.sendString(member.id, data, channel)
- else
- success, size = steam.networking.sendStringUnreliable(member.id, data, channel)
- end
-
-
- success = tonumber(tostring(success))
- --GamePrint("Sent message of size " .. tostring(size) .. " to " .. member.name .. " (" .. tostring(success) .. ")")
- if (success ~= 1) then
- GamePrint("Failed to send message ["..event.."] to " .. member.name .. " (" .. tostring(success) .. ")")
- else
- local id = event
- if(id ~= nil and type(id) == "string")then
- if(bytes_sent_per_type[id] == nil)then
- bytes_sent_per_type[id] = 0
- end
- bytes_sent_per_type[id] = bytes_sent_per_type[id] + size
- end
- bytes_sent = bytes_sent + size
- end
- end
- end
- end,
- [steam_utils.messageTypes.Host] = function(data, lobby, reliable, include_spectators, event, channel)
- --networking_log:print("Sending message ["..bitser.loads(data)[1].."] to Host")
- local success, size = 0, 0
-
- -- if we are the player hosting the lobby, send the message to ourselves
-
- if(steam_utils.IsOwner())then
- HandleMessage({msg_size = 0, user = steam_utils.getSteamID(), data = data})
- goto continue
- end
-
-
- if (reliable) then
- success, size = steam.networking.sendString(steam.matchmaking.getLobbyOwner(lobby), data, channel)
- else
- success, size = steam.networking.sendStringUnreliable(steam.matchmaking.getLobbyOwner(lobby), data, channel)
- end
-
- success = tonumber(tostring(success))
- --GamePrint("Sent message of size " .. tostring(size) .. " to " .. steam.friends.getFriendPersonaName(steam.matchmaking.getLobbyOwner(lobby)) .. " (" .. tostring(success) .. ")")
- if (success ~= 1) then
- GamePrint("Failed to send message ["..event.."] to Host (" .. tostring(success) .. ")")
- else
- local id = event
- if(id ~= nil and type(id) == "string")then
- if(bytes_sent_per_type[id] == nil)then
- bytes_sent_per_type[id] = 0
- end
- bytes_sent_per_type[id] = bytes_sent_per_type[id] + size
- end
- bytes_sent = bytes_sent + size
- end
-
- ::continue::
- end,
- [steam_utils.messageTypes.Spectators] = function(data, lobby, reliable, include_spectators, event, channel)
- local members = steamutils.getLobbyMembers(lobby, true)
- for k, member in pairs(members) do
- local spectating = steam.matchmaking.getLobbyData(lobby_code, tostring(member.id) .. "_spectator") == "true"
- if (member.id ~= steam_utils.getSteamID() and spectating) then
- --networking_log:print("Sending message ["..bitser.loads(data)[1].."] to " .. member.name)
- local success, size = 0, 0
-
- if (reliable) then
- success, size = steam.networking.sendString(member.id, data, channel)
- else
- success, size = steam.networking.sendStringUnreliable(member.id, data, channel)
- end
-
- success = tonumber(tostring(success))
- --GamePrint("Sent message of size " .. tostring(size) .. " to " .. member.name .. " (" .. tostring(success) .. ")")
- if (success ~= 1) then
- GamePrint("Failed to send message ["..event.."] to " .. member.name .. " (" .. tostring(success) .. ")")
- else
- local id = event
- if(id ~= nil and type(id) == "string")then
- if(bytes_sent_per_type[id] == nil)then
- bytes_sent_per_type[id] = 0
- end
- bytes_sent_per_type[id] = bytes_sent_per_type[id] + size
- end
- bytes_sent = bytes_sent + size
- end
- end
- end
- end,
-}
-
---[[
-steam_utils.sendData = function(data, messageType, lobby, reliable)
-
- --print("Sending data")
- --print(json.stringify(data))
- --print(tostring(bitser.dumps(data)))
-
- local encodedData = bitser.dumps(data)--json.stringify(data)
- if(encodedData ~= nil and (type(encodedData) == "string" or type(encodedData) == "number"))then
- if(type(encodedData) == "number")then
- encodedData = tostring(encodedData)
- end
- message_handlers[messageType](encodedData, lobby, reliable)
- else
- GamePrint("Failed to send data, encodedData is nil or not a string")
- end
-end
-
-steam_utils.sendDataToPlayer = function(data, player, reliable)
- local encodedData = bitser.dumps(data)--json.stringify(data)
- if(encodedData ~= nil and (type(encodedData) == "string" or type(encodedData) == "number"))then
- if(type(encodedData) == "number")then
- encodedData = tostring(encodedData)
- end
- local success, size = 0, 0
-
- if(reliable)then
- success, size = steam.networking.sendStringReliable(player, encodedData)
- else
- success, size = steam.networking.sendString(player, encodedData)
- end
-
- success = tonumber(tostring(success))
- if(success ~= 1)then
- GamePrint("Failed to send message to " .. steam.friends.getFriendPersonaName(player) .. " (" .. tostring(success) .. ")")
- else
- bytes_sent = bytes_sent + size
- end
- else
- GamePrint("Failed to send data, encodedData is nil or not a string")
- end
-end
-]]
-steam_utils.send = function(event, message, messageType, lobby, reliable, include_spectators, channel)
- -- disabled because channels don't work for some reason
- channel = 0
- local data = { event, message }
-
- if (not reliable) then
- table.insert(data, GameGetFrameNum())
- end
- local encodedData = bitser.dumps(data)
-
- if (encodedData ~= nil and (type(encodedData) == "string" or type(encodedData) == "number")) then
- if (type(encodedData) == "number") then
- encodedData = tostring(encodedData)
- end
- message_handlers[messageType](encodedData, lobby, reliable, include_spectators, event, channel)
- else
- GamePrint("Failed to send data, encodedData is nil or not a string")
- end
-end
-
-steam_utils.sendToPlayer = function(event, message, player, reliable, channel)
- -- disabled because channels don't work for some reason
- channel = 0
- local data = { event, message }
-
- if (not reliable) then
- table.insert(data, GameGetFrameNum())
- end
-
- local encodedData = bitser.dumps(data)
-
- if (encodedData ~= nil and (type(encodedData) == "string" or type(encodedData) == "number")) then
- if (type(encodedData) == "number") then
- encodedData = tostring(encodedData)
- end
- local success, size = 0, 0
-
- if (reliable) then
- success, size = steam.networking.sendString(player, encodedData, channel)
- else
- success, size = steam.networking.sendStringUnreliable(player, encodedData, channel)
- end
-
- success = tonumber(tostring(success))
- if (success ~= 1) then
- GamePrint("Failed to send message ["..event.."] to " .. steamutils.getTranslatedPersonaName(player) .. " (" .. tostring(success) .. ")")
- else
- bytes_sent = bytes_sent + size
- end
- else
- GamePrint("Failed to send data, encodedData is nil or not a string")
- end
-end
-
-local function split(str, delimiter)
- local result = {}
- local from = 1
- local delim_from, delim_to = string.find(str, delimiter, from)
- while delim_from do
- table.insert(result, string.sub(str, from, delim_from - 1))
- from = delim_to + 1
- delim_from, delim_to = string.find(str, delimiter, from)
- end
- table.insert(result, string.sub(str, from))
- return result
-end
-
-
-steam_utils.parseData = function(data)
- local decodedData = nil
-
- local str = data--zstd:decompress(data)
-
- decodedData = bitser.loads(str)
-
- return decodedData
-end
-
-return steam_utils
diff --git a/lib/streaming.lua b/lib/streaming.lua
deleted file mode 100644
index 21d922e..0000000
--- a/lib/streaming.lua
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-streaming = {
- apps = {
- "obs32.exe",
- "obs64.exe",
- "obs.exe",
- "xsplit.core.exe",
- "livehime.exe",
- "pandatool.exe",
- "yymixer.exe",
- "douyutool.exe",
- "huomaotool.exe",
- "dytool.exe",
- "twitchstudio.exe",
- "gamecaster.exe",
- "evcapture.exe",
- "kk.exe",
- "streamlabs obs.exe"
- },
-}
-
--- Function to check if a streaming app is running
-streaming.IsStreaming = function()
- os.execute("tasklist > tasklist.txt")
-
- local file = io.open("tasklist.txt", "r")
- if not file then
- return false, "Unable to open tasklist.txt"
- end
-
- local content = file:read("*a")
- file:close()
-
- -- remove the file
- os.remove("tasklist.txt")
-
- for _, app in ipairs(streaming.apps) do
- if content:find(app) then
- return true, app
- end
- end
-
-
- return false, "No streaming apps are running"
-end
-
-
-return streaming
\ No newline at end of file
diff --git a/lib/translations.lua b/lib/translations.lua
deleted file mode 100644
index f0c8ed5..0000000
--- a/lib/translations.lua
+++ /dev/null
@@ -1,39 +0,0 @@
-function register_localizations(translation_file, clear_count)
-
- clear_count = clear_count or 0
-
- local loc_content = ModTextFileGetContent("data/translations/common.csv") -- Gets the original translations of the game
-
- --[[
- if(debug_log)then
- debug_log:print("loc_content: " .. loc_content)
- end
- ]]
-
- local append_content = ModTextFileGetContent(translation_file) -- Gets my own translations file
-
- -- Split the append_content into lines
- local lines = {}
- for line in append_content:gmatch("[^\n]+") do
- table.insert(lines, line)
- end
-
- -- Remove the first clear_count lines
- for i = 1, clear_count do
- table.remove(lines, 1)
- end
-
- -- Reconstruct append_content after removing clear_count lines
- local new_append_content = table.concat(lines, "\n")
-
- -- if loc_content does not end with a new line, add one
- if not loc_content:match("\n$") then
- loc_content = loc_content .. "\n"
- end
-
- -- Concatenate loc_content and new_append_content without extra newline character
- local new_content = loc_content .. new_append_content .. "\n"
-
- -- Set the new content to the file
- ModTextFileSetContent("data/translations/common.csv", new_content)
-end
\ No newline at end of file
diff --git a/lib/try_catch.lua b/lib/try_catch.lua
deleted file mode 100644
index 5c4288c..0000000
--- a/lib/try_catch.lua
+++ /dev/null
@@ -1,53 +0,0 @@
-local functionType = "function"
-
----
--- @param tryBlock The block of code to execute as the try block.
---
--- @return A table that can be used to chain try/catch/finally blocks. (Call .catch or .finally of the return value)
---
-local function try (tryBlock)
- local status, err = true, nil
-
- if type(tryBlock) == functionType then
- if(disable_error_catching)then
- -- run without pcall, and add result to status err thing
- status, err = true, tryBlock()
- end
- status, err = xpcall(tryBlock, debug.traceback)
- end
-
- local finally = function (finallyBlock, catchBlockDeclared)
- if type(finallyBlock) == functionType then
- finallyBlock()
- end
-
- if not catchBlockDeclared and not status then
- error(err)
- end
- end
-
- local catch = function (catchBlock)
- local catchBlockDeclared = type(catchBlock) == functionType;
-
- if not status and catchBlockDeclared then
- local ex = err or "unknown error occurred"
- catchBlock(ex)
- end
-
- return {
- finally = function(finallyBlock)
- finally(finallyBlock, catchBlockDeclared)
- end
- }
- end
-
- return
- {
- catch = catch,
- finally = function(finallyBlock)
- finally(finallyBlock, false)
- end
- }
-end
-
-return try
\ No newline at end of file
diff --git a/lib/unicorndecode.lua b/lib/unicorndecode.lua
deleted file mode 100644
index 673ef6e..0000000
--- a/lib/unicorndecode.lua
+++ /dev/null
@@ -1,144 +0,0 @@
-local unicorndecode = {
- _VERSION = 'unicorndecode 1.0.1',
- _DESCRIPTION = 'Unidecode for Lua',
- _URL = 'https://github.com/FourierTransformer/unicorndecode',
- _LICENSE = [[
- The MIT License (MIT)
- Copyright (c) 2016-2019 Shakil Thakur
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- ]]
-}
-
--- get the lua version (this is later used for compat)
-local luaver = tonumber(_VERSION:sub(5))
-
--- load up the unicode magic python/perl tables!
-local unicodeMagics = require('unidecode_data')
-
--- create a fallback mechanism... (just returns '[?]')
-local backupTable = setmetatable({}, {__index = function() return '[?]' end})
-setmetatable(unicodeMagics, {__index = function() return backupTable end})
-
--- luajit has a bit module builtin and returns luaver 5.1
--- for lua 5.1, luabitop would need to be installed
-local bor, blshift, brshift
-if luaver == 5.1 then
- bit = require("bit")
- bor, blshift, brshift = bit.bor, bit.lshift, bit.rshift
-elseif luaver == 5.2 then
- bor, blshift, brshift = bit32.bor, bit32.lshift, bit32.rshift
-end
-
--- load up utf8.codes. In lua 5.3+ this is baked in, otherwise the lua function provides
--- similar functionality
-local utf8codes
-if luaver > 5.2 then
- utf8codes = utf8.codes
-else
- -- declare the function!
- utf8codes = function(inputString)
-
- -- determines how many additional bytes are needed to parse the unicode char
- -- NOTE: assumes the UTF-8 input is clean - which may get dangerous.
- local function additionalBytes(val)
- -- these don't really exist yet...
- -- and are definitely not in the data tables...
- -- if val >= 252 then
- -- return 5, 252
- -- elseif val >= 248 then
- -- return 4, 248
- -- elseif val >= 240 then
- if val >= 240 then
- return 3, 240
- elseif val >= 224 then
- return 2, 224
- elseif val >= 192 then
- return 1, 192
- else
- return 0, 0
- end
- end
-
- -- PERF!
- local sbyte = string.byte
- local i, startI = 1, 1
- local val
-
- return function()
- -- the beginning is returned...
- startI = i
-
- -- get the byte value of the current char
- val = sbyte(inputString, i)
- if not val then return nil end
-
- -- figure out how many additional bytes are needed
- extraBytes, byteVal = additionalBytes(val)
-
- -- if there are additional bytes this is UTF-8!
- -- remove the preceding 1's in binary
- val = val - byteVal
- -- print("val", val)
-
- -- add each additional byte to get the unicode value
- --[[ ex: for the two byte unicode value (in binary):
- 110xxxxx 10yyyyyy
- has the unicdoe value: xxxxxyyyyyy
- ]]
- for j = 1, extraBytes do
- extraByteVal = sbyte(inputString, i+j)
- -- print("extraByteVal", extraByteVal)
- extraByteVal = extraByteVal - 128 --remove the header byte
- val = bor(blshift(val, 6), extraByteVal) --combines it
- end
-
-
- i = i + 1 + extraBytes
-
- return startI, val
- end
- end
-end
-
-local function trim(s)
- return s:match'^()%s*$' and '' or s:match'^%s*(.*%S)'
-end
-
-function unicorndecode.decode(inputString)
- -- SO MANY VARS!
- local val, extraBytes, byteVal, extraByteVal
- local inputLength = #inputString
- -- print("inputLength", inputLength)
-
- -- STRING BUILDER!
- local output = {}
- local count = 0
-
- -- iterate over the string
- for p, c in utf8codes(inputString) do
- -- print(p, c)
- -- add the equivalent ascii char to the output
- count = count + 1
- output[count] = unicodeMagics[math.floor(c/256)][(c % 256)+1]
- end
-
- -- concat the string together!
- local final = table.concat(output)
- return trim(final), inputLength ~= (count) -- this is more of a byte count than anything
-end
-
-return unicorndecode
diff --git a/lib/unidecode_data.lua b/lib/unidecode_data.lua
deleted file mode 100644
index 63389b7..0000000
--- a/lib/unidecode_data.lua
+++ /dev/null
@@ -1,261 +0,0 @@
-local data = {
- {"A", "a", "A", "a", "A", "a", "C", "c", "C", "c", "C", "c", "C", "c", "D", "d", "D", "d", "E", "e", "E", "e", "E", "e", "E", "e", "E", "e", "G", "g", "G", "g", "G", "g", "G", "g", "H", "h", "H", "h", "I", "i", "I", "i", "I", "i", "I", "i", "I", "i", "IJ", "ij", "J", "j", "K", "k", "k", "L", "l", "L", "l", "L", "l", "L", "l", "L", "l", "N", "n", "N", "n", "N", "n", "'n", "ng", "NG", "O", "o", "O", "o", "O", "o", "OE", "oe", "R", "r", "R", "r", "R", "r", "S", "s", "S", "s", "S", "s", "S", "s", "T", "t", "T", "t", "T", "t", "U", "u", "U", "u", "U", "u", "U", "u", "U", "u", "U", "u", "W", "w", "Y", "y", "Y", "Z", "z", "Z", "z", "Z", "z", "s", "b", "B", "B", "b", "6", "6", "O", "C", "c", "D", "D", "D", "d", "d", "3", "@", "E", "F", "f", "G", "G", "hv", "I", "I", "K", "k", "l", "l", "W", "N", "n", "O", "O", "o", "OI", "oi", "P", "p", "YR", "2", "2", "SH", "sh", "t", "T", "t", "T", "U", "u", "Y", "V", "Y", "y", "Z", "z", "ZH", "ZH", "zh", "zh", "2", "5", "5", "ts", "w", "|", "||", "|=", "!", "DZ", "Dz", "dz", "LJ", "Lj", "lj", "NJ", "Nj", "nj", "A", "a", "I", "i", "O", "o", "U", "u", "U", "u", "U", "u", "U", "u", "U", "u", "@", "A", "a", "A", "a", "AE", "ae", "G", "g", "G", "g", "K", "k", "O", "o", "O", "o", "ZH", "zh", "j", "DZ", "Dz", "dz", "G", "g", "HV", "W", "N", "n", "A", "a", "AE", "ae", "O", "o"},
- {"A", "a", "A", "a", "E", "e", "E", "e", "I", "i", "I", "i", "O", "o", "O", "o", "R", "r", "R", "r", "U", "u", "U", "u", "S", "s", "T", "t", "Y", "y", "H", "h", "N", "d", "OU", "ou", "Z", "z", "A", "a", "E", "e", "O", "o", "O", "o", "O", "o", "O", "o", "Y", "y", "l", "n", "t", "j", "db", "qp", "A", "C", "c", "L", "T", "s", "z", "[?]", "[?]", "B", "U", "^", "E", "e", "J", "j", "q", "q", "R", "r", "Y", "y", "a", "a", "a", "b", "o", "c", "d", "d", "e", "@", "@", "e", "e", "e", "e", "j", "g", "g", "g", "g", "u", "Y", "h", "h", "i", "i", "I", "l", "l", "l", "lZ", "W", "W", "m", "n", "n", "n", "o", "OE", "O", "F", "r", "r", "r", "r", "r", "r", "r", "R", "R", "s", "S", "j", "S", "S", "t", "t", "u", "U", "v", "^", "w", "y", "Y", "z", "z", "Z", "Z", "?", "?", "?", "C", "@", "B", "E", "G", "H", "j", "k", "L", "q", "?", "?", "dz", "dZ", "dz", "ts", "tS", "tC", "fN", "ls", "lz", "WW", "]]", "h", "h", "h", "h", "j", "r", "r", "r", "r", "w", "y", "'", "\"", "`", "'", "`", "`", "'", "?", "?", "<", ">", "^", "V", "^", "V", "'", "-", "/", "\\", ",", "_", "\\", "/", ":", ".", "`", "'", "^", "V", "+", "-", "V", ".", "@", ",", "~", "\"", "R", "X", "G", "l", "s", "x", "?", "5", "4", "3", "2", "1", "/", "\\", "V", "=", "\"", "V", "^", "<", ">", "o", "`", "``", "//", "~", ":", "[-", "-]", "[_", "_]", "_", "_", "<"},
- {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "", "", "", "a", "e", "i", "o", "u", "c", "d", "h", "m", "r", "t", "v", "x", "[?]", "[?]", "[?]", "[?]", "'", ",", "[?]", "[?]", "[?]", "[?]", "", "[?]", "[?]", "[?]", "?", "[?]", "[?]", "[?]", "[?]", "[?]", "", "", "A", ";", "E", "E", "I", "[?]", "O", "[?]", "U", "O", "I", "A", "B", "G", "D", "E", "Z", "E", "Th", "I", "K", "L", "M", "N", "Ks", "O", "P", "R", "[?]", "S", "T", "U", "Ph", "Kh", "Ps", "O", "I", "U", "a", "e", "e", "i", "u", "a", "b", "g", "d", "e", "z", "e", "th", "i", "k", "l", "m", "n", "x", "o", "p", "r", "s", "s", "t", "u", "ph", "kh", "ps", "o", "i", "u", "o", "u", "o", "[?]", "b", "th", "U", "U", "U", "ph", "p", "&", "[?]", "[?]", "St", "st", "W", "w", "Q", "q", "Sp", "sp", "Sh", "sh", "F", "f", "Kh", "kh", "H", "h", "G", "g", "CH", "ch", "Ti", "ti", "k", "r", "c", "j", "TH", "e", "e", "Sh", "sh", "s", "[?]", "[?]", "r/", "S", "S.", "S."},
- {"Ie", "Io", "Dj", "Gj", "E", "Dz", "I", "Yi", "J", "Lj", "Nj", "Tsh", "Kj", "I", "U", "Dzh", "A", "B", "V", "G", "D", "E", "Zh", "Z", "I", "I", "K", "L", "M", "N", "O", "P", "R", "S", "T", "U", "F", "Kh", "Ts", "Ch", "Sh", "Shch", "", "Y", "'", "E", "Iu", "Ia", "a", "b", "v", "g", "d", "e", "zh", "z", "i", "i", "k", "l", "m", "n", "o", "p", "r", "s", "t", "u", "f", "kh", "ts", "ch", "sh", "shch", "", "y", "'", "e", "iu", "ia", "ie", "io", "dj", "gj", "ie", "dz", "i", "yi", "j", "lj", "nj", "tsh", "kj", "i", "u", "dzh", "O", "o", "E", "e", "Ie", "ie", "E", "e", "Ie", "ie", "O", "o", "Io", "io", "Ks", "ks", "Ps", "ps", "F", "f", "Y", "y", "Y", "y", "u", "u", "O", "o", "O", "o", "Ot", "ot", "Q", "q", "*1000*", "", "", "", "", "[?]", "*100.000*", "*1.000.000*", "[?]", "[?]", "\"", "\"", "R'", "r'", "G'", "g'", "G'", "g'", "G'", "g'", "Zh'", "zh'", "Z'", "z'", "K'", "k'", "K'", "k'", "K'", "k'", "K'", "k'", "N'", "n'", "Ng", "ng", "P'", "p'", "Kh", "kh", "S'", "s'", "T'", "t'", "U", "u", "U'", "u'", "Kh'", "kh'", "Tts", "tts", "Ch'", "ch'", "Ch'", "ch'", "H", "h", "Ch", "ch", "Ch'", "ch'", "`", "Zh", "zh", "K'", "k'", "[?]", "[?]", "N'", "n'", "[?]", "[?]", "Ch", "ch", "[?]", "[?]", "[?]", "a", "a", "A", "a", "Ae", "ae", "Ie", "ie", "@", "@", "@", "@", "Zh", "zh", "Z", "z", "Dz", "dz", "I", "i", "I", "i", "O", "o", "O", "o", "O", "o", "E", "e", "U", "u", "U", "u", "U", "u", "Ch", "ch", "[?]", "[?]", "Y", "y", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "A", "B", "G", "D", "E", "Z", "E", "E", "T`", "Zh", "I", "L", "Kh", "Ts", "K", "H", "Dz", "Gh", "Ch", "M", "Y", "N", "Sh", "O", "Ch`", "P", "J", "Rh", "S", "V", "T", "R", "Ts`", "W", "P`", "K`", "O", "F", "[?]", "[?]", "<", "'", "/", "!", ",", "?", ".", "[?]", "a", "b", "g", "d", "e", "z", "e", "e", "t`", "zh", "i", "l", "kh", "ts", "k", "h", "dz", "gh", "ch", "m", "y", "n", "sh", "o", "ch`", "p", "j", "rh", "s", "v", "t", "r", "ts`", "w", "p`", "k`", "o", "f", "ew", "[?]", ".", "-", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "@", "e", "a", "o", "i", "e", "e", "a", "a", "o", "[?]", "u", "'", "", "", "", "|", "", "", ":", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "", "b", "g", "d", "h", "v", "z", "kh", "t", "y", "k", "k", "l", "m", "m", "n", "n", "s", "`", "p", "p", "ts", "ts", "q", "r", "sh", "t", "[?]", "[?]", "[?]", "[?]", "[?]", "V", "oy", "i", "'", "\"", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", ",", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", ";", "[?]", "[?]", "[?]", "?", "[?]", "", "a", "'", "w'", "", "y'", "", "b", "@", "t", "th", "j", "H", "kh", "d", "dh", "r", "z", "s", "sh", "S", "D", "T", "Z", "`", "G", "[?]", "[?]", "[?]", "[?]", "[?]", "", "f", "q", "k", "l", "m", "n", "h", "w", "~", "y", "an", "un", "in", "a", "u", "i", "W", "", "", "'", "'", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "%", ".", ",", "*", "[?]", "[?]", "", "'", "'", "'", "", "'", "'w", "'u", "'y", "tt", "tth", "b", "t", "T", "p", "th", "bh", "'h", "H", "ny", "dy", "H", "ch", "cch", "dd", "D", "D", "Dt", "dh", "ddh", "d", "D", "D", "rr", "R", "R", "R", "R", "R", "R", "j", "R", "S", "S", "S", "S", "S", "T", "GH", "F", "F", "F", "v", "f", "ph", "Q", "Q", "kh", "k", "K", "K", "ng", "K", "g", "G", "N", "G", "G", "G", "L", "L", "L", "L", "N", "N", "N", "N", "N", "h", "Ch", "hy", "h", "H", "@", "W", "oe", "oe", "u", "yu", "yu", "W", "v", "y", "Y", "Y", "W", "", "", "y", "y'", ".", "ae", "", "", "", "", "", "", "", "@", "#", "", "", "", "", "", "", "", "", "", "", "^", "", "", "", "", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Sh", "D", "Gh", "&", "+m", "h"},
- {"//", "/", ",", "!", "!", "-", ",", ",", ";", "?", "~", "{", "}", "*", "[?]", "", "'", "", "b", "g", "g", "d", "d", "h", "w", "z", "H", "t", "t", "y", "yh", "k", "l", "m", "n", "s", "s", "`", "p", "p", "S", "q", "r", "sh", "t", "[?]", "[?]", "[?]", "a", "a", "a", "A", "A", "A", "e", "e", "e", "E", "i", "i", "u", "u", "u", "o", "", "`", "'", "", "", "X", "Q", "@", "@", "|", "+", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "h", "sh", "n", "r", "b", "L", "k", "'", "v", "m", "f", "dh", "th", "l", "g", "ny", "s", "d", "z", "t", "y", "p", "j", "ch", "tt", "hh", "kh", "th", "z", "sh", "s", "d", "t", "z", "`", "gh", "q", "w", "a", "aa", "i", "ee", "u", "oo", "e", "ey", "o", "oa", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?]", "N", "N", "H", "[?]", "a", "aa", "i", "ii", "u", "uu", "R", "L", "eN", "e", "e", "ai", "oN", "o", "o", "au", "k", "kh", "g", "gh", "ng", "c", "ch", "j", "jh", "ny", "tt", "tth", "dd", "ddh", "nn", "t", "th", "d", "dh", "n", "nnn", "p", "ph", "b", "bh", "m", "y", "r", "rr", "l", "l", "lll", "v", "sh", "ss", "s", "h", "[?]", "[?]", "'", "'", "aa", "i", "ii", "u", "uu", "R", "RR", "eN", "e", "e", "ai", "oN", "o", "o", "au", "", "[?]", "[?]", "AUM", "'", "'", "`", "'", "[?]", "[?]", "[?]", "q", "khh", "ghh", "z", "dddh", "rh", "f", "yy", "RR", "LL", "L", "LL", " / ", " // ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "N", "N", "H", "[?]", "a", "aa", "i", "ii", "u", "uu", "R", "RR", "[?]", "[?]", "e", "ai", "[?]", "[?]", "o", "au", "k", "kh", "g", "gh", "ng", "c", "ch", "j", "jh", "ny", "tt", "tth", "dd", "ddh", "nn", "t", "th", "d", "dh", "n", "[?]", "p", "ph", "b", "bh", "m", "y", "r", "[?]", "l", "[?]", "[?]", "[?]", "sh", "ss", "s", "h", "[?]", "[?]", "'", "[?]", "aa", "i", "ii", "u", "uu", "R", "RR", "[?]", "[?]", "e", "ai", "[?]", "[?]", "o", "au", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "+", "[?]", "[?]", "[?]", "[?]", "rr", "rh", "[?]", "yy", "RR", "LL", "L", "LL", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "r'", "r`", "Rs", "Rs", "1/", "2/", "3/", "4/", " 1 - 1/", "/16", "", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "[?]", "N", "[?]", "[?]", "a", "aa", "i", "ii", "u", "uu", "[?]", "[?]", "[?]", "[?]", "ee", "ai", "[?]", "[?]", "oo", "au", "k", "kh", "g", "gh", "ng", "c", "ch", "j", "jh", "ny", "tt", "tth", "dd", "ddh", "nn", "t", "th", "d", "dh", "n", "[?]", "p", "ph", "b", "bb", "m", "y", "r", "[?]", "l", "ll", "[?]", "v", "sh", "[?]", "s", "h", "[?]", "[?]", "'", "[?]", "aa", "i", "ii", "u", "uu", "[?]", "[?]", "[?]", "[?]", "ee", "ai", "[?]", "[?]", "oo", "au", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "khh", "ghh", "z", "rr", "[?]", "f", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "N", "H", "", "", "G.E.O.", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "N", "N", "H", "[?]", "a", "aa", "i", "ii", "u", "uu", "R", "[?]", "eN", "[?]", "e", "ai", "oN", "[?]", "o", "au", "k", "kh", "g", "gh", "ng", "c", "ch", "j", "jh", "ny", "tt", "tth", "dd", "ddh", "nn", "t", "th", "d", "dh", "n", "[?]", "p", "ph", "b", "bh", "m", "ya", "r", "[?]", "l", "ll", "[?]", "v", "sh", "ss", "s", "h", "[?]", "[?]", "'", "'", "aa", "i", "ii", "u", "uu", "R", "RR", "eN", "[?]", "e", "ai", "oN", "[?]", "o", "au", "", "[?]", "[?]", "AUM", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "RR", "[?]", "[?]", "[?]", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "R", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "zh", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "N", "N", "H", "[?]", "a", "aa", "i", "ii", "u", "uu", "R", "L", "[?]", "[?]", "e", "ai", "[?]", "[?]", "o", "au", "k", "kh", "g", "gh", "ng", "c", "ch", "j", "jh", "ny", "tt", "tth", "dd", "ddh", "nn", "t", "th", "d", "dh", "n", "[?]", "p", "ph", "b", "bh", "m", "y", "r", "[?]", "l", "ll", "[?]", "", "sh", "ss", "s", "h", "[?]", "[?]", "'", "'", "aa", "i", "ii", "u", "uu", "R", "[?]", "[?]", "[?]", "e", "ai", "[?]", "[?]", "o", "au", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "+", "+", "[?]", "[?]", "[?]", "[?]", "rr", "rh", "[?]", "yy", "RR", "LL", "[?]", "[?]", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "N", "H", "[?]", "a", "aa", "i", "ii", "u", "uu", "[?]", "[?]", "[?]", "e", "ee", "ai", "[?]", "o", "oo", "au", "k", "[?]", "[?]", "[?]", "ng", "c", "[?]", "j", "[?]", "ny", "tt", "[?]", "[?]", "[?]", "nn", "t", "[?]", "[?]", "[?]", "n", "nnn", "p", "[?]", "[?]", "[?]", "m", "y", "r", "rr", "l", "ll", "lll", "v", "[?]", "ss", "s", "h", "[?]", "[?]", "[?]", "[?]", "aa", "i", "ii", "u", "uu", "[?]", "[?]", "[?]", "e", "ee", "ai", "[?]", "o", "oo", "au", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "+", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+10+", "+100+", "+1000+", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "N", "N", "H", "[?]", "a", "aa", "i", "ii", "u", "uu", "R", "L", "[?]", "e", "ee", "ai", "[?]", "o", "oo", "au", "k", "kh", "g", "gh", "ng", "c", "ch", "j", "jh", "ny", "tt", "tth", "dd", "ddh", "nn", "t", "th", "d", "dh", "n", "[?]", "p", "ph", "b", "bh", "m", "y", "r", "rr", "l", "ll", "[?]", "v", "sh", "ss", "s", "h", "[?]", "[?]", "[?]", "[?]", "aa", "i", "ii", "u", "uu", "R", "RR", "[?]", "e", "ee", "ai", "[?]", "o", "oo", "au", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "+", "+", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "RR", "LL", "[?]", "[?]", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "N", "H", "[?]", "a", "aa", "i", "ii", "u", "uu", "R", "L", "[?]", "e", "ee", "ai", "[?]", "o", "oo", "au", "k", "kh", "g", "gh", "ng", "c", "ch", "j", "jh", "ny", "tt", "tth", "dd", "ddh", "nn", "t", "th", "d", "dh", "n", "[?]", "p", "ph", "b", "bh", "m", "y", "r", "rr", "l", "ll", "[?]", "v", "sh", "ss", "s", "h", "[?]", "[?]", "[?]", "[?]", "aa", "i", "ii", "u", "uu", "R", "RR", "[?]", "e", "ee", "ai", "[?]", "o", "oo", "au", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "+", "+", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "lll", "[?]", "RR", "LL", "[?]", "[?]", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "[?]", "N", "H", "[?]", "a", "aa", "i", "ii", "u", "uu", "R", "L", "[?]", "e", "ee", "ai", "[?]", "o", "oo", "au", "k", "kh", "g", "gh", "ng", "c", "ch", "j", "jh", "ny", "tt", "tth", "dd", "ddh", "nn", "t", "th", "d", "dh", "n", "[?]", "p", "ph", "b", "bh", "m", "y", "r", "rr", "l", "ll", "lll", "v", "sh", "ss", "s", "h", "[?]", "[?]", "[?]", "[?]", "aa", "i", "ii", "u", "uu", "R", "[?]", "[?]", "e", "ee", "ai", "", "o", "oo", "au", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "+", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "RR", "LL", "[?]", "[?]", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "N", "H", "[?]", "a", "aa", "ae", "aae", "i", "ii", "u", "uu", "R", "RR", "L", "LL", "e", "ee", "ai", "o", "oo", "au", "[?]", "[?]", "[?]", "k", "kh", "g", "gh", "ng", "nng", "c", "ch", "j", "jh", "ny", "jny", "nyj", "tt", "tth", "dd", "ddh", "nn", "nndd", "t", "th", "d", "dh", "n", "[?]", "nd", "p", "ph", "b", "bh", "m", "mb", "y", "r", "[?]", "l", "[?]", "[?]", "v", "sh", "ss", "s", "h", "ll", "f", "[?]", "[?]", "[?]", "", "[?]", "[?]", "[?]", "[?]", "aa", "ae", "aae", "i", "ii", "u", "[?]", "uu", "[?]", "R", "e", "ee", "ai", "o", "oo", "au", "L", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "RR", "LL", " . ", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "k", "kh", "kh", "kh", "kh", "kh", "ng", "cch", "ch", "ch", "ch", "ch", "y", "d", "t", "th", "th", "th", "n", "d", "t", "th", "th", "th", "n", "b", "p", "ph", "f", "ph", "f", "ph", "m", "y", "r", "R", "l", "L", "w", "s", "s", "s", "h", "l", "`", "h", "~", "a", "a", "aa", "am", "i", "ii", "ue", "uue", "u", "uu", "'", "[?]", "[?]", "[?]", "[?]", "Bh.", "e", "ae", "o", "ai", "ai", "ao", "+", "", "", "", "", "", "", "M", "", " * ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", " // ", " /// ", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "k", "kh", "[?]", "kh", "[?]", "[?]", "ng", "ch", "[?]", "s", "[?]", "[?]", "ny", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "d", "h", "th", "th", "[?]", "n", "b", "p", "ph", "f", "ph", "f", "[?]", "m", "y", "r", "[?]", "l", "[?]", "w", "[?]", "[?]", "s", "h", "[?]", "`", "", "~", "a", "", "aa", "am", "i", "ii", "y", "yy", "u", "uu", "[?]", "o", "l", "ny", "[?]", "[?]", "e", "ei", "o", "ay", "ai", "[?]", "+", "[?]", "", "", "", "", "", "M", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "[?]", "[?]", "hn", "hm", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"AUM", "", "", "", "", "", "", "", " // ", " * ", "", "-", " / ", " / ", " // ", " -/ ", " +/ ", " X/ ", " /XX/ ", " /X/ ", ", ", "", "", "", "", "", "", "", "", "", "", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".5", "1.5", "2.5", "3.5", "4.5", "5.5", "6.5", "7.5", "8.5", "-.5", "+", "*", "^", "_", "", "~", "[?]", "]", "[[", "]]", "", "", "k", "kh", "g", "gh", "ng", "c", "ch", "j", "[?]", "ny", "tt", "tth", "dd", "ddh", "nn", "t", "th", "d", "dh", "n", "p", "ph", "b", "bh", "m", "ts", "tsh", "dz", "dzh", "w", "zh", "z", "'", "y", "r", "l", "sh", "ssh", "s", "h", "a", "kss", "r", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "aa", "i", "ii", "u", "uu", "R", "RR", "L", "LL", "e", "ee", "o", "oo", "M", "H", "i", "ii", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "k", "kh", "g", "gh", "ng", "c", "ch", "j", "[?]", "ny", "tt", "tth", "dd", "ddh", "nn", "t", "th", "d", "dh", "n", "p", "ph", "b", "bh", "m", "ts", "tsh", "dz", "dzh", "w", "zh", "z", "'", "y", "r", "l", "sh", "ss", "s", "h", "a", "kss", "w", "y", "r", "[?]", "X", " :X: ", " /O/ ", " /o/ ", " \\o\\ ", " (O) ", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"k", "kh", "g", "gh", "ng", "c", "ch", "j", "jh", "ny", "nny", "tt", "tth", "dd", "ddh", "nn", "tt", "th", "d", "dh", "n", "p", "ph", "b", "bh", "m", "y", "r", "l", "w", "s", "h", "ll", "a", "[?]", "i", "ii", "u", "uu", "e", "[?]", "o", "au", "[?]", "aa", "i", "ii", "u", "uu", "e", "ai", "[?]", "[?]", "[?]", "N", "'", ":", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", " / ", " // ", "n*", "r*", "l*", "e*", "sh", "ss", "R", "RR", "L", "LL", "R", "RR", "L", "LL", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "A", "B", "G", "D", "E", "V", "Z", "T`", "I", "K", "L", "M", "N", "O", "P", "Zh", "R", "S", "T", "U", "P`", "K`", "G'", "Q", "Sh", "Ch`", "C`", "Z'", "C", "Ch", "X", "J", "H", "E", "Y", "W", "Xh", "OE", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "a", "b", "g", "d", "e", "v", "z", "t`", "i", "k", "l", "m", "n", "o", "p", "zh", "r", "s", "t", "u", "p`", "k`", "g'", "q", "sh", "ch`", "c`", "z'", "c", "ch", "x", "j", "h", "e", "y", "w", "xh", "oe", "f", "[?]", "[?]", "[?]", "[?]", " // ", "[?]", "[?]", "[?]", "[?]"},
- {"g", "gg", "n", "d", "dd", "r", "m", "b", "bb", "s", "ss", "", "j", "jj", "c", "k", "t", "p", "h", "ng", "nn", "nd", "nb", "dg", "rn", "rr", "rh", "rN", "mb", "mN", "bg", "bn", "", "bs", "bsg", "bst", "bsb", "bss", "bsj", "bj", "bc", "bt", "bp", "bN", "bbN", "sg", "sn", "sd", "sr", "sm", "sb", "sbg", "sss", "s", "sj", "sc", "sk", "st", "sp", "sh", "", "", "", "", "Z", "g", "d", "m", "b", "s", "Z", "", "j", "c", "t", "p", "N", "j", "", "", "", "", "ck", "ch", "", "", "pb", "pN", "hh", "Q", "[?]", "[?]", "[?]", "[?]", "[?]", "", "", "a", "ae", "ya", "yae", "eo", "e", "yeo", "ye", "o", "wa", "wae", "oe", "yo", "u", "weo", "we", "wi", "yu", "eu", "yi", "i", "a-o", "a-u", "ya-o", "ya-yo", "eo-o", "eo-u", "eo-eu", "yeo-o", "yeo-u", "o-eo", "o-e", "o-ye", "o-o", "o-u", "yo-ya", "yo-yae", "yo-yeo", "yo-o", "yo-i", "u-a", "u-ae", "u-eo-eu", "u-ye", "u-u", "yu-a", "yu-eo", "yu-e", "yu-yeo", "yu-ye", "yu-u", "yu-i", "eu-u", "eu-eu", "yi-u", "i-a", "i-ya", "i-o", "i-u", "i-eu", "i-U", "U", "U-eo", "U-u", "U-i", "UU", "[?]", "[?]", "[?]", "[?]", "[?]", "g", "gg", "gs", "n", "nj", "nh", "d", "l", "lg", "lm", "lb", "ls", "lt", "lp", "lh", "m", "b", "bs", "s", "ss", "ng", "j", "c", "k", "t", "p", "h", "gl", "gsg", "ng", "nd", "ns", "nZ", "nt", "dg", "tl", "lgs", "ln", "ld", "lth", "ll", "lmg", "lms", "lbs", "lbh", "rNp", "lss", "lZ", "lk", "lQ", "mg", "ml", "mb", "ms", "mss", "mZ", "mc", "mh", "mN", "bl", "bp", "ph", "pN", "sg", "sd", "sl", "sb", "Z", "g", "ss", "", "kh", "N", "Ns", "NZ", "pb", "pN", "hn", "hl", "hm", "hb", "Q", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"ha", "hu", "hi", "haa", "hee", "he", "ho", "[?]", "la", "lu", "li", "laa", "lee", "le", "lo", "lwa", "hha", "hhu", "hhi", "hhaa", "hhee", "hhe", "hho", "hhwa", "ma", "mu", "mi", "maa", "mee", "me", "mo", "mwa", "sza", "szu", "szi", "szaa", "szee", "sze", "szo", "szwa", "ra", "ru", "ri", "raa", "ree", "re", "ro", "rwa", "sa", "su", "si", "saa", "see", "se", "so", "swa", "sha", "shu", "shi", "shaa", "shee", "she", "sho", "shwa", "qa", "qu", "qi", "qaa", "qee", "qe", "qo", "[?]", "qwa", "[?]", "qwi", "qwaa", "qwee", "qwe", "[?]", "[?]", "qha", "qhu", "qhi", "qhaa", "qhee", "qhe", "qho", "[?]", "qhwa", "[?]", "qhwi", "qhwaa", "qhwee", "qhwe", "[?]", "[?]", "ba", "bu", "bi", "baa", "bee", "be", "bo", "bwa", "va", "vu", "vi", "vaa", "vee", "ve", "vo", "vwa", "ta", "tu", "ti", "taa", "tee", "te", "to", "twa", "ca", "cu", "ci", "caa", "cee", "ce", "co", "cwa", "xa", "xu", "xi", "xaa", "xee", "xe", "xo", "[?]", "xwa", "[?]", "xwi", "xwaa", "xwee", "xwe", "[?]", "[?]", "na", "nu", "ni", "naa", "nee", "ne", "no", "nwa", "nya", "nyu", "nyi", "nyaa", "nyee", "nye", "nyo", "nywa", "'a", "'u", "[?]", "'aa", "'ee", "'e", "'o", "'wa", "ka", "ku", "ki", "kaa", "kee", "ke", "ko", "[?]", "kwa", "[?]", "kwi", "kwaa", "kwee", "kwe", "[?]", "[?]", "kxa", "kxu", "kxi", "kxaa", "kxee", "kxe", "kxo", "[?]", "kxwa", "[?]", "kxwi", "kxwaa", "kxwee", "kxwe", "[?]", "[?]", "wa", "wu", "wi", "waa", "wee", "we", "wo", "[?]", "`a", "`u", "`i", "`aa", "`ee", "`e", "`o", "[?]", "za", "zu", "zi", "zaa", "zee", "ze", "zo", "zwa", "zha", "zhu", "zhi", "zhaa", "zhee", "zhe", "zho", "zhwa", "ya", "yu", "yi", "yaa", "yee", "ye", "yo", "[?]", "da", "du", "di", "daa", "dee", "de", "do", "dwa", "dda", "ddu", "ddi", "ddaa", "ddee", "dde", "ddo", "ddwa"},
- {"ja", "ju", "ji", "jaa", "jee", "je", "jo", "jwa", "ga", "gu", "gi", "gaa", "gee", "ge", "go", "[?]", "gwa", "[?]", "gwi", "gwaa", "gwee", "gwe", "[?]", "[?]", "gga", "ggu", "ggi", "ggaa", "ggee", "gge", "ggo", "[?]", "tha", "thu", "thi", "thaa", "thee", "the", "tho", "thwa", "cha", "chu", "chi", "chaa", "chee", "che", "cho", "chwa", "pha", "phu", "phi", "phaa", "phee", "phe", "pho", "phwa", "tsa", "tsu", "tsi", "tsaa", "tsee", "tse", "tso", "tswa", "tza", "tzu", "tzi", "tzaa", "tzee", "tze", "tzo", "[?]", "fa", "fu", "fi", "faa", "fee", "fe", "fo", "fwa", "pa", "pu", "pi", "paa", "pee", "pe", "po", "pwa", "rya", "mya", "fya", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", " ", ".", ",", ";", ":", ":: ", "?", "//", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10+", "20+", "30+", "40+", "50+", "60+", "70+", "80+", "90+", "100+", "10,000+", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "a", "e", "i", "o", "u", "v", "ga", "ka", "ge", "gi", "go", "gu", "gv", "ha", "he", "hi", "ho", "hu", "hv", "la", "le", "li", "lo", "lu", "lv", "ma", "me", "mi", "mo", "mu", "na", "hna", "nah", "ne", "ni", "no", "nu", "nv", "qua", "que", "qui", "quo", "quu", "quv", "sa", "s", "se", "si", "so", "su", "sv", "da", "ta", "de", "te", "di", "ti", "do", "du", "dv", "dla", "tla", "tle", "tli", "tlo", "tlu", "tlv", "tsa", "tse", "tsi", "tso", "tsu", "tsv", "wa", "we", "wi", "wo", "wu", "wv", "ya", "ye", "yi", "yo", "yu", "yv", "MV", "[?]", "[?]", "ye", "yi", "yo", "yu", "yv", "mv", "[?]", "[?]"},
- {"[?]", "e", "aai", "i", "ii", "o", "oo", "oo", "ee", "i", "a", "aa", "we", "we", "wi", "wi", "wii", "wii", "wo", "wo", "woo", "woo", "woo", "wa", "wa", "waa", "waa", "waa", "ai", "w", "'", "t", "k", "sh", "s", "n", "w", "n", "[?]", "w", "c", "?", "l", "en", "in", "on", "an", "pe", "paai", "pi", "pii", "po", "poo", "poo", "hee", "hi", "pa", "paa", "pwe", "pwe", "pwi", "pwi", "pwii", "pwii", "pwo", "pwo", "pwoo", "pwoo", "pwa", "pwa", "pwaa", "pwaa", "pwaa", "p", "p", "h", "te", "taai", "ti", "tii", "to", "too", "too", "dee", "di", "ta", "taa", "twe", "twe", "twi", "twi", "twii", "twii", "two", "two", "twoo", "twoo", "twa", "twa", "twaa", "twaa", "twaa", "t", "tte", "tti", "tto", "tta", "ke", "kaai", "ki", "kii", "ko", "koo", "koo", "ka", "kaa", "kwe", "kwe", "kwi", "kwi", "kwii", "kwii", "kwo", "kwo", "kwoo", "kwoo", "kwa", "kwa", "kwaa", "kwaa", "kwaa", "k", "kw", "keh", "kih", "koh", "kah", "ce", "caai", "ci", "cii", "co", "coo", "coo", "ca", "caa", "cwe", "cwe", "cwi", "cwi", "cwii", "cwii", "cwo", "cwo", "cwoo", "cwoo", "cwa", "cwa", "cwaa", "cwaa", "cwaa", "c", "th", "me", "maai", "mi", "mii", "mo", "moo", "moo", "ma", "maa", "mwe", "mwe", "mwi", "mwi", "mwii", "mwii", "mwo", "mwo", "mwoo", "mwoo", "mwa", "mwa", "mwaa", "mwaa", "mwaa", "m", "m", "mh", "m", "m", "ne", "naai", "ni", "nii", "no", "noo", "noo", "na", "naa", "nwe", "nwe", "nwa", "nwa", "nwaa", "nwaa", "nwaa", "n", "ng", "nh", "le", "laai", "li", "lii", "lo", "loo", "loo", "la", "laa", "lwe", "lwe", "lwi", "lwi", "lwii", "lwii", "lwo", "lwo", "lwoo", "lwoo", "lwa", "lwa", "lwaa", "lwaa", "l", "l", "l", "se", "saai", "si", "sii", "so", "soo", "soo", "sa", "saa", "swe", "swe", "swi", "swi", "swii", "swii", "swo", "swo", "swoo", "swoo"},
- {"swa", "swa", "swaa", "swaa", "swaa", "s", "s", "sw", "s", "sk", "skw", "sW", "spwa", "stwa", "skwa", "scwa", "she", "shi", "shii", "sho", "shoo", "sha", "shaa", "shwe", "shwe", "shwi", "shwi", "shwii", "shwii", "shwo", "shwo", "shwoo", "shwoo", "shwa", "shwa", "shwaa", "shwaa", "sh", "ye", "yaai", "yi", "yii", "yo", "yoo", "yoo", "ya", "yaa", "ywe", "ywe", "ywi", "ywi", "ywii", "ywii", "ywo", "ywo", "ywoo", "ywoo", "ywa", "ywa", "ywaa", "ywaa", "ywaa", "y", "y", "y", "yi", "re", "re", "le", "raai", "ri", "rii", "ro", "roo", "lo", "ra", "raa", "la", "rwaa", "rwaa", "r", "r", "r", "fe", "faai", "fi", "fii", "fo", "foo", "fa", "faa", "fwaa", "fwaa", "f", "the", "the", "thi", "thi", "thii", "thii", "tho", "thoo", "tha", "thaa", "thwaa", "thwaa", "th", "tthe", "tthi", "ttho", "ttha", "tth", "tye", "tyi", "tyo", "tya", "he", "hi", "hii", "ho", "hoo", "ha", "haa", "h", "h", "hk", "qaai", "qi", "qii", "qo", "qoo", "qa", "qaa", "q", "tlhe", "tlhi", "tlho", "tlha", "re", "ri", "ro", "ra", "ngaai", "ngi", "ngii", "ngo", "ngoo", "nga", "ngaa", "ng", "nng", "she", "shi", "sho", "sha", "the", "thi", "tho", "tha", "th", "lhi", "lhii", "lho", "lhoo", "lha", "lhaa", "lh", "the", "thi", "thii", "tho", "thoo", "tha", "thaa", "th", "b", "e", "i", "o", "a", "we", "wi", "wo", "wa", "ne", "ni", "no", "na", "ke", "ki", "ko", "ka", "he", "hi", "ho", "ha", "ghu", "gho", "ghe", "ghee", "ghi", "gha", "ru", "ro", "re", "ree", "ri", "ra", "wu", "wo", "we", "wee", "wi", "wa", "hwu", "hwo", "hwe", "hwee", "hwi", "hwa", "thu", "tho", "the", "thee", "thi", "tha", "ttu", "tto", "tte", "ttee", "tti", "tta", "pu", "po", "pe", "pee", "pi", "pa", "p", "gu", "go", "ge", "gee", "gi", "ga", "khu", "kho", "khe", "khee", "khi", "kha", "kku", "kko", "kke", "kkee", "kki"},
- {"kka", "kk", "nu", "no", "ne", "nee", "ni", "na", "mu", "mo", "me", "mee", "mi", "ma", "yu", "yo", "ye", "yee", "yi", "ya", "ju", "ju", "jo", "je", "jee", "ji", "ji", "ja", "jju", "jjo", "jje", "jjee", "jji", "jja", "lu", "lo", "le", "lee", "li", "la", "dlu", "dlo", "dle", "dlee", "dli", "dla", "lhu", "lho", "lhe", "lhee", "lhi", "lha", "tlhu", "tlho", "tlhe", "tlhee", "tlhi", "tlha", "tlu", "tlo", "tle", "tlee", "tli", "tla", "zu", "zo", "ze", "zee", "zi", "za", "z", "z", "dzu", "dzo", "dze", "dzee", "dzi", "dza", "su", "so", "se", "see", "si", "sa", "shu", "sho", "she", "shee", "shi", "sha", "sh", "tsu", "tso", "tse", "tsee", "tsi", "tsa", "chu", "cho", "che", "chee", "chi", "cha", "ttsu", "ttso", "ttse", "ttsee", "ttsi", "ttsa", "X", ".", "qai", "ngai", "nngi", "nngii", "nngo", "nngoo", "nnga", "nngaa", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", " ", "b", "l", "f", "s", "n", "h", "d", "t", "c", "q", "m", "g", "ng", "z", "r", "a", "o", "u", "e", "i", "ch", "th", "ph", "p", "x", "p", "<", ">", "[?]", "[?]", "[?]", "f", "v", "u", "yr", "y", "w", "th", "th", "a", "o", "ac", "ae", "o", "o", "o", "oe", "on", "r", "k", "c", "k", "g", "ng", "g", "g", "w", "h", "h", "h", "h", "n", "n", "n", "i", "e", "j", "g", "ae", "a", "eo", "p", "z", "s", "s", "s", "c", "z", "t", "t", "d", "b", "b", "p", "p", "e", "m", "m", "m", "l", "l", "ng", "ng", "d", "o", "ear", "ior", "qu", "qu", "qu", "s", "yr", "yr", "yr", "q", "x", ".", ":", "+", "17", "18", "19", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "k", "kh", "g", "gh", "ng", "c", "ch", "j", "jh", "ny", "t", "tth", "d", "ddh", "nn", "t", "th", "d", "dh", "n", "p", "ph", "b", "bh", "m", "y", "r", "l", "v", "sh", "ss", "s", "h", "l", "q", "a", "aa", "i", "ii", "u", "uk", "uu", "uuv", "ry", "ryy", "ly", "lyy", "e", "ai", "oo", "oo", "au", "a", "aa", "aa", "i", "ii", "y", "yy", "u", "uu", "ua", "oe", "ya", "ie", "e", "ae", "ai", "oo", "au", "M", "H", "a`", "", "", "", "r", "", "!", "", "", "", "", "", ".", " // ", ":", "+", "++", " * ", " /// ", "KR", "'", "[?]", "[?]", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {" @ ", " ... ", ", ", ". ", ": ", " // ", "", "-", ", ", ". ", "", "", "", "", "", "[?]", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "a", "e", "i", "o", "u", "O", "U", "ee", "n", "ng", "b", "p", "q", "g", "m", "l", "s", "sh", "t", "d", "ch", "j", "y", "r", "w", "f", "k", "kha", "ts", "z", "h", "zr", "lh", "zh", "ch", "-", "e", "i", "o", "u", "O", "U", "ng", "b", "p", "q", "g", "m", "t", "d", "ch", "j", "ts", "y", "w", "k", "g", "h", "jy", "ny", "dz", "e", "i", "iy", "U", "u", "ng", "k", "g", "h", "p", "sh", "t", "d", "j", "f", "g", "h", "ts", "z", "r", "ch", "zh", "i", "k", "r", "f", "zh", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "H", "X", "W", "M", " 3 ", " 333 ", "a", "i", "k", "ng", "c", "tt", "tth", "dd", "nn", "t", "d", "p", "ph", "ss", "zh", "z", "a", "t", "zh", "gh", "ng", "c", "jh", "tta", "ddh", "t", "dh", "ss", "cy", "zh", "z", "u", "y", "bh", "'", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"A", "a", "B", "b", "B", "b", "B", "b", "C", "c", "D", "d", "D", "d", "D", "d", "D", "d", "D", "d", "E", "e", "E", "e", "E", "e", "E", "e", "E", "e", "F", "f", "G", "g", "H", "h", "H", "h", "H", "h", "H", "h", "H", "h", "I", "i", "I", "i", "K", "k", "K", "k", "K", "k", "L", "l", "L", "l", "L", "l", "L", "l", "M", "m", "M", "m", "M", "m", "N", "n", "N", "n", "N", "n", "N", "n", "O", "o", "O", "o", "O", "o", "O", "o", "P", "p", "P", "p", "R", "r", "R", "r", "R", "r", "R", "r", "S", "s", "S", "s", "S", "s", "S", "s", "S", "s", "T", "t", "T", "t", "T", "t", "T", "t", "U", "u", "U", "u", "U", "u", "U", "u", "U", "u", "V", "v", "V", "v", "W", "w", "W", "w", "W", "w", "W", "w", "W", "w", "X", "x", "X", "x", "Y", "y", "Z", "z", "Z", "z", "Z", "z", "h", "t", "w", "y", "a", "s", "s", "s", "Ss", "d", "A", "a", "A", "a", "A", "a", "A", "a", "A", "a", "A", "a", "A", "a", "A", "a", "A", "a", "A", "a", "A", "a", "A", "a", "E", "e", "E", "e", "E", "e", "E", "e", "E", "e", "E", "e", "E", "e", "E", "e", "I", "i", "I", "i", "O", "o", "O", "o", "O", "o", "O", "o", "O", "o", "O", "o", "O", "o", "O", "o", "O", "o", "O", "o", "O", "o", "O", "o", "U", "u", "U", "u", "U", "u", "U", "u", "U", "u", "U", "u", "U", "u", "Y", "y", "Y", "y", "Y", "y", "Y", "y", "LL", "ll", "V", "v", "Y", "y"},
- {"a", "a", "a", "a", "a", "a", "a", "a", "A", "A", "A", "A", "A", "A", "A", "A", "e", "e", "e", "e", "e", "e", "[?]", "[?]", "E", "E", "E", "E", "E", "E", "[?]", "[?]", "e", "e", "e", "e", "e", "e", "e", "e", "E", "E", "E", "E", "E", "E", "E", "E", "i", "i", "i", "i", "i", "i", "i", "i", "I", "I", "I", "I", "I", "I", "I", "I", "o", "o", "o", "o", "o", "o", "[?]", "[?]", "O", "O", "O", "O", "O", "O", "[?]", "[?]", "u", "u", "u", "u", "u", "u", "u", "u", "[?]", "U", "[?]", "U", "[?]", "U", "[?]", "U", "o", "o", "o", "o", "o", "o", "o", "o", "O", "O", "O", "O", "O", "O", "O", "O", "a", "a", "e", "e", "e", "e", "i", "i", "o", "o", "u", "u", "o", "o", "[?]", "[?]", "a", "a", "a", "a", "a", "a", "a", "a", "A", "A", "A", "A", "A", "A", "A", "A", "e", "e", "e", "e", "e", "e", "e", "e", "E", "E", "E", "E", "E", "E", "E", "E", "o", "o", "o", "o", "o", "o", "o", "o", "O", "O", "O", "O", "O", "O", "O", "O", "a", "a", "a", "a", "a", "[?]", "a", "a", "A", "A", "A", "A", "A", "'", "i", "'", "~", "\"~", "e", "e", "e", "[?]", "e", "e", "E", "E", "E", "E", "E", "'`", "''", "'~", "i", "i", "i", "i", "[?]", "[?]", "i", "i", "I", "I", "I", "I", "[?]", "`'", "`'", "`~", "u", "u", "u", "u", "R", "R", "u", "u", "U", "U", "U", "U", "R", "\"`", "\"'", "`", "[?]", "[?]", "o", "o", "o", "[?]", "o", "o", "O", "O", "O", "O", "O", "'", "`", "[?]"},
- {" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "", "", "", "", "-", "-", "-", "-", "--", "--", "||", "_", "'", "'", ",", "'", "\"", "\"", ",,", "\"", "+", "++", "*", "*>", ".", "..", "...", ".", "\n", "\n\n", "", "", "", "", "", " ", "%0", "%00", "'", "''", "'''", "`", "``", "```", "^", "<", ">", "*", "!!", "!?", "-", "_", "-", "^", "***", "--", "/", "-[", "]-", "[?]", "?!", "!?", "7", "PP", "(]", "[)", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "", "", "", "", "", "", "0", "", "", "", "4", "5", "6", "7", "8", "9", "+", "-", "=", "(", ")", "n", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "-", "=", "(", ")", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "ECU", "CL", "Cr", "FF", "L", "mil", "N", "Pts", "Rs", "W", "NS", "D", "EUR", "K", "T", "Dr", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "tm", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", " 1/3 ", " 2/3 ", " 1/5 ", " 2/5 ", " 3/5 ", " 4/5 ", " 1/6 ", " 5/6 ", " 1/8 ", " 3/8 ", " 5/8 ", " 7/8 ", " 1/", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "L", "C", "D", "M", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x", "xi", "xii", "l", "c", "d", "m", "(D", "D)", "((|))", ")", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "-", "|", "-", "|", "-", "|", "\\", "/", "\\", "/", "-", "-", "~", "~", "-", "|", "-", "|", "-", "-", "-", "|", "-", "|", "|", "-", "-", "-", "-", "-", "-", "|", "|", "|", "|", "|", "|", "|", "^", "V", "\\", "=", "V", "^", "-", "-", "|", "|", "-", "-", "|", "|", "=", "|", "=", "=", "|", "=", "|", "=", "=", "=", "=", "=", "=", "|", "=", "|", "=", "|", "\\", "/", "\\", "/", "=", "=", "~", "~", "|", "|", "-", "|", "-", "|", "-", "-", "-", "|", "-", "|", "|", "|", "|", "|", "|", "|", "-", "\\", "\\", "|", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"-", "-", "|", "|", "-", "-", "|", "|", "-", "-", "|", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "-", "-", "|", "|", "-", "|", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "+", "/", "\\", "X", "-", "|", "-", "|", "-", "|", "-", "|", "-", "|", "-", "|", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "-", "|", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "#", "^", "^", "^", "^", ">", ">", ">", ">", ">", ">", "V", "V", "V", "V", "<", "<", "<", "<", "<", "<", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "#", "#", "#", "#", "#", "^", "^", "^", "O", "#", "#", "#", "#", "O", "O", "O", "O", "/", "\\", "\\", "#", "#", "#", "#", "/"},
- {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {" ", "a", "1", "b", "'", "k", "2", "l", "@", "c", "i", "f", "/", "m", "s", "p", "\"", "e", "3", "h", "9", "o", "6", "r", "^", "d", "j", "g", ">", "n", "t", "q", ",", "*", "5", "<", "-", "u", "8", "v", ".", "%", "[", "$", "+", "x", "!", "&", ";", ":", "4", "\\", "0", "z", "7", "(", "_", "?", "w", "]", "#", "y", ")", "=", "[d7]", "[d17]", "[d27]", "[d127]", "[d37]", "[d137]", "[d237]", "[d1237]", "[d47]", "[d147]", "[d247]", "[d1247]", "[d347]", "[d1347]", "[d2347]", "[d12347]", "[d57]", "[d157]", "[d257]", "[d1257]", "[d357]", "[d1357]", "[d2357]", "[d12357]", "[d457]", "[d1457]", "[d2457]", "[d12457]", "[d3457]", "[d13457]", "[d23457]", "[d123457]", "[d67]", "[d167]", "[d267]", "[d1267]", "[d367]", "[d1367]", "[d2367]", "[d12367]", "[d467]", "[d1467]", "[d2467]", "[d12467]", "[d3467]", "[d13467]", "[d23467]", "[d123467]", "[d567]", "[d1567]", "[d2567]", "[d12567]", "[d3567]", "[d13567]", "[d23567]", "[d123567]", "[d4567]", "[d14567]", "[d24567]", "[d124567]", "[d34567]", "[d134567]", "[d234567]", "[d1234567]", "[d8]", "[d18]", "[d28]", "[d128]", "[d38]", "[d138]", "[d238]", "[d1238]", "[d48]", "[d148]", "[d248]", "[d1248]", "[d348]", "[d1348]", "[d2348]", "[d12348]", "[d58]", "[d158]", "[d258]", "[d1258]", "[d358]", "[d1358]", "[d2358]", "[d12358]", "[d458]", "[d1458]", "[d2458]", "[d12458]", "[d3458]", "[d13458]", "[d23458]", "[d123458]", "[d68]", "[d168]", "[d268]", "[d1268]", "[d368]", "[d1368]", "[d2368]", "[d12368]", "[d468]", "[d1468]", "[d2468]", "[d12468]", "[d3468]", "[d13468]", "[d23468]", "[d123468]", "[d568]", "[d1568]", "[d2568]", "[d12568]", "[d3568]", "[d13568]", "[d23568]", "[d123568]", "[d4568]", "[d14568]", "[d24568]", "[d124568]", "[d34568]", "[d134568]", "[d234568]", "[d1234568]", "[d78]", "[d178]", "[d278]", "[d1278]", "[d378]", "[d1378]", "[d2378]", "[d12378]", "[d478]", "[d1478]", "[d2478]", "[d12478]", "[d3478]", "[d13478]", "[d23478]", "[d123478]", "[d578]", "[d1578]", "[d2578]", "[d12578]", "[d3578]", "[d13578]", "[d23578]", "[d123578]", "[d4578]", "[d14578]", "[d24578]", "[d124578]", "[d34578]", "[d134578]", "[d234578]", "[d1234578]", "[d678]", "[d1678]", "[d2678]", "[d12678]", "[d3678]", "[d13678]", "[d23678]", "[d123678]", "[d4678]", "[d14678]", "[d24678]", "[d124678]", "[d34678]", "[d134678]", "[d234678]", "[d1234678]", "[d5678]", "[d15678]", "[d25678]", "[d125678]", "[d35678]", "[d135678]", "[d235678]", "[d1235678]", "[d45678]", "[d145678]", "[d245678]", "[d1245678]", "[d345678]", "[d1345678]", "[d2345678]", "[d12345678]"},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?]", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?]", "[?]", "[?]", "[?]"},
- {" ", ", ", ". ", "\"", "[JIS]", "\"", "/", "0", "<", "> ", "<<", ">> ", "[", "] ", "{", "} ", "[(", ")] ", "@", "X ", "[", "] ", "[[", "]] ", "((", ")) ", "[[", "]] ", "~ ", "``", "''", ",,", "@", "1", "2", "3", "4", "5", "6", "7", "8", "9", "", "", "", "", "", "", "~", "+", "+", "+", "+", "", "@", " // ", "+10+", "+20+", "+30+", "[?]", "[?]", "[?]", "", "", "[?]", "a", "a", "i", "i", "u", "u", "e", "e", "o", "o", "ka", "ga", "ki", "gi", "ku", "gu", "ke", "ge", "ko", "go", "sa", "za", "si", "zi", "su", "zu", "se", "ze", "so", "zo", "ta", "da", "ti", "di", "tu", "tu", "du", "te", "de", "to", "do", "na", "ni", "nu", "ne", "no", "ha", "ba", "pa", "hi", "bi", "pi", "hu", "bu", "pu", "he", "be", "pe", "ho", "bo", "po", "ma", "mi", "mu", "me", "mo", "ya", "ya", "yu", "yu", "yo", "yo", "ra", "ri", "ru", "re", "ro", "wa", "wa", "wi", "we", "wo", "n", "vu", "[?]", "[?]", "[?]", "[?]", "", "", "", "", "\"", "\"", "[?]", "[?]", "a", "a", "i", "i", "u", "u", "e", "e", "o", "o", "ka", "ga", "ki", "gi", "ku", "gu", "ke", "ge", "ko", "go", "sa", "za", "si", "zi", "su", "zu", "se", "ze", "so", "zo", "ta", "da", "ti", "di", "tu", "tu", "du", "te", "de", "to", "do", "na", "ni", "nu", "ne", "no", "ha", "ba", "pa", "hi", "bi", "pi", "hu", "bu", "pu", "he", "be", "pe", "ho", "bo", "po", "ma", "mi", "mu", "me", "mo", "ya", "ya", "yu", "yu", "yo", "yo", "ra", "ri", "ru", "re", "ro", "wa", "wa", "wi", "we", "wo", "n", "vu", "ka", "ke", "va", "vi", "ve", "vo", "", "", "\"", "\"", "koto"},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "B", "P", "M", "F", "D", "T", "N", "L", "G", "K", "H", "J", "Q", "X", "ZH", "CH", "SH", "R", "Z", "C", "S", "A", "O", "E", "EH", "AI", "EI", "AU", "OU", "AN", "EN", "ANG", "ENG", "ER", "I", "U", "IU", "V", "NG", "GN", "[?]", "[?]", "[?]", "[?]", "g", "gg", "gs", "n", "nj", "nh", "d", "dd", "r", "lg", "lm", "lb", "ls", "lt", "lp", "rh", "m", "b", "bb", "bs", "s", "ss", "", "j", "jj", "c", "k", "t", "p", "h", "a", "ae", "ya", "yae", "eo", "e", "yeo", "ye", "o", "wa", "wae", "oe", "yo", "u", "weo", "we", "wi", "yu", "eu", "yi", "i", "", "nn", "nd", "ns", "nZ", "lgs", "ld", "lbs", "lZ", "lQ", "mb", "ms", "mZ", "mN", "bg", "", "bsg", "bst", "bj", "bt", "bN", "bbN", "sg", "sn", "sd", "sb", "sj", "Z", "", "N", "Ns", "NZ", "pN", "hh", "Q", "yo-ya", "yo-yae", "yo-i", "yu-yeo", "yu-ye", "yu-i", "U", "U-i", "[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "BU", "ZI", "JI", "GU", "EE", "ENN", "OO", "ONN", "IR", "ANN", "INN", "UNN", "IM", "NGG", "AINN", "AUNN", "AM", "OM", "ONG", "INNN", "P", "T", "K", "H", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"(g)", "(n)", "(d)", "(r)", "(m)", "(b)", "(s)", "()", "(j)", "(c)", "(k)", "(t)", "(p)", "(h)", "(ga)", "(na)", "(da)", "(ra)", "(ma)", "(ba)", "(sa)", "(a)", "(ja)", "(ca)", "(ka)", "(ta)", "(pa)", "(ha)", "(ju)", "[?]", "[?]", "[?]", "(1) ", "(2) ", "(3) ", "(4) ", "(5) ", "(6) ", "(7) ", "(8) ", "(9) ", "(10) ", "(Yue) ", "(Huo) ", "(Shui) ", "(Mu) ", "(Jin) ", "(Tu) ", "(Ri) ", "(Zhu) ", "(You) ", "(She) ", "(Ming) ", "(Te) ", "(Cai) ", "(Zhu) ", "(Lao) ", "(Dai) ", "(Hu) ", "(Xue) ", "(Jian) ", "(Qi) ", "(Zi) ", "(Xie) ", "(Ji) ", "(Xiu) ", "<<", ">>", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "(g)", "(n)", "(d)", "(r)", "(m)", "(b)", "(s)", "()", "(j)", "(c)", "(k)", "(t)", "(p)", "(h)", "(ga)", "(na)", "(da)", "(ra)", "(ma)", "(ba)", "(sa)", "(a)", "(ja)", "(ca)", "(ka)", "(ta)", "(pa)", "(ha)", "[?]", "[?]", "[?]", "KIS ", "(1) ", "(2) ", "(3) ", "(4) ", "(5) ", "(6) ", "(7) ", "(8) ", "(9) ", "(10) ", "(Yue) ", "(Huo) ", "(Shui) ", "(Mu) ", "(Jin) ", "(Tu) ", "(Ri) ", "(Zhu) ", "(You) ", "(She) ", "(Ming) ", "(Te) ", "(Cai) ", "(Zhu) ", "(Lao) ", "(Mi) ", "(Nan) ", "(Nu) ", "(Shi) ", "(You) ", "(Yin) ", "(Zhu) ", "(Xiang) ", "(Xiu) ", "(Xie) ", "(Zheng) ", "(Shang) ", "(Zhong) ", "(Xia) ", "(Zuo) ", "(You) ", "(Yi) ", "(Zong) ", "(Xue) ", "(Jian) ", "(Qi) ", "(Zi) ", "(Xie) ", "(Ye) ", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "1M", "2M", "3M", "4M", "5M", "6M", "7M", "8M", "9M", "10M", "11M", "12M", "[?]", "[?]", "[?]", "[?]", "a", "i", "u", "u", "o", "ka", "ki", "ku", "ke", "ko", "sa", "si", "su", "se", "so", "ta", "ti", "tu", "te", "to", "na", "ni", "nu", "ne", "no", "ha", "hi", "hu", "he", "ho", "ma", "mi", "mu", "me", "mo", "ya", "yu", "yo", "ra", "ri", "ru", "re", "ro", "wa", "wi", "we", "wo", "[?]"},
- {"apartment", "alpha", "ampere", "are", "inning", "inch", "won", "escudo", "acre", "ounce", "ohm", "kai-ri", "carat", "calorie", "gallon", "gamma", "giga", "guinea", "curie", "guilder", "kilo", "kilogram", "kilometer", "kilowatt", "gram", "gram ton", "cruzeiro", "krone", "case", "koruna", "co-op", "cycle", "centime", "shilling", "centi", "cent", "dozen", "desi", "dollar", "ton", "nano", "knot", "heights", "percent", "parts", "barrel", "piaster", "picul", "pico", "building", "farad", "feet", "bushel", "franc", "hectare", "peso", "pfennig", "hertz", "pence", "page", "beta", "point", "volt", "hon", "pound", "hall", "horn", "micro", "mile", "mach", "mark", "mansion", "micron", "milli", "millibar", "mega", "megaton", "meter", "yard", "yard", "yuan", "liter", "lira", "rupee", "ruble", "rem", "roentgen", "watt", "0h", "1h", "2h", "3h", "4h", "5h", "6h", "7h", "8h", "9h", "10h", "11h", "12h", "13h", "14h", "15h", "16h", "17h", "18h", "19h", "20h", "21h", "22h", "23h", "24h", "HPA", "da", "AU", "bar", "oV", "pc", "[?]", "[?]", "[?]", "[?]", "Heisei", "Syouwa", "Taisyou", "Meiji", "Inc.", "pA", "nA", "microamp", "mA", "kA", "kB", "MB", "GB", "cal", "kcal", "pF", "nF", "microFarad", "microgram", "mg", "kg", "Hz", "kHz", "MHz", "GHz", "THz", "microliter", "ml", "dl", "kl", "fm", "nm", "micrometer", "mm", "cm", "km", "mm^2", "cm^2", "m^2", "km^2", "mm^4", "cm^3", "m^3", "km^3", "m/s", "m/s^2", "Pa", "kPa", "MPa", "GPa", "rad", "rad/s", "rad/s^2", "ps", "ns", "microsecond", "ms", "pV", "nV", "microvolt", "mV", "kV", "MV", "pW", "nW", "microwatt", "mW", "kW", "MW", "kOhm", "MOhm", "a.m.", "Bq", "cc", "cd", "C/kg", "Co.", "dB", "Gy", "ha", "HP", "in", "K.K.", "KM", "kt", "lm", "ln", "log", "lx", "mb", "mil", "mol", "pH", "p.m.", "PPM", "PR", "sr", "Sv", "Wb", "[?]", "[?]", "1d", "2d", "3d", "4d", "5d", "6d", "7d", "8d", "9d", "10d", "11d", "12d", "13d", "14d", "15d", "16d", "17d", "18d", "19d", "20d", "21d", "22d", "23d", "24d", "25d", "26d", "27d", "28d", "29d", "30d", "31d", "gal"},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"Yi ", "Ding ", "Kao ", "Qi ", "Shang ", "Xia ", "[?] ", "Mo ", "Zhang ", "San ", "Shang ", "Xia ", "Ji ", "Bu ", "Yu ", "Mian ", "Gai ", "Chou ", "Chou ", "Zhuan ", "Qie ", "Pi ", "Shi ", "Shi ", "Qiu ", "Bing ", "Ye ", "Cong ", "Dong ", "Si ", "Cheng ", "Diu ", "Qiu ", "Liang ", "Diu ", "You ", "Liang ", "Yan ", "Bing ", "Sang ", "Gun ", "Jiu ", "Ge ", "Ya ", "Qiang ", "Zhong ", "Ji ", "Jie ", "Feng ", "Guan ", "Chuan ", "Chan ", "Lin ", "Zhuo ", "Zhu ", "Ha ", "Wan ", "Dan ", "Wei ", "Zhu ", "Jing ", "Li ", "Ju ", "Pie ", "Fu ", "Yi ", "Yi ", "Nai ", "Shime ", "Jiu ", "Jiu ", "Zhe ", "Yao ", "Yi ", "[?] ", "Zhi ", "Wu ", "Zha ", "Hu ", "Fa ", "Le ", "Zhong ", "Ping ", "Pang ", "Qiao ", "Hu ", "Guai ", "Cheng ", "Cheng ", "Yi ", "Yin ", "[?] ", "Mie ", "Jiu ", "Qi ", "Ye ", "Xi ", "Xiang ", "Gai ", "Diu ", "Hal ", "[?] ", "Shu ", "Twul ", "Shi ", "Ji ", "Nang ", "Jia ", "Kel ", "Shi ", "[?] ", "Ol ", "Mai ", "Luan ", "Cal ", "Ru ", "Xue ", "Yan ", "Fu ", "Sha ", "Na ", "Gan ", "Sol ", "El ", "Cwul ", "[?] ", "Gan ", "Chi ", "Gui ", "Gan ", "Luan ", "Lin ", "Yi ", "Jue ", "Liao ", "Ma ", "Yu ", "Zheng ", "Shi ", "Shi ", "Er ", "Chu ", "Yu ", "Yu ", "Yu ", "Yun ", "Hu ", "Qi ", "Wu ", "Jing ", "Si ", "Sui ", "Gen ", "Gen ", "Ya ", "Xie ", "Ya ", "Qi ", "Ya ", "Ji ", "Tou ", "Wang ", "Kang ", "Ta ", "Jiao ", "Hai ", "Yi ", "Chan ", "Heng ", "Mu ", "[?] ", "Xiang ", "Jing ", "Ting ", "Liang ", "Xiang ", "Jing ", "Ye ", "Qin ", "Bo ", "You ", "Xie ", "Dan ", "Lian ", "Duo ", "Wei ", "Ren ", "Ren ", "Ji ", "La ", "Wang ", "Yi ", "Shi ", "Ren ", "Le ", "Ding ", "Ze ", "Jin ", "Pu ", "Chou ", "Ba ", "Zhang ", "Jin ", "Jie ", "Bing ", "Reng ", "Cong ", "Fo ", "San ", "Lun ", "Sya ", "Cang ", "Zi ", "Shi ", "Ta ", "Zhang ", "Fu ", "Xian ", "Xian ", "Tuo ", "Hong ", "Tong ", "Ren ", "Qian ", "Gan ", "Yi ", "Di ", "Dai ", "Ling ", "Yi ", "Chao ", "Chang ", "Sa ", "[?] ", "Yi ", "Mu ", "Men ", "Ren ", "Jia ", "Chao ", "Yang ", "Qian ", "Zhong ", "Pi ", "Wan ", "Wu ", "Jian ", "Jie ", "Yao ", "Feng ", "Cang ", "Ren ", "Wang ", "Fen ", "Di ", "Fang "},
- {"Zhong ", "Qi ", "Pei ", "Yu ", "Diao ", "Dun ", "Wen ", "Yi ", "Xin ", "Kang ", "Yi ", "Ji ", "Ai ", "Wu ", "Ji ", "Fu ", "Fa ", "Xiu ", "Jin ", "Bei ", "Dan ", "Fu ", "Tang ", "Zhong ", "You ", "Huo ", "Hui ", "Yu ", "Cui ", "Chuan ", "San ", "Wei ", "Chuan ", "Che ", "Ya ", "Xian ", "Shang ", "Chang ", "Lun ", "Cang ", "Xun ", "Xin ", "Wei ", "Zhu ", "[?] ", "Xuan ", "Nu ", "Bo ", "Gu ", "Ni ", "Ni ", "Xie ", "Ban ", "Xu ", "Ling ", "Zhou ", "Shen ", "Qu ", "Si ", "Beng ", "Si ", "Jia ", "Pi ", "Yi ", "Si ", "Ai ", "Zheng ", "Dian ", "Han ", "Mai ", "Dan ", "Zhu ", "Bu ", "Qu ", "Bi ", "Shao ", "Ci ", "Wei ", "Di ", "Zhu ", "Zuo ", "You ", "Yang ", "Ti ", "Zhan ", "He ", "Bi ", "Tuo ", "She ", "Yu ", "Yi ", "Fo ", "Zuo ", "Kou ", "Ning ", "Tong ", "Ni ", "Xuan ", "Qu ", "Yong ", "Wa ", "Qian ", "[?] ", "Ka ", "[?] ", "Pei ", "Huai ", "He ", "Lao ", "Xiang ", "Ge ", "Yang ", "Bai ", "Fa ", "Ming ", "Jia ", "Er ", "Bing ", "Ji ", "Hen ", "Huo ", "Gui ", "Quan ", "Tiao ", "Jiao ", "Ci ", "Yi ", "Shi ", "Xing ", "Shen ", "Tuo ", "Kan ", "Zhi ", "Gai ", "Lai ", "Yi ", "Chi ", "Kua ", "Guang ", "Li ", "Yin ", "Shi ", "Mi ", "Zhu ", "Xu ", "You ", "An ", "Lu ", "Mou ", "Er ", "Lun ", "Tong ", "Cha ", "Chi ", "Xun ", "Gong ", "Zhou ", "Yi ", "Ru ", "Jian ", "Xia ", "Jia ", "Zai ", "Lu ", "Ko ", "Jiao ", "Zhen ", "Ce ", "Qiao ", "Kuai ", "Chai ", "Ning ", "Nong ", "Jin ", "Wu ", "Hou ", "Jiong ", "Cheng ", "Zhen ", "Zuo ", "Chou ", "Qin ", "Lu ", "Ju ", "Shu ", "Ting ", "Shen ", "Tuo ", "Bo ", "Nan ", "Hao ", "Bian ", "Tui ", "Yu ", "Xi ", "Cu ", "E ", "Qiu ", "Xu ", "Kuang ", "Ku ", "Wu ", "Jun ", "Yi ", "Fu ", "Lang ", "Zu ", "Qiao ", "Li ", "Yong ", "Hun ", "Jing ", "Xian ", "San ", "Pai ", "Su ", "Fu ", "Xi ", "Li ", "Fu ", "Ping ", "Bao ", "Yu ", "Si ", "Xia ", "Xin ", "Xiu ", "Yu ", "Ti ", "Che ", "Chou ", "[?] ", "Yan ", "Lia ", "Li ", "Lai ", "[?] ", "Jian ", "Xiu ", "Fu ", "He ", "Ju ", "Xiao ", "Pai ", "Jian ", "Biao ", "Chu ", "Fei ", "Feng ", "Ya ", "An ", "Bei ", "Yu ", "Xin ", "Bi ", "Jian "},
- {"Chang ", "Chi ", "Bing ", "Zan ", "Yao ", "Cui ", "Lia ", "Wan ", "Lai ", "Cang ", "Zong ", "Ge ", "Guan ", "Bei ", "Tian ", "Shu ", "Shu ", "Men ", "Dao ", "Tan ", "Jue ", "Chui ", "Xing ", "Peng ", "Tang ", "Hou ", "Yi ", "Qi ", "Ti ", "Gan ", "Jing ", "Jie ", "Sui ", "Chang ", "Jie ", "Fang ", "Zhi ", "Kong ", "Juan ", "Zong ", "Ju ", "Qian ", "Ni ", "Lun ", "Zhuo ", "Wei ", "Luo ", "Song ", "Leng ", "Hun ", "Dong ", "Zi ", "Ben ", "Wu ", "Ju ", "Nai ", "Cai ", "Jian ", "Zhai ", "Ye ", "Zhi ", "Sha ", "Qing ", "[?] ", "Ying ", "Cheng ", "Jian ", "Yan ", "Nuan ", "Zhong ", "Chun ", "Jia ", "Jie ", "Wei ", "Yu ", "Bing ", "Ruo ", "Ti ", "Wei ", "Pian ", "Yan ", "Feng ", "Tang ", "Wo ", "E ", "Xie ", "Che ", "Sheng ", "Kan ", "Di ", "Zuo ", "Cha ", "Ting ", "Bei ", "Ye ", "Huang ", "Yao ", "Zhan ", "Chou ", "Yan ", "You ", "Jian ", "Xu ", "Zha ", "Ci ", "Fu ", "Bi ", "Zhi ", "Zong ", "Mian ", "Ji ", "Yi ", "Xie ", "Xun ", "Si ", "Duan ", "Ce ", "Zhen ", "Ou ", "Tou ", "Tou ", "Bei ", "Za ", "Lu ", "Jie ", "Wei ", "Fen ", "Chang ", "Gui ", "Sou ", "Zhi ", "Su ", "Xia ", "Fu ", "Yuan ", "Rong ", "Li ", "Ru ", "Yun ", "Gou ", "Ma ", "Bang ", "Dian ", "Tang ", "Hao ", "Jie ", "Xi ", "Shan ", "Qian ", "Jue ", "Cang ", "Chu ", "San ", "Bei ", "Xiao ", "Yong ", "Yao ", "Tan ", "Suo ", "Yang ", "Fa ", "Bing ", "Jia ", "Dai ", "Zai ", "Tang ", "[?] ", "Bin ", "Chu ", "Nuo ", "Can ", "Lei ", "Cui ", "Yong ", "Zao ", "Zong ", "Peng ", "Song ", "Ao ", "Chuan ", "Yu ", "Zhai ", "Cou ", "Shang ", "Qiang ", "Jing ", "Chi ", "Sha ", "Han ", "Zhang ", "Qing ", "Yan ", "Di ", "Xi ", "Lu ", "Bei ", "Piao ", "Jin ", "Lian ", "Lu ", "Man ", "Qian ", "Xian ", "Tan ", "Ying ", "Dong ", "Zhuan ", "Xiang ", "Shan ", "Qiao ", "Jiong ", "Tui ", "Zun ", "Pu ", "Xi ", "Lao ", "Chang ", "Guang ", "Liao ", "Qi ", "Deng ", "Chan ", "Wei ", "Ji ", "Fan ", "Hui ", "Chuan ", "Jian ", "Dan ", "Jiao ", "Jiu ", "Seng ", "Fen ", "Xian ", "Jue ", "E ", "Jiao ", "Jian ", "Tong ", "Lin ", "Bo ", "Gu ", "[?] ", "Su ", "Xian ", "Jiang ", "Min ", "Ye ", "Jin ", "Jia ", "Qiao ", "Pi ", "Feng ", "Zhou ", "Ai ", "Sai "},
- {"Yi ", "Jun ", "Nong ", "Chan ", "Yi ", "Dang ", "Jing ", "Xuan ", "Kuai ", "Jian ", "Chu ", "Dan ", "Jiao ", "Sha ", "Zai ", "[?] ", "Bin ", "An ", "Ru ", "Tai ", "Chou ", "Chai ", "Lan ", "Ni ", "Jin ", "Qian ", "Meng ", "Wu ", "Ning ", "Qiong ", "Ni ", "Chang ", "Lie ", "Lei ", "Lu ", "Kuang ", "Bao ", "Du ", "Biao ", "Zan ", "Zhi ", "Si ", "You ", "Hao ", "Chen ", "Chen ", "Li ", "Teng ", "Wei ", "Long ", "Chu ", "Chan ", "Rang ", "Shu ", "Hui ", "Li ", "Luo ", "Zan ", "Nuo ", "Tang ", "Yan ", "Lei ", "Nang ", "Er ", "Wu ", "Yun ", "Zan ", "Yuan ", "Xiong ", "Chong ", "Zhao ", "Xiong ", "Xian ", "Guang ", "Dui ", "Ke ", "Dui ", "Mian ", "Tu ", "Chang ", "Er ", "Dui ", "Er ", "Xin ", "Tu ", "Si ", "Yan ", "Yan ", "Shi ", "Shi ", "Dang ", "Qian ", "Dou ", "Fen ", "Mao ", "Shen ", "Dou ", "Bai ", "Jing ", "Li ", "Huang ", "Ru ", "Wang ", "Nei ", "Quan ", "Liang ", "Yu ", "Ba ", "Gong ", "Liu ", "Xi ", "[?] ", "Lan ", "Gong ", "Tian ", "Guan ", "Xing ", "Bing ", "Qi ", "Ju ", "Dian ", "Zi ", "Ppwun ", "Yang ", "Jian ", "Shou ", "Ji ", "Yi ", "Ji ", "Chan ", "Jiong ", "Mao ", "Ran ", "Nei ", "Yuan ", "Mao ", "Gang ", "Ran ", "Ce ", "Jiong ", "Ce ", "Zai ", "Gua ", "Jiong ", "Mao ", "Zhou ", "Mou ", "Gou ", "Xu ", "Mian ", "Mi ", "Rong ", "Yin ", "Xie ", "Kan ", "Jun ", "Nong ", "Yi ", "Mi ", "Shi ", "Guan ", "Meng ", "Zhong ", "Ju ", "Yuan ", "Ming ", "Kou ", "Lam ", "Fu ", "Xie ", "Mi ", "Bing ", "Dong ", "Tai ", "Gang ", "Feng ", "Bing ", "Hu ", "Chong ", "Jue ", "Hu ", "Kuang ", "Ye ", "Leng ", "Pan ", "Fu ", "Min ", "Dong ", "Xian ", "Lie ", "Xia ", "Jian ", "Jing ", "Shu ", "Mei ", "Tu ", "Qi ", "Gu ", "Zhun ", "Song ", "Jing ", "Liang ", "Qing ", "Diao ", "Ling ", "Dong ", "Gan ", "Jian ", "Yin ", "Cou ", "Yi ", "Li ", "Cang ", "Ming ", "Zhuen ", "Cui ", "Si ", "Duo ", "Jin ", "Lin ", "Lin ", "Ning ", "Xi ", "Du ", "Ji ", "Fan ", "Fan ", "Fan ", "Feng ", "Ju ", "Chu ", "Tako ", "Feng ", "Mok ", "Ci ", "Fu ", "Feng ", "Ping ", "Feng ", "Kai ", "Huang ", "Kai ", "Gan ", "Deng ", "Ping ", "Qu ", "Xiong ", "Kuai ", "Tu ", "Ao ", "Chu ", "Ji ", "Dang ", "Han ", "Han ", "Zao "},
- {"Dao ", "Diao ", "Dao ", "Ren ", "Ren ", "Chuang ", "Fen ", "Qie ", "Yi ", "Ji ", "Kan ", "Qian ", "Cun ", "Chu ", "Wen ", "Ji ", "Dan ", "Xing ", "Hua ", "Wan ", "Jue ", "Li ", "Yue ", "Lie ", "Liu ", "Ze ", "Gang ", "Chuang ", "Fu ", "Chu ", "Qu ", "Ju ", "Shan ", "Min ", "Ling ", "Zhong ", "Pan ", "Bie ", "Jie ", "Jie ", "Bao ", "Li ", "Shan ", "Bie ", "Chan ", "Jing ", "Gua ", "Gen ", "Dao ", "Chuang ", "Kui ", "Ku ", "Duo ", "Er ", "Zhi ", "Shua ", "Quan ", "Cha ", "Ci ", "Ke ", "Jie ", "Gui ", "Ci ", "Gui ", "Kai ", "Duo ", "Ji ", "Ti ", "Jing ", "Lou ", "Gen ", "Ze ", "Yuan ", "Cuo ", "Xue ", "Ke ", "La ", "Qian ", "Cha ", "Chuang ", "Gua ", "Jian ", "Cuo ", "Li ", "Ti ", "Fei ", "Pou ", "Chan ", "Qi ", "Chuang ", "Zi ", "Gang ", "Wan ", "Bo ", "Ji ", "Duo ", "Qing ", "Yan ", "Zhuo ", "Jian ", "Ji ", "Bo ", "Yan ", "Ju ", "Huo ", "Sheng ", "Jian ", "Duo ", "Duan ", "Wu ", "Gua ", "Fu ", "Sheng ", "Jian ", "Ge ", "Zha ", "Kai ", "Chuang ", "Juan ", "Chan ", "Tuan ", "Lu ", "Li ", "Fou ", "Shan ", "Piao ", "Kou ", "Jiao ", "Gua ", "Qiao ", "Jue ", "Hua ", "Zha ", "Zhuo ", "Lian ", "Ju ", "Pi ", "Liu ", "Gui ", "Jiao ", "Gui ", "Jian ", "Jian ", "Tang ", "Huo ", "Ji ", "Jian ", "Yi ", "Jian ", "Zhi ", "Chan ", "Cuan ", "Mo ", "Li ", "Zhu ", "Li ", "Ya ", "Quan ", "Ban ", "Gong ", "Jia ", "Wu ", "Mai ", "Lie ", "Jin ", "Keng ", "Xie ", "Zhi ", "Dong ", "Zhu ", "Nu ", "Jie ", "Qu ", "Shao ", "Yi ", "Zhu ", "Miao ", "Li ", "Jing ", "Lao ", "Lao ", "Juan ", "Kou ", "Yang ", "Wa ", "Xiao ", "Mou ", "Kuang ", "Jie ", "Lie ", "He ", "Shi ", "Ke ", "Jing ", "Hao ", "Bo ", "Min ", "Chi ", "Lang ", "Yong ", "Yong ", "Mian ", "Ke ", "Xun ", "Juan ", "Qing ", "Lu ", "Pou ", "Meng ", "Lai ", "Le ", "Kai ", "Mian ", "Dong ", "Xu ", "Xu ", "Kan ", "Wu ", "Yi ", "Xun ", "Weng ", "Sheng ", "Lao ", "Mu ", "Lu ", "Piao ", "Shi ", "Ji ", "Qin ", "Qiang ", "Jiao ", "Quan ", "Yang ", "Yi ", "Jue ", "Fan ", "Juan ", "Tong ", "Ju ", "Dan ", "Xie ", "Mai ", "Xun ", "Xun ", "Lu ", "Li ", "Che ", "Rang ", "Quan ", "Bao ", "Shao ", "Yun ", "Jiu ", "Bao ", "Gou ", "Wu "},
- {"Yun ", "Mwun ", "Nay ", "Gai ", "Gai ", "Bao ", "Cong ", "[?] ", "Xiong ", "Peng ", "Ju ", "Tao ", "Ge ", "Pu ", "An ", "Pao ", "Fu ", "Gong ", "Da ", "Jiu ", "Qiong ", "Bi ", "Hua ", "Bei ", "Nao ", "Chi ", "Fang ", "Jiu ", "Yi ", "Za ", "Jiang ", "Kang ", "Jiang ", "Kuang ", "Hu ", "Xia ", "Qu ", "Bian ", "Gui ", "Qie ", "Zang ", "Kuang ", "Fei ", "Hu ", "Tou ", "Gui ", "Gui ", "Hui ", "Dan ", "Gui ", "Lian ", "Lian ", "Suan ", "Du ", "Jiu ", "Qu ", "Xi ", "Pi ", "Qu ", "Yi ", "Qia ", "Yan ", "Bian ", "Ni ", "Qu ", "Shi ", "Xin ", "Qian ", "Nian ", "Sa ", "Zu ", "Sheng ", "Wu ", "Hui ", "Ban ", "Shi ", "Xi ", "Wan ", "Hua ", "Xie ", "Wan ", "Bei ", "Zu ", "Zhuo ", "Xie ", "Dan ", "Mai ", "Nan ", "Dan ", "Ji ", "Bo ", "Shuai ", "Bu ", "Kuang ", "Bian ", "Bu ", "Zhan ", "Qia ", "Lu ", "You ", "Lu ", "Xi ", "Gua ", "Wo ", "Xie ", "Jie ", "Jie ", "Wei ", "Ang ", "Qiong ", "Zhi ", "Mao ", "Yin ", "Wei ", "Shao ", "Ji ", "Que ", "Luan ", "Shi ", "Juan ", "Xie ", "Xu ", "Jin ", "Que ", "Wu ", "Ji ", "E ", "Qing ", "Xi ", "[?] ", "Han ", "Zhan ", "E ", "Ting ", "Li ", "Zhe ", "Han ", "Li ", "Ya ", "Ya ", "Yan ", "She ", "Zhi ", "Zha ", "Pang ", "[?] ", "He ", "Ya ", "Zhi ", "Ce ", "Pang ", "Ti ", "Li ", "She ", "Hou ", "Ting ", "Zui ", "Cuo ", "Fei ", "Yuan ", "Ce ", "Yuan ", "Xiang ", "Yan ", "Li ", "Jue ", "Sha ", "Dian ", "Chu ", "Jiu ", "Qin ", "Ao ", "Gui ", "Yan ", "Si ", "Li ", "Chang ", "Lan ", "Li ", "Yan ", "Yan ", "Yuan ", "Si ", "Gong ", "Lin ", "Qiu ", "Qu ", "Qu ", "Uk ", "Lei ", "Du ", "Xian ", "Zhuan ", "San ", "Can ", "Can ", "Can ", "Can ", "Ai ", "Dai ", "You ", "Cha ", "Ji ", "You ", "Shuang ", "Fan ", "Shou ", "Guai ", "Ba ", "Fa ", "Ruo ", "Shi ", "Shu ", "Zhuo ", "Qu ", "Shou ", "Bian ", "Xu ", "Jia ", "Pan ", "Sou ", "Gao ", "Wei ", "Sou ", "Die ", "Rui ", "Cong ", "Kou ", "Gu ", "Ju ", "Ling ", "Gua ", "Tao ", "Kou ", "Zhi ", "Jiao ", "Zhao ", "Ba ", "Ding ", "Ke ", "Tai ", "Chi ", "Shi ", "You ", "Qiu ", "Po ", "Xie ", "Hao ", "Si ", "Tan ", "Chi ", "Le ", "Diao ", "Ji ", "[?] ", "Hong "},
- {"Mie ", "Xu ", "Mang ", "Chi ", "Ge ", "Xuan ", "Yao ", "Zi ", "He ", "Ji ", "Diao ", "Cun ", "Tong ", "Ming ", "Hou ", "Li ", "Tu ", "Xiang ", "Zha ", "Xia ", "Ye ", "Lu ", "A ", "Ma ", "Ou ", "Xue ", "Yi ", "Jun ", "Chou ", "Lin ", "Tun ", "Yin ", "Fei ", "Bi ", "Qin ", "Qin ", "Jie ", "Bu ", "Fou ", "Ba ", "Dun ", "Fen ", "E ", "Han ", "Ting ", "Hang ", "Shun ", "Qi ", "Hong ", "Zhi ", "Shen ", "Wu ", "Wu ", "Chao ", "Ne ", "Xue ", "Xi ", "Chui ", "Dou ", "Wen ", "Hou ", "Ou ", "Wu ", "Gao ", "Ya ", "Jun ", "Lu ", "E ", "Ge ", "Mei ", "Ai ", "Qi ", "Cheng ", "Wu ", "Gao ", "Fu ", "Jiao ", "Hong ", "Chi ", "Sheng ", "Ne ", "Tun ", "Fu ", "Yi ", "Dai ", "Ou ", "Li ", "Bai ", "Yuan ", "Kuai ", "[?] ", "Qiang ", "Wu ", "E ", "Shi ", "Quan ", "Pen ", "Wen ", "Ni ", "M ", "Ling ", "Ran ", "You ", "Di ", "Zhou ", "Shi ", "Zhou ", "Tie ", "Xi ", "Yi ", "Qi ", "Ping ", "Zi ", "Gu ", "Zi ", "Wei ", "Xu ", "He ", "Nao ", "Xia ", "Pei ", "Yi ", "Xiao ", "Shen ", "Hu ", "Ming ", "Da ", "Qu ", "Ju ", "Gem ", "Za ", "Tuo ", "Duo ", "Pou ", "Pao ", "Bi ", "Fu ", "Yang ", "He ", "Zha ", "He ", "Hai ", "Jiu ", "Yong ", "Fu ", "Que ", "Zhou ", "Wa ", "Ka ", "Gu ", "Ka ", "Zuo ", "Bu ", "Long ", "Dong ", "Ning ", "Tha ", "Si ", "Xian ", "Huo ", "Qi ", "Er ", "E ", "Guang ", "Zha ", "Xi ", "Yi ", "Lie ", "Zi ", "Mie ", "Mi ", "Zhi ", "Yao ", "Ji ", "Zhou ", "Ge ", "Shuai ", "Zan ", "Xiao ", "Ke ", "Hui ", "Kua ", "Huai ", "Tao ", "Xian ", "E ", "Xuan ", "Xiu ", "Wai ", "Yan ", "Lao ", "Yi ", "Ai ", "Pin ", "Shen ", "Tong ", "Hong ", "Xiong ", "Chi ", "Wa ", "Ha ", "Zai ", "Yu ", "Di ", "Pai ", "Xiang ", "Ai ", "Hen ", "Kuang ", "Ya ", "Da ", "Xiao ", "Bi ", "Yue ", "[?] ", "Hua ", "Sasou ", "Kuai ", "Duo ", "[?] ", "Ji ", "Nong ", "Mou ", "Yo ", "Hao ", "Yuan ", "Long ", "Pou ", "Mang ", "Ge ", "E ", "Chi ", "Shao ", "Li ", "Na ", "Zu ", "He ", "Ku ", "Xiao ", "Xian ", "Lao ", "Bo ", "Zhe ", "Zha ", "Liang ", "Ba ", "Mie ", "Le ", "Sui ", "Fou ", "Bu ", "Han ", "Heng ", "Geng ", "Shuo ", "Ge "},
- {"You ", "Yan ", "Gu ", "Gu ", "Bai ", "Han ", "Suo ", "Chun ", "Yi ", "Ai ", "Jia ", "Tu ", "Xian ", "Huan ", "Li ", "Xi ", "Tang ", "Zuo ", "Qiu ", "Che ", "Wu ", "Zao ", "Ya ", "Dou ", "Qi ", "Di ", "Qin ", "Ma ", "Mal ", "Hong ", "Dou ", "Kes ", "Lao ", "Liang ", "Suo ", "Zao ", "Huan ", "Lang ", "Sha ", "Ji ", "Zuo ", "Wo ", "Feng ", "Yin ", "Hu ", "Qi ", "Shou ", "Wei ", "Shua ", "Chang ", "Er ", "Li ", "Qiang ", "An ", "Jie ", "Yo ", "Nian ", "Yu ", "Tian ", "Lai ", "Sha ", "Xi ", "Tuo ", "Hu ", "Ai ", "Zhou ", "Nou ", "Ken ", "Zhuo ", "Zhuo ", "Shang ", "Di ", "Heng ", "Lan ", "A ", "Xiao ", "Xiang ", "Tun ", "Wu ", "Wen ", "Cui ", "Sha ", "Hu ", "Qi ", "Qi ", "Tao ", "Dan ", "Dan ", "Ye ", "Zi ", "Bi ", "Cui ", "Chuo ", "He ", "Ya ", "Qi ", "Zhe ", "Pei ", "Liang ", "Xian ", "Pi ", "Sha ", "La ", "Ze ", "Qing ", "Gua ", "Pa ", "Zhe ", "Se ", "Zhuan ", "Nie ", "Guo ", "Luo ", "Yan ", "Di ", "Quan ", "Tan ", "Bo ", "Ding ", "Lang ", "Xiao ", "[?] ", "Tang ", "Chi ", "Ti ", "An ", "Jiu ", "Dan ", "Ke ", "Yong ", "Wei ", "Nan ", "Shan ", "Yu ", "Zhe ", "La ", "Jie ", "Hou ", "Han ", "Die ", "Zhou ", "Chai ", "Wai ", "Re ", "Yu ", "Yin ", "Zan ", "Yao ", "Wo ", "Mian ", "Hu ", "Yun ", "Chuan ", "Hui ", "Huan ", "Huan ", "Xi ", "He ", "Ji ", "Kui ", "Zhong ", "Wei ", "Sha ", "Xu ", "Huang ", "Du ", "Nie ", "Xuan ", "Liang ", "Yu ", "Sang ", "Chi ", "Qiao ", "Yan ", "Dan ", "Pen ", "Can ", "Li ", "Yo ", "Zha ", "Wei ", "Miao ", "Ying ", "Pen ", "Phos ", "Kui ", "Xi ", "Yu ", "Jie ", "Lou ", "Ku ", "Sao ", "Huo ", "Ti ", "Yao ", "He ", "A ", "Xiu ", "Qiang ", "Se ", "Yong ", "Su ", "Hong ", "Xie ", "Yi ", "Suo ", "Ma ", "Cha ", "Hai ", "Ke ", "Ta ", "Sang ", "Tian ", "Ru ", "Sou ", "Wa ", "Ji ", "Pang ", "Wu ", "Xian ", "Shi ", "Ge ", "Zi ", "Jie ", "Luo ", "Weng ", "Wa ", "Si ", "Chi ", "Hao ", "Suo ", "Jia ", "Hai ", "Suo ", "Qin ", "Nie ", "He ", "Cis ", "Sai ", "Ng ", "Ge ", "Na ", "Dia ", "Ai ", "[?] ", "Tong ", "Bi ", "Ao ", "Ao ", "Lian ", "Cui ", "Zhe ", "Mo ", "Sou ", "Sou ", "Tan "},
- {"Di ", "Qi ", "Jiao ", "Chong ", "Jiao ", "Kai ", "Tan ", "San ", "Cao ", "Jia ", "Ai ", "Xiao ", "Piao ", "Lou ", "Ga ", "Gu ", "Xiao ", "Hu ", "Hui ", "Guo ", "Ou ", "Xian ", "Ze ", "Chang ", "Xu ", "Po ", "De ", "Ma ", "Ma ", "Hu ", "Lei ", "Du ", "Ga ", "Tang ", "Ye ", "Beng ", "Ying ", "Saai ", "Jiao ", "Mi ", "Xiao ", "Hua ", "Mai ", "Ran ", "Zuo ", "Peng ", "Lao ", "Xiao ", "Ji ", "Zhu ", "Chao ", "Kui ", "Zui ", "Xiao ", "Si ", "Hao ", "Fu ", "Liao ", "Qiao ", "Xi ", "Xiu ", "Tan ", "Tan ", "Mo ", "Xun ", "E ", "Zun ", "Fan ", "Chi ", "Hui ", "Zan ", "Chuang ", "Cu ", "Dan ", "Yu ", "Tun ", "Cheng ", "Jiao ", "Ye ", "Xi ", "Qi ", "Hao ", "Lian ", "Xu ", "Deng ", "Hui ", "Yin ", "Pu ", "Jue ", "Qin ", "Xun ", "Nie ", "Lu ", "Si ", "Yan ", "Ying ", "Da ", "Dan ", "Yu ", "Zhou ", "Jin ", "Nong ", "Yue ", "Hui ", "Qi ", "E ", "Zao ", "Yi ", "Shi ", "Jiao ", "Yuan ", "Ai ", "Yong ", "Jue ", "Kuai ", "Yu ", "Pen ", "Dao ", "Ge ", "Xin ", "Dun ", "Dang ", "Sin ", "Sai ", "Pi ", "Pi ", "Yin ", "Zui ", "Ning ", "Di ", "Lan ", "Ta ", "Huo ", "Ru ", "Hao ", "Xia ", "Ya ", "Duo ", "Xi ", "Chou ", "Ji ", "Jin ", "Hao ", "Ti ", "Chang ", "[?] ", "[?] ", "Ca ", "Ti ", "Lu ", "Hui ", "Bo ", "You ", "Nie ", "Yin ", "Hu ", "Mo ", "Huang ", "Zhe ", "Li ", "Liu ", "Haai ", "Nang ", "Xiao ", "Mo ", "Yan ", "Li ", "Lu ", "Long ", "Fu ", "Dan ", "Chen ", "Pin ", "Pi ", "Xiang ", "Huo ", "Mo ", "Xi ", "Duo ", "Ku ", "Yan ", "Chan ", "Ying ", "Rang ", "Dian ", "La ", "Ta ", "Xiao ", "Jiao ", "Chuo ", "Huan ", "Huo ", "Zhuan ", "Nie ", "Xiao ", "Ca ", "Li ", "Chan ", "Chai ", "Li ", "Yi ", "Luo ", "Nang ", "Zan ", "Su ", "Xi ", "So ", "Jian ", "Za ", "Zhu ", "Lan ", "Nie ", "Nang ", "[?] ", "[?] ", "Wei ", "Hui ", "Yin ", "Qiu ", "Si ", "Nin ", "Jian ", "Hui ", "Xin ", "Yin ", "Nan ", "Tuan ", "Tuan ", "Dun ", "Kang ", "Yuan ", "Jiong ", "Pian ", "Yun ", "Cong ", "Hu ", "Hui ", "Yuan ", "You ", "Guo ", "Kun ", "Cong ", "Wei ", "Tu ", "Wei ", "Lun ", "Guo ", "Qun ", "Ri ", "Ling ", "Gu ", "Guo ", "Tai ", "Guo ", "Tu ", "You "},
- {"Guo ", "Yin ", "Hun ", "Pu ", "Yu ", "Han ", "Yuan ", "Lun ", "Quan ", "Yu ", "Qing ", "Guo ", "Chuan ", "Wei ", "Yuan ", "Quan ", "Ku ", "Fu ", "Yuan ", "Yuan ", "E ", "Tu ", "Tu ", "Tu ", "Tuan ", "Lue ", "Hui ", "Yi ", "Yuan ", "Luan ", "Luan ", "Tu ", "Ya ", "Tu ", "Ting ", "Sheng ", "Pu ", "Lu ", "Iri ", "Ya ", "Zai ", "Wei ", "Ge ", "Yu ", "Wu ", "Gui ", "Pi ", "Yi ", "Di ", "Qian ", "Qian ", "Zhen ", "Zhuo ", "Dang ", "Qia ", "Akutsu ", "Yama ", "Kuang ", "Chang ", "Qi ", "Nie ", "Mo ", "Ji ", "Jia ", "Zhi ", "Zhi ", "Ban ", "Xun ", "Tou ", "Qin ", "Fen ", "Jun ", "Keng ", "Tun ", "Fang ", "Fen ", "Ben ", "Tan ", "Kan ", "Pi ", "Zuo ", "Keng ", "Bi ", "Xing ", "Di ", "Jing ", "Ji ", "Kuai ", "Di ", "Jing ", "Jian ", "Tan ", "Li ", "Ba ", "Wu ", "Fen ", "Zhui ", "Po ", "Pan ", "Tang ", "Kun ", "Qu ", "Tan ", "Zhi ", "Tuo ", "Gan ", "Ping ", "Dian ", "Gua ", "Ni ", "Tai ", "Pi ", "Jiong ", "Yang ", "Fo ", "Ao ", "Liu ", "Qiu ", "Mu ", "Ke ", "Gou ", "Xue ", "Ba ", "Chi ", "Che ", "Ling ", "Zhu ", "Fu ", "Hu ", "Zhi ", "Chui ", "La ", "Long ", "Long ", "Lu ", "Ao ", "Tay ", "Pao ", "[?] ", "Xing ", "Dong ", "Ji ", "Ke ", "Lu ", "Ci ", "Chi ", "Lei ", "Gai ", "Yin ", "Hou ", "Dui ", "Zhao ", "Fu ", "Guang ", "Yao ", "Duo ", "Duo ", "Gui ", "Cha ", "Yang ", "Yin ", "Fa ", "Gou ", "Yuan ", "Die ", "Xie ", "Ken ", "Jiong ", "Shou ", "E ", "Ha ", "Dian ", "Hong ", "Wu ", "Kua ", "[?] ", "Tao ", "Dang ", "Kai ", "Gake ", "Nao ", "An ", "Xing ", "Xian ", "Huan ", "Bang ", "Pei ", "Ba ", "Yi ", "Yin ", "Han ", "Xu ", "Chui ", "Cen ", "Geng ", "Ai ", "Peng ", "Fang ", "Que ", "Yong ", "Xun ", "Jia ", "Di ", "Mai ", "Lang ", "Xuan ", "Cheng ", "Yan ", "Jin ", "Zhe ", "Lei ", "Lie ", "Bu ", "Cheng ", "Gomi ", "Bu ", "Shi ", "Xun ", "Guo ", "Jiong ", "Ye ", "Nian ", "Di ", "Yu ", "Bu ", "Ya ", "Juan ", "Sui ", "Pi ", "Cheng ", "Wan ", "Ju ", "Lun ", "Zheng ", "Kong ", "Chong ", "Dong ", "Dai ", "Tan ", "An ", "Cai ", "Shu ", "Beng ", "Kan ", "Zhi ", "Duo ", "Yi ", "Zhi ", "Yi ", "Pei ", "Ji ", "Zhun ", "Qi ", "Sao ", "Ju ", "Ni "},
- {"Ku ", "Ke ", "Tang ", "Kun ", "Ni ", "Jian ", "Dui ", "Jin ", "Gang ", "Yu ", "E ", "Peng ", "Gu ", "Tu ", "Leng ", "[?] ", "Ya ", "Qian ", "[?] ", "An ", "[?] ", "Duo ", "Nao ", "Tu ", "Cheng ", "Yin ", "Hun ", "Bi ", "Lian ", "Guo ", "Die ", "Zhuan ", "Hou ", "Bao ", "Bao ", "Yu ", "Di ", "Mao ", "Jie ", "Ruan ", "E ", "Geng ", "Kan ", "Zong ", "Yu ", "Huang ", "E ", "Yao ", "Yan ", "Bao ", "Ji ", "Mei ", "Chang ", "Du ", "Tuo ", "Yin ", "Feng ", "Zhong ", "Jie ", "Zhen ", "Feng ", "Gang ", "Chuan ", "Jian ", "Pyeng ", "Toride ", "Xiang ", "Huang ", "Leng ", "Duan ", "[?] ", "Xuan ", "Ji ", "Ji ", "Kuai ", "Ying ", "Ta ", "Cheng ", "Yong ", "Kai ", "Su ", "Su ", "Shi ", "Mi ", "Ta ", "Weng ", "Cheng ", "Tu ", "Tang ", "Que ", "Zhong ", "Li ", "Peng ", "Bang ", "Sai ", "Zang ", "Dui ", "Tian ", "Wu ", "Cheng ", "Xun ", "Ge ", "Zhen ", "Ai ", "Gong ", "Yan ", "Kan ", "Tian ", "Yuan ", "Wen ", "Xie ", "Liu ", "Ama ", "Lang ", "Chang ", "Peng ", "Beng ", "Chen ", "Cu ", "Lu ", "Ou ", "Qian ", "Mei ", "Mo ", "Zhuan ", "Shuang ", "Shu ", "Lou ", "Chi ", "Man ", "Biao ", "Jing ", "Qi ", "Shu ", "Di ", "Zhang ", "Kan ", "Yong ", "Dian ", "Chen ", "Zhi ", "Xi ", "Guo ", "Qiang ", "Jin ", "Di ", "Shang ", "Mu ", "Cui ", "Yan ", "Ta ", "Zeng ", "Qi ", "Qiang ", "Liang ", "[?] ", "Zhui ", "Qiao ", "Zeng ", "Xu ", "Shan ", "Shan ", "Ba ", "Pu ", "Kuai ", "Dong ", "Fan ", "Que ", "Mo ", "Dun ", "Dun ", "Dun ", "Di ", "Sheng ", "Duo ", "Duo ", "Tan ", "Deng ", "Wu ", "Fen ", "Huang ", "Tan ", "Da ", "Ye ", "Sho ", "Mama ", "Yu ", "Qiang ", "Ji ", "Qiao ", "Ken ", "Yi ", "Pi ", "Bi ", "Dian ", "Jiang ", "Ye ", "Yong ", "Bo ", "Tan ", "Lan ", "Ju ", "Huai ", "Dang ", "Rang ", "Qian ", "Xun ", "Lan ", "Xi ", "He ", "Ai ", "Ya ", "Dao ", "Hao ", "Ruan ", "Mama ", "Lei ", "Kuang ", "Lu ", "Yan ", "Tan ", "Wei ", "Huai ", "Long ", "Long ", "Rui ", "Li ", "Lin ", "Rang ", "Ten ", "Xun ", "Yan ", "Lei ", "Ba ", "[?] ", "Shi ", "Ren ", "[?] ", "Zhuang ", "Zhuang ", "Sheng ", "Yi ", "Mai ", "Ke ", "Zhu ", "Zhuang ", "Hu ", "Hu ", "Kun ", "Yi ", "Hu ", "Xu ", "Kun ", "Shou ", "Mang ", "Zun "},
- {"Shou ", "Yi ", "Zhi ", "Gu ", "Chu ", "Jiang ", "Feng ", "Bei ", "Cay ", "Bian ", "Sui ", "Qun ", "Ling ", "Fu ", "Zuo ", "Xia ", "Xiong ", "[?] ", "Nao ", "Xia ", "Kui ", "Xi ", "Wai ", "Yuan ", "Mao ", "Su ", "Duo ", "Duo ", "Ye ", "Qing ", "Uys ", "Gou ", "Gou ", "Qi ", "Meng ", "Meng ", "Yin ", "Huo ", "Chen ", "Da ", "Ze ", "Tian ", "Tai ", "Fu ", "Guai ", "Yao ", "Yang ", "Hang ", "Gao ", "Shi ", "Ben ", "Tai ", "Tou ", "Yan ", "Bi ", "Yi ", "Kua ", "Jia ", "Duo ", "Kwu ", "Kuang ", "Yun ", "Jia ", "Pa ", "En ", "Lian ", "Huan ", "Di ", "Yan ", "Pao ", "Quan ", "Qi ", "Nai ", "Feng ", "Xie ", "Fen ", "Dian ", "[?] ", "Kui ", "Zou ", "Huan ", "Qi ", "Kai ", "Zha ", "Ben ", "Yi ", "Jiang ", "Tao ", "Zang ", "Ben ", "Xi ", "Xiang ", "Fei ", "Diao ", "Xun ", "Keng ", "Dian ", "Ao ", "She ", "Weng ", "Pan ", "Ao ", "Wu ", "Ao ", "Jiang ", "Lian ", "Duo ", "Yun ", "Jiang ", "Shi ", "Fen ", "Huo ", "Bi ", "Lian ", "Duo ", "Nu ", "Nu ", "Ding ", "Nai ", "Qian ", "Jian ", "Ta ", "Jiu ", "Nan ", "Cha ", "Hao ", "Xian ", "Fan ", "Ji ", "Shuo ", "Ru ", "Fei ", "Wang ", "Hong ", "Zhuang ", "Fu ", "Ma ", "Dan ", "Ren ", "Fu ", "Jing ", "Yan ", "Xie ", "Wen ", "Zhong ", "Pa ", "Du ", "Ji ", "Keng ", "Zhong ", "Yao ", "Jin ", "Yun ", "Miao ", "Pei ", "Shi ", "Yue ", "Zhuang ", "Niu ", "Yan ", "Na ", "Xin ", "Fen ", "Bi ", "Yu ", "Tuo ", "Feng ", "Yuan ", "Fang ", "Wu ", "Yu ", "Gui ", "Du ", "Ba ", "Ni ", "Zhou ", "Zhuo ", "Zhao ", "Da ", "Nai ", "Yuan ", "Tou ", "Xuan ", "Zhi ", "E ", "Mei ", "Mo ", "Qi ", "Bi ", "Shen ", "Qie ", "E ", "He ", "Xu ", "Fa ", "Zheng ", "Min ", "Ban ", "Mu ", "Fu ", "Ling ", "Zi ", "Zi ", "Shi ", "Ran ", "Shan ", "Yang ", "Man ", "Jie ", "Gu ", "Si ", "Xing ", "Wei ", "Zi ", "Ju ", "Shan ", "Pin ", "Ren ", "Yao ", "Tong ", "Jiang ", "Shu ", "Ji ", "Gai ", "Shang ", "Kuo ", "Juan ", "Jiao ", "Gou ", "Mu ", "Jian ", "Jian ", "Yi ", "Nian ", "Zhi ", "Ji ", "Ji ", "Xian ", "Heng ", "Guang ", "Jun ", "Kua ", "Yan ", "Ming ", "Lie ", "Pei ", "Yan ", "You ", "Yan ", "Cha ", "Shen ", "Yin ", "Chi ", "Gui ", "Quan ", "Zi "},
- {"Song ", "Wei ", "Hong ", "Wa ", "Lou ", "Ya ", "Rao ", "Jiao ", "Luan ", "Ping ", "Xian ", "Shao ", "Li ", "Cheng ", "Xiao ", "Mang ", "Fu ", "Suo ", "Wu ", "Wei ", "Ke ", "Lai ", "Chuo ", "Ding ", "Niang ", "Xing ", "Nan ", "Yu ", "Nuo ", "Pei ", "Nei ", "Juan ", "Shen ", "Zhi ", "Han ", "Di ", "Zhuang ", "E ", "Pin ", "Tui ", "Han ", "Mian ", "Wu ", "Yan ", "Wu ", "Xi ", "Yan ", "Yu ", "Si ", "Yu ", "Wa ", "[?] ", "Xian ", "Ju ", "Qu ", "Shui ", "Qi ", "Xian ", "Zhui ", "Dong ", "Chang ", "Lu ", "Ai ", "E ", "E ", "Lou ", "Mian ", "Cong ", "Pou ", "Ju ", "Po ", "Cai ", "Ding ", "Wan ", "Biao ", "Xiao ", "Shu ", "Qi ", "Hui ", "Fu ", "E ", "Wo ", "Tan ", "Fei ", "Wei ", "Jie ", "Tian ", "Ni ", "Quan ", "Jing ", "Hun ", "Jing ", "Qian ", "Dian ", "Xing ", "Hu ", "Wa ", "Lai ", "Bi ", "Yin ", "Chou ", "Chuo ", "Fu ", "Jing ", "Lun ", "Yan ", "Lan ", "Kun ", "Yin ", "Ya ", "Ju ", "Li ", "Dian ", "Xian ", "Hwa ", "Hua ", "Ying ", "Chan ", "Shen ", "Ting ", "Dang ", "Yao ", "Wu ", "Nan ", "Ruo ", "Jia ", "Tou ", "Xu ", "Yu ", "Wei ", "Ti ", "Rou ", "Mei ", "Dan ", "Ruan ", "Qin ", "Hui ", "Wu ", "Qian ", "Chun ", "Mao ", "Fu ", "Jie ", "Duan ", "Xi ", "Zhong ", "Mei ", "Huang ", "Mian ", "An ", "Ying ", "Xuan ", "Jie ", "Wei ", "Mei ", "Yuan ", "Zhen ", "Qiu ", "Ti ", "Xie ", "Tuo ", "Lian ", "Mao ", "Ran ", "Si ", "Pian ", "Wei ", "Wa ", "Jiu ", "Hu ", "Ao ", "[?] ", "Bou ", "Xu ", "Tou ", "Gui ", "Zou ", "Yao ", "Pi ", "Xi ", "Yuan ", "Ying ", "Rong ", "Ru ", "Chi ", "Liu ", "Mei ", "Pan ", "Ao ", "Ma ", "Gou ", "Kui ", "Qin ", "Jia ", "Sao ", "Zhen ", "Yuan ", "Cha ", "Yong ", "Ming ", "Ying ", "Ji ", "Su ", "Niao ", "Xian ", "Tao ", "Pang ", "Lang ", "Nao ", "Bao ", "Ai ", "Pi ", "Pin ", "Yi ", "Piao ", "Yu ", "Lei ", "Xuan ", "Man ", "Yi ", "Zhang ", "Kang ", "Yong ", "Ni ", "Li ", "Di ", "Gui ", "Yan ", "Jin ", "Zhuan ", "Chang ", "Ce ", "Han ", "Nen ", "Lao ", "Mo ", "Zhe ", "Hu ", "Hu ", "Ao ", "Nen ", "Qiang ", "Ma ", "Pie ", "Gu ", "Wu ", "Jiao ", "Tuo ", "Zhan ", "Mao ", "Xian ", "Xian ", "Mo ", "Liao ", "Lian ", "Hua "},
- {"Gui ", "Deng ", "Zhi ", "Xu ", "Yi ", "Hua ", "Xi ", "Hui ", "Rao ", "Xi ", "Yan ", "Chan ", "Jiao ", "Mei ", "Fan ", "Fan ", "Xian ", "Yi ", "Wei ", "Jiao ", "Fu ", "Shi ", "Bi ", "Shan ", "Sui ", "Qiang ", "Lian ", "Huan ", "Xin ", "Niao ", "Dong ", "Yi ", "Can ", "Ai ", "Niang ", "Neng ", "Ma ", "Tiao ", "Chou ", "Jin ", "Ci ", "Yu ", "Pin ", "Yong ", "Xu ", "Nai ", "Yan ", "Tai ", "Ying ", "Can ", "Niao ", "Wo ", "Ying ", "Mian ", "Kaka ", "Ma ", "Shen ", "Xing ", "Ni ", "Du ", "Liu ", "Yuan ", "Lan ", "Yan ", "Shuang ", "Ling ", "Jiao ", "Niang ", "Lan ", "Xian ", "Ying ", "Shuang ", "Shuai ", "Quan ", "Mi ", "Li ", "Luan ", "Yan ", "Zhu ", "Lan ", "Zi ", "Jie ", "Jue ", "Jue ", "Kong ", "Yun ", "Zi ", "Zi ", "Cun ", "Sun ", "Fu ", "Bei ", "Zi ", "Xiao ", "Xin ", "Meng ", "Si ", "Tai ", "Bao ", "Ji ", "Gu ", "Nu ", "Xue ", "[?] ", "Zhuan ", "Hai ", "Luan ", "Sun ", "Huai ", "Mie ", "Cong ", "Qian ", "Shu ", "Chan ", "Ya ", "Zi ", "Ni ", "Fu ", "Zi ", "Li ", "Xue ", "Bo ", "Ru ", "Lai ", "Nie ", "Nie ", "Ying ", "Luan ", "Mian ", "Zhu ", "Rong ", "Ta ", "Gui ", "Zhai ", "Qiong ", "Yu ", "Shou ", "An ", "Tu ", "Song ", "Wan ", "Rou ", "Yao ", "Hong ", "Yi ", "Jing ", "Zhun ", "Mi ", "Zhu ", "Dang ", "Hong ", "Zong ", "Guan ", "Zhou ", "Ding ", "Wan ", "Yi ", "Bao ", "Shi ", "Shi ", "Chong ", "Shen ", "Ke ", "Xuan ", "Shi ", "You ", "Huan ", "Yi ", "Tiao ", "Shi ", "Xian ", "Gong ", "Cheng ", "Qun ", "Gong ", "Xiao ", "Zai ", "Zha ", "Bao ", "Hai ", "Yan ", "Xiao ", "Jia ", "Shen ", "Chen ", "Rong ", "Huang ", "Mi ", "Kou ", "Kuan ", "Bin ", "Su ", "Cai ", "Zan ", "Ji ", "Yuan ", "Ji ", "Yin ", "Mi ", "Kou ", "Qing ", "Que ", "Zhen ", "Jian ", "Fu ", "Ning ", "Bing ", "Huan ", "Mei ", "Qin ", "Han ", "Yu ", "Shi ", "Ning ", "Qin ", "Ning ", "Zhi ", "Yu ", "Bao ", "Kuan ", "Ning ", "Qin ", "Mo ", "Cha ", "Ju ", "Gua ", "Qin ", "Hu ", "Wu ", "Liao ", "Shi ", "Zhu ", "Zhai ", "Shen ", "Wei ", "Xie ", "Kuan ", "Hui ", "Liao ", "Jun ", "Huan ", "Yi ", "Yi ", "Bao ", "Qin ", "Chong ", "Bao ", "Feng ", "Cun ", "Dui ", "Si ", "Xun ", "Dao ", "Lu ", "Dui ", "Shou "},
- {"Po ", "Feng ", "Zhuan ", "Fu ", "She ", "Ke ", "Jiang ", "Jiang ", "Zhuan ", "Wei ", "Zun ", "Xun ", "Shu ", "Dui ", "Dao ", "Xiao ", "Ji ", "Shao ", "Er ", "Er ", "Er ", "Ga ", "Jian ", "Shu ", "Chen ", "Shang ", "Shang ", "Mo ", "Ga ", "Chang ", "Liao ", "Xian ", "Xian ", "[?] ", "Wang ", "Wang ", "You ", "Liao ", "Liao ", "Yao ", "Mang ", "Wang ", "Wang ", "Wang ", "Ga ", "Yao ", "Duo ", "Kui ", "Zhong ", "Jiu ", "Gan ", "Gu ", "Gan ", "Tui ", "Gan ", "Gan ", "Shi ", "Yin ", "Chi ", "Kao ", "Ni ", "Jin ", "Wei ", "Niao ", "Ju ", "Pi ", "Ceng ", "Xi ", "Bi ", "Ju ", "Jie ", "Tian ", "Qu ", "Ti ", "Jie ", "Wu ", "Diao ", "Shi ", "Shi ", "Ping ", "Ji ", "Xie ", "Chen ", "Xi ", "Ni ", "Zhan ", "Xi ", "[?] ", "Man ", "E ", "Lou ", "Ping ", "Ti ", "Fei ", "Shu ", "Xie ", "Tu ", "Lu ", "Lu ", "Xi ", "Ceng ", "Lu ", "Ju ", "Xie ", "Ju ", "Jue ", "Liao ", "Jue ", "Shu ", "Xi ", "Che ", "Tun ", "Ni ", "Shan ", "[?] ", "Xian ", "Li ", "Xue ", "Nata ", "[?] ", "Long ", "Yi ", "Qi ", "Ren ", "Wu ", "Han ", "Shen ", "Yu ", "Chu ", "Sui ", "Qi ", "[?] ", "Yue ", "Ban ", "Yao ", "Ang ", "Ya ", "Wu ", "Jie ", "E ", "Ji ", "Qian ", "Fen ", "Yuan ", "Qi ", "Cen ", "Qian ", "Qi ", "Cha ", "Jie ", "Qu ", "Gang ", "Xian ", "Ao ", "Lan ", "Dao ", "Ba ", "Zuo ", "Zuo ", "Yang ", "Ju ", "Gang ", "Ke ", "Gou ", "Xue ", "Bei ", "Li ", "Tiao ", "Ju ", "Yan ", "Fu ", "Xiu ", "Jia ", "Ling ", "Tuo ", "Pei ", "You ", "Dai ", "Kuang ", "Yue ", "Qu ", "Hu ", "Po ", "Min ", "An ", "Tiao ", "Ling ", "Chi ", "Yuri ", "Dong ", "Cem ", "Kui ", "Xiu ", "Mao ", "Tong ", "Xue ", "Yi ", "Kura ", "He ", "Ke ", "Luo ", "E ", "Fu ", "Xun ", "Die ", "Lu ", "An ", "Er ", "Gai ", "Quan ", "Tong ", "Yi ", "Mu ", "Shi ", "An ", "Wei ", "Hu ", "Zhi ", "Mi ", "Li ", "Ji ", "Tong ", "Wei ", "You ", "Sang ", "Xia ", "Li ", "Yao ", "Jiao ", "Zheng ", "Luan ", "Jiao ", "E ", "E ", "Yu ", "Ye ", "Bu ", "Qiao ", "Qun ", "Feng ", "Feng ", "Nao ", "Li ", "You ", "Xian ", "Hong ", "Dao ", "Shen ", "Cheng ", "Tu ", "Geng ", "Jun ", "Hao ", "Xia ", "Yin ", "Yu "},
- {"Lang ", "Kan ", "Lao ", "Lai ", "Xian ", "Que ", "Kong ", "Chong ", "Chong ", "Ta ", "Lin ", "Hua ", "Ju ", "Lai ", "Qi ", "Min ", "Kun ", "Kun ", "Zu ", "Gu ", "Cui ", "Ya ", "Ya ", "Gang ", "Lun ", "Lun ", "Leng ", "Jue ", "Duo ", "Zheng ", "Guo ", "Yin ", "Dong ", "Han ", "Zheng ", "Wei ", "Yao ", "Pi ", "Yan ", "Song ", "Jie ", "Beng ", "Zu ", "Jue ", "Dong ", "Zhan ", "Gu ", "Yin ", "[?] ", "Ze ", "Huang ", "Yu ", "Wei ", "Yang ", "Feng ", "Qiu ", "Dun ", "Ti ", "Yi ", "Zhi ", "Shi ", "Zai ", "Yao ", "E ", "Zhu ", "Kan ", "Lu ", "Yan ", "Mei ", "Gan ", "Ji ", "Ji ", "Huan ", "Ting ", "Sheng ", "Mei ", "Qian ", "Wu ", "Yu ", "Zong ", "Lan ", "Jue ", "Yan ", "Yan ", "Wei ", "Zong ", "Cha ", "Sui ", "Rong ", "Yamashina ", "Qin ", "Yu ", "Kewashii ", "Lou ", "Tu ", "Dui ", "Xi ", "Weng ", "Cang ", "Dang ", "Hong ", "Jie ", "Ai ", "Liu ", "Wu ", "Song ", "Qiao ", "Zi ", "Wei ", "Beng ", "Dian ", "Cuo ", "Qian ", "Yong ", "Nie ", "Cuo ", "Ji ", "[?] ", "Tao ", "Song ", "Zong ", "Jiang ", "Liao ", "Kang ", "Chan ", "Die ", "Cen ", "Ding ", "Tu ", "Lou ", "Zhang ", "Zhan ", "Zhan ", "Ao ", "Cao ", "Qu ", "Qiang ", "Zui ", "Zui ", "Dao ", "Dao ", "Xi ", "Yu ", "Bo ", "Long ", "Xiang ", "Ceng ", "Bo ", "Qin ", "Jiao ", "Yan ", "Lao ", "Zhan ", "Lin ", "Liao ", "Liao ", "Jin ", "Deng ", "Duo ", "Zun ", "Jiao ", "Gui ", "Yao ", "Qiao ", "Yao ", "Jue ", "Zhan ", "Yi ", "Xue ", "Nao ", "Ye ", "Ye ", "Yi ", "E ", "Xian ", "Ji ", "Xie ", "Ke ", "Xi ", "Di ", "Ao ", "Zui ", "[?] ", "Ni ", "Rong ", "Dao ", "Ling ", "Za ", "Yu ", "Yue ", "Yin ", "[?] ", "Jie ", "Li ", "Sui ", "Long ", "Long ", "Dian ", "Ying ", "Xi ", "Ju ", "Chan ", "Ying ", "Kui ", "Yan ", "Wei ", "Nao ", "Quan ", "Chao ", "Cuan ", "Luan ", "Dian ", "Dian ", "[?] ", "Yan ", "Yan ", "Yan ", "Nao ", "Yan ", "Chuan ", "Gui ", "Chuan ", "Zhou ", "Huang ", "Jing ", "Xun ", "Chao ", "Chao ", "Lie ", "Gong ", "Zuo ", "Qiao ", "Ju ", "Gong ", "Kek ", "Wu ", "Pwu ", "Pwu ", "Chai ", "Qiu ", "Qiu ", "Ji ", "Yi ", "Si ", "Ba ", "Zhi ", "Zhao ", "Xiang ", "Yi ", "Jin ", "Xun ", "Juan ", "Phas ", "Xun ", "Jin ", "Fu "},
- {"Za ", "Bi ", "Shi ", "Bu ", "Ding ", "Shuai ", "Fan ", "Nie ", "Shi ", "Fen ", "Pa ", "Zhi ", "Xi ", "Hu ", "Dan ", "Wei ", "Zhang ", "Tang ", "Dai ", "Ma ", "Pei ", "Pa ", "Tie ", "Fu ", "Lian ", "Zhi ", "Zhou ", "Bo ", "Zhi ", "Di ", "Mo ", "Yi ", "Yi ", "Ping ", "Qia ", "Juan ", "Ru ", "Shuai ", "Dai ", "Zheng ", "Shui ", "Qiao ", "Zhen ", "Shi ", "Qun ", "Xi ", "Bang ", "Dai ", "Gui ", "Chou ", "Ping ", "Zhang ", "Sha ", "Wan ", "Dai ", "Wei ", "Chang ", "Sha ", "Qi ", "Ze ", "Guo ", "Mao ", "Du ", "Hou ", "Zheng ", "Xu ", "Mi ", "Wei ", "Wo ", "Fu ", "Yi ", "Bang ", "Ping ", "Tazuna ", "Gong ", "Pan ", "Huang ", "Dao ", "Mi ", "Jia ", "Teng ", "Hui ", "Zhong ", "Shan ", "Man ", "Mu ", "Biao ", "Guo ", "Ze ", "Mu ", "Bang ", "Zhang ", "Jiong ", "Chan ", "Fu ", "Zhi ", "Hu ", "Fan ", "Chuang ", "Bi ", "Hei ", "[?] ", "Mi ", "Qiao ", "Chan ", "Fen ", "Meng ", "Bang ", "Chou ", "Mie ", "Chu ", "Jie ", "Xian ", "Lan ", "Gan ", "Ping ", "Nian ", "Qian ", "Bing ", "Bing ", "Xing ", "Gan ", "Yao ", "Huan ", "You ", "You ", "Ji ", "Yan ", "Pi ", "Ting ", "Ze ", "Guang ", "Zhuang ", "Mo ", "Qing ", "Bi ", "Qin ", "Dun ", "Chuang ", "Gui ", "Ya ", "Bai ", "Jie ", "Xu ", "Lu ", "Wu ", "[?] ", "Ku ", "Ying ", "Di ", "Pao ", "Dian ", "Ya ", "Miao ", "Geng ", "Ci ", "Fu ", "Tong ", "Pang ", "Fei ", "Xiang ", "Yi ", "Zhi ", "Tiao ", "Zhi ", "Xiu ", "Du ", "Zuo ", "Xiao ", "Tu ", "Gui ", "Ku ", "Pang ", "Ting ", "You ", "Bu ", "Ding ", "Cheng ", "Lai ", "Bei ", "Ji ", "An ", "Shu ", "Kang ", "Yong ", "Tuo ", "Song ", "Shu ", "Qing ", "Yu ", "Yu ", "Miao ", "Sou ", "Ce ", "Xiang ", "Fei ", "Jiu ", "He ", "Hui ", "Liu ", "Sha ", "Lian ", "Lang ", "Sou ", "Jian ", "Pou ", "Qing ", "Jiu ", "Jiu ", "Qin ", "Ao ", "Kuo ", "Lou ", "Yin ", "Liao ", "Dai ", "Lu ", "Yi ", "Chu ", "Chan ", "Tu ", "Si ", "Xin ", "Miao ", "Chang ", "Wu ", "Fei ", "Guang ", "Koc ", "Kuai ", "Bi ", "Qiang ", "Xie ", "Lin ", "Lin ", "Liao ", "Lu ", "[?] ", "Ying ", "Xian ", "Ting ", "Yong ", "Li ", "Ting ", "Yin ", "Xun ", "Yan ", "Ting ", "Di ", "Po ", "Jian ", "Hui ", "Nai ", "Hui ", "Gong ", "Nian "},
- {"Kai ", "Bian ", "Yi ", "Qi ", "Nong ", "Fen ", "Ju ", "Yan ", "Yi ", "Zang ", "Bi ", "Yi ", "Yi ", "Er ", "San ", "Shi ", "Er ", "Shi ", "Shi ", "Gong ", "Diao ", "Yin ", "Hu ", "Fu ", "Hong ", "Wu ", "Tui ", "Chi ", "Jiang ", "Ba ", "Shen ", "Di ", "Zhang ", "Jue ", "Tao ", "Fu ", "Di ", "Mi ", "Xian ", "Hu ", "Chao ", "Nu ", "Jing ", "Zhen ", "Yi ", "Mi ", "Quan ", "Wan ", "Shao ", "Ruo ", "Xuan ", "Jing ", "Dun ", "Zhang ", "Jiang ", "Qiang ", "Peng ", "Dan ", "Qiang ", "Bi ", "Bi ", "She ", "Dan ", "Jian ", "Gou ", "Sei ", "Fa ", "Bi ", "Kou ", "Nagi ", "Bie ", "Xiao ", "Dan ", "Kuo ", "Qiang ", "Hong ", "Mi ", "Kuo ", "Wan ", "Jue ", "Ji ", "Ji ", "Gui ", "Dang ", "Lu ", "Lu ", "Tuan ", "Hui ", "Zhi ", "Hui ", "Hui ", "Yi ", "Yi ", "Yi ", "Yi ", "Huo ", "Huo ", "Shan ", "Xing ", "Wen ", "Tong ", "Yan ", "Yan ", "Yu ", "Chi ", "Cai ", "Biao ", "Diao ", "Bin ", "Peng ", "Yong ", "Piao ", "Zhang ", "Ying ", "Chi ", "Chi ", "Zhuo ", "Tuo ", "Ji ", "Pang ", "Zhong ", "Yi ", "Wang ", "Che ", "Bi ", "Chi ", "Ling ", "Fu ", "Wang ", "Zheng ", "Cu ", "Wang ", "Jing ", "Dai ", "Xi ", "Xun ", "Hen ", "Yang ", "Huai ", "Lu ", "Hou ", "Wa ", "Cheng ", "Zhi ", "Xu ", "Jing ", "Tu ", "Cong ", "[?] ", "Lai ", "Cong ", "De ", "Pai ", "Xi ", "[?] ", "Qi ", "Chang ", "Zhi ", "Cong ", "Zhou ", "Lai ", "Yu ", "Xie ", "Jie ", "Jian ", "Chi ", "Jia ", "Bian ", "Huang ", "Fu ", "Xun ", "Wei ", "Pang ", "Yao ", "Wei ", "Xi ", "Zheng ", "Piao ", "Chi ", "De ", "Zheng ", "Zheng ", "Bie ", "De ", "Chong ", "Che ", "Jiao ", "Wei ", "Jiao ", "Hui ", "Mei ", "Long ", "Xiang ", "Bao ", "Qu ", "Xin ", "Shu ", "Bi ", "Yi ", "Le ", "Ren ", "Dao ", "Ding ", "Gai ", "Ji ", "Ren ", "Ren ", "Chan ", "Tan ", "Te ", "Te ", "Gan ", "Qi ", "Shi ", "Cun ", "Zhi ", "Wang ", "Mang ", "Xi ", "Fan ", "Ying ", "Tian ", "Min ", "Min ", "Zhong ", "Chong ", "Wu ", "Ji ", "Wu ", "Xi ", "Ye ", "You ", "Wan ", "Cong ", "Zhong ", "Kuai ", "Yu ", "Bian ", "Zhi ", "Qi ", "Cui ", "Chen ", "Tai ", "Tun ", "Qian ", "Nian ", "Hun ", "Xiong ", "Niu ", "Wang ", "Xian ", "Xin ", "Kang ", "Hu ", "Kai ", "Fen "},
- {"Huai ", "Tai ", "Song ", "Wu ", "Ou ", "Chang ", "Chuang ", "Ju ", "Yi ", "Bao ", "Chao ", "Min ", "Pei ", "Zuo ", "Zen ", "Yang ", "Kou ", "Ban ", "Nu ", "Nao ", "Zheng ", "Pa ", "Bu ", "Tie ", "Gu ", "Hu ", "Ju ", "Da ", "Lian ", "Si ", "Chou ", "Di ", "Dai ", "Yi ", "Tu ", "You ", "Fu ", "Ji ", "Peng ", "Xing ", "Yuan ", "Ni ", "Guai ", "Fu ", "Xi ", "Bi ", "You ", "Qie ", "Xuan ", "Cong ", "Bing ", "Huang ", "Xu ", "Chu ", "Pi ", "Xi ", "Xi ", "Tan ", "Koraeru ", "Zong ", "Dui ", "[?] ", "Ki ", "Yi ", "Chi ", "Ren ", "Xun ", "Shi ", "Xi ", "Lao ", "Heng ", "Kuang ", "Mu ", "Zhi ", "Xie ", "Lian ", "Tiao ", "Huang ", "Die ", "Hao ", "Kong ", "Gui ", "Heng ", "Xi ", "Xiao ", "Shu ", "S ", "Kua ", "Qiu ", "Yang ", "Hui ", "Hui ", "Chi ", "Jia ", "Yi ", "Xiong ", "Guai ", "Lin ", "Hui ", "Zi ", "Xu ", "Chi ", "Xiang ", "Nu ", "Hen ", "En ", "Ke ", "Tong ", "Tian ", "Gong ", "Quan ", "Xi ", "Qia ", "Yue ", "Peng ", "Ken ", "De ", "Hui ", "E ", "Kyuu ", "Tong ", "Yan ", "Kai ", "Ce ", "Nao ", "Yun ", "Mang ", "Yong ", "Yong ", "Yuan ", "Pi ", "Kun ", "Qiao ", "Yue ", "Yu ", "Yu ", "Jie ", "Xi ", "Zhe ", "Lin ", "Ti ", "Han ", "Hao ", "Qie ", "Ti ", "Bu ", "Yi ", "Qian ", "Hui ", "Xi ", "Bei ", "Man ", "Yi ", "Heng ", "Song ", "Quan ", "Cheng ", "Hui ", "Wu ", "Wu ", "You ", "Li ", "Liang ", "Huan ", "Cong ", "Yi ", "Yue ", "Li ", "Nin ", "Nao ", "E ", "Que ", "Xuan ", "Qian ", "Wu ", "Min ", "Cong ", "Fei ", "Bei ", "Duo ", "Cui ", "Chang ", "Men ", "Li ", "Ji ", "Guan ", "Guan ", "Xing ", "Dao ", "Qi ", "Kong ", "Tian ", "Lun ", "Xi ", "Kan ", "Kun ", "Ni ", "Qing ", "Chou ", "Dun ", "Guo ", "Chan ", "Liang ", "Wan ", "Yuan ", "Jin ", "Ji ", "Lin ", "Yu ", "Huo ", "He ", "Quan ", "Tan ", "Ti ", "Ti ", "Nie ", "Wang ", "Chuo ", "Bu ", "Hun ", "Xi ", "Tang ", "Xin ", "Wei ", "Hui ", "E ", "Rui ", "Zong ", "Jian ", "Yong ", "Dian ", "Ju ", "Can ", "Cheng ", "De ", "Bei ", "Qie ", "Can ", "Dan ", "Guan ", "Duo ", "Nao ", "Yun ", "Xiang ", "Zhui ", "Die ", "Huang ", "Chun ", "Qiong ", "Re ", "Xing ", "Ce ", "Bian ", "Hun ", "Zong ", "Ti "},
- {"Qiao ", "Chou ", "Bei ", "Xuan ", "Wei ", "Ge ", "Qian ", "Wei ", "Yu ", "Yu ", "Bi ", "Xuan ", "Huan ", "Min ", "Bi ", "Yi ", "Mian ", "Yong ", "Kai ", "Dang ", "Yin ", "E ", "Chen ", "Mou ", "Ke ", "Ke ", "Yu ", "Ai ", "Qie ", "Yan ", "Nuo ", "Gan ", "Yun ", "Zong ", "Sai ", "Leng ", "Fen ", "[?] ", "Kui ", "Kui ", "Que ", "Gong ", "Yun ", "Su ", "Su ", "Qi ", "Yao ", "Song ", "Huang ", "Ji ", "Gu ", "Ju ", "Chuang ", "Ni ", "Xie ", "Kai ", "Zheng ", "Yong ", "Cao ", "Sun ", "Shen ", "Bo ", "Kai ", "Yuan ", "Xie ", "Hun ", "Yong ", "Yang ", "Li ", "Sao ", "Tao ", "Yin ", "Ci ", "Xu ", "Qian ", "Tai ", "Huang ", "Yun ", "Shen ", "Ming ", "[?] ", "She ", "Cong ", "Piao ", "Mo ", "Mu ", "Guo ", "Chi ", "Can ", "Can ", "Can ", "Cui ", "Min ", "Te ", "Zhang ", "Tong ", "Ao ", "Shuang ", "Man ", "Guan ", "Que ", "Zao ", "Jiu ", "Hui ", "Kai ", "Lian ", "Ou ", "Song ", "Jin ", "Yin ", "Lu ", "Shang ", "Wei ", "Tuan ", "Man ", "Qian ", "She ", "Yong ", "Qing ", "Kang ", "Di ", "Zhi ", "Lou ", "Juan ", "Qi ", "Qi ", "Yu ", "Ping ", "Liao ", "Cong ", "You ", "Chong ", "Zhi ", "Tong ", "Cheng ", "Qi ", "Qu ", "Peng ", "Bei ", "Bie ", "Chun ", "Jiao ", "Zeng ", "Chi ", "Lian ", "Ping ", "Kui ", "Hui ", "Qiao ", "Cheng ", "Yin ", "Yin ", "Xi ", "Xi ", "Dan ", "Tan ", "Duo ", "Dui ", "Dui ", "Su ", "Jue ", "Ce ", "Xiao ", "Fan ", "Fen ", "Lao ", "Lao ", "Chong ", "Han ", "Qi ", "Xian ", "Min ", "Jing ", "Liao ", "Wu ", "Can ", "Jue ", "Cu ", "Xian ", "Tan ", "Sheng ", "Pi ", "Yi ", "Chu ", "Xian ", "Nao ", "Dan ", "Tan ", "Jing ", "Song ", "Han ", "Jiao ", "Wai ", "Huan ", "Dong ", "Qin ", "Qin ", "Qu ", "Cao ", "Ken ", "Xie ", "Ying ", "Ao ", "Mao ", "Yi ", "Lin ", "Se ", "Jun ", "Huai ", "Men ", "Lan ", "Ai ", "Lin ", "Yan ", "Gua ", "Xia ", "Chi ", "Yu ", "Yin ", "Dai ", "Meng ", "Ai ", "Meng ", "Dui ", "Qi ", "Mo ", "Lan ", "Men ", "Chou ", "Zhi ", "Nuo ", "Nuo ", "Yan ", "Yang ", "Bo ", "Zhi ", "Kuang ", "Kuang ", "You ", "Fu ", "Liu ", "Mie ", "Cheng ", "[?] ", "Chan ", "Meng ", "Lan ", "Huai ", "Xuan ", "Rang ", "Chan ", "Ji ", "Ju ", "Huan ", "She ", "Yi "},
- {"Lian ", "Nan ", "Mi ", "Tang ", "Jue ", "Gang ", "Gang ", "Gang ", "Ge ", "Yue ", "Wu ", "Jian ", "Xu ", "Shu ", "Rong ", "Xi ", "Cheng ", "Wo ", "Jie ", "Ge ", "Jian ", "Qiang ", "Huo ", "Qiang ", "Zhan ", "Dong ", "Qi ", "Jia ", "Die ", "Zei ", "Jia ", "Ji ", "Shi ", "Kan ", "Ji ", "Kui ", "Gai ", "Deng ", "Zhan ", "Chuang ", "Ge ", "Jian ", "Jie ", "Yu ", "Jian ", "Yan ", "Lu ", "Xi ", "Zhan ", "Xi ", "Xi ", "Chuo ", "Dai ", "Qu ", "Hu ", "Hu ", "Hu ", "E ", "Shi ", "Li ", "Mao ", "Hu ", "Li ", "Fang ", "Suo ", "Bian ", "Dian ", "Jiong ", "Shang ", "Yi ", "Yi ", "Shan ", "Hu ", "Fei ", "Yan ", "Shou ", "T ", "Cai ", "Zha ", "Qiu ", "Le ", "Bu ", "Ba ", "Da ", "Reng ", "Fu ", "Hameru ", "Zai ", "Tuo ", "Zhang ", "Diao ", "Kang ", "Yu ", "Ku ", "Han ", "Shen ", "Cha ", "Yi ", "Gu ", "Kou ", "Wu ", "Tuo ", "Qian ", "Zhi ", "Ren ", "Kuo ", "Men ", "Sao ", "Yang ", "Niu ", "Ban ", "Che ", "Rao ", "Xi ", "Qian ", "Ban ", "Jia ", "Yu ", "Fu ", "Ao ", "Xi ", "Pi ", "Zhi ", "Zi ", "E ", "Dun ", "Zhao ", "Cheng ", "Ji ", "Yan ", "Kuang ", "Bian ", "Chao ", "Ju ", "Wen ", "Hu ", "Yue ", "Jue ", "Ba ", "Qin ", "Zhen ", "Zheng ", "Yun ", "Wan ", "Nu ", "Yi ", "Shu ", "Zhua ", "Pou ", "Tou ", "Dou ", "Kang ", "Zhe ", "Pou ", "Fu ", "Pao ", "Ba ", "Ao ", "Ze ", "Tuan ", "Kou ", "Lun ", "Qiang ", "[?] ", "Hu ", "Bao ", "Bing ", "Zhi ", "Peng ", "Tan ", "Pu ", "Pi ", "Tai ", "Yao ", "Zhen ", "Zha ", "Yang ", "Bao ", "He ", "Ni ", "Yi ", "Di ", "Chi ", "Pi ", "Za ", "Mo ", "Mo ", "Shen ", "Ya ", "Chou ", "Qu ", "Min ", "Chu ", "Jia ", "Fu ", "Zhan ", "Zhu ", "Dan ", "Chai ", "Mu ", "Nian ", "La ", "Fu ", "Pao ", "Ban ", "Pai ", "Ling ", "Na ", "Guai ", "Qian ", "Ju ", "Tuo ", "Ba ", "Tuo ", "Tuo ", "Ao ", "Ju ", "Zhuo ", "Pan ", "Zhao ", "Bai ", "Bai ", "Di ", "Ni ", "Ju ", "Kuo ", "Long ", "Jian ", "[?] ", "Yong ", "Lan ", "Ning ", "Bo ", "Ze ", "Qian ", "Hen ", "Gua ", "Shi ", "Jie ", "Zheng ", "Nin ", "Gong ", "Gong ", "Quan ", "Shuan ", "Cun ", "Zan ", "Kao ", "Chi ", "Xie ", "Ce ", "Hui ", "Pin ", "Zhuai ", "Shi ", "Na "},
- {"Bo ", "Chi ", "Gua ", "Zhi ", "Kuo ", "Duo ", "Duo ", "Zhi ", "Qie ", "An ", "Nong ", "Zhen ", "Ge ", "Jiao ", "Ku ", "Dong ", "Ru ", "Tiao ", "Lie ", "Zha ", "Lu ", "Die ", "Wa ", "Jue ", "Mushiru ", "Ju ", "Zhi ", "Luan ", "Ya ", "Zhua ", "Ta ", "Xie ", "Nao ", "Dang ", "Jiao ", "Zheng ", "Ji ", "Hui ", "Xun ", "Ku ", "Ai ", "Tuo ", "Nuo ", "Cuo ", "Bo ", "Geng ", "Ti ", "Zhen ", "Cheng ", "Suo ", "Suo ", "Keng ", "Mei ", "Long ", "Ju ", "Peng ", "Jian ", "Yi ", "Ting ", "Shan ", "Nuo ", "Wan ", "Xie ", "Cha ", "Feng ", "Jiao ", "Wu ", "Jun ", "Jiu ", "Tong ", "Kun ", "Huo ", "Tu ", "Zhuo ", "Pou ", "Le ", "Ba ", "Han ", "Shao ", "Nie ", "Juan ", "Ze ", "Song ", "Ye ", "Jue ", "Bu ", "Huan ", "Bu ", "Zun ", "Yi ", "Zhai ", "Lu ", "Sou ", "Tuo ", "Lao ", "Sun ", "Bang ", "Jian ", "Huan ", "Dao ", "[?] ", "Wan ", "Qin ", "Peng ", "She ", "Lie ", "Min ", "Men ", "Fu ", "Bai ", "Ju ", "Dao ", "Wo ", "Ai ", "Juan ", "Yue ", "Zong ", "Chen ", "Chui ", "Jie ", "Tu ", "Ben ", "Na ", "Nian ", "Nuo ", "Zu ", "Wo ", "Xi ", "Xian ", "Cheng ", "Dian ", "Sao ", "Lun ", "Qing ", "Gang ", "Duo ", "Shou ", "Diao ", "Pou ", "Di ", "Zhang ", "Gun ", "Ji ", "Tao ", "Qia ", "Qi ", "Pai ", "Shu ", "Qian ", "Ling ", "Yi ", "Ya ", "Jue ", "Zheng ", "Liang ", "Gua ", "Yi ", "Huo ", "Shan ", "Zheng ", "Lue ", "Cai ", "Tan ", "Che ", "Bing ", "Jie ", "Ti ", "Kong ", "Tui ", "Yan ", "Cuo ", "Zou ", "Ju ", "Tian ", "Qian ", "Ken ", "Bai ", "Shou ", "Jie ", "Lu ", "Guo ", "Haba ", "[?] ", "Zhi ", "Dan ", "Mang ", "Xian ", "Sao ", "Guan ", "Peng ", "Yuan ", "Nuo ", "Jian ", "Zhen ", "Jiu ", "Jian ", "Yu ", "Yan ", "Kui ", "Nan ", "Hong ", "Rou ", "Pi ", "Wei ", "Sai ", "Zou ", "Xuan ", "Miao ", "Ti ", "Nie ", "Cha ", "Shi ", "Zong ", "Zhen ", "Yi ", "Shun ", "Heng ", "Bian ", "Yang ", "Huan ", "Yan ", "Zuan ", "An ", "Xu ", "Ya ", "Wo ", "Ke ", "Chuai ", "Ji ", "Ti ", "La ", "La ", "Cheng ", "Kai ", "Jiu ", "Jiu ", "Tu ", "Jie ", "Hui ", "Geng ", "Chong ", "Shuo ", "She ", "Xie ", "Yuan ", "Qian ", "Ye ", "Cha ", "Zha ", "Bei ", "Yao ", "[?] ", "[?] ", "Lan ", "Wen ", "Qin "},
- {"Chan ", "Ge ", "Lou ", "Zong ", "Geng ", "Jiao ", "Gou ", "Qin ", "Yong ", "Que ", "Chou ", "Chi ", "Zhan ", "Sun ", "Sun ", "Bo ", "Chu ", "Rong ", "Beng ", "Cuo ", "Sao ", "Ke ", "Yao ", "Dao ", "Zhi ", "Nu ", "Xie ", "Jian ", "Sou ", "Qiu ", "Gao ", "Xian ", "Shuo ", "Sang ", "Jin ", "Mie ", "E ", "Chui ", "Nuo ", "Shan ", "Ta ", "Jie ", "Tang ", "Pan ", "Ban ", "Da ", "Li ", "Tao ", "Hu ", "Zhi ", "Wa ", "Xia ", "Qian ", "Wen ", "Qiang ", "Tian ", "Zhen ", "E ", "Xi ", "Nuo ", "Quan ", "Cha ", "Zha ", "Ge ", "Wu ", "En ", "She ", "Kang ", "She ", "Shu ", "Bai ", "Yao ", "Bin ", "Sou ", "Tan ", "Sa ", "Chan ", "Suo ", "Liao ", "Chong ", "Chuang ", "Guo ", "Bing ", "Feng ", "Shuai ", "Di ", "Qi ", "Sou ", "Zhai ", "Lian ", "Tang ", "Chi ", "Guan ", "Lu ", "Luo ", "Lou ", "Zong ", "Gai ", "Hu ", "Zha ", "Chuang ", "Tang ", "Hua ", "Cui ", "Nai ", "Mo ", "Jiang ", "Gui ", "Ying ", "Zhi ", "Ao ", "Zhi ", "Nie ", "Man ", "Shan ", "Kou ", "Shu ", "Suo ", "Tuan ", "Jiao ", "Mo ", "Mo ", "Zhe ", "Xian ", "Keng ", "Piao ", "Jiang ", "Yin ", "Gou ", "Qian ", "Lue ", "Ji ", "Ying ", "Jue ", "Pie ", "Pie ", "Lao ", "Dun ", "Xian ", "Ruan ", "Kui ", "Zan ", "Yi ", "Xun ", "Cheng ", "Cheng ", "Sa ", "Nao ", "Heng ", "Si ", "Qian ", "Huang ", "Da ", "Zun ", "Nian ", "Lin ", "Zheng ", "Hui ", "Zhuang ", "Jiao ", "Ji ", "Cao ", "Dan ", "Dan ", "Che ", "Bo ", "Che ", "Jue ", "Xiao ", "Liao ", "Ben ", "Fu ", "Qiao ", "Bo ", "Cuo ", "Zhuo ", "Zhuan ", "Tuo ", "Pu ", "Qin ", "Dun ", "Nian ", "[?] ", "Xie ", "Lu ", "Jiao ", "Cuan ", "Ta ", "Han ", "Qiao ", "Zhua ", "Jian ", "Gan ", "Yong ", "Lei ", "Kuo ", "Lu ", "Shan ", "Zhuo ", "Ze ", "Pu ", "Chuo ", "Ji ", "Dang ", "Suo ", "Cao ", "Qing ", "Jing ", "Huan ", "Jie ", "Qin ", "Kuai ", "Dan ", "Xi ", "Ge ", "Pi ", "Bo ", "Ao ", "Ju ", "Ye ", "[?] ", "Mang ", "Sou ", "Mi ", "Ji ", "Tai ", "Zhuo ", "Dao ", "Xing ", "Lan ", "Ca ", "Ju ", "Ye ", "Ru ", "Ye ", "Ye ", "Ni ", "Hu ", "Ji ", "Bin ", "Ning ", "Ge ", "Zhi ", "Jie ", "Kuo ", "Mo ", "Jian ", "Xie ", "Lie ", "Tan ", "Bai ", "Sou ", "Lu ", "Lue ", "Rao ", "Zhi "},
- {"Pan ", "Yang ", "Lei ", "Sa ", "Shu ", "Zan ", "Nian ", "Xian ", "Jun ", "Huo ", "Li ", "La ", "Han ", "Ying ", "Lu ", "Long ", "Qian ", "Qian ", "Zan ", "Qian ", "Lan ", "San ", "Ying ", "Mei ", "Rang ", "Chan ", "[?] ", "Cuan ", "Xi ", "She ", "Luo ", "Jun ", "Mi ", "Li ", "Zan ", "Luan ", "Tan ", "Zuan ", "Li ", "Dian ", "Wa ", "Dang ", "Jiao ", "Jue ", "Lan ", "Li ", "Nang ", "Zhi ", "Gui ", "Gui ", "Qi ", "Xin ", "Pu ", "Sui ", "Shou ", "Kao ", "You ", "Gai ", "Yi ", "Gong ", "Gan ", "Ban ", "Fang ", "Zheng ", "Bo ", "Dian ", "Kou ", "Min ", "Wu ", "Gu ", "He ", "Ce ", "Xiao ", "Mi ", "Chu ", "Ge ", "Di ", "Xu ", "Jiao ", "Min ", "Chen ", "Jiu ", "Zhen ", "Duo ", "Yu ", "Chi ", "Ao ", "Bai ", "Xu ", "Jiao ", "Duo ", "Lian ", "Nie ", "Bi ", "Chang ", "Dian ", "Duo ", "Yi ", "Gan ", "San ", "Ke ", "Yan ", "Dun ", "Qi ", "Dou ", "Xiao ", "Duo ", "Jiao ", "Jing ", "Yang ", "Xia ", "Min ", "Shu ", "Ai ", "Qiao ", "Ai ", "Zheng ", "Di ", "Zhen ", "Fu ", "Shu ", "Liao ", "Qu ", "Xiong ", "Xi ", "Jiao ", "Sen ", "Jiao ", "Zhuo ", "Yi ", "Lian ", "Bi ", "Li ", "Xiao ", "Xiao ", "Wen ", "Xue ", "Qi ", "Qi ", "Zhai ", "Bin ", "Jue ", "Zhai ", "[?] ", "Fei ", "Ban ", "Ban ", "Lan ", "Yu ", "Lan ", "Wei ", "Dou ", "Sheng ", "Liao ", "Jia ", "Hu ", "Xie ", "Jia ", "Yu ", "Zhen ", "Jiao ", "Wo ", "Tou ", "Chu ", "Jin ", "Chi ", "Yin ", "Fu ", "Qiang ", "Zhan ", "Qu ", "Zhuo ", "Zhan ", "Duan ", "Zhuo ", "Si ", "Xin ", "Zhuo ", "Zhuo ", "Qin ", "Lin ", "Zhuo ", "Chu ", "Duan ", "Zhu ", "Fang ", "Xie ", "Hang ", "Yu ", "Shi ", "Pei ", "You ", "Mye ", "Pang ", "Qi ", "Zhan ", "Mao ", "Lu ", "Pei ", "Pi ", "Liu ", "Fu ", "Fang ", "Xuan ", "Jing ", "Jing ", "Ni ", "Zu ", "Zhao ", "Yi ", "Liu ", "Shao ", "Jian ", "Es ", "Yi ", "Qi ", "Zhi ", "Fan ", "Piao ", "Fan ", "Zhan ", "Guai ", "Sui ", "Yu ", "Wu ", "Ji ", "Ji ", "Ji ", "Huo ", "Ri ", "Dan ", "Jiu ", "Zhi ", "Zao ", "Xie ", "Tiao ", "Xun ", "Xu ", "Xu ", "Xu ", "Gan ", "Han ", "Tai ", "Di ", "Xu ", "Chan ", "Shi ", "Kuang ", "Yang ", "Shi ", "Wang ", "Min ", "Min ", "Tun ", "Chun ", "Wu "},
- {"Yun ", "Bei ", "Ang ", "Ze ", "Ban ", "Jie ", "Kun ", "Sheng ", "Hu ", "Fang ", "Hao ", "Gui ", "Chang ", "Xuan ", "Ming ", "Hun ", "Fen ", "Qin ", "Hu ", "Yi ", "Xi ", "Xin ", "Yan ", "Ze ", "Fang ", "Tan ", "Shen ", "Ju ", "Yang ", "Zan ", "Bing ", "Xing ", "Ying ", "Xuan ", "Pei ", "Zhen ", "Ling ", "Chun ", "Hao ", "Mei ", "Zuo ", "Mo ", "Bian ", "Xu ", "Hun ", "Zhao ", "Zong ", "Shi ", "Shi ", "Yu ", "Fei ", "Die ", "Mao ", "Ni ", "Chang ", "Wen ", "Dong ", "Ai ", "Bing ", "Ang ", "Zhou ", "Long ", "Xian ", "Kuang ", "Tiao ", "Chao ", "Shi ", "Huang ", "Huang ", "Xuan ", "Kui ", "Xu ", "Jiao ", "Jin ", "Zhi ", "Jin ", "Shang ", "Tong ", "Hong ", "Yan ", "Gai ", "Xiang ", "Shai ", "Xiao ", "Ye ", "Yun ", "Hui ", "Han ", "Han ", "Jun ", "Wan ", "Xian ", "Kun ", "Zhou ", "Xi ", "Cheng ", "Sheng ", "Bu ", "Zhe ", "Zhe ", "Wu ", "Han ", "Hui ", "Hao ", "Chen ", "Wan ", "Tian ", "Zhuo ", "Zui ", "Zhou ", "Pu ", "Jing ", "Xi ", "Shan ", "Yi ", "Xi ", "Qing ", "Qi ", "Jing ", "Gui ", "Zhen ", "Yi ", "Zhi ", "An ", "Wan ", "Lin ", "Liang ", "Chang ", "Wang ", "Xiao ", "Zan ", "Hi ", "Xuan ", "Xuan ", "Yi ", "Xia ", "Yun ", "Hui ", "Fu ", "Min ", "Kui ", "He ", "Ying ", "Du ", "Wei ", "Shu ", "Qing ", "Mao ", "Nan ", "Jian ", "Nuan ", "An ", "Yang ", "Chun ", "Yao ", "Suo ", "Jin ", "Ming ", "Jiao ", "Kai ", "Gao ", "Weng ", "Chang ", "Qi ", "Hao ", "Yan ", "Li ", "Ai ", "Ji ", "Gui ", "Men ", "Zan ", "Xie ", "Hao ", "Mu ", "Mo ", "Cong ", "Ni ", "Zhang ", "Hui ", "Bao ", "Han ", "Xuan ", "Chuan ", "Liao ", "Xian ", "Dan ", "Jing ", "Pie ", "Lin ", "Tun ", "Xi ", "Yi ", "Ji ", "Huang ", "Tai ", "Ye ", "Ye ", "Li ", "Tan ", "Tong ", "Xiao ", "Fei ", "Qin ", "Zhao ", "Hao ", "Yi ", "Xiang ", "Xing ", "Sen ", "Jiao ", "Bao ", "Jing ", "Yian ", "Ai ", "Ye ", "Ru ", "Shu ", "Meng ", "Xun ", "Yao ", "Pu ", "Li ", "Chen ", "Kuang ", "Die ", "[?] ", "Yan ", "Huo ", "Lu ", "Xi ", "Rong ", "Long ", "Nang ", "Luo ", "Luan ", "Shai ", "Tang ", "Yan ", "Chu ", "Yue ", "Yue ", "Qu ", "Yi ", "Geng ", "Ye ", "Hu ", "He ", "Shu ", "Cao ", "Cao ", "Noboru ", "Man ", "Ceng ", "Ceng ", "Ti "},
- {"Zui ", "Can ", "Xu ", "Hui ", "Yin ", "Qie ", "Fen ", "Pi ", "Yue ", "You ", "Ruan ", "Peng ", "Ban ", "Fu ", "Ling ", "Fei ", "Qu ", "[?] ", "Nu ", "Tiao ", "Shuo ", "Zhen ", "Lang ", "Lang ", "Juan ", "Ming ", "Huang ", "Wang ", "Tun ", "Zhao ", "Ji ", "Qi ", "Ying ", "Zong ", "Wang ", "Tong ", "Lang ", "[?] ", "Meng ", "Long ", "Mu ", "Deng ", "Wei ", "Mo ", "Ben ", "Zha ", "Zhu ", "Zhu ", "[?] ", "Zhu ", "Ren ", "Ba ", "Po ", "Duo ", "Duo ", "Dao ", "Li ", "Qiu ", "Ji ", "Jiu ", "Bi ", "Xiu ", "Ting ", "Ci ", "Sha ", "Eburi ", "Za ", "Quan ", "Qian ", "Yu ", "Gan ", "Wu ", "Cha ", "Shan ", "Xun ", "Fan ", "Wu ", "Zi ", "Li ", "Xing ", "Cai ", "Cun ", "Ren ", "Shao ", "Tuo ", "Di ", "Zhang ", "Mang ", "Chi ", "Yi ", "Gu ", "Gong ", "Du ", "Yi ", "Qi ", "Shu ", "Gang ", "Tiao ", "Moku ", "Soma ", "Tochi ", "Lai ", "Sugi ", "Mang ", "Yang ", "Ma ", "Miao ", "Si ", "Yuan ", "Hang ", "Fei ", "Bei ", "Jie ", "Dong ", "Gao ", "Yao ", "Xian ", "Chu ", "Qun ", "Pa ", "Shu ", "Hua ", "Xin ", "Chou ", "Zhu ", "Chou ", "Song ", "Ban ", "Song ", "Ji ", "Yue ", "Jin ", "Gou ", "Ji ", "Mao ", "Pi ", "Bi ", "Wang ", "Ang ", "Fang ", "Fen ", "Yi ", "Fu ", "Nan ", "Xi ", "Hu ", "Ya ", "Dou ", "Xun ", "Zhen ", "Yao ", "Lin ", "Rui ", "E ", "Mei ", "Zhao ", "Guo ", "Zhi ", "Cong ", "Yun ", "Waku ", "Dou ", "Shu ", "Zao ", "[?] ", "Li ", "Haze ", "Jian ", "Cheng ", "Matsu ", "Qiang ", "Feng ", "Nan ", "Xiao ", "Xian ", "Ku ", "Ping ", "Yi ", "Xi ", "Zhi ", "Guai ", "Xiao ", "Jia ", "Jia ", "Gou ", "Fu ", "Mo ", "Yi ", "Ye ", "Ye ", "Shi ", "Nie ", "Bi ", "Duo ", "Yi ", "Ling ", "Bing ", "Ni ", "La ", "He ", "Pan ", "Fan ", "Zhong ", "Dai ", "Ci ", "Yang ", "Fu ", "Bo ", "Mou ", "Gan ", "Qi ", "Ran ", "Rou ", "Mao ", "Zhao ", "Song ", "Zhe ", "Xia ", "You ", "Shen ", "Ju ", "Tuo ", "Zuo ", "Nan ", "Ning ", "Yong ", "Di ", "Zhi ", "Zha ", "Cha ", "Dan ", "Gu ", "Pu ", "Jiu ", "Ao ", "Fu ", "Jian ", "Bo ", "Duo ", "Ke ", "Nai ", "Zhu ", "Bi ", "Liu ", "Chai ", "Zha ", "Si ", "Zhu ", "Pei ", "Shi ", "Guai ", "Cha ", "Yao ", "Jue ", "Jiu ", "Shi "},
- {"Zhi ", "Liu ", "Mei ", "Hoy ", "Rong ", "Zha ", "[?] ", "Biao ", "Zhan ", "Jie ", "Long ", "Dong ", "Lu ", "Sayng ", "Li ", "Lan ", "Yong ", "Shu ", "Xun ", "Shuan ", "Qi ", "Zhen ", "Qi ", "Li ", "Yi ", "Xiang ", "Zhen ", "Li ", "Su ", "Gua ", "Kan ", "Bing ", "Ren ", "Xiao ", "Bo ", "Ren ", "Bing ", "Zi ", "Chou ", "Yi ", "Jie ", "Xu ", "Zhu ", "Jian ", "Zui ", "Er ", "Er ", "You ", "Fa ", "Gong ", "Kao ", "Lao ", "Zhan ", "Li ", "Yin ", "Yang ", "He ", "Gen ", "Zhi ", "Chi ", "Ge ", "Zai ", "Luan ", "Fu ", "Jie ", "Hang ", "Gui ", "Tao ", "Guang ", "Wei ", "Kuang ", "Ru ", "An ", "An ", "Juan ", "Yi ", "Zhuo ", "Ku ", "Zhi ", "Qiong ", "Tong ", "Sang ", "Sang ", "Huan ", "Jie ", "Jiu ", "Xue ", "Duo ", "Zhui ", "Yu ", "Zan ", "Kasei ", "Ying ", "Masu ", "[?] ", "Zhan ", "Ya ", "Nao ", "Zhen ", "Dang ", "Qi ", "Qiao ", "Hua ", "Kuai ", "Jiang ", "Zhuang ", "Xun ", "Suo ", "Sha ", "Zhen ", "Bei ", "Ting ", "Gua ", "Jing ", "Bo ", "Ben ", "Fu ", "Rui ", "Tong ", "Jue ", "Xi ", "Lang ", "Liu ", "Feng ", "Qi ", "Wen ", "Jun ", "Gan ", "Cu ", "Liang ", "Qiu ", "Ting ", "You ", "Mei ", "Bang ", "Long ", "Peng ", "Zhuang ", "Di ", "Xuan ", "Tu ", "Zao ", "Ao ", "Gu ", "Bi ", "Di ", "Han ", "Zi ", "Zhi ", "Ren ", "Bei ", "Geng ", "Jian ", "Huan ", "Wan ", "Nuo ", "Jia ", "Tiao ", "Ji ", "Xiao ", "Lu ", "Huan ", "Shao ", "Cen ", "Fen ", "Song ", "Meng ", "Wu ", "Li ", "Li ", "Dou ", "Cen ", "Ying ", "Suo ", "Ju ", "Ti ", "Jie ", "Kun ", "Zhuo ", "Shu ", "Chan ", "Fan ", "Wei ", "Jing ", "Li ", "Bing ", "Fumoto ", "Shikimi ", "Tao ", "Zhi ", "Lai ", "Lian ", "Jian ", "Zhuo ", "Ling ", "Li ", "Qi ", "Bing ", "Zhun ", "Cong ", "Qian ", "Mian ", "Qi ", "Qi ", "Cai ", "Gun ", "Chan ", "Te ", "Fei ", "Pai ", "Bang ", "Pou ", "Hun ", "Zong ", "Cheng ", "Zao ", "Ji ", "Li ", "Peng ", "Yu ", "Yu ", "Gu ", "Hun ", "Dong ", "Tang ", "Gang ", "Wang ", "Di ", "Xi ", "Fan ", "Cheng ", "Zhan ", "Qi ", "Yuan ", "Yan ", "Yu ", "Quan ", "Yi ", "Sen ", "Ren ", "Chui ", "Leng ", "Qi ", "Zhuo ", "Fu ", "Ke ", "Lai ", "Zou ", "Zou ", "Zhuo ", "Guan ", "Fen ", "Fen ", "Chen ", "Qiong ", "Nie "},
- {"Wan ", "Guo ", "Lu ", "Hao ", "Jie ", "Yi ", "Chou ", "Ju ", "Ju ", "Cheng ", "Zuo ", "Liang ", "Qiang ", "Zhi ", "Zhui ", "Ya ", "Ju ", "Bei ", "Jiao ", "Zhuo ", "Zi ", "Bin ", "Peng ", "Ding ", "Chu ", "Chang ", "Kunugi ", "Momiji ", "Jian ", "Gui ", "Xi ", "Du ", "Qian ", "Kunugi ", "Soko ", "Shide ", "Luo ", "Zhi ", "Ken ", "Myeng ", "Tafu ", "[?] ", "Peng ", "Zhan ", "[?] ", "Tuo ", "Sen ", "Duo ", "Ye ", "Fou ", "Wei ", "Wei ", "Duan ", "Jia ", "Zong ", "Jian ", "Yi ", "Shen ", "Xi ", "Yan ", "Yan ", "Chuan ", "Zhan ", "Chun ", "Yu ", "He ", "Zha ", "Wo ", "Pian ", "Bi ", "Yao ", "Huo ", "Xu ", "Ruo ", "Yang ", "La ", "Yan ", "Ben ", "Hun ", "Kui ", "Jie ", "Kui ", "Si ", "Feng ", "Xie ", "Tuo ", "Zhi ", "Jian ", "Mu ", "Mao ", "Chu ", "Hu ", "Hu ", "Lian ", "Leng ", "Ting ", "Nan ", "Yu ", "You ", "Mei ", "Song ", "Xuan ", "Xuan ", "Ying ", "Zhen ", "Pian ", "Ye ", "Ji ", "Jie ", "Ye ", "Chu ", "Shun ", "Yu ", "Cou ", "Wei ", "Mei ", "Di ", "Ji ", "Jie ", "Kai ", "Qiu ", "Ying ", "Rou ", "Heng ", "Lou ", "Le ", "Hazou ", "Katsura ", "Pin ", "Muro ", "Gai ", "Tan ", "Lan ", "Yun ", "Yu ", "Chen ", "Lu ", "Ju ", "Sakaki ", "[?] ", "Pi ", "Xie ", "Jia ", "Yi ", "Zhan ", "Fu ", "Nai ", "Mi ", "Lang ", "Rong ", "Gu ", "Jian ", "Ju ", "Ta ", "Yao ", "Zhen ", "Bang ", "Sha ", "Yuan ", "Zi ", "Ming ", "Su ", "Jia ", "Yao ", "Jie ", "Huang ", "Gan ", "Fei ", "Zha ", "Qian ", "Ma ", "Sun ", "Yuan ", "Xie ", "Rong ", "Shi ", "Zhi ", "Cui ", "Yun ", "Ting ", "Liu ", "Rong ", "Tang ", "Que ", "Zhai ", "Si ", "Sheng ", "Ta ", "Ke ", "Xi ", "Gu ", "Qi ", "Kao ", "Gao ", "Sun ", "Pan ", "Tao ", "Ge ", "Xun ", "Dian ", "Nou ", "Ji ", "Shuo ", "Gou ", "Chui ", "Qiang ", "Cha ", "Qian ", "Huai ", "Mei ", "Xu ", "Gang ", "Gao ", "Zhuo ", "Tuo ", "Hashi ", "Yang ", "Dian ", "Jia ", "Jian ", "Zui ", "Kashi ", "Ori ", "Bin ", "Zhu ", "[?] ", "Xi ", "Qi ", "Lian ", "Hui ", "Yong ", "Qian ", "Guo ", "Gai ", "Gai ", "Tuan ", "Hua ", "Cu ", "Sen ", "Cui ", "Beng ", "You ", "Hu ", "Jiang ", "Hu ", "Huan ", "Kui ", "Yi ", "Nie ", "Gao ", "Kang ", "Gui ", "Gui ", "Cao ", "Man ", "Jin "},
- {"Di ", "Zhuang ", "Le ", "Lang ", "Chen ", "Cong ", "Li ", "Xiu ", "Qing ", "Shuang ", "Fan ", "Tong ", "Guan ", "Ji ", "Suo ", "Lei ", "Lu ", "Liang ", "Mi ", "Lou ", "Chao ", "Su ", "Ke ", "Shu ", "Tang ", "Biao ", "Lu ", "Jiu ", "Shu ", "Zha ", "Shu ", "Zhang ", "Men ", "Mo ", "Niao ", "Yang ", "Tiao ", "Peng ", "Zhu ", "Sha ", "Xi ", "Quan ", "Heng ", "Jian ", "Cong ", "[?] ", "Hokuso ", "Qiang ", "Tara ", "Ying ", "Er ", "Xin ", "Zhi ", "Qiao ", "Zui ", "Cong ", "Pu ", "Shu ", "Hua ", "Kui ", "Zhen ", "Zun ", "Yue ", "Zhan ", "Xi ", "Xun ", "Dian ", "Fa ", "Gan ", "Mo ", "Wu ", "Qiao ", "Nao ", "Lin ", "Liu ", "Qiao ", "Xian ", "Run ", "Fan ", "Zhan ", "Tuo ", "Lao ", "Yun ", "Shun ", "Tui ", "Cheng ", "Tang ", "Meng ", "Ju ", "Cheng ", "Su ", "Jue ", "Jue ", "Tan ", "Hui ", "Ji ", "Nuo ", "Xiang ", "Tuo ", "Ning ", "Rui ", "Zhu ", "Chuang ", "Zeng ", "Fen ", "Qiong ", "Ran ", "Heng ", "Cen ", "Gu ", "Liu ", "Lao ", "Gao ", "Chu ", "Zusa ", "Nude ", "Ca ", "San ", "Ji ", "Dou ", "Shou ", "Lu ", "[?] ", "[?] ", "Yuan ", "Ta ", "Shu ", "Jiang ", "Tan ", "Lin ", "Nong ", "Yin ", "Xi ", "Sui ", "Shan ", "Zui ", "Xuan ", "Cheng ", "Gan ", "Ju ", "Zui ", "Yi ", "Qin ", "Pu ", "Yan ", "Lei ", "Feng ", "Hui ", "Dang ", "Ji ", "Sui ", "Bo ", "Bi ", "Ding ", "Chu ", "Zhua ", "Kuai ", "Ji ", "Jie ", "Jia ", "Qing ", "Zhe ", "Jian ", "Qiang ", "Dao ", "Yi ", "Biao ", "Song ", "She ", "Lin ", "Kunugi ", "Cha ", "Meng ", "Yin ", "Tao ", "Tai ", "Mian ", "Qi ", "Toan ", "Bin ", "Huo ", "Ji ", "Qian ", "Mi ", "Ning ", "Yi ", "Gao ", "Jian ", "Yin ", "Er ", "Qing ", "Yan ", "Qi ", "Mi ", "Zhao ", "Gui ", "Chun ", "Ji ", "Kui ", "Po ", "Deng ", "Chu ", "[?] ", "Mian ", "You ", "Zhi ", "Guang ", "Qian ", "Lei ", "Lei ", "Sa ", "Lu ", "Li ", "Cuan ", "Lu ", "Mie ", "Hui ", "Ou ", "Lu ", "Jie ", "Gao ", "Du ", "Yuan ", "Li ", "Fei ", "Zhuo ", "Sou ", "Lian ", "Tamo ", "Chu ", "[?] ", "Zhu ", "Lu ", "Yan ", "Li ", "Zhu ", "Chen ", "Jie ", "E ", "Su ", "Huai ", "Nie ", "Yu ", "Long ", "Lai ", "[?] ", "Xian ", "Kwi ", "Ju ", "Xiao ", "Ling ", "Ying ", "Jian ", "Yin ", "You ", "Ying "},
- {"Xiang ", "Nong ", "Bo ", "Chan ", "Lan ", "Ju ", "Shuang ", "She ", "Wei ", "Cong ", "Quan ", "Qu ", "Cang ", "[?] ", "Yu ", "Luo ", "Li ", "Zan ", "Luan ", "Dang ", "Jue ", "Em ", "Lan ", "Lan ", "Zhu ", "Lei ", "Li ", "Ba ", "Nang ", "Yu ", "Ling ", "Tsuki ", "Qian ", "Ci ", "Huan ", "Xin ", "Yu ", "Yu ", "Qian ", "Ou ", "Xu ", "Chao ", "Chu ", "Chi ", "Kai ", "Yi ", "Jue ", "Xi ", "Xu ", "Xia ", "Yu ", "Kuai ", "Lang ", "Kuan ", "Shuo ", "Xi ", "Ai ", "Yi ", "Qi ", "Hu ", "Chi ", "Qin ", "Kuan ", "Kan ", "Kuan ", "Kan ", "Chuan ", "Sha ", "Gua ", "Yin ", "Xin ", "Xie ", "Yu ", "Qian ", "Xiao ", "Yi ", "Ge ", "Wu ", "Tan ", "Jin ", "Ou ", "Hu ", "Ti ", "Huan ", "Xu ", "Pen ", "Xi ", "Xiao ", "Xu ", "Xi ", "Sen ", "Lian ", "Chu ", "Yi ", "Kan ", "Yu ", "Chuo ", "Huan ", "Zhi ", "Zheng ", "Ci ", "Bu ", "Wu ", "Qi ", "Bu ", "Bu ", "Wai ", "Ju ", "Qian ", "Chi ", "Se ", "Chi ", "Se ", "Zhong ", "Sui ", "Sui ", "Li ", "Cuo ", "Yu ", "Li ", "Gui ", "Dai ", "Dai ", "Si ", "Jian ", "Zhe ", "Mo ", "Mo ", "Yao ", "Mo ", "Cu ", "Yang ", "Tian ", "Sheng ", "Dai ", "Shang ", "Xu ", "Xun ", "Shu ", "Can ", "Jue ", "Piao ", "Qia ", "Qiu ", "Su ", "Qing ", "Yun ", "Lian ", "Yi ", "Fou ", "Zhi ", "Ye ", "Can ", "Hun ", "Dan ", "Ji ", "Ye ", "Zhen ", "Yun ", "Wen ", "Chou ", "Bin ", "Ti ", "Jin ", "Shang ", "Yin ", "Diao ", "Cu ", "Hui ", "Cuan ", "Yi ", "Dan ", "Du ", "Jiang ", "Lian ", "Bin ", "Du ", "Tsukusu ", "Jian ", "Shu ", "Ou ", "Duan ", "Zhu ", "Yin ", "Qing ", "Yi ", "Sha ", "Que ", "Ke ", "Yao ", "Jun ", "Dian ", "Hui ", "Hui ", "Gu ", "Que ", "Ji ", "Yi ", "Ou ", "Hui ", "Duan ", "Yi ", "Xiao ", "Wu ", "Guan ", "Mu ", "Mei ", "Mei ", "Ai ", "Zuo ", "Du ", "Yu ", "Bi ", "Bi ", "Bi ", "Pi ", "Pi ", "Bi ", "Chan ", "Mao ", "[?] ", "[?] ", "Pu ", "Mushiru ", "Jia ", "Zhan ", "Sai ", "Mu ", "Tuo ", "Xun ", "Er ", "Rong ", "Xian ", "Ju ", "Mu ", "Hao ", "Qiu ", "Dou ", "Mushiru ", "Tan ", "Pei ", "Ju ", "Duo ", "Cui ", "Bi ", "San ", "[?] ", "Mao ", "Sui ", "Yu ", "Yu ", "Tuo ", "He ", "Jian ", "Ta ", "San "},
- {"Lu ", "Mu ", "Li ", "Tong ", "Rong ", "Chang ", "Pu ", "Luo ", "Zhan ", "Sao ", "Zhan ", "Meng ", "Luo ", "Qu ", "Die ", "Shi ", "Di ", "Min ", "Jue ", "Mang ", "Qi ", "Pie ", "Nai ", "Qi ", "Dao ", "Xian ", "Chuan ", "Fen ", "Ri ", "Nei ", "[?] ", "Fu ", "Shen ", "Dong ", "Qing ", "Qi ", "Yin ", "Xi ", "Hai ", "Yang ", "An ", "Ya ", "Ke ", "Qing ", "Ya ", "Dong ", "Dan ", "Lu ", "Qing ", "Yang ", "Yun ", "Yun ", "Shui ", "San ", "Zheng ", "Bing ", "Yong ", "Dang ", "Shitamizu ", "Le ", "Ni ", "Tun ", "Fan ", "Gui ", "Ting ", "Zhi ", "Qiu ", "Bin ", "Ze ", "Mian ", "Cuan ", "Hui ", "Diao ", "Yi ", "Cha ", "Zhuo ", "Chuan ", "Wan ", "Fan ", "Dai ", "Xi ", "Tuo ", "Mang ", "Qiu ", "Qi ", "Shan ", "Pai ", "Han ", "Qian ", "Wu ", "Wu ", "Xun ", "Si ", "Ru ", "Gong ", "Jiang ", "Chi ", "Wu ", "Tsuchi ", "[?] ", "Tang ", "Zhi ", "Chi ", "Qian ", "Mi ", "Yu ", "Wang ", "Qing ", "Jing ", "Rui ", "Jun ", "Hong ", "Tai ", "Quan ", "Ji ", "Bian ", "Bian ", "Gan ", "Wen ", "Zhong ", "Fang ", "Xiong ", "Jue ", "Hang ", "Niou ", "Qi ", "Fen ", "Xu ", "Xu ", "Qin ", "Yi ", "Wo ", "Yun ", "Yuan ", "Hang ", "Yan ", "Chen ", "Chen ", "Dan ", "You ", "Dun ", "Hu ", "Huo ", "Qie ", "Mu ", "Rou ", "Mei ", "Ta ", "Mian ", "Wu ", "Chong ", "Tian ", "Bi ", "Sha ", "Zhi ", "Pei ", "Pan ", "Zhui ", "Za ", "Gou ", "Liu ", "Mei ", "Ze ", "Feng ", "Ou ", "Li ", "Lun ", "Cang ", "Feng ", "Wei ", "Hu ", "Mo ", "Mei ", "Shu ", "Ju ", "Zan ", "Tuo ", "Tuo ", "Tuo ", "He ", "Li ", "Mi ", "Yi ", "Fa ", "Fei ", "You ", "Tian ", "Zhi ", "Zhao ", "Gu ", "Zhan ", "Yan ", "Si ", "Kuang ", "Jiong ", "Ju ", "Xie ", "Qiu ", "Yi ", "Jia ", "Zhong ", "Quan ", "Bo ", "Hui ", "Mi ", "Ben ", "Zhuo ", "Chu ", "Le ", "You ", "Gu ", "Hong ", "Gan ", "Fa ", "Mao ", "Si ", "Hu ", "Ping ", "Ci ", "Fan ", "Chi ", "Su ", "Ning ", "Cheng ", "Ling ", "Pao ", "Bo ", "Qi ", "Si ", "Ni ", "Ju ", "Yue ", "Zhu ", "Sheng ", "Lei ", "Xuan ", "Xue ", "Fu ", "Pan ", "Min ", "Tai ", "Yang ", "Ji ", "Yong ", "Guan ", "Beng ", "Xue ", "Long ", "Lu ", "[?] ", "Bo ", "Xie ", "Po ", "Ze ", "Jing ", "Yin "},
- {"Zhou ", "Ji ", "Yi ", "Hui ", "Hui ", "Zui ", "Cheng ", "Yin ", "Wei ", "Hou ", "Jian ", "Yang ", "Lie ", "Si ", "Ji ", "Er ", "Xing ", "Fu ", "Sa ", "Suo ", "Zhi ", "Yin ", "Wu ", "Xi ", "Kao ", "Zhu ", "Jiang ", "Luo ", "[?] ", "An ", "Dong ", "Yi ", "Mou ", "Lei ", "Yi ", "Mi ", "Quan ", "Jin ", "Mo ", "Wei ", "Xiao ", "Xie ", "Hong ", "Xu ", "Shuo ", "Kuang ", "Tao ", "Qie ", "Ju ", "Er ", "Zhou ", "Ru ", "Ping ", "Xun ", "Xiong ", "Zhi ", "Guang ", "Huan ", "Ming ", "Huo ", "Wa ", "Qia ", "Pai ", "Wu ", "Qu ", "Liu ", "Yi ", "Jia ", "Jing ", "Qian ", "Jiang ", "Jiao ", "Cheng ", "Shi ", "Zhuo ", "Ce ", "Pal ", "Kuai ", "Ji ", "Liu ", "Chan ", "Hun ", "Hu ", "Nong ", "Xun ", "Jin ", "Lie ", "Qiu ", "Wei ", "Zhe ", "Jun ", "Han ", "Bang ", "Mang ", "Zhuo ", "You ", "Xi ", "Bo ", "Dou ", "Wan ", "Hong ", "Yi ", "Pu ", "Ying ", "Lan ", "Hao ", "Lang ", "Han ", "Li ", "Geng ", "Fu ", "Wu ", "Lian ", "Chun ", "Feng ", "Yi ", "Yu ", "Tong ", "Lao ", "Hai ", "Jin ", "Jia ", "Chong ", "Weng ", "Mei ", "Sui ", "Cheng ", "Pei ", "Xian ", "Shen ", "Tu ", "Kun ", "Pin ", "Nie ", "Han ", "Jing ", "Xiao ", "She ", "Nian ", "Tu ", "Yong ", "Xiao ", "Xian ", "Ting ", "E ", "Su ", "Tun ", "Juan ", "Cen ", "Ti ", "Li ", "Shui ", "Si ", "Lei ", "Shui ", "Tao ", "Du ", "Lao ", "Lai ", "Lian ", "Wei ", "Wo ", "Yun ", "Huan ", "Di ", "[?] ", "Run ", "Jian ", "Zhang ", "Se ", "Fu ", "Guan ", "Xing ", "Shou ", "Shuan ", "Ya ", "Chuo ", "Zhang ", "Ye ", "Kong ", "Wo ", "Han ", "Tuo ", "Dong ", "He ", "Wo ", "Ju ", "Gan ", "Liang ", "Hun ", "Ta ", "Zhuo ", "Dian ", "Qie ", "De ", "Juan ", "Zi ", "Xi ", "Yao ", "Qi ", "Gu ", "Guo ", "Han ", "Lin ", "Tang ", "Zhou ", "Peng ", "Hao ", "Chang ", "Shu ", "Qi ", "Fang ", "Chi ", "Lu ", "Nao ", "Ju ", "Tao ", "Cong ", "Lei ", "Zhi ", "Peng ", "Fei ", "Song ", "Tian ", "Pi ", "Dan ", "Yu ", "Ni ", "Yu ", "Lu ", "Gan ", "Mi ", "Jing ", "Ling ", "Lun ", "Yin ", "Cui ", "Qu ", "Huai ", "Yu ", "Nian ", "Shen ", "Piao ", "Chun ", "Wa ", "Yuan ", "Lai ", "Hun ", "Qing ", "Yan ", "Qian ", "Tian ", "Miao ", "Zhi ", "Yin ", "Mi "},
- {"Ben ", "Yuan ", "Wen ", "Re ", "Fei ", "Qing ", "Yuan ", "Ke ", "Ji ", "She ", "Yuan ", "Shibui ", "Lu ", "Zi ", "Du ", "[?] ", "Jian ", "Min ", "Pi ", "Tani ", "Yu ", "Yuan ", "Shen ", "Shen ", "Rou ", "Huan ", "Zhu ", "Jian ", "Nuan ", "Yu ", "Qiu ", "Ting ", "Qu ", "Du ", "Feng ", "Zha ", "Bo ", "Wo ", "Wo ", "Di ", "Wei ", "Wen ", "Ru ", "Xie ", "Ce ", "Wei ", "Ge ", "Gang ", "Yan ", "Hong ", "Xuan ", "Mi ", "Ke ", "Mao ", "Ying ", "Yan ", "You ", "Hong ", "Miao ", "Xing ", "Mei ", "Zai ", "Hun ", "Nai ", "Kui ", "Shi ", "E ", "Pai ", "Mei ", "Lian ", "Qi ", "Qi ", "Mei ", "Tian ", "Cou ", "Wei ", "Can ", "Tuan ", "Mian ", "Hui ", "Mo ", "Xu ", "Ji ", "Pen ", "Jian ", "Jian ", "Hu ", "Feng ", "Xiang ", "Yi ", "Yin ", "Zhan ", "Shi ", "Jie ", "Cheng ", "Huang ", "Tan ", "Yu ", "Bi ", "Min ", "Shi ", "Tu ", "Sheng ", "Yong ", "Qu ", "Zhong ", "Suei ", "Jiu ", "Jiao ", "Qiou ", "Yin ", "Tang ", "Long ", "Huo ", "Yuan ", "Nan ", "Ban ", "You ", "Quan ", "Chui ", "Liang ", "Chan ", "Yan ", "Chun ", "Nie ", "Zi ", "Wan ", "Shi ", "Man ", "Ying ", "Ratsu ", "Kui ", "[?] ", "Jian ", "Xu ", "Lu ", "Gui ", "Gai ", "[?] ", "[?] ", "Po ", "Jin ", "Gui ", "Tang ", "Yuan ", "Suo ", "Yuan ", "Lian ", "Yao ", "Meng ", "Zhun ", "Sheng ", "Ke ", "Tai ", "Da ", "Wa ", "Liu ", "Gou ", "Sao ", "Ming ", "Zha ", "Shi ", "Yi ", "Lun ", "Ma ", "Pu ", "Wei ", "Li ", "Cai ", "Wu ", "Xi ", "Wen ", "Qiang ", "Ze ", "Shi ", "Su ", "Yi ", "Zhen ", "Sou ", "Yun ", "Xiu ", "Yin ", "Rong ", "Hun ", "Su ", "Su ", "Ni ", "Ta ", "Shi ", "Ru ", "Wei ", "Pan ", "Chu ", "Chu ", "Pang ", "Weng ", "Cang ", "Mie ", "He ", "Dian ", "Hao ", "Huang ", "Xi ", "Zi ", "Di ", "Zhi ", "Ying ", "Fu ", "Jie ", "Hua ", "Ge ", "Zi ", "Tao ", "Teng ", "Sui ", "Bi ", "Jiao ", "Hui ", "Gun ", "Yin ", "Gao ", "Long ", "Zhi ", "Yan ", "She ", "Man ", "Ying ", "Chun ", "Lu ", "Lan ", "Luan ", "[?] ", "Bin ", "Tan ", "Yu ", "Sou ", "Hu ", "Bi ", "Biao ", "Zhi ", "Jiang ", "Kou ", "Shen ", "Shang ", "Di ", "Mi ", "Ao ", "Lu ", "Hu ", "Hu ", "You ", "Chan ", "Fan ", "Yong ", "Gun ", "Man "},
- {"Qing ", "Yu ", "Piao ", "Ji ", "Ya ", "Jiao ", "Qi ", "Xi ", "Ji ", "Lu ", "Lu ", "Long ", "Jin ", "Guo ", "Cong ", "Lou ", "Zhi ", "Gai ", "Qiang ", "Li ", "Yan ", "Cao ", "Jiao ", "Cong ", "Qun ", "Tuan ", "Ou ", "Teng ", "Ye ", "Xi ", "Mi ", "Tang ", "Mo ", "Shang ", "Han ", "Lian ", "Lan ", "Wa ", "Li ", "Qian ", "Feng ", "Xuan ", "Yi ", "Man ", "Zi ", "Mang ", "Kang ", "Lei ", "Peng ", "Shu ", "Zhang ", "Zhang ", "Chong ", "Xu ", "Huan ", "Kuo ", "Jian ", "Yan ", "Chuang ", "Liao ", "Cui ", "Ti ", "Yang ", "Jiang ", "Cong ", "Ying ", "Hong ", "Xun ", "Shu ", "Guan ", "Ying ", "Xiao ", "[?] ", "[?] ", "Xu ", "Lian ", "Zhi ", "Wei ", "Pi ", "Jue ", "Jiao ", "Po ", "Dang ", "Hui ", "Jie ", "Wu ", "Pa ", "Ji ", "Pan ", "Gui ", "Xiao ", "Qian ", "Qian ", "Xi ", "Lu ", "Xi ", "Xuan ", "Dun ", "Huang ", "Min ", "Run ", "Su ", "Liao ", "Zhen ", "Zhong ", "Yi ", "Di ", "Wan ", "Dan ", "Tan ", "Chao ", "Xun ", "Kui ", "Yie ", "Shao ", "Tu ", "Zhu ", "San ", "Hei ", "Bi ", "Shan ", "Chan ", "Chan ", "Shu ", "Tong ", "Pu ", "Lin ", "Wei ", "Se ", "Se ", "Cheng ", "Jiong ", "Cheng ", "Hua ", "Jiao ", "Lao ", "Che ", "Gan ", "Cun ", "Heng ", "Si ", "Shu ", "Peng ", "Han ", "Yun ", "Liu ", "Hong ", "Fu ", "Hao ", "He ", "Xian ", "Jian ", "Shan ", "Xi ", "Oki ", "[?] ", "Lan ", "[?] ", "Yu ", "Lin ", "Min ", "Zao ", "Dang ", "Wan ", "Ze ", "Xie ", "Yu ", "Li ", "Shi ", "Xue ", "Ling ", "Man ", "Zi ", "Yong ", "Kuai ", "Can ", "Lian ", "Dian ", "Ye ", "Ao ", "Huan ", "Zhen ", "Chan ", "Man ", "Dan ", "Dan ", "Yi ", "Sui ", "Pi ", "Ju ", "Ta ", "Qin ", "Ji ", "Zhuo ", "Lian ", "Nong ", "Guo ", "Jin ", "Fen ", "Se ", "Ji ", "Sui ", "Hui ", "Chu ", "Ta ", "Song ", "Ding ", "[?] ", "Zhu ", "Lai ", "Bin ", "Lian ", "Mi ", "Shi ", "Shu ", "Mi ", "Ning ", "Ying ", "Ying ", "Meng ", "Jin ", "Qi ", "Pi ", "Ji ", "Hao ", "Ru ", "Zui ", "Wo ", "Tao ", "Yin ", "Yin ", "Dui ", "Ci ", "Huo ", "Jing ", "Lan ", "Jun ", "Ai ", "Pu ", "Zhuo ", "Wei ", "Bin ", "Gu ", "Qian ", "Xing ", "Hama ", "Kuo ", "Fei ", "[?] ", "Boku ", "Jian ", "Wei ", "Luo ", "Zan ", "Lu ", "Li "},
- {"You ", "Yang ", "Lu ", "Si ", "Jie ", "Ying ", "Du ", "Wang ", "Hui ", "Xie ", "Pan ", "Shen ", "Biao ", "Chan ", "Mo ", "Liu ", "Jian ", "Pu ", "Se ", "Cheng ", "Gu ", "Bin ", "Huo ", "Xian ", "Lu ", "Qin ", "Han ", "Ying ", "Yong ", "Li ", "Jing ", "Xiao ", "Ying ", "Sui ", "Wei ", "Xie ", "Huai ", "Hao ", "Zhu ", "Long ", "Lai ", "Dui ", "Fan ", "Hu ", "Lai ", "[?] ", "[?] ", "Ying ", "Mi ", "Ji ", "Lian ", "Jian ", "Ying ", "Fen ", "Lin ", "Yi ", "Jian ", "Yue ", "Chan ", "Dai ", "Rang ", "Jian ", "Lan ", "Fan ", "Shuang ", "Yuan ", "Zhuo ", "Feng ", "She ", "Lei ", "Lan ", "Cong ", "Qu ", "Yong ", "Qian ", "Fa ", "Guan ", "Que ", "Yan ", "Hao ", "Hyeng ", "Sa ", "Zan ", "Luan ", "Yan ", "Li ", "Mi ", "Shan ", "Tan ", "Dang ", "Jiao ", "Chan ", "[?] ", "Hao ", "Ba ", "Zhu ", "Lan ", "Lan ", "Nang ", "Wan ", "Luan ", "Xun ", "Xian ", "Yan ", "Gan ", "Yan ", "Yu ", "Huo ", "Si ", "Mie ", "Guang ", "Deng ", "Hui ", "Xiao ", "Xiao ", "Hu ", "Hong ", "Ling ", "Zao ", "Zhuan ", "Jiu ", "Zha ", "Xie ", "Chi ", "Zhuo ", "Zai ", "Zai ", "Can ", "Yang ", "Qi ", "Zhong ", "Fen ", "Niu ", "Jiong ", "Wen ", "Po ", "Yi ", "Lu ", "Chui ", "Pi ", "Kai ", "Pan ", "Yan ", "Kai ", "Pang ", "Mu ", "Chao ", "Liao ", "Gui ", "Kang ", "Tun ", "Guang ", "Xin ", "Zhi ", "Guang ", "Guang ", "Wei ", "Qiang ", "[?] ", "Da ", "Xia ", "Zheng ", "Zhu ", "Ke ", "Zhao ", "Fu ", "Ba ", "Duo ", "Duo ", "Ling ", "Zhuo ", "Xuan ", "Ju ", "Tan ", "Pao ", "Jiong ", "Pao ", "Tai ", "Tai ", "Bing ", "Yang ", "Tong ", "Han ", "Zhu ", "Zha ", "Dian ", "Wei ", "Shi ", "Lian ", "Chi ", "Huang ", "[?] ", "Hu ", "Shuo ", "Lan ", "Jing ", "Jiao ", "Xu ", "Xing ", "Quan ", "Lie ", "Huan ", "Yang ", "Xiao ", "Xiu ", "Xian ", "Yin ", "Wu ", "Zhou ", "Yao ", "Shi ", "Wei ", "Tong ", "Xue ", "Zai ", "Kai ", "Hong ", "Luo ", "Xia ", "Zhu ", "Xuan ", "Zheng ", "Po ", "Yan ", "Hui ", "Guang ", "Zhe ", "Hui ", "Kao ", "[?] ", "Fan ", "Shao ", "Ye ", "Hui ", "[?] ", "Tang ", "Jin ", "Re ", "[?] ", "Xi ", "Fu ", "Jiong ", "Che ", "Pu ", "Jing ", "Zhuo ", "Ting ", "Wan ", "Hai ", "Peng ", "Lang ", "Shan ", "Hu ", "Feng ", "Chi ", "Rong "},
- {"Hu ", "Xi ", "Shu ", "He ", "Xun ", "Ku ", "Jue ", "Xiao ", "Xi ", "Yan ", "Han ", "Zhuang ", "Jun ", "Di ", "Xie ", "Ji ", "Wu ", "[?] ", "[?] ", "Han ", "Yan ", "Huan ", "Men ", "Ju ", "Chou ", "Bei ", "Fen ", "Lin ", "Kun ", "Hun ", "Tun ", "Xi ", "Cui ", "Wu ", "Hong ", "Ju ", "Fu ", "Wo ", "Jiao ", "Cong ", "Feng ", "Ping ", "Qiong ", "Ruo ", "Xi ", "Qiong ", "Xin ", "Zhuo ", "Yan ", "Yan ", "Yi ", "Jue ", "Yu ", "Gang ", "Ran ", "Pi ", "Gu ", "[?] ", "Sheng ", "Chang ", "Shao ", "[?] ", "[?] ", "[?] ", "[?] ", "Chen ", "He ", "Kui ", "Zhong ", "Duan ", "Xia ", "Hui ", "Feng ", "Lian ", "Xuan ", "Xing ", "Huang ", "Jiao ", "Jian ", "Bi ", "Ying ", "Zhu ", "Wei ", "Tuan ", "Tian ", "Xi ", "Nuan ", "Nuan ", "Chan ", "Yan ", "Jiong ", "Jiong ", "Yu ", "Mei ", "Sha ", "Wei ", "Ye ", "Xin ", "Qiong ", "Rou ", "Mei ", "Huan ", "Xu ", "Zhao ", "Wei ", "Fan ", "Qiu ", "Sui ", "Yang ", "Lie ", "Zhu ", "Jie ", "Gao ", "Gua ", "Bao ", "Hu ", "Yun ", "Xia ", "[?] ", "[?] ", "Bian ", "Gou ", "Tui ", "Tang ", "Chao ", "Shan ", "N ", "Bo ", "Huang ", "Xie ", "Xi ", "Wu ", "Xi ", "Yun ", "He ", "He ", "Xi ", "Yun ", "Xiong ", "Nai ", "Shan ", "Qiong ", "Yao ", "Xun ", "Mi ", "Lian ", "Ying ", "Wen ", "Rong ", "Oozutsu ", "[?] ", "Qiang ", "Liu ", "Xi ", "Bi ", "Biao ", "Zong ", "Lu ", "Jian ", "Shou ", "Yi ", "Lou ", "Feng ", "Sui ", "Yi ", "Tong ", "Jue ", "Zong ", "Yun ", "Hu ", "Yi ", "Zhi ", "Ao ", "Wei ", "Liao ", "Han ", "Ou ", "Re ", "Jiong ", "Man ", "[?] ", "Shang ", "Cuan ", "Zeng ", "Jian ", "Xi ", "Xi ", "Xi ", "Yi ", "Xiao ", "Chi ", "Huang ", "Chan ", "Ye ", "Qian ", "Ran ", "Yan ", "Xian ", "Qiao ", "Zun ", "Deng ", "Dun ", "Shen ", "Jiao ", "Fen ", "Si ", "Liao ", "Yu ", "Lin ", "Tong ", "Shao ", "Fen ", "Fan ", "Yan ", "Xun ", "Lan ", "Mei ", "Tang ", "Yi ", "Jing ", "Men ", "[?] ", "[?] ", "Ying ", "Yu ", "Yi ", "Xue ", "Lan ", "Tai ", "Zao ", "Can ", "Sui ", "Xi ", "Que ", "Cong ", "Lian ", "Hui ", "Zhu ", "Xie ", "Ling ", "Wei ", "Yi ", "Xie ", "Zhao ", "Hui ", "Tatsu ", "Nung ", "Lan ", "Ru ", "Xian ", "Kao ", "Xun ", "Jin ", "Chou ", "Chou ", "Yao "},
- {"He ", "Lan ", "Biao ", "Rong ", "Li ", "Mo ", "Bao ", "Ruo ", "Lu ", "La ", "Ao ", "Xun ", "Kuang ", "Shuo ", "[?] ", "Li ", "Lu ", "Jue ", "Liao ", "Yan ", "Xi ", "Xie ", "Long ", "Ye ", "[?] ", "Rang ", "Yue ", "Lan ", "Cong ", "Jue ", "Tong ", "Guan ", "[?] ", "Che ", "Mi ", "Tang ", "Lan ", "Zhu ", "[?] ", "Ling ", "Cuan ", "Yu ", "Zhua ", "Tsumekanmuri ", "Pa ", "Zheng ", "Pao ", "Cheng ", "Yuan ", "Ai ", "Wei ", "[?] ", "Jue ", "Jue ", "Fu ", "Ye ", "Ba ", "Die ", "Ye ", "Yao ", "Zu ", "Shuang ", "Er ", "Qiang ", "Chuang ", "Ge ", "Zang ", "Die ", "Qiang ", "Yong ", "Qiang ", "Pian ", "Ban ", "Pan ", "Shao ", "Jian ", "Pai ", "Du ", "Chuang ", "Tou ", "Zha ", "Bian ", "Die ", "Bang ", "Bo ", "Chuang ", "You ", "[?] ", "Du ", "Ya ", "Cheng ", "Niu ", "Ushihen ", "Pin ", "Jiu ", "Mou ", "Tuo ", "Mu ", "Lao ", "Ren ", "Mang ", "Fang ", "Mao ", "Mu ", "Gang ", "Wu ", "Yan ", "Ge ", "Bei ", "Si ", "Jian ", "Gu ", "You ", "Ge ", "Sheng ", "Mu ", "Di ", "Qian ", "Quan ", "Quan ", "Zi ", "Te ", "Xi ", "Mang ", "Keng ", "Qian ", "Wu ", "Gu ", "Xi ", "Li ", "Li ", "Pou ", "Ji ", "Gang ", "Zhi ", "Ben ", "Quan ", "Run ", "Du ", "Ju ", "Jia ", "Jian ", "Feng ", "Pian ", "Ke ", "Ju ", "Kao ", "Chu ", "Xi ", "Bei ", "Luo ", "Jie ", "Ma ", "San ", "Wei ", "Li ", "Dun ", "Tong ", "[?] ", "Jiang ", "Ikenie ", "Li ", "Du ", "Lie ", "Pi ", "Piao ", "Bao ", "Xi ", "Chou ", "Wei ", "Kui ", "Chou ", "Quan ", "Fan ", "Ba ", "Fan ", "Qiu ", "Ji ", "Cai ", "Chuo ", "An ", "Jie ", "Zhuang ", "Guang ", "Ma ", "You ", "Kang ", "Bo ", "Hou ", "Ya ", "Yin ", "Huan ", "Zhuang ", "Yun ", "Kuang ", "Niu ", "Di ", "Qing ", "Zhong ", "Mu ", "Bei ", "Pi ", "Ju ", "Ni ", "Sheng ", "Pao ", "Xia ", "Tuo ", "Hu ", "Ling ", "Fei ", "Pi ", "Ni ", "Ao ", "You ", "Gou ", "Yue ", "Ju ", "Dan ", "Po ", "Gu ", "Xian ", "Ning ", "Huan ", "Hen ", "Jiao ", "He ", "Zhao ", "Ji ", "Xun ", "Shan ", "Ta ", "Rong ", "Shou ", "Tong ", "Lao ", "Du ", "Xia ", "Shi ", "Hua ", "Zheng ", "Yu ", "Sun ", "Yu ", "Bi ", "Mang ", "Xi ", "Juan ", "Li ", "Xia ", "Yin ", "Suan ", "Lang ", "Bei ", "Zhi ", "Yan "},
- {"Sha ", "Li ", "Han ", "Xian ", "Jing ", "Pai ", "Fei ", "Yao ", "Ba ", "Qi ", "Ni ", "Biao ", "Yin ", "Lai ", "Xi ", "Jian ", "Qiang ", "Kun ", "Yan ", "Guo ", "Zong ", "Mi ", "Chang ", "Yi ", "Zhi ", "Zheng ", "Ya ", "Meng ", "Cai ", "Cu ", "She ", "Kari ", "Cen ", "Luo ", "Hu ", "Zong ", "Ji ", "Wei ", "Feng ", "Wo ", "Yuan ", "Xing ", "Zhu ", "Mao ", "Wei ", "Yuan ", "Xian ", "Tuan ", "Ya ", "Nao ", "Xie ", "Jia ", "Hou ", "Bian ", "You ", "You ", "Mei ", "Zha ", "Yao ", "Sun ", "Bo ", "Ming ", "Hua ", "Yuan ", "Sou ", "Ma ", "Yuan ", "Dai ", "Yu ", "Shi ", "Hao ", "[?] ", "Yi ", "Zhen ", "Chuang ", "Hao ", "Man ", "Jing ", "Jiang ", "Mu ", "Zhang ", "Chan ", "Ao ", "Ao ", "Hao ", "Cui ", "Fen ", "Jue ", "Bi ", "Bi ", "Huang ", "Pu ", "Lin ", "Yu ", "Tong ", "Yao ", "Liao ", "Shuo ", "Xiao ", "Swu ", "Ton ", "Xi ", "Ge ", "Juan ", "Du ", "Hui ", "Kuai ", "Xian ", "Xie ", "Ta ", "Xian ", "Xun ", "Ning ", "Pin ", "Huo ", "Nou ", "Meng ", "Lie ", "Nao ", "Guang ", "Shou ", "Lu ", "Ta ", "Xian ", "Mi ", "Rang ", "Huan ", "Nao ", "Luo ", "Xian ", "Qi ", "Jue ", "Xuan ", "Miao ", "Zi ", "Lu ", "Lu ", "Yu ", "Su ", "Wang ", "Qiu ", "Ga ", "Ding ", "Le ", "Ba ", "Ji ", "Hong ", "Di ", "Quan ", "Gan ", "Jiu ", "Yu ", "Ji ", "Yu ", "Yang ", "Ma ", "Gong ", "Wu ", "Fu ", "Wen ", "Jie ", "Ya ", "Fen ", "Bian ", "Beng ", "Yue ", "Jue ", "Yun ", "Jue ", "Wan ", "Jian ", "Mei ", "Dan ", "Pi ", "Wei ", "Huan ", "Xian ", "Qiang ", "Ling ", "Dai ", "Yi ", "An ", "Ping ", "Dian ", "Fu ", "Xuan ", "Xi ", "Bo ", "Ci ", "Gou ", "Jia ", "Shao ", "Po ", "Ci ", "Ke ", "Ran ", "Sheng ", "Shen ", "Yi ", "Zu ", "Jia ", "Min ", "Shan ", "Liu ", "Bi ", "Zhen ", "Zhen ", "Jue ", "Fa ", "Long ", "Jin ", "Jiao ", "Jian ", "Li ", "Guang ", "Xian ", "Zhou ", "Gong ", "Yan ", "Xiu ", "Yang ", "Xu ", "Luo ", "Su ", "Zhu ", "Qin ", "Ken ", "Xun ", "Bao ", "Er ", "Xiang ", "Yao ", "Xia ", "Heng ", "Gui ", "Chong ", "Xu ", "Ban ", "Pei ", "[?] ", "Dang ", "Ei ", "Hun ", "Wen ", "E ", "Cheng ", "Ti ", "Wu ", "Wu ", "Cheng ", "Jun ", "Mei ", "Bei ", "Ting ", "Xian ", "Chuo "},
- {"Han ", "Xuan ", "Yan ", "Qiu ", "Quan ", "Lang ", "Li ", "Xiu ", "Fu ", "Liu ", "Ye ", "Xi ", "Ling ", "Li ", "Jin ", "Lian ", "Suo ", "Chiisai ", "[?] ", "Wan ", "Dian ", "Pin ", "Zhan ", "Cui ", "Min ", "Yu ", "Ju ", "Chen ", "Lai ", "Wen ", "Sheng ", "Wei ", "Dian ", "Chu ", "Zhuo ", "Pei ", "Cheng ", "Hu ", "Qi ", "E ", "Kun ", "Chang ", "Qi ", "Beng ", "Wan ", "Lu ", "Cong ", "Guan ", "Yan ", "Diao ", "Bei ", "Lin ", "Qin ", "Pi ", "Pa ", "Que ", "Zhuo ", "Qin ", "Fa ", "[?] ", "Qiong ", "Du ", "Jie ", "Hun ", "Yu ", "Mao ", "Mei ", "Chun ", "Xuan ", "Ti ", "Xing ", "Dai ", "Rou ", "Min ", "Zhen ", "Wei ", "Ruan ", "Huan ", "Jie ", "Chuan ", "Jian ", "Zhuan ", "Yang ", "Lian ", "Quan ", "Xia ", "Duan ", "Yuan ", "Ye ", "Nao ", "Hu ", "Ying ", "Yu ", "Huang ", "Rui ", "Se ", "Liu ", "Shi ", "Rong ", "Suo ", "Yao ", "Wen ", "Wu ", "Jin ", "Jin ", "Ying ", "Ma ", "Tao ", "Liu ", "Tang ", "Li ", "Lang ", "Gui ", "Zhen ", "Qiang ", "Cuo ", "Jue ", "Zhao ", "Yao ", "Ai ", "Bin ", "Tu ", "Chang ", "Kun ", "Zhuan ", "Cong ", "Jin ", "Yi ", "Cui ", "Cong ", "Qi ", "Li ", "Ying ", "Suo ", "Qiu ", "Xuan ", "Ao ", "Lian ", "Man ", "Zhang ", "Yin ", "[?] ", "Ying ", "Zhi ", "Lu ", "Wu ", "Deng ", "Xiou ", "Zeng ", "Xun ", "Qu ", "Dang ", "Lin ", "Liao ", "Qiong ", "Su ", "Huang ", "Gui ", "Pu ", "Jing ", "Fan ", "Jin ", "Liu ", "Ji ", "[?] ", "Jing ", "Ai ", "Bi ", "Can ", "Qu ", "Zao ", "Dang ", "Jiao ", "Gun ", "Tan ", "Hui ", "Huan ", "Se ", "Sui ", "Tian ", "[?] ", "Yu ", "Jin ", "Lu ", "Bin ", "Shou ", "Wen ", "Zui ", "Lan ", "Xi ", "Ji ", "Xuan ", "Ruan ", "Huo ", "Gai ", "Lei ", "Du ", "Li ", "Zhi ", "Rou ", "Li ", "Zan ", "Qiong ", "Zhe ", "Gui ", "Sui ", "La ", "Long ", "Lu ", "Li ", "Zan ", "Lan ", "Ying ", "Mi ", "Xiang ", "Xi ", "Guan ", "Dao ", "Zan ", "Huan ", "Gua ", "Bo ", "Die ", "Bao ", "Hu ", "Zhi ", "Piao ", "Ban ", "Rang ", "Li ", "Wa ", "Dekaguramu ", "Jiang ", "Qian ", "Fan ", "Pen ", "Fang ", "Dan ", "Weng ", "Ou ", "Deshiguramu ", "Miriguramu ", "Thon ", "Hu ", "Ling ", "Yi ", "Ping ", "Ci ", "Hekutogura ", "Juan ", "Chang ", "Chi ", "Sarake ", "Dang ", "Meng ", "Pou "},
- {"Zhui ", "Ping ", "Bian ", "Zhou ", "Zhen ", "Senchigura ", "Ci ", "Ying ", "Qi ", "Xian ", "Lou ", "Di ", "Ou ", "Meng ", "Zhuan ", "Peng ", "Lin ", "Zeng ", "Wu ", "Pi ", "Dan ", "Weng ", "Ying ", "Yan ", "Gan ", "Dai ", "Shen ", "Tian ", "Tian ", "Han ", "Chang ", "Sheng ", "Qing ", "Sheng ", "Chan ", "Chan ", "Rui ", "Sheng ", "Su ", "Sen ", "Yong ", "Shuai ", "Lu ", "Fu ", "Yong ", "Beng ", "Feng ", "Ning ", "Tian ", "You ", "Jia ", "Shen ", "Zha ", "Dian ", "Fu ", "Nan ", "Dian ", "Ping ", "Ting ", "Hua ", "Ting ", "Quan ", "Zi ", "Meng ", "Bi ", "Qi ", "Liu ", "Xun ", "Liu ", "Chang ", "Mu ", "Yun ", "Fan ", "Fu ", "Geng ", "Tian ", "Jie ", "Jie ", "Quan ", "Wei ", "Fu ", "Tian ", "Mu ", "Tap ", "Pan ", "Jiang ", "Wa ", "Da ", "Nan ", "Liu ", "Ben ", "Zhen ", "Chu ", "Mu ", "Mu ", "Ce ", "Cen ", "Gai ", "Bi ", "Da ", "Zhi ", "Lue ", "Qi ", "Lue ", "Pan ", "Kesa ", "Fan ", "Hua ", "Yu ", "Yu ", "Mu ", "Jun ", "Yi ", "Liu ", "Yu ", "Die ", "Chou ", "Hua ", "Dang ", "Chuo ", "Ji ", "Wan ", "Jiang ", "Sheng ", "Chang ", "Tuan ", "Lei ", "Ji ", "Cha ", "Liu ", "Tatamu ", "Tuan ", "Lin ", "Jiang ", "Jiang ", "Chou ", "Bo ", "Die ", "Die ", "Pi ", "Nie ", "Dan ", "Shu ", "Shu ", "Zhi ", "Yi ", "Chuang ", "Nai ", "Ding ", "Bi ", "Jie ", "Liao ", "Gong ", "Ge ", "Jiu ", "Zhou ", "Xia ", "Shan ", "Xu ", "Nue ", "Li ", "Yang ", "Chen ", "You ", "Ba ", "Jie ", "Jue ", "Zhi ", "Xia ", "Cui ", "Bi ", "Yi ", "Li ", "Zong ", "Chuang ", "Feng ", "Zhu ", "Pao ", "Pi ", "Gan ", "Ke ", "Ci ", "Xie ", "Qi ", "Dan ", "Zhen ", "Fa ", "Zhi ", "Teng ", "Ju ", "Ji ", "Fei ", "Qu ", "Dian ", "Jia ", "Xian ", "Cha ", "Bing ", "Ni ", "Zheng ", "Yong ", "Jing ", "Quan ", "Chong ", "Tong ", "Yi ", "Kai ", "Wei ", "Hui ", "Duo ", "Yang ", "Chi ", "Zhi ", "Hen ", "Ya ", "Mei ", "Dou ", "Jing ", "Xiao ", "Tong ", "Tu ", "Mang ", "Pi ", "Xiao ", "Suan ", "Pu ", "Li ", "Zhi ", "Cuo ", "Duo ", "Wu ", "Sha ", "Lao ", "Shou ", "Huan ", "Xian ", "Yi ", "Peng ", "Zhang ", "Guan ", "Tan ", "Fei ", "Ma ", "Lin ", "Chi ", "Ji ", "Dian ", "An ", "Chi ", "Bi ", "Bei ", "Min ", "Gu ", "Dui ", "E ", "Wei "},
- {"Yu ", "Cui ", "Ya ", "Zhu ", "Cu ", "Dan ", "Shen ", "Zhung ", "Ji ", "Yu ", "Hou ", "Feng ", "La ", "Yang ", "Shen ", "Tu ", "Yu ", "Gua ", "Wen ", "Huan ", "Ku ", "Jia ", "Yin ", "Yi ", "Lu ", "Sao ", "Jue ", "Chi ", "Xi ", "Guan ", "Yi ", "Wen ", "Ji ", "Chuang ", "Ban ", "Lei ", "Liu ", "Chai ", "Shou ", "Nue ", "Dian ", "Da ", "Pie ", "Tan ", "Zhang ", "Biao ", "Shen ", "Cu ", "Luo ", "Yi ", "Zong ", "Chou ", "Zhang ", "Zhai ", "Sou ", "Suo ", "Que ", "Diao ", "Lou ", "Lu ", "Mo ", "Jin ", "Yin ", "Ying ", "Huang ", "Fu ", "Liao ", "Long ", "Qiao ", "Liu ", "Lao ", "Xian ", "Fei ", "Dan ", "Yin ", "He ", "Yan ", "Ban ", "Xian ", "Guan ", "Guai ", "Nong ", "Yu ", "Wei ", "Yi ", "Yong ", "Pi ", "Lei ", "Li ", "Shu ", "Dan ", "Lin ", "Dian ", "Lin ", "Lai ", "Pie ", "Ji ", "Chi ", "Yang ", "Xian ", "Jie ", "Zheng ", "[?] ", "Li ", "Huo ", "Lai ", "Shaku ", "Dian ", "Xian ", "Ying ", "Yin ", "Qu ", "Yong ", "Tan ", "Dian ", "Luo ", "Luan ", "Luan ", "Bo ", "[?] ", "Gui ", "Po ", "Fa ", "Deng ", "Fa ", "Bai ", "Bai ", "Qie ", "Bi ", "Zao ", "Zao ", "Mao ", "De ", "Pa ", "Jie ", "Huang ", "Gui ", "Ci ", "Ling ", "Gao ", "Mo ", "Ji ", "Jiao ", "Peng ", "Gao ", "Ai ", "E ", "Hao ", "Han ", "Bi ", "Wan ", "Chou ", "Qian ", "Xi ", "Ai ", "Jiong ", "Hao ", "Huang ", "Hao ", "Ze ", "Cui ", "Hao ", "Xiao ", "Ye ", "Po ", "Hao ", "Jiao ", "Ai ", "Xing ", "Huang ", "Li ", "Piao ", "He ", "Jiao ", "Pi ", "Gan ", "Pao ", "Zhou ", "Jun ", "Qiu ", "Cun ", "Que ", "Zha ", "Gu ", "Jun ", "Jun ", "Zhou ", "Zha ", "Gu ", "Zhan ", "Du ", "Min ", "Qi ", "Ying ", "Yu ", "Bei ", "Zhao ", "Zhong ", "Pen ", "He ", "Ying ", "He ", "Yi ", "Bo ", "Wan ", "He ", "Ang ", "Zhan ", "Yan ", "Jian ", "He ", "Yu ", "Kui ", "Fan ", "Gai ", "Dao ", "Pan ", "Fu ", "Qiu ", "Sheng ", "Dao ", "Lu ", "Zhan ", "Meng ", "Li ", "Jin ", "Xu ", "Jian ", "Pan ", "Guan ", "An ", "Lu ", "Shu ", "Zhou ", "Dang ", "An ", "Gu ", "Li ", "Mu ", "Cheng ", "Gan ", "Xu ", "Mang ", "Mang ", "Zhi ", "Qi ", "Ruan ", "Tian ", "Xiang ", "Dun ", "Xin ", "Xi ", "Pan ", "Feng ", "Dun ", "Min "},
- {"Ming ", "Sheng ", "Shi ", "Yun ", "Mian ", "Pan ", "Fang ", "Miao ", "Dan ", "Mei ", "Mao ", "Kan ", "Xian ", "Ou ", "Shi ", "Yang ", "Zheng ", "Yao ", "Shen ", "Huo ", "Da ", "Zhen ", "Kuang ", "Ju ", "Shen ", "Chi ", "Sheng ", "Mei ", "Mo ", "Zhu ", "Zhen ", "Zhen ", "Mian ", "Di ", "Yuan ", "Die ", "Yi ", "Zi ", "Zi ", "Chao ", "Zha ", "Xuan ", "Bing ", "Mi ", "Long ", "Sui ", "Dong ", "Mi ", "Die ", "Yi ", "Er ", "Ming ", "Xuan ", "Chi ", "Kuang ", "Juan ", "Mou ", "Zhen ", "Tiao ", "Yang ", "Yan ", "Mo ", "Zhong ", "Mai ", "Zhao ", "Zheng ", "Mei ", "Jun ", "Shao ", "Han ", "Huan ", "Di ", "Cheng ", "Cuo ", "Juan ", "E ", "Wan ", "Xian ", "Xi ", "Kun ", "Lai ", "Jian ", "Shan ", "Tian ", "Hun ", "Wan ", "Ling ", "Shi ", "Qiong ", "Lie ", "Yai ", "Jing ", "Zheng ", "Li ", "Lai ", "Sui ", "Juan ", "Shui ", "Sui ", "Du ", "Bi ", "Bi ", "Mu ", "Hun ", "Ni ", "Lu ", "Yi ", "Jie ", "Cai ", "Zhou ", "Yu ", "Hun ", "Ma ", "Xia ", "Xing ", "Xi ", "Gun ", "Cai ", "Chun ", "Jian ", "Mei ", "Du ", "Hou ", "Xuan ", "Ti ", "Kui ", "Gao ", "Rui ", "Mou ", "Xu ", "Fa ", "Wen ", "Miao ", "Chou ", "Kui ", "Mi ", "Weng ", "Kou ", "Dang ", "Chen ", "Ke ", "Sou ", "Xia ", "Qiong ", "Mao ", "Ming ", "Man ", "Shui ", "Ze ", "Zhang ", "Yi ", "Diao ", "Ou ", "Mo ", "Shun ", "Cong ", "Lou ", "Chi ", "Man ", "Piao ", "Cheng ", "Ji ", "Meng ", "[?] ", "Run ", "Pie ", "Xi ", "Qiao ", "Pu ", "Zhu ", "Deng ", "Shen ", "Shun ", "Liao ", "Che ", "Xian ", "Kan ", "Ye ", "Xu ", "Tong ", "Mou ", "Lin ", "Kui ", "Xian ", "Ye ", "Ai ", "Hui ", "Zhan ", "Jian ", "Gu ", "Zhao ", "Qu ", "Wei ", "Chou ", "Sao ", "Ning ", "Xun ", "Yao ", "Huo ", "Meng ", "Mian ", "Bin ", "Mian ", "Li ", "Kuang ", "Jue ", "Xuan ", "Mian ", "Huo ", "Lu ", "Meng ", "Long ", "Guan ", "Man ", "Xi ", "Chu ", "Tang ", "Kan ", "Zhu ", "Mao ", "Jin ", "Lin ", "Yu ", "Shuo ", "Ce ", "Jue ", "Shi ", "Yi ", "Shen ", "Zhi ", "Hou ", "Shen ", "Ying ", "Ju ", "Zhou ", "Jiao ", "Cuo ", "Duan ", "Ai ", "Jiao ", "Zeng ", "Huo ", "Bai ", "Shi ", "Ding ", "Qi ", "Ji ", "Zi ", "Gan ", "Wu ", "Tuo ", "Ku ", "Qiang ", "Xi ", "Fan ", "Kuang "},
- {"Dang ", "Ma ", "Sha ", "Dan ", "Jue ", "Li ", "Fu ", "Min ", "Nuo ", "Huo ", "Kang ", "Zhi ", "Qi ", "Kan ", "Jie ", "Fen ", "E ", "Ya ", "Pi ", "Zhe ", "Yan ", "Sui ", "Zhuan ", "Che ", "Dun ", "Pan ", "Yan ", "[?] ", "Feng ", "Fa ", "Mo ", "Zha ", "Qu ", "Yu ", "Luo ", "Tuo ", "Tuo ", "Di ", "Zhai ", "Zhen ", "Ai ", "Fei ", "Mu ", "Zhu ", "Li ", "Bian ", "Nu ", "Ping ", "Peng ", "Ling ", "Pao ", "Le ", "Po ", "Bo ", "Po ", "Shen ", "Za ", "Nuo ", "Li ", "Long ", "Tong ", "[?] ", "Li ", "Aragane ", "Chu ", "Keng ", "Quan ", "Zhu ", "Kuang ", "Huo ", "E ", "Nao ", "Jia ", "Lu ", "Wei ", "Ai ", "Luo ", "Ken ", "Xing ", "Yan ", "Tong ", "Peng ", "Xi ", "[?] ", "Hong ", "Shuo ", "Xia ", "Qiao ", "[?] ", "Wei ", "Qiao ", "[?] ", "Keng ", "Xiao ", "Que ", "Chan ", "Lang ", "Hong ", "Yu ", "Xiao ", "Xia ", "Mang ", "Long ", "Iong ", "Che ", "Che ", "E ", "Liu ", "Ying ", "Mang ", "Que ", "Yan ", "Sha ", "Kun ", "Yu ", "[?] ", "Kaki ", "Lu ", "Chen ", "Jian ", "Nue ", "Song ", "Zhuo ", "Keng ", "Peng ", "Yan ", "Zhui ", "Kong ", "Ceng ", "Qi ", "Zong ", "Qing ", "Lin ", "Jun ", "Bo ", "Ding ", "Min ", "Diao ", "Jian ", "He ", "Lu ", "Ai ", "Sui ", "Que ", "Ling ", "Bei ", "Yin ", "Dui ", "Wu ", "Qi ", "Lun ", "Wan ", "Dian ", "Gang ", "Pei ", "Qi ", "Chen ", "Ruan ", "Yan ", "Die ", "Ding ", "Du ", "Tuo ", "Jie ", "Ying ", "Bian ", "Ke ", "Bi ", "Wei ", "Shuo ", "Zhen ", "Duan ", "Xia ", "Dang ", "Ti ", "Nao ", "Peng ", "Jian ", "Di ", "Tan ", "Cha ", "Seki ", "Qi ", "[?] ", "Feng ", "Xuan ", "Que ", "Que ", "Ma ", "Gong ", "Nian ", "Su ", "E ", "Ci ", "Liu ", "Si ", "Tang ", "Bang ", "Hua ", "Pi ", "Wei ", "Sang ", "Lei ", "Cuo ", "Zhen ", "Xia ", "Qi ", "Lian ", "Pan ", "Wei ", "Yun ", "Dui ", "Zhe ", "Ke ", "La ", "[?] ", "Qing ", "Gun ", "Zhuan ", "Chan ", "Qi ", "Ao ", "Peng ", "Lu ", "Lu ", "Kan ", "Qiang ", "Chen ", "Yin ", "Lei ", "Biao ", "Qi ", "Mo ", "Qi ", "Cui ", "Zong ", "Qing ", "Chuo ", "[?] ", "Ji ", "Shan ", "Lao ", "Qu ", "Zeng ", "Deng ", "Jian ", "Xi ", "Lin ", "Ding ", "Dian ", "Huang ", "Pan ", "Za ", "Qiao ", "Di ", "Li "},
- {"Tani ", "Jiao ", "[?] ", "Zhang ", "Qiao ", "Dun ", "Xian ", "Yu ", "Zhui ", "He ", "Huo ", "Zhai ", "Lei ", "Ke ", "Chu ", "Ji ", "Que ", "Dang ", "Yi ", "Jiang ", "Pi ", "Pi ", "Yu ", "Pin ", "Qi ", "Ai ", "Kai ", "Jian ", "Yu ", "Ruan ", "Meng ", "Pao ", "Ci ", "[?] ", "[?] ", "Mie ", "Ca ", "Xian ", "Kuang ", "Lei ", "Lei ", "Zhi ", "Li ", "Li ", "Fan ", "Que ", "Pao ", "Ying ", "Li ", "Long ", "Long ", "Mo ", "Bo ", "Shuang ", "Guan ", "Lan ", "Zan ", "Yan ", "Shi ", "Shi ", "Li ", "Reng ", "She ", "Yue ", "Si ", "Qi ", "Ta ", "Ma ", "Xie ", "Xian ", "Xian ", "Zhi ", "Qi ", "Zhi ", "Beng ", "Dui ", "Zhong ", "[?] ", "Yi ", "Shi ", "You ", "Zhi ", "Tiao ", "Fu ", "Fu ", "Mi ", "Zu ", "Zhi ", "Suan ", "Mei ", "Zuo ", "Qu ", "Hu ", "Zhu ", "Shen ", "Sui ", "Ci ", "Chai ", "Mi ", "Lu ", "Yu ", "Xiang ", "Wu ", "Tiao ", "Piao ", "Zhu ", "Gui ", "Xia ", "Zhi ", "Ji ", "Gao ", "Zhen ", "Gao ", "Shui ", "Jin ", "Chen ", "Gai ", "Kun ", "Di ", "Dao ", "Huo ", "Tao ", "Qi ", "Gu ", "Guan ", "Zui ", "Ling ", "Lu ", "Bing ", "Jin ", "Dao ", "Zhi ", "Lu ", "Shan ", "Bei ", "Zhe ", "Hui ", "You ", "Xi ", "Yin ", "Zi ", "Huo ", "Zhen ", "Fu ", "Yuan ", "Wu ", "Xian ", "Yang ", "Ti ", "Yi ", "Mei ", "Si ", "Di ", "[?] ", "Zhuo ", "Zhen ", "Yong ", "Ji ", "Gao ", "Tang ", "Si ", "Ma ", "Ta ", "[?] ", "Xuan ", "Qi ", "Yu ", "Xi ", "Ji ", "Si ", "Chan ", "Tan ", "Kuai ", "Sui ", "Li ", "Nong ", "Ni ", "Dao ", "Li ", "Rang ", "Yue ", "Ti ", "Zan ", "Lei ", "Rou ", "Yu ", "Yu ", "Chi ", "Xie ", "Qin ", "He ", "Tu ", "Xiu ", "Si ", "Ren ", "Tu ", "Zi ", "Cha ", "Gan ", "Yi ", "Xian ", "Bing ", "Nian ", "Qiu ", "Qiu ", "Chong ", "Fen ", "Hao ", "Yun ", "Ke ", "Miao ", "Zhi ", "Geng ", "Bi ", "Zhi ", "Yu ", "Mi ", "Ku ", "Ban ", "Pi ", "Ni ", "Li ", "You ", "Zu ", "Pi ", "Ba ", "Ling ", "Mo ", "Cheng ", "Nian ", "Qin ", "Yang ", "Zuo ", "Zhi ", "Zhi ", "Shu ", "Ju ", "Zi ", "Huo ", "Ji ", "Cheng ", "Tong ", "Zhi ", "Huo ", "He ", "Yin ", "Zi ", "Zhi ", "Jie ", "Ren ", "Du ", "Yi ", "Zhu ", "Hui ", "Nong ", "Fu "},
- {"Xi ", "Kao ", "Lang ", "Fu ", "Ze ", "Shui ", "Lu ", "Kun ", "Gan ", "Geng ", "Ti ", "Cheng ", "Tu ", "Shao ", "Shui ", "Ya ", "Lun ", "Lu ", "Gu ", "Zuo ", "Ren ", "Zhun ", "Bang ", "Bai ", "Ji ", "Zhi ", "Zhi ", "Kun ", "Leng ", "Peng ", "Ke ", "Bing ", "Chou ", "Zu ", "Yu ", "Su ", "Lue ", "[?] ", "Yi ", "Xi ", "Bian ", "Ji ", "Fu ", "Bi ", "Nuo ", "Jie ", "Zhong ", "Zong ", "Xu ", "Cheng ", "Dao ", "Wen ", "Lian ", "Zi ", "Yu ", "Ji ", "Xu ", "Zhen ", "Zhi ", "Dao ", "Jia ", "Ji ", "Gao ", "Gao ", "Gu ", "Rong ", "Sui ", "You ", "Ji ", "Kang ", "Mu ", "Shan ", "Men ", "Zhi ", "Ji ", "Lu ", "Su ", "Ji ", "Ying ", "Wen ", "Qiu ", "Se ", "[?] ", "Yi ", "Huang ", "Qie ", "Ji ", "Sui ", "Xiao ", "Pu ", "Jiao ", "Zhuo ", "Tong ", "Sai ", "Lu ", "Sui ", "Nong ", "Se ", "Hui ", "Rang ", "Nuo ", "Yu ", "Bin ", "Ji ", "Tui ", "Wen ", "Cheng ", "Huo ", "Gong ", "Lu ", "Biao ", "[?] ", "Rang ", "Zhuo ", "Li ", "Zan ", "Xue ", "Wa ", "Jiu ", "Qiong ", "Xi ", "Qiong ", "Kong ", "Yu ", "Sen ", "Jing ", "Yao ", "Chuan ", "Zhun ", "Tu ", "Lao ", "Qie ", "Zhai ", "Yao ", "Bian ", "Bao ", "Yao ", "Bing ", "Wa ", "Zhu ", "Jiao ", "Qiao ", "Diao ", "Wu ", "Gui ", "Yao ", "Zhi ", "Chuang ", "Yao ", "Tiao ", "Jiao ", "Chuang ", "Jiong ", "Xiao ", "Cheng ", "Kou ", "Cuan ", "Wo ", "Dan ", "Ku ", "Ke ", "Zhui ", "Xu ", "Su ", "Guan ", "Kui ", "Dou ", "[?] ", "Yin ", "Wo ", "Wa ", "Ya ", "Yu ", "Ju ", "Qiong ", "Yao ", "Yao ", "Tiao ", "Chao ", "Yu ", "Tian ", "Diao ", "Ju ", "Liao ", "Xi ", "Wu ", "Kui ", "Chuang ", "Zhao ", "[?] ", "Kuan ", "Long ", "Cheng ", "Cui ", "Piao ", "Zao ", "Cuan ", "Qiao ", "Qiong ", "Dou ", "Zao ", "Long ", "Qie ", "Li ", "Chu ", "Shi ", "Fou ", "Qian ", "Chu ", "Hong ", "Qi ", "Qian ", "Gong ", "Shi ", "Shu ", "Miao ", "Ju ", "Zhan ", "Zhu ", "Ling ", "Long ", "Bing ", "Jing ", "Jing ", "Zhang ", "Yi ", "Si ", "Jun ", "Hong ", "Tong ", "Song ", "Jing ", "Diao ", "Yi ", "Shu ", "Jing ", "Qu ", "Jie ", "Ping ", "Duan ", "Shao ", "Zhuan ", "Ceng ", "Deng ", "Cui ", "Huai ", "Jing ", "Kan ", "Jing ", "Zhu ", "Zhu ", "Le ", "Peng ", "Yu ", "Chi ", "Gan "},
- {"Mang ", "Zhu ", "Utsubo ", "Du ", "Ji ", "Xiao ", "Ba ", "Suan ", "Ji ", "Zhen ", "Zhao ", "Sun ", "Ya ", "Zhui ", "Yuan ", "Hu ", "Gang ", "Xiao ", "Cen ", "Pi ", "Bi ", "Jian ", "Yi ", "Dong ", "Shan ", "Sheng ", "Xia ", "Di ", "Zhu ", "Na ", "Chi ", "Gu ", "Li ", "Qie ", "Min ", "Bao ", "Tiao ", "Si ", "Fu ", "Ce ", "Ben ", "Pei ", "Da ", "Zi ", "Di ", "Ling ", "Ze ", "Nu ", "Fu ", "Gou ", "Fan ", "Jia ", "Ge ", "Fan ", "Shi ", "Mao ", "Po ", "Sey ", "Jian ", "Qiong ", "Long ", "Souke ", "Bian ", "Luo ", "Gui ", "Qu ", "Chi ", "Yin ", "Yao ", "Xian ", "Bi ", "Qiong ", "Gua ", "Deng ", "Jiao ", "Jin ", "Quan ", "Sun ", "Ru ", "Fa ", "Kuang ", "Zhu ", "Tong ", "Ji ", "Da ", "Xing ", "Ce ", "Zhong ", "Kou ", "Lai ", "Bi ", "Shai ", "Dang ", "Zheng ", "Ce ", "Fu ", "Yun ", "Tu ", "Pa ", "Li ", "Lang ", "Ju ", "Guan ", "Jian ", "Han ", "Tong ", "Xia ", "Zhi ", "Cheng ", "Suan ", "Shi ", "Zhu ", "Zuo ", "Xiao ", "Shao ", "Ting ", "Ce ", "Yan ", "Gao ", "Kuai ", "Gan ", "Chou ", "Kago ", "Gang ", "Yun ", "O ", "Qian ", "Xiao ", "Jian ", "Pu ", "Lai ", "Zou ", "Bi ", "Bi ", "Bi ", "Ge ", "Chi ", "Guai ", "Yu ", "Jian ", "Zhao ", "Gu ", "Chi ", "Zheng ", "Jing ", "Sha ", "Zhou ", "Lu ", "Bo ", "Ji ", "Lin ", "Suan ", "Jun ", "Fu ", "Zha ", "Gu ", "Kong ", "Qian ", "Quan ", "Jun ", "Chui ", "Guan ", "Yuan ", "Ce ", "Ju ", "Bo ", "Ze ", "Qie ", "Tuo ", "Luo ", "Dan ", "Xiao ", "Ruo ", "Jian ", "Xuan ", "Bian ", "Sun ", "Xiang ", "Xian ", "Ping ", "Zhen ", "Sheng ", "Hu ", "Shi ", "Zhu ", "Yue ", "Chun ", "Lu ", "Wu ", "Dong ", "Xiao ", "Ji ", "Jie ", "Huang ", "Xing ", "Mei ", "Fan ", "Chui ", "Zhuan ", "Pian ", "Feng ", "Zhu ", "Hong ", "Qie ", "Hou ", "Qiu ", "Miao ", "Qian ", "[?] ", "Kui ", "Sik ", "Lou ", "Yun ", "He ", "Tang ", "Yue ", "Chou ", "Gao ", "Fei ", "Ruo ", "Zheng ", "Gou ", "Nie ", "Qian ", "Xiao ", "Cuan ", "Gong ", "Pang ", "Du ", "Li ", "Bi ", "Zhuo ", "Chu ", "Shai ", "Chi ", "Zhu ", "Qiang ", "Long ", "Lan ", "Jian ", "Bu ", "Li ", "Hui ", "Bi ", "Di ", "Cong ", "Yan ", "Peng ", "Sen ", "Zhuan ", "Pai ", "Piao ", "Dou ", "Yu ", "Mie ", "Zhuan "},
- {"Ze ", "Xi ", "Guo ", "Yi ", "Hu ", "Chan ", "Kou ", "Cu ", "Ping ", "Chou ", "Ji ", "Gui ", "Su ", "Lou ", "Zha ", "Lu ", "Nian ", "Suo ", "Cuan ", "Sasara ", "Suo ", "Le ", "Duan ", "Yana ", "Xiao ", "Bo ", "Mi ", "Si ", "Dang ", "Liao ", "Dan ", "Dian ", "Fu ", "Jian ", "Min ", "Kui ", "Dai ", "Qiao ", "Deng ", "Huang ", "Sun ", "Lao ", "Zan ", "Xiao ", "Du ", "Shi ", "Zan ", "[?] ", "Pai ", "Hata ", "Pai ", "Gan ", "Ju ", "Du ", "Lu ", "Yan ", "Bo ", "Dang ", "Sai ", "Ke ", "Long ", "Qian ", "Lian ", "Bo ", "Zhou ", "Lai ", "[?] ", "Lan ", "Kui ", "Yu ", "Yue ", "Hao ", "Zhen ", "Tai ", "Ti ", "Mi ", "Chou ", "Ji ", "[?] ", "Hata ", "Teng ", "Zhuan ", "Zhou ", "Fan ", "Sou ", "Zhou ", "Kuji ", "Zhuo ", "Teng ", "Lu ", "Lu ", "Jian ", "Tuo ", "Ying ", "Yu ", "Lai ", "Long ", "Shinshi ", "Lian ", "Lan ", "Qian ", "Yue ", "Zhong ", "Qu ", "Lian ", "Bian ", "Duan ", "Zuan ", "Li ", "Si ", "Luo ", "Ying ", "Yue ", "Zhuo ", "Xu ", "Mi ", "Di ", "Fan ", "Shen ", "Zhe ", "Shen ", "Nu ", "Xie ", "Lei ", "Xian ", "Zi ", "Ni ", "Cun ", "[?] ", "Qian ", "Kume ", "Bi ", "Ban ", "Wu ", "Sha ", "Kang ", "Rou ", "Fen ", "Bi ", "Cui ", "[?] ", "Li ", "Chi ", "Nukamiso ", "Ro ", "Ba ", "Li ", "Gan ", "Ju ", "Po ", "Mo ", "Cu ", "Nian ", "Zhou ", "Li ", "Su ", "Tiao ", "Li ", "Qi ", "Su ", "Hong ", "Tong ", "Zi ", "Ce ", "Yue ", "Zhou ", "Lin ", "Zhuang ", "Bai ", "[?] ", "Fen ", "Ji ", "[?] ", "Sukumo ", "Liang ", "Xian ", "Fu ", "Liang ", "Can ", "Geng ", "Li ", "Yue ", "Lu ", "Ju ", "Qi ", "Cui ", "Bai ", "Zhang ", "Lin ", "Zong ", "Jing ", "Guo ", "Kouji ", "San ", "San ", "Tang ", "Bian ", "Rou ", "Mian ", "Hou ", "Xu ", "Zong ", "Hu ", "Jian ", "Zan ", "Ci ", "Li ", "Xie ", "Fu ", "Ni ", "Bei ", "Gu ", "Xiu ", "Gao ", "Tang ", "Qiu ", "Sukumo ", "Cao ", "Zhuang ", "Tang ", "Mi ", "San ", "Fen ", "Zao ", "Kang ", "Jiang ", "Mo ", "San ", "San ", "Nuo ", "Xi ", "Liang ", "Jiang ", "Kuai ", "Bo ", "Huan ", "[?] ", "Zong ", "Xian ", "Nuo ", "Tuan ", "Nie ", "Li ", "Zuo ", "Di ", "Nie ", "Tiao ", "Lan ", "Mi ", "Jiao ", "Jiu ", "Xi ", "Gong ", "Zheng ", "Jiu ", "You "},
- {"Ji ", "Cha ", "Zhou ", "Xun ", "Yue ", "Hong ", "Yu ", "He ", "Wan ", "Ren ", "Wen ", "Wen ", "Qiu ", "Na ", "Zi ", "Tou ", "Niu ", "Fou ", "Jie ", "Shu ", "Chun ", "Pi ", "Yin ", "Sha ", "Hong ", "Zhi ", "Ji ", "Fen ", "Yun ", "Ren ", "Dan ", "Jin ", "Su ", "Fang ", "Suo ", "Cui ", "Jiu ", "Zha ", "Kinu ", "Jin ", "Fu ", "Zhi ", "Ci ", "Zi ", "Chou ", "Hong ", "Zha ", "Lei ", "Xi ", "Fu ", "Xie ", "Shen ", "Bei ", "Zhu ", "Qu ", "Ling ", "Zhu ", "Shao ", "Gan ", "Yang ", "Fu ", "Tuo ", "Zhen ", "Dai ", "Zhuo ", "Shi ", "Zhong ", "Xian ", "Zu ", "Jiong ", "Ban ", "Ju ", "Mo ", "Shu ", "Zui ", "Wata ", "Jing ", "Ren ", "Heng ", "Xie ", "Jie ", "Zhu ", "Chou ", "Gua ", "Bai ", "Jue ", "Kuang ", "Hu ", "Ci ", "Geng ", "Geng ", "Tao ", "Xie ", "Ku ", "Jiao ", "Quan ", "Gai ", "Luo ", "Xuan ", "Bing ", "Xian ", "Fu ", "Gei ", "Tong ", "Rong ", "Tiao ", "Yin ", "Lei ", "Xie ", "Quan ", "Xu ", "Lun ", "Die ", "Tong ", "Si ", "Jiang ", "Xiang ", "Hui ", "Jue ", "Zhi ", "Jian ", "Juan ", "Chi ", "Mian ", "Zhen ", "Lu ", "Cheng ", "Qiu ", "Shu ", "Bang ", "Tong ", "Xiao ", "Wan ", "Qin ", "Geng ", "Xiu ", "Ti ", "Xiu ", "Xie ", "Hong ", "Xi ", "Fu ", "Ting ", "Sui ", "Dui ", "Kun ", "Fu ", "Jing ", "Hu ", "Zhi ", "Yan ", "Jiong ", "Feng ", "Ji ", "Sok ", "Kase ", "Zong ", "Lin ", "Duo ", "Li ", "Lu ", "Liang ", "Chou ", "Quan ", "Shao ", "Qi ", "Qi ", "Zhun ", "Qi ", "Wan ", "Qian ", "Xian ", "Shou ", "Wei ", "Qi ", "Tao ", "Wan ", "Gang ", "Wang ", "Beng ", "Zhui ", "Cai ", "Guo ", "Cui ", "Lun ", "Liu ", "Qi ", "Zhan ", "Bei ", "Chuo ", "Ling ", "Mian ", "Qi ", "Qie ", "Tan ", "Zong ", "Gun ", "Zou ", "Yi ", "Zi ", "Xing ", "Liang ", "Jin ", "Fei ", "Rui ", "Min ", "Yu ", "Zong ", "Fan ", "Lu ", "Xu ", "Yingl ", "Zhang ", "Kasuri ", "Xu ", "Xiang ", "Jian ", "Ke ", "Xian ", "Ruan ", "Mian ", "Qi ", "Duan ", "Zhong ", "Di ", "Min ", "Miao ", "Yuan ", "Xie ", "Bao ", "Si ", "Qiu ", "Bian ", "Huan ", "Geng ", "Cong ", "Mian ", "Wei ", "Fu ", "Wei ", "Yu ", "Gou ", "Miao ", "Xie ", "Lian ", "Zong ", "Bian ", "Yun ", "Yin ", "Ti ", "Gua ", "Zhi ", "Yun ", "Cheng ", "Chan ", "Dai "},
- {"Xia ", "Yuan ", "Zong ", "Xu ", "Nawa ", "Odoshi ", "Geng ", "Sen ", "Ying ", "Jin ", "Yi ", "Zhui ", "Ni ", "Bang ", "Gu ", "Pan ", "Zhou ", "Jian ", "Cuo ", "Quan ", "Shuang ", "Yun ", "Xia ", "Shuai ", "Xi ", "Rong ", "Tao ", "Fu ", "Yun ", "Zhen ", "Gao ", "Ru ", "Hu ", "Zai ", "Teng ", "Xian ", "Su ", "Zhen ", "Zong ", "Tao ", "Horo ", "Cai ", "Bi ", "Feng ", "Cu ", "Li ", "Suo ", "Yin ", "Xi ", "Zong ", "Lei ", "Zhuan ", "Qian ", "Man ", "Zhi ", "Lu ", "Mo ", "Piao ", "Lian ", "Mi ", "Xuan ", "Zong ", "Ji ", "Shan ", "Sui ", "Fan ", "Shuai ", "Beng ", "Yi ", "Sao ", "Mou ", "Zhou ", "Qiang ", "Hun ", "Sem ", "Xi ", "Jung ", "Xiu ", "Ran ", "Xuan ", "Hui ", "Qiao ", "Zeng ", "Zuo ", "Zhi ", "Shan ", "San ", "Lin ", "Yu ", "Fan ", "Liao ", "Chuo ", "Zun ", "Jian ", "Rao ", "Chan ", "Rui ", "Xiu ", "Hui ", "Hua ", "Zuan ", "Xi ", "Qiang ", "Un ", "Da ", "Sheng ", "Hui ", "Xi ", "Se ", "Jian ", "Jiang ", "Huan ", "Zao ", "Cong ", "Jie ", "Jiao ", "Bo ", "Chan ", "Yi ", "Nao ", "Sui ", "Yi ", "Shai ", "Xu ", "Ji ", "Bin ", "Qian ", "Lan ", "Pu ", "Xun ", "Zuan ", "Qi ", "Peng ", "Li ", "Mo ", "Lei ", "Xie ", "Zuan ", "Kuang ", "You ", "Xu ", "Lei ", "Xian ", "Chan ", "Kou ", "Lu ", "Chan ", "Ying ", "Cai ", "Xiang ", "Xian ", "Zui ", "Zuan ", "Luo ", "Xi ", "Dao ", "Lan ", "Lei ", "Lian ", "Si ", "Jiu ", "Yu ", "Hong ", "Zhou ", "Xian ", "He ", "Yue ", "Ji ", "Wan ", "Kuang ", "Ji ", "Ren ", "Wei ", "Yun ", "Hong ", "Chun ", "Pi ", "Sha ", "Gang ", "Na ", "Ren ", "Zong ", "Lun ", "Fen ", "Zhi ", "Wen ", "Fang ", "Zhu ", "Yin ", "Niu ", "Shu ", "Xian ", "Gan ", "Xie ", "Fu ", "Lian ", "Zu ", "Shen ", "Xi ", "Zhi ", "Zhong ", "Zhou ", "Ban ", "Fu ", "Zhuo ", "Shao ", "Yi ", "Jing ", "Dai ", "Bang ", "Rong ", "Jie ", "Ku ", "Rao ", "Die ", "Heng ", "Hui ", "Gei ", "Xuan ", "Jiang ", "Luo ", "Jue ", "Jiao ", "Tong ", "Geng ", "Xiao ", "Juan ", "Xiu ", "Xi ", "Sui ", "Tao ", "Ji ", "Ti ", "Ji ", "Xu ", "Ling ", "[?] ", "Xu ", "Qi ", "Fei ", "Chuo ", "Zhang ", "Gun ", "Sheng ", "Wei ", "Mian ", "Shou ", "Beng ", "Chou ", "Tao ", "Liu ", "Quan ", "Zong ", "Zhan ", "Wan ", "Lu "},
- {"Zhui ", "Zi ", "Ke ", "Xiang ", "Jian ", "Mian ", "Lan ", "Ti ", "Miao ", "Qi ", "Yun ", "Hui ", "Si ", "Duo ", "Duan ", "Bian ", "Xian ", "Gou ", "Zhui ", "Huan ", "Di ", "Lu ", "Bian ", "Min ", "Yuan ", "Jin ", "Fu ", "Ru ", "Zhen ", "Feng ", "Shuai ", "Gao ", "Chan ", "Li ", "Yi ", "Jian ", "Bin ", "Piao ", "Man ", "Lei ", "Ying ", "Suo ", "Mou ", "Sao ", "Xie ", "Liao ", "Shan ", "Zeng ", "Jiang ", "Qian ", "Zao ", "Huan ", "Jiao ", "Zuan ", "Fou ", "Xie ", "Gang ", "Fou ", "Que ", "Fou ", "Kaakeru ", "Bo ", "Ping ", "Hou ", "[?] ", "Gang ", "Ying ", "Ying ", "Qing ", "Xia ", "Guan ", "Zun ", "Tan ", "Chang ", "Qi ", "Weng ", "Ying ", "Lei ", "Tan ", "Lu ", "Guan ", "Wang ", "Wang ", "Gang ", "Wang ", "Han ", "[?] ", "Luo ", "Fu ", "Mi ", "Fa ", "Gu ", "Zhu ", "Ju ", "Mao ", "Gu ", "Min ", "Gang ", "Ba ", "Gua ", "Ti ", "Juan ", "Fu ", "Lin ", "Yan ", "Zhao ", "Zui ", "Gua ", "Zhuo ", "Yu ", "Zhi ", "An ", "Fa ", "Nan ", "Shu ", "Si ", "Pi ", "Ma ", "Liu ", "Ba ", "Fa ", "Li ", "Chao ", "Wei ", "Bi ", "Ji ", "Zeng ", "Tong ", "Liu ", "Ji ", "Juan ", "Mi ", "Zhao ", "Luo ", "Pi ", "Ji ", "Ji ", "Luan ", "Yang ", "Mie ", "Qiang ", "Ta ", "Mei ", "Yang ", "You ", "You ", "Fen ", "Ba ", "Gao ", "Yang ", "Gu ", "Qiang ", "Zang ", "Gao ", "Ling ", "Yi ", "Zhu ", "Di ", "Xiu ", "Qian ", "Yi ", "Xian ", "Rong ", "Qun ", "Qun ", "Qian ", "Huan ", "Zui ", "Xian ", "Yi ", "Yashinau ", "Qiang ", "Xian ", "Yu ", "Geng ", "Jie ", "Tang ", "Yuan ", "Xi ", "Fan ", "Shan ", "Fen ", "Shan ", "Lian ", "Lei ", "Geng ", "Nou ", "Qiang ", "Chan ", "Yu ", "Gong ", "Yi ", "Chong ", "Weng ", "Fen ", "Hong ", "Chi ", "Chi ", "Cui ", "Fu ", "Xia ", "Pen ", "Yi ", "La ", "Yi ", "Pi ", "Ling ", "Liu ", "Zhi ", "Qu ", "Xi ", "Xie ", "Xiang ", "Xi ", "Xi ", "Qi ", "Qiao ", "Hui ", "Hui ", "Xiao ", "Se ", "Hong ", "Jiang ", "Di ", "Cui ", "Fei ", "Tao ", "Sha ", "Chi ", "Zhu ", "Jian ", "Xuan ", "Shi ", "Pian ", "Zong ", "Wan ", "Hui ", "Hou ", "He ", "He ", "Han ", "Ao ", "Piao ", "Yi ", "Lian ", "Qu ", "[?] ", "Lin ", "Pen ", "Qiao ", "Ao ", "Fan ", "Yi ", "Hui ", "Xuan ", "Dao "},
- {"Yao ", "Lao ", "[?] ", "Kao ", "Mao ", "Zhe ", "Qi ", "Gou ", "Gou ", "Gou ", "Die ", "Die ", "Er ", "Shua ", "Ruan ", "Er ", "Nai ", "Zhuan ", "Lei ", "Ting ", "Zi ", "Geng ", "Chao ", "Hao ", "Yun ", "Pa ", "Pi ", "Chi ", "Si ", "Chu ", "Jia ", "Ju ", "He ", "Chu ", "Lao ", "Lun ", "Ji ", "Tang ", "Ou ", "Lou ", "Nou ", "Gou ", "Pang ", "Ze ", "Lou ", "Ji ", "Lao ", "Huo ", "You ", "Mo ", "Huai ", "Er ", "Zhe ", "Ting ", "Ye ", "Da ", "Song ", "Qin ", "Yun ", "Chi ", "Dan ", "Dan ", "Hong ", "Geng ", "Zhi ", "[?] ", "Nie ", "Dan ", "Zhen ", "Che ", "Ling ", "Zheng ", "You ", "Wa ", "Liao ", "Long ", "Zhi ", "Ning ", "Tiao ", "Er ", "Ya ", "Die ", "Gua ", "[?] ", "Lian ", "Hao ", "Sheng ", "Lie ", "Pin ", "Jing ", "Ju ", "Bi ", "Di ", "Guo ", "Wen ", "Xu ", "Ping ", "Cong ", "Shikato ", "[?] ", "Ting ", "Yu ", "Cong ", "Kui ", "Tsuraneru ", "Kui ", "Cong ", "Lian ", "Weng ", "Kui ", "Lian ", "Lian ", "Cong ", "Ao ", "Sheng ", "Song ", "Ting ", "Kui ", "Nie ", "Zhi ", "Dan ", "Ning ", "Qie ", "Ji ", "Ting ", "Ting ", "Long ", "Yu ", "Yu ", "Zhao ", "Si ", "Su ", "Yi ", "Su ", "Si ", "Zhao ", "Zhao ", "Rou ", "Yi ", "Le ", "Ji ", "Qiu ", "Ken ", "Cao ", "Ge ", "Di ", "Huan ", "Huang ", "Yi ", "Ren ", "Xiao ", "Ru ", "Zhou ", "Yuan ", "Du ", "Gang ", "Rong ", "Gan ", "Cha ", "Wo ", "Chang ", "Gu ", "Zhi ", "Han ", "Fu ", "Fei ", "Fen ", "Pei ", "Pang ", "Jian ", "Fang ", "Zhun ", "You ", "Na ", "Hang ", "Ken ", "Ran ", "Gong ", "Yu ", "Wen ", "Yao ", "Jin ", "Pi ", "Qian ", "Xi ", "Xi ", "Fei ", "Ken ", "Jing ", "Tai ", "Shen ", "Zhong ", "Zhang ", "Xie ", "Shen ", "Wei ", "Zhou ", "Die ", "Dan ", "Fei ", "Ba ", "Bo ", "Qu ", "Tian ", "Bei ", "Gua ", "Tai ", "Zi ", "Ku ", "Zhi ", "Ni ", "Ping ", "Zi ", "Fu ", "Pang ", "Zhen ", "Xian ", "Zuo ", "Pei ", "Jia ", "Sheng ", "Zhi ", "Bao ", "Mu ", "Qu ", "Hu ", "Ke ", "Yi ", "Yin ", "Xu ", "Yang ", "Long ", "Dong ", "Ka ", "Lu ", "Jing ", "Nu ", "Yan ", "Pang ", "Kua ", "Yi ", "Guang ", "Gai ", "Ge ", "Dong ", "Zhi ", "Xiao ", "Xiong ", "Xiong ", "Er ", "E ", "Xing ", "Pian ", "Neng ", "Zi ", "Gui "},
- {"Cheng ", "Tiao ", "Zhi ", "Cui ", "Mei ", "Xie ", "Cui ", "Xie ", "Mo ", "Mai ", "Ji ", "Obiyaakasu ", "[?] ", "Kuai ", "Sa ", "Zang ", "Qi ", "Nao ", "Mi ", "Nong ", "Luan ", "Wan ", "Bo ", "Wen ", "Guan ", "Qiu ", "Jiao ", "Jing ", "Rou ", "Heng ", "Cuo ", "Lie ", "Shan ", "Ting ", "Mei ", "Chun ", "Shen ", "Xie ", "De ", "Zui ", "Cu ", "Xiu ", "Xin ", "Tuo ", "Pao ", "Cheng ", "Nei ", "Fu ", "Dou ", "Tuo ", "Niao ", "Noy ", "Pi ", "Gu ", "Gua ", "Li ", "Lian ", "Zhang ", "Cui ", "Jie ", "Liang ", "Zhou ", "Pi ", "Biao ", "Lun ", "Pian ", "Guo ", "Kui ", "Chui ", "Dan ", "Tian ", "Nei ", "Jing ", "Jie ", "La ", "Yi ", "An ", "Ren ", "Shen ", "Chuo ", "Fu ", "Fu ", "Ju ", "Fei ", "Qiang ", "Wan ", "Dong ", "Pi ", "Guo ", "Zong ", "Ding ", "Wu ", "Mei ", "Ruan ", "Zhuan ", "Zhi ", "Cou ", "Gua ", "Ou ", "Di ", "An ", "Xing ", "Nao ", "Yu ", "Chuan ", "Nan ", "Yun ", "Zhong ", "Rou ", "E ", "Sai ", "Tu ", "Yao ", "Jian ", "Wei ", "Jiao ", "Yu ", "Jia ", "Duan ", "Bi ", "Chang ", "Fu ", "Xian ", "Ni ", "Mian ", "Wa ", "Teng ", "Tui ", "Bang ", "Qian ", "Lu ", "Wa ", "Sou ", "Tang ", "Su ", "Zhui ", "Ge ", "Yi ", "Bo ", "Liao ", "Ji ", "Pi ", "Xie ", "Gao ", "Lu ", "Bin ", "Ou ", "Chang ", "Lu ", "Guo ", "Pang ", "Chuai ", "Piao ", "Jiang ", "Fu ", "Tang ", "Mo ", "Xi ", "Zhuan ", "Lu ", "Jiao ", "Ying ", "Lu ", "Zhi ", "Tara ", "Chun ", "Lian ", "Tong ", "Peng ", "Ni ", "Zha ", "Liao ", "Cui ", "Gui ", "Xiao ", "Teng ", "Fan ", "Zhi ", "Jiao ", "Shan ", "Wu ", "Cui ", "Run ", "Xiang ", "Sui ", "Fen ", "Ying ", "Tan ", "Zhua ", "Dan ", "Kuai ", "Nong ", "Tun ", "Lian ", "Bi ", "Yong ", "Jue ", "Chu ", "Yi ", "Juan ", "La ", "Lian ", "Sao ", "Tun ", "Gu ", "Qi ", "Cui ", "Bin ", "Xun ", "Ru ", "Huo ", "Zang ", "Xian ", "Biao ", "Xing ", "Kuan ", "La ", "Yan ", "Lu ", "Huo ", "Zang ", "Luo ", "Qu ", "Zang ", "Luan ", "Ni ", "Zang ", "Chen ", "Qian ", "Wo ", "Guang ", "Zang ", "Lin ", "Guang ", "Zi ", "Jiao ", "Nie ", "Chou ", "Ji ", "Gao ", "Chou ", "Mian ", "Nie ", "Zhi ", "Zhi ", "Ge ", "Jian ", "Die ", "Zhi ", "Xiu ", "Tai ", "Zhen ", "Jiu ", "Xian ", "Yu ", "Cha "},
- {"Yao ", "Yu ", "Chong ", "Xi ", "Xi ", "Jiu ", "Yu ", "Yu ", "Xing ", "Ju ", "Jiu ", "Xin ", "She ", "She ", "Yadoru ", "Jiu ", "Shi ", "Tan ", "Shu ", "Shi ", "Tian ", "Dan ", "Pu ", "Pu ", "Guan ", "Hua ", "Tan ", "Chuan ", "Shun ", "Xia ", "Wu ", "Zhou ", "Dao ", "Gang ", "Shan ", "Yi ", "[?] ", "Pa ", "Tai ", "Fan ", "Ban ", "Chuan ", "Hang ", "Fang ", "Ban ", "Que ", "Hesaki ", "Zhong ", "Jian ", "Cang ", "Ling ", "Zhu ", "Ze ", "Duo ", "Bo ", "Xian ", "Ge ", "Chuan ", "Jia ", "Lu ", "Hong ", "Pang ", "Xi ", "[?] ", "Fu ", "Zao ", "Feng ", "Li ", "Shao ", "Yu ", "Lang ", "Ting ", "[?] ", "Wei ", "Bo ", "Meng ", "Nian ", "Ju ", "Huang ", "Shou ", "Zong ", "Bian ", "Mao ", "Die ", "[?] ", "Bang ", "Cha ", "Yi ", "Sao ", "Cang ", "Cao ", "Lou ", "Dai ", "Sori ", "Yao ", "Tong ", "Yofune ", "Dang ", "Tan ", "Lu ", "Yi ", "Jie ", "Jian ", "Huo ", "Meng ", "Qi ", "Lu ", "Lu ", "Chan ", "Shuang ", "Gen ", "Liang ", "Jian ", "Jian ", "Se ", "Yan ", "Fu ", "Ping ", "Yan ", "Yan ", "Cao ", "Cao ", "Yi ", "Le ", "Ting ", "Qiu ", "Ai ", "Nai ", "Tiao ", "Jiao ", "Jie ", "Peng ", "Wan ", "Yi ", "Chai ", "Mian ", "Mie ", "Gan ", "Qian ", "Yu ", "Yu ", "Shuo ", "Qiong ", "Tu ", "Xia ", "Qi ", "Mang ", "Zi ", "Hui ", "Sui ", "Zhi ", "Xiang ", "Bi ", "Fu ", "Tun ", "Wei ", "Wu ", "Zhi ", "Qi ", "Shan ", "Wen ", "Qian ", "Ren ", "Fou ", "Kou ", "Jie ", "Lu ", "Xu ", "Ji ", "Qin ", "Qi ", "Yuan ", "Fen ", "Ba ", "Rui ", "Xin ", "Ji ", "Hua ", "Hua ", "Fang ", "Wu ", "Jue ", "Gou ", "Zhi ", "Yun ", "Qin ", "Ao ", "Chu ", "Mao ", "Ya ", "Fei ", "Reng ", "Hang ", "Cong ", "Yin ", "You ", "Bian ", "Yi ", "Susa ", "Wei ", "Li ", "Pi ", "E ", "Xian ", "Chang ", "Cang ", "Meng ", "Su ", "Yi ", "Yuan ", "Ran ", "Ling ", "Tai ", "Tiao ", "Di ", "Miao ", "Qiong ", "Li ", "Yong ", "Ke ", "Mu ", "Pei ", "Bao ", "Gou ", "Min ", "Yi ", "Yi ", "Ju ", "Pi ", "Ruo ", "Ku ", "Zhu ", "Ni ", "Bo ", "Bing ", "Shan ", "Qiu ", "Yao ", "Xian ", "Ben ", "Hong ", "Ying ", "Zha ", "Dong ", "Ju ", "Die ", "Nie ", "Gan ", "Hu ", "Ping ", "Mei ", "Fu ", "Sheng ", "Gu ", "Bi ", "Wei "},
- {"Fu ", "Zhuo ", "Mao ", "Fan ", "Qie ", "Mao ", "Mao ", "Ba ", "Zi ", "Mo ", "Zi ", "Di ", "Chi ", "Ji ", "Jing ", "Long ", "[?] ", "Niao ", "[?] ", "Xue ", "Ying ", "Qiong ", "Ge ", "Ming ", "Li ", "Rong ", "Yin ", "Gen ", "Qian ", "Chai ", "Chen ", "Yu ", "Xiu ", "Zi ", "Lie ", "Wu ", "Ji ", "Kui ", "Ce ", "Chong ", "Ci ", "Gou ", "Guang ", "Mang ", "Chi ", "Jiao ", "Jiao ", "Fu ", "Yu ", "Zhu ", "Zi ", "Jiang ", "Hui ", "Yin ", "Cha ", "Fa ", "Rong ", "Ru ", "Chong ", "Mang ", "Tong ", "Zhong ", "[?] ", "Zhu ", "Xun ", "Huan ", "Kua ", "Quan ", "Gai ", "Da ", "Jing ", "Xing ", "Quan ", "Cao ", "Jing ", "Er ", "An ", "Shou ", "Chi ", "Ren ", "Jian ", "Ti ", "Huang ", "Ping ", "Li ", "Jin ", "Lao ", "Shu ", "Zhuang ", "Da ", "Jia ", "Rao ", "Bi ", "Ze ", "Qiao ", "Hui ", "Qi ", "Dang ", "[?] ", "Rong ", "Hun ", "Ying ", "Luo ", "Ying ", "Xun ", "Jin ", "Sun ", "Yin ", "Mai ", "Hong ", "Zhou ", "Yao ", "Du ", "Wei ", "Chu ", "Dou ", "Fu ", "Ren ", "Yin ", "He ", "Bi ", "Bu ", "Yun ", "Di ", "Tu ", "Sui ", "Sui ", "Cheng ", "Chen ", "Wu ", "Bie ", "Xi ", "Geng ", "Li ", "Fu ", "Zhu ", "Mo ", "Li ", "Zhuang ", "Ji ", "Duo ", "Qiu ", "Sha ", "Suo ", "Chen ", "Feng ", "Ju ", "Mei ", "Meng ", "Xing ", "Jing ", "Che ", "Xin ", "Jun ", "Yan ", "Ting ", "Diao ", "Cuo ", "Wan ", "Han ", "You ", "Cuo ", "Jia ", "Wang ", "You ", "Niu ", "Shao ", "Xian ", "Lang ", "Fu ", "E ", "Mo ", "Wen ", "Jie ", "Nan ", "Mu ", "Kan ", "Lai ", "Lian ", "Shi ", "Wo ", "Usagi ", "Lian ", "Huo ", "You ", "Ying ", "Ying ", "Nuc ", "Chun ", "Mang ", "Mang ", "Ci ", "Wan ", "Jing ", "Di ", "Qu ", "Dong ", "Jian ", "Zou ", "Gu ", "La ", "Lu ", "Ju ", "Wei ", "Jun ", "Nie ", "Kun ", "He ", "Pu ", "Zi ", "Gao ", "Guo ", "Fu ", "Lun ", "Chang ", "Chou ", "Song ", "Chui ", "Zhan ", "Men ", "Cai ", "Ba ", "Li ", "Tu ", "Bo ", "Han ", "Bao ", "Qin ", "Juan ", "Xi ", "Qin ", "Di ", "Jie ", "Pu ", "Dang ", "Jin ", "Zhao ", "Tai ", "Geng ", "Hua ", "Gu ", "Ling ", "Fei ", "Jin ", "An ", "Wang ", "Beng ", "Zhou ", "Yan ", "Ju ", "Jian ", "Lin ", "Tan ", "Shu ", "Tian ", "Dao "},
- {"Hu ", "Qi ", "He ", "Cui ", "Tao ", "Chun ", "Bei ", "Chang ", "Huan ", "Fei ", "Lai ", "Qi ", "Meng ", "Ping ", "Wei ", "Dan ", "Sha ", "Huan ", "Yan ", "Yi ", "Tiao ", "Qi ", "Wan ", "Ce ", "Nai ", "Kutabireru ", "Tuo ", "Jiu ", "Tie ", "Luo ", "[?] ", "[?] ", "Meng ", "[?] ", "Yaji ", "[?] ", "Ying ", "Ying ", "Ying ", "Xiao ", "Sa ", "Qiu ", "Ke ", "Xiang ", "Wan ", "Yu ", "Yu ", "Fu ", "Lian ", "Xuan ", "Yuan ", "Nan ", "Ze ", "Wo ", "Chun ", "Xiao ", "Yu ", "Pian ", "Mao ", "An ", "E ", "Luo ", "Ying ", "Huo ", "Gua ", "Jiang ", "Mian ", "Zuo ", "Zuo ", "Ju ", "Bao ", "Rou ", "Xi ", "Xie ", "An ", "Qu ", "Jian ", "Fu ", "Lu ", "Jing ", "Pen ", "Feng ", "Hong ", "Hong ", "Hou ", "Yan ", "Tu ", "Zhu ", "Zi ", "Xiang ", "Shen ", "Ge ", "Jie ", "Jing ", "Mi ", "Huang ", "Shen ", "Pu ", "Gai ", "Dong ", "Zhou ", "Qian ", "Wei ", "Bo ", "Wei ", "Pa ", "Ji ", "Hu ", "Zang ", "Jia ", "Duan ", "Yao ", "Jun ", "Cong ", "Quan ", "Wei ", "Xian ", "Kui ", "Ting ", "Hun ", "Xi ", "Shi ", "Qi ", "Lan ", "Zong ", "Yao ", "Yuan ", "Mei ", "Yun ", "Shu ", "Di ", "Zhuan ", "Guan ", "Sukumo ", "Xue ", "Chan ", "Kai ", "Kui ", "[?] ", "Jiang ", "Lou ", "Wei ", "Pai ", "[?] ", "Sou ", "Yin ", "Shi ", "Chun ", "Shi ", "Yun ", "Zhen ", "Lang ", "Nu ", "Meng ", "He ", "Que ", "Suan ", "Yuan ", "Li ", "Ju ", "Xi ", "Pang ", "Chu ", "Xu ", "Tu ", "Liu ", "Wo ", "Zhen ", "Qian ", "Zu ", "Po ", "Cuo ", "Yuan ", "Chu ", "Yu ", "Kuai ", "Pan ", "Pu ", "Pu ", "Na ", "Shuo ", "Xi ", "Fen ", "Yun ", "Zheng ", "Jian ", "Ji ", "Ruo ", "Cang ", "En ", "Mi ", "Hao ", "Sun ", "Zhen ", "Ming ", "Sou ", "Xu ", "Liu ", "Xi ", "Gu ", "Lang ", "Rong ", "Weng ", "Gai ", "Cuo ", "Shi ", "Tang ", "Luo ", "Ru ", "Suo ", "Xian ", "Bei ", "Yao ", "Gui ", "Bi ", "Zong ", "Gun ", "Za ", "Xiu ", "Ce ", "Hai ", "Lan ", "[?] ", "Ji ", "Li ", "Can ", "Lang ", "Yu ", "[?] ", "Ying ", "Mo ", "Diao ", "Tiao ", "Mao ", "Tong ", "Zhu ", "Peng ", "An ", "Lian ", "Cong ", "Xi ", "Ping ", "Qiu ", "Jin ", "Chun ", "Jie ", "Wei ", "Tui ", "Cao ", "Yu ", "Yi ", "Ji ", "Liao ", "Bi ", "Lu ", "Su "},
- {"Bu ", "Zhang ", "Luo ", "Jiang ", "Man ", "Yan ", "Ling ", "Ji ", "Piao ", "Gun ", "Han ", "Di ", "Su ", "Lu ", "She ", "Shang ", "Di ", "Mie ", "Xun ", "Man ", "Bo ", "Di ", "Cuo ", "Zhe ", "Sen ", "Xuan ", "Wei ", "Hu ", "Ao ", "Mi ", "Lou ", "Cu ", "Zhong ", "Cai ", "Po ", "Jiang ", "Mi ", "Cong ", "Niao ", "Hui ", "Jun ", "Yin ", "Jian ", "Yan ", "Shu ", "Yin ", "Kui ", "Chen ", "Hu ", "Sha ", "Kou ", "Qian ", "Ma ", "Zang ", "Sonoko ", "Qiang ", "Dou ", "Lian ", "Lin ", "Kou ", "Ai ", "Bi ", "Li ", "Wei ", "Ji ", "Xun ", "Sheng ", "Fan ", "Meng ", "Ou ", "Chan ", "Dian ", "Xun ", "Jiao ", "Rui ", "Rui ", "Lei ", "Yu ", "Qiao ", "Chu ", "Hua ", "Jian ", "Mai ", "Yun ", "Bao ", "You ", "Qu ", "Lu ", "Rao ", "Hui ", "E ", "Teng ", "Fei ", "Jue ", "Zui ", "Fa ", "Ru ", "Fen ", "Kui ", "Shun ", "Rui ", "Ya ", "Xu ", "Fu ", "Jue ", "Dang ", "Wu ", "Tong ", "Si ", "Xiao ", "Xi ", "Long ", "Yun ", "[?] ", "Qi ", "Jian ", "Yun ", "Sun ", "Ling ", "Yu ", "Xia ", "Yong ", "Ji ", "Hong ", "Si ", "Nong ", "Lei ", "Xuan ", "Yun ", "Yu ", "Xi ", "Hao ", "Bo ", "Hao ", "Ai ", "Wei ", "Hui ", "Wei ", "Ji ", "Ci ", "Xiang ", "Luan ", "Mie ", "Yi ", "Leng ", "Jiang ", "Can ", "Shen ", "Qiang ", "Lian ", "Ke ", "Yuan ", "Da ", "Ti ", "Tang ", "Xie ", "Bi ", "Zhan ", "Sun ", "Lian ", "Fan ", "Ding ", "Jie ", "Gu ", "Xie ", "Shu ", "Jian ", "Kao ", "Hong ", "Sa ", "Xin ", "Xun ", "Yao ", "Hie ", "Sou ", "Shu ", "Xun ", "Dui ", "Pin ", "Wei ", "Neng ", "Chou ", "Mai ", "Ru ", "Piao ", "Tai ", "Qi ", "Zao ", "Chen ", "Zhen ", "Er ", "Ni ", "Ying ", "Gao ", "Cong ", "Xiao ", "Qi ", "Fa ", "Jian ", "Xu ", "Kui ", "Jie ", "Bian ", "Diao ", "Mi ", "Lan ", "Jin ", "Cang ", "Miao ", "Qiong ", "Qie ", "Xian ", "[?] ", "Ou ", "Xian ", "Su ", "Lu ", "Yi ", "Xu ", "Xie ", "Li ", "Yi ", "La ", "Lei ", "Xiao ", "Di ", "Zhi ", "Bei ", "Teng ", "Yao ", "Mo ", "Huan ", "Piao ", "Fan ", "Sou ", "Tan ", "Tui ", "Qiong ", "Qiao ", "Wei ", "Liu ", "Hui ", "[?] ", "Gao ", "Yun ", "[?] ", "Li ", "Shu ", "Chu ", "Ai ", "Lin ", "Zao ", "Xuan ", "Chen ", "Lai ", "Huo "},
- {"Tuo ", "Wu ", "Rui ", "Rui ", "Qi ", "Heng ", "Lu ", "Su ", "Tui ", "Mang ", "Yun ", "Pin ", "Yu ", "Xun ", "Ji ", "Jiong ", "Xian ", "Mo ", "Hagi ", "Su ", "Jiong ", "[?] ", "Nie ", "Bo ", "Rang ", "Yi ", "Xian ", "Yu ", "Ju ", "Lian ", "Lian ", "Yin ", "Qiang ", "Ying ", "Long ", "Tong ", "Wei ", "Yue ", "Ling ", "Qu ", "Yao ", "Fan ", "Mi ", "Lan ", "Kui ", "Lan ", "Ji ", "Dang ", "Katsura ", "Lei ", "Lei ", "Hua ", "Feng ", "Zhi ", "Wei ", "Kui ", "Zhan ", "Huai ", "Li ", "Ji ", "Mi ", "Lei ", "Huai ", "Luo ", "Ji ", "Kui ", "Lu ", "Jian ", "San ", "[?] ", "Lei ", "Quan ", "Xiao ", "Yi ", "Luan ", "Men ", "Bie ", "Hu ", "Hu ", "Lu ", "Nue ", "Lu ", "Si ", "Xiao ", "Qian ", "Chu ", "Hu ", "Xu ", "Cuo ", "Fu ", "Xu ", "Xu ", "Lu ", "Hu ", "Yu ", "Hao ", "Jiao ", "Ju ", "Guo ", "Bao ", "Yan ", "Zhan ", "Zhan ", "Kui ", "Ban ", "Xi ", "Shu ", "Chong ", "Qiu ", "Diao ", "Ji ", "Qiu ", "Cheng ", "Shi ", "[?] ", "Di ", "Zhe ", "She ", "Yu ", "Gan ", "Zi ", "Hong ", "Hui ", "Meng ", "Ge ", "Sui ", "Xia ", "Chai ", "Shi ", "Yi ", "Ma ", "Xiang ", "Fang ", "E ", "Pa ", "Chi ", "Qian ", "Wen ", "Wen ", "Rui ", "Bang ", "Bi ", "Yue ", "Yue ", "Jun ", "Qi ", "Ran ", "Yin ", "Qi ", "Tian ", "Yuan ", "Jue ", "Hui ", "Qin ", "Qi ", "Zhong ", "Ya ", "Ci ", "Mu ", "Wang ", "Fen ", "Fen ", "Hang ", "Gong ", "Zao ", "Fu ", "Ran ", "Jie ", "Fu ", "Chi ", "Dou ", "Piao ", "Xian ", "Ni ", "Te ", "Qiu ", "You ", "Zha ", "Ping ", "Chi ", "You ", "He ", "Han ", "Ju ", "Li ", "Fu ", "Ran ", "Zha ", "Gou ", "Pi ", "Bo ", "Xian ", "Zhu ", "Diao ", "Bie ", "Bing ", "Gu ", "Ran ", "Qu ", "She ", "Tie ", "Ling ", "Gu ", "Dan ", "Gu ", "Ying ", "Li ", "Cheng ", "Qu ", "Mou ", "Ge ", "Ci ", "Hui ", "Hui ", "Mang ", "Fu ", "Yang ", "Wa ", "Lie ", "Zhu ", "Yi ", "Xian ", "Kuo ", "Jiao ", "Li ", "Yi ", "Ping ", "Ji ", "Ha ", "She ", "Yi ", "Wang ", "Mo ", "Qiong ", "Qie ", "Gui ", "Gong ", "Zhi ", "Man ", "Ebi ", "Zhi ", "Jia ", "Rao ", "Si ", "Qi ", "Xing ", "Lie ", "Qiu ", "Shao ", "Yong ", "Jia ", "Shui ", "Che ", "Bai ", "E ", "Han "},
- {"Shu ", "Xuan ", "Feng ", "Shen ", "Zhen ", "Fu ", "Xian ", "Zhe ", "Wu ", "Fu ", "Li ", "Lang ", "Bi ", "Chu ", "Yuan ", "You ", "Jie ", "Dan ", "Yan ", "Ting ", "Dian ", "Shui ", "Hui ", "Gua ", "Zhi ", "Song ", "Fei ", "Ju ", "Mi ", "Qi ", "Qi ", "Yu ", "Jun ", "Zha ", "Meng ", "Qiang ", "Si ", "Xi ", "Lun ", "Li ", "Die ", "Tiao ", "Tao ", "Kun ", "Gan ", "Han ", "Yu ", "Bang ", "Fei ", "Pi ", "Wei ", "Dun ", "Yi ", "Yuan ", "Su ", "Quan ", "Qian ", "Rui ", "Ni ", "Qing ", "Wei ", "Liang ", "Guo ", "Wan ", "Dong ", "E ", "Ban ", "Di ", "Wang ", "Can ", "Yang ", "Ying ", "Guo ", "Chan ", "[?] ", "La ", "Ke ", "Ji ", "He ", "Ting ", "Mai ", "Xu ", "Mian ", "Yu ", "Jie ", "Shi ", "Xuan ", "Huang ", "Yan ", "Bian ", "Rou ", "Wei ", "Fu ", "Yuan ", "Mei ", "Wei ", "Fu ", "Ruan ", "Xie ", "You ", "Qiu ", "Mao ", "Xia ", "Ying ", "Shi ", "Chong ", "Tang ", "Zhu ", "Zong ", "Ti ", "Fu ", "Yuan ", "Hui ", "Meng ", "La ", "Du ", "Hu ", "Qiu ", "Die ", "Li ", "Gua ", "Yun ", "Ju ", "Nan ", "Lou ", "Qun ", "Rong ", "Ying ", "Jiang ", "[?] ", "Lang ", "Pang ", "Si ", "Xi ", "Ci ", "Xi ", "Yuan ", "Weng ", "Lian ", "Sou ", "Ban ", "Rong ", "Rong ", "Ji ", "Wu ", "Qiu ", "Han ", "Qin ", "Yi ", "Bi ", "Hua ", "Tang ", "Yi ", "Du ", "Nai ", "He ", "Hu ", "Hui ", "Ma ", "Ming ", "Yi ", "Wen ", "Ying ", "Teng ", "Yu ", "Cang ", "So ", "Ebi ", "Man ", "[?] ", "Shang ", "Zhe ", "Cao ", "Chi ", "Di ", "Ao ", "Lu ", "Wei ", "Zhi ", "Tang ", "Chen ", "Piao ", "Qu ", "Pi ", "Yu ", "Jian ", "Luo ", "Lou ", "Qin ", "Zhong ", "Yin ", "Jiang ", "Shuai ", "Wen ", "Jiao ", "Wan ", "Zhi ", "Zhe ", "Ma ", "Ma ", "Guo ", "Liu ", "Mao ", "Xi ", "Cong ", "Li ", "Man ", "Xiao ", "Kamakiri ", "Zhang ", "Mang ", "Xiang ", "Mo ", "Zui ", "Si ", "Qiu ", "Te ", "Zhi ", "Peng ", "Peng ", "Jiao ", "Qu ", "Bie ", "Liao ", "Pan ", "Gui ", "Xi ", "Ji ", "Zhuan ", "Huang ", "Fei ", "Lao ", "Jue ", "Jue ", "Hui ", "Yin ", "Chan ", "Jiao ", "Shan ", "Rao ", "Xiao ", "Mou ", "Chong ", "Xun ", "Si ", "[?] ", "Cheng ", "Dang ", "Li ", "Xie ", "Shan ", "Yi ", "Jing ", "Da ", "Chan ", "Qi "},
- {"Ci ", "Xiang ", "She ", "Luo ", "Qin ", "Ying ", "Chai ", "Li ", "Ze ", "Xuan ", "Lian ", "Zhu ", "Ze ", "Xie ", "Mang ", "Xie ", "Qi ", "Rong ", "Jian ", "Meng ", "Hao ", "Ruan ", "Huo ", "Zhuo ", "Jie ", "Bin ", "He ", "Mie ", "Fan ", "Lei ", "Jie ", "La ", "Mi ", "Li ", "Chun ", "Li ", "Qiu ", "Nie ", "Lu ", "Du ", "Xiao ", "Zhu ", "Long ", "Li ", "Long ", "Feng ", "Ye ", "Beng ", "Shang ", "Gu ", "Juan ", "Ying ", "[?] ", "Xi ", "Can ", "Qu ", "Quan ", "Du ", "Can ", "Man ", "Jue ", "Jie ", "Zhu ", "Zha ", "Xie ", "Huang ", "Niu ", "Pei ", "Nu ", "Xin ", "Zhong ", "Mo ", "Er ", "Ke ", "Mie ", "Xi ", "Xing ", "Yan ", "Kan ", "Yuan ", "[?] ", "Ling ", "Xuan ", "Shu ", "Xian ", "Tong ", "Long ", "Jie ", "Xian ", "Ya ", "Hu ", "Wei ", "Dao ", "Chong ", "Wei ", "Dao ", "Zhun ", "Heng ", "Qu ", "Yi ", "Yi ", "Bu ", "Gan ", "Yu ", "Biao ", "Cha ", "Yi ", "Shan ", "Chen ", "Fu ", "Gun ", "Fen ", "Shuai ", "Jie ", "Na ", "Zhong ", "Dan ", "Ri ", "Zhong ", "Zhong ", "Xie ", "Qi ", "Xie ", "Ran ", "Zhi ", "Ren ", "Qin ", "Jin ", "Jun ", "Yuan ", "Mei ", "Chai ", "Ao ", "Niao ", "Hui ", "Ran ", "Jia ", "Tuo ", "Ling ", "Dai ", "Bao ", "Pao ", "Yao ", "Zuo ", "Bi ", "Shao ", "Tan ", "Ju ", "He ", "Shu ", "Xiu ", "Zhen ", "Yi ", "Pa ", "Bo ", "Di ", "Wa ", "Fu ", "Gun ", "Zhi ", "Zhi ", "Ran ", "Pan ", "Yi ", "Mao ", "Tuo ", "Na ", "Kou ", "Xian ", "Chan ", "Qu ", "Bei ", "Gun ", "Xi ", "Ne ", "Bo ", "Horo ", "Fu ", "Yi ", "Chi ", "Ku ", "Ren ", "Jiang ", "Jia ", "Cun ", "Mo ", "Jie ", "Er ", "Luo ", "Ru ", "Zhu ", "Gui ", "Yin ", "Cai ", "Lie ", "Kamishimo ", "Yuki ", "Zhuang ", "Dang ", "[?] ", "Kun ", "Ken ", "Niao ", "Shu ", "Jia ", "Kun ", "Cheng ", "Li ", "Juan ", "Shen ", "Pou ", "Ge ", "Yi ", "Yu ", "Zhen ", "Liu ", "Qiu ", "Qun ", "Ji ", "Yi ", "Bu ", "Zhuang ", "Shui ", "Sha ", "Qun ", "Li ", "Lian ", "Lian ", "Ku ", "Jian ", "Fou ", "Chan ", "Bi ", "Gun ", "Tao ", "Yuan ", "Ling ", "Chi ", "Chang ", "Chou ", "Duo ", "Biao ", "Liang ", "Chang ", "Pei ", "Pei ", "Fei ", "Yuan ", "Luo ", "Guo ", "Yan ", "Du ", "Xi ", "Zhi ", "Ju ", "Qi "},
- {"Ji ", "Zhi ", "Gua ", "Ken ", "Che ", "Ti ", "Ti ", "Fu ", "Chong ", "Xie ", "Bian ", "Die ", "Kun ", "Duan ", "Xiu ", "Xiu ", "He ", "Yuan ", "Bao ", "Bao ", "Fu ", "Yu ", "Tuan ", "Yan ", "Hui ", "Bei ", "Chu ", "Lu ", "Ena ", "Hitoe ", "Yun ", "Da ", "Gou ", "Da ", "Huai ", "Rong ", "Yuan ", "Ru ", "Nai ", "Jiong ", "Suo ", "Ban ", "Tun ", "Chi ", "Sang ", "Niao ", "Ying ", "Jie ", "Qian ", "Huai ", "Ku ", "Lian ", "Bao ", "Li ", "Zhe ", "Shi ", "Lu ", "Yi ", "Die ", "Xie ", "Xian ", "Wei ", "Biao ", "Cao ", "Ji ", "Jiang ", "Sen ", "Bao ", "Xiang ", "Chihaya ", "Pu ", "Jian ", "Zhuan ", "Jian ", "Zui ", "Ji ", "Dan ", "Za ", "Fan ", "Bo ", "Xiang ", "Xin ", "Bie ", "Rao ", "Man ", "Lan ", "Ao ", "Duo ", "Gui ", "Cao ", "Sui ", "Nong ", "Chan ", "Lian ", "Bi ", "Jin ", "Dang ", "Shu ", "Tan ", "Bi ", "Lan ", "Pu ", "Ru ", "Zhi ", "[?] ", "Shu ", "Wa ", "Shi ", "Bai ", "Xie ", "Bo ", "Chen ", "Lai ", "Long ", "Xi ", "Xian ", "Lan ", "Zhe ", "Dai ", "Tasuki ", "Zan ", "Shi ", "Jian ", "Pan ", "Yi ", "Ran ", "Ya ", "Xi ", "Xi ", "Yao ", "Feng ", "Tan ", "[?] ", "Biao ", "Fu ", "Ba ", "He ", "Ji ", "Ji ", "Jian ", "Guan ", "Bian ", "Yan ", "Gui ", "Jue ", "Pian ", "Mao ", "Mi ", "Mi ", "Mie ", "Shi ", "Si ", "Zhan ", "Luo ", "Jue ", "Mi ", "Tiao ", "Lian ", "Yao ", "Zhi ", "Jun ", "Xi ", "Shan ", "Wei ", "Xi ", "Tian ", "Yu ", "Lan ", "E ", "Du ", "Qin ", "Pang ", "Ji ", "Ming ", "Ying ", "Gou ", "Qu ", "Zhan ", "Jin ", "Guan ", "Deng ", "Jian ", "Luo ", "Qu ", "Jian ", "Wei ", "Jue ", "Qu ", "Luo ", "Lan ", "Shen ", "Di ", "Guan ", "Jian ", "Guan ", "Yan ", "Gui ", "Mi ", "Shi ", "Zhan ", "Lan ", "Jue ", "Ji ", "Xi ", "Di ", "Tian ", "Yu ", "Gou ", "Jin ", "Qu ", "Jiao ", "Jiu ", "Jin ", "Cu ", "Jue ", "Zhi ", "Chao ", "Ji ", "Gu ", "Dan ", "Zui ", "Di ", "Shang ", "Hua ", "Quan ", "Ge ", "Chi ", "Jie ", "Gui ", "Gong ", "Hong ", "Jie ", "Hun ", "Qiu ", "Xing ", "Su ", "Ni ", "Ji ", "Lu ", "Zhi ", "Zha ", "Bi ", "Xing ", "Hu ", "Shang ", "Gong ", "Zhi ", "Xue ", "Chu ", "Xi ", "Yi ", "Lu ", "Jue ", "Xi ", "Yan ", "Xi "},
- {"Yan ", "Yan ", "Ding ", "Fu ", "Qiu ", "Qiu ", "Jiao ", "Hong ", "Ji ", "Fan ", "Xun ", "Diao ", "Hong ", "Cha ", "Tao ", "Xu ", "Jie ", "Yi ", "Ren ", "Xun ", "Yin ", "Shan ", "Qi ", "Tuo ", "Ji ", "Xun ", "Yin ", "E ", "Fen ", "Ya ", "Yao ", "Song ", "Shen ", "Yin ", "Xin ", "Jue ", "Xiao ", "Ne ", "Chen ", "You ", "Zhi ", "Xiong ", "Fang ", "Xin ", "Chao ", "She ", "Xian ", "Sha ", "Tun ", "Xu ", "Yi ", "Yi ", "Su ", "Chi ", "He ", "Shen ", "He ", "Xu ", "Zhen ", "Zhu ", "Zheng ", "Gou ", "Zi ", "Zi ", "Zhan ", "Gu ", "Fu ", "Quan ", "Die ", "Ling ", "Di ", "Yang ", "Li ", "Nao ", "Pan ", "Zhou ", "Gan ", "Yi ", "Ju ", "Ao ", "Zha ", "Tuo ", "Yi ", "Qu ", "Zhao ", "Ping ", "Bi ", "Xiong ", "Qu ", "Ba ", "Da ", "Zu ", "Tao ", "Zhu ", "Ci ", "Zhe ", "Yong ", "Xu ", "Xun ", "Yi ", "Huang ", "He ", "Shi ", "Cha ", "Jiao ", "Shi ", "Hen ", "Cha ", "Gou ", "Gui ", "Quan ", "Hui ", "Jie ", "Hua ", "Gai ", "Xiang ", "Wei ", "Shen ", "Chou ", "Tong ", "Mi ", "Zhan ", "Ming ", "E ", "Hui ", "Yan ", "Xiong ", "Gua ", "Er ", "Beng ", "Tiao ", "Chi ", "Lei ", "Zhu ", "Kuang ", "Kua ", "Wu ", "Yu ", "Teng ", "Ji ", "Zhi ", "Ren ", "Su ", "Lang ", "E ", "Kuang ", "E ", "Shi ", "Ting ", "Dan ", "Bo ", "Chan ", "You ", "Heng ", "Qiao ", "Qin ", "Shua ", "An ", "Yu ", "Xiao ", "Cheng ", "Jie ", "Xian ", "Wu ", "Wu ", "Gao ", "Song ", "Pu ", "Hui ", "Jing ", "Shuo ", "Zhen ", "Shuo ", "Du ", "Yasashi ", "Chang ", "Shui ", "Jie ", "Ke ", "Qu ", "Cong ", "Xiao ", "Sui ", "Wang ", "Xuan ", "Fei ", "Chi ", "Ta ", "Yi ", "Na ", "Yin ", "Diao ", "Pi ", "Chuo ", "Chan ", "Chen ", "Zhun ", "Ji ", "Qi ", "Tan ", "Zhui ", "Wei ", "Ju ", "Qing ", "Jian ", "Zheng ", "Ze ", "Zou ", "Qian ", "Zhuo ", "Liang ", "Jian ", "Zhu ", "Hao ", "Lun ", "Shen ", "Biao ", "Huai ", "Pian ", "Yu ", "Die ", "Xu ", "Pian ", "Shi ", "Xuan ", "Shi ", "Hun ", "Hua ", "E ", "Zhong ", "Di ", "Xie ", "Fu ", "Pu ", "Ting ", "Jian ", "Qi ", "Yu ", "Zi ", "Chuan ", "Xi ", "Hui ", "Yin ", "An ", "Xian ", "Nan ", "Chen ", "Feng ", "Zhu ", "Yang ", "Yan ", "Heng ", "Xuan ", "Ge ", "Nuo ", "Qi "},
- {"Mou ", "Ye ", "Wei ", "[?] ", "Teng ", "Zou ", "Shan ", "Jian ", "Bo ", "Ku ", "Huang ", "Huo ", "Ge ", "Ying ", "Mi ", "Xiao ", "Mi ", "Xi ", "Qiang ", "Chen ", "Nue ", "Ti ", "Su ", "Bang ", "Chi ", "Qian ", "Shi ", "Jiang ", "Yuan ", "Xie ", "Xue ", "Tao ", "Yao ", "Yao ", "[?] ", "Yu ", "Biao ", "Cong ", "Qing ", "Li ", "Mo ", "Mo ", "Shang ", "Zhe ", "Miu ", "Jian ", "Ze ", "Jie ", "Lian ", "Lou ", "Can ", "Ou ", "Guan ", "Xi ", "Zhuo ", "Ao ", "Ao ", "Jin ", "Zhe ", "Yi ", "Hu ", "Jiang ", "Man ", "Chao ", "Han ", "Hua ", "Chan ", "Xu ", "Zeng ", "Se ", "Xi ", "She ", "Dui ", "Zheng ", "Nao ", "Lan ", "E ", "Ying ", "Jue ", "Ji ", "Zun ", "Jiao ", "Bo ", "Hui ", "Zhuan ", "Mu ", "Zen ", "Zha ", "Shi ", "Qiao ", "Tan ", "Zen ", "Pu ", "Sheng ", "Xuan ", "Zao ", "Tan ", "Dang ", "Sui ", "Qian ", "Ji ", "Jiao ", "Jing ", "Lian ", "Nou ", "Yi ", "Ai ", "Zhan ", "Pi ", "Hui ", "Hua ", "Yi ", "Yi ", "Shan ", "Rang ", "Nou ", "Qian ", "Zhui ", "Ta ", "Hu ", "Zhou ", "Hao ", "Ye ", "Ying ", "Jian ", "Yu ", "Jian ", "Hui ", "Du ", "Zhe ", "Xuan ", "Zan ", "Lei ", "Shen ", "Wei ", "Chan ", "Li ", "Yi ", "Bian ", "Zhe ", "Yan ", "E ", "Chou ", "Wei ", "Chou ", "Yao ", "Chan ", "Rang ", "Yin ", "Lan ", "Chen ", "Huo ", "Zhe ", "Huan ", "Zan ", "Yi ", "Dang ", "Zhan ", "Yan ", "Du ", "Yan ", "Ji ", "Ding ", "Fu ", "Ren ", "Ji ", "Jie ", "Hong ", "Tao ", "Rang ", "Shan ", "Qi ", "Tuo ", "Xun ", "Yi ", "Xun ", "Ji ", "Ren ", "Jiang ", "Hui ", "Ou ", "Ju ", "Ya ", "Ne ", "Xu ", "E ", "Lun ", "Xiong ", "Song ", "Feng ", "She ", "Fang ", "Jue ", "Zheng ", "Gu ", "He ", "Ping ", "Zu ", "Shi ", "Xiong ", "Zha ", "Su ", "Zhen ", "Di ", "Zou ", "Ci ", "Qu ", "Zhao ", "Bi ", "Yi ", "Yi ", "Kuang ", "Lei ", "Shi ", "Gua ", "Shi ", "Jie ", "Hui ", "Cheng ", "Zhu ", "Shen ", "Hua ", "Dan ", "Gou ", "Quan ", "Gui ", "Xun ", "Yi ", "Zheng ", "Gai ", "Xiang ", "Cha ", "Hun ", "Xu ", "Zhou ", "Jie ", "Wu ", "Yu ", "Qiao ", "Wu ", "Gao ", "You ", "Hui ", "Kuang ", "Shuo ", "Song ", "Ai ", "Qing ", "Zhu ", "Zou ", "Nuo ", "Du ", "Zhuo ", "Fei ", "Ke ", "Wei "},
- {"Yu ", "Shui ", "Shen ", "Diao ", "Chan ", "Liang ", "Zhun ", "Sui ", "Tan ", "Shen ", "Yi ", "Mou ", "Chen ", "Die ", "Huang ", "Jian ", "Xie ", "Nue ", "Ye ", "Wei ", "E ", "Yu ", "Xuan ", "Chan ", "Zi ", "An ", "Yan ", "Di ", "Mi ", "Pian ", "Xu ", "Mo ", "Dang ", "Su ", "Xie ", "Yao ", "Bang ", "Shi ", "Qian ", "Mi ", "Jin ", "Man ", "Zhe ", "Jian ", "Miu ", "Tan ", "Zen ", "Qiao ", "Lan ", "Pu ", "Jue ", "Yan ", "Qian ", "Zhan ", "Chen ", "Gu ", "Qian ", "Hong ", "Xia ", "Jue ", "Hong ", "Han ", "Hong ", "Xi ", "Xi ", "Huo ", "Liao ", "Han ", "Du ", "Long ", "Dou ", "Jiang ", "Qi ", "Shi ", "Li ", "Deng ", "Wan ", "Bi ", "Shu ", "Xian ", "Feng ", "Zhi ", "Zhi ", "Yan ", "Yan ", "Shi ", "Chu ", "Hui ", "Tun ", "Yi ", "Tun ", "Yi ", "Jian ", "Ba ", "Hou ", "E ", "Cu ", "Xiang ", "Huan ", "Jian ", "Ken ", "Gai ", "Qu ", "Fu ", "Xi ", "Bin ", "Hao ", "Yu ", "Zhu ", "Jia ", "[?] ", "Xi ", "Bo ", "Wen ", "Huan ", "Bin ", "Di ", "Zong ", "Fen ", "Yi ", "Zhi ", "Bao ", "Chai ", "Han ", "Pi ", "Na ", "Pi ", "Gou ", "Na ", "You ", "Diao ", "Mo ", "Si ", "Xiu ", "Huan ", "Kun ", "He ", "He ", "Mo ", "Han ", "Mao ", "Li ", "Ni ", "Bi ", "Yu ", "Jia ", "Tuan ", "Mao ", "Pi ", "Xi ", "E ", "Ju ", "Mo ", "Chu ", "Tan ", "Huan ", "Jue ", "Bei ", "Zhen ", "Yuan ", "Fu ", "Cai ", "Gong ", "Te ", "Yi ", "Hang ", "Wan ", "Pin ", "Huo ", "Fan ", "Tan ", "Guan ", "Ze ", "Zhi ", "Er ", "Zhu ", "Shi ", "Bi ", "Zi ", "Er ", "Gui ", "Pian ", "Bian ", "Mai ", "Dai ", "Sheng ", "Kuang ", "Fei ", "Tie ", "Yi ", "Chi ", "Mao ", "He ", "Bi ", "Lu ", "Ren ", "Hui ", "Gai ", "Pian ", "Zi ", "Jia ", "Xu ", "Zei ", "Jiao ", "Gai ", "Zang ", "Jian ", "Ying ", "Xun ", "Zhen ", "She ", "Bin ", "Bin ", "Qiu ", "She ", "Chuan ", "Zang ", "Zhou ", "Lai ", "Zan ", "Si ", "Chen ", "Shang ", "Tian ", "Pei ", "Geng ", "Xian ", "Mai ", "Jian ", "Sui ", "Fu ", "Tan ", "Cong ", "Cong ", "Zhi ", "Ji ", "Zhang ", "Du ", "Jin ", "Xiong ", "Shun ", "Yun ", "Bao ", "Zai ", "Lai ", "Feng ", "Cang ", "Ji ", "Sheng ", "Ai ", "Zhuan ", "Fu ", "Gou ", "Sai ", "Ze ", "Liao "},
- {"Wei ", "Bai ", "Chen ", "Zhuan ", "Zhi ", "Zhui ", "Biao ", "Yun ", "Zeng ", "Tan ", "Zan ", "Yan ", "[?] ", "Shan ", "Wan ", "Ying ", "Jin ", "Gan ", "Xian ", "Zang ", "Bi ", "Du ", "Shu ", "Yan ", "[?] ", "Xuan ", "Long ", "Gan ", "Zang ", "Bei ", "Zhen ", "Fu ", "Yuan ", "Gong ", "Cai ", "Ze ", "Xian ", "Bai ", "Zhang ", "Huo ", "Zhi ", "Fan ", "Tan ", "Pin ", "Bian ", "Gou ", "Zhu ", "Guan ", "Er ", "Jian ", "Bi ", "Shi ", "Tie ", "Gui ", "Kuang ", "Dai ", "Mao ", "Fei ", "He ", "Yi ", "Zei ", "Zhi ", "Jia ", "Hui ", "Zi ", "Ren ", "Lu ", "Zang ", "Zi ", "Gai ", "Jin ", "Qiu ", "Zhen ", "Lai ", "She ", "Fu ", "Du ", "Ji ", "Shu ", "Shang ", "Si ", "Bi ", "Zhou ", "Geng ", "Pei ", "Tan ", "Lai ", "Feng ", "Zhui ", "Fu ", "Zhuan ", "Sai ", "Ze ", "Yan ", "Zan ", "Yun ", "Zeng ", "Shan ", "Ying ", "Gan ", "Chi ", "Xi ", "She ", "Nan ", "Xiong ", "Xi ", "Cheng ", "He ", "Cheng ", "Zhe ", "Xia ", "Tang ", "Zou ", "Zou ", "Li ", "Jiu ", "Fu ", "Zhao ", "Gan ", "Qi ", "Shan ", "Qiong ", "Qin ", "Xian ", "Ci ", "Jue ", "Qin ", "Chi ", "Ci ", "Chen ", "Chen ", "Die ", "Ju ", "Chao ", "Di ", "Se ", "Zhan ", "Zhu ", "Yue ", "Qu ", "Jie ", "Chi ", "Chu ", "Gua ", "Xue ", "Ci ", "Tiao ", "Duo ", "Lie ", "Gan ", "Suo ", "Cu ", "Xi ", "Zhao ", "Su ", "Yin ", "Ju ", "Jian ", "Que ", "Tang ", "Chuo ", "Cui ", "Lu ", "Qu ", "Dang ", "Qiu ", "Zi ", "Ti ", "Qu ", "Chi ", "Huang ", "Qiao ", "Qiao ", "Yao ", "Zao ", "Ti ", "[?] ", "Zan ", "Zan ", "Zu ", "Pa ", "Bao ", "Ku ", "Ke ", "Dun ", "Jue ", "Fu ", "Chen ", "Jian ", "Fang ", "Zhi ", "Sa ", "Yue ", "Pa ", "Qi ", "Yue ", "Qiang ", "Tuo ", "Tai ", "Yi ", "Nian ", "Ling ", "Mei ", "Ba ", "Die ", "Ku ", "Tuo ", "Jia ", "Ci ", "Pao ", "Qia ", "Zhu ", "Ju ", "Die ", "Zhi ", "Fu ", "Pan ", "Ju ", "Shan ", "Bo ", "Ni ", "Ju ", "Li ", "Gen ", "Yi ", "Ji ", "Dai ", "Xian ", "Jiao ", "Duo ", "Zhu ", "Zhuan ", "Kua ", "Zhuai ", "Gui ", "Qiong ", "Kui ", "Xiang ", "Chi ", "Lu ", "Beng ", "Zhi ", "Jia ", "Tiao ", "Cai ", "Jian ", "Ta ", "Qiao ", "Bi ", "Xian ", "Duo ", "Ji ", "Ju ", "Ji ", "Shu ", "Tu "},
- {"Chu ", "Jing ", "Nie ", "Xiao ", "Bo ", "Chi ", "Qun ", "Mou ", "Shu ", "Lang ", "Yong ", "Jiao ", "Chou ", "Qiao ", "[?] ", "Ta ", "Jian ", "Qi ", "Wo ", "Wei ", "Zhuo ", "Jie ", "Ji ", "Nie ", "Ju ", "Ju ", "Lun ", "Lu ", "Leng ", "Huai ", "Ju ", "Chi ", "Wan ", "Quan ", "Ti ", "Bo ", "Zu ", "Qie ", "Ji ", "Cu ", "Zong ", "Cai ", "Zong ", "Peng ", "Zhi ", "Zheng ", "Dian ", "Zhi ", "Yu ", "Duo ", "Dun ", "Chun ", "Yong ", "Zhong ", "Di ", "Zhe ", "Chen ", "Chuai ", "Jian ", "Gua ", "Tang ", "Ju ", "Fu ", "Zu ", "Die ", "Pian ", "Rou ", "Nuo ", "Ti ", "Cha ", "Tui ", "Jian ", "Dao ", "Cuo ", "Xi ", "Ta ", "Qiang ", "Zhan ", "Dian ", "Ti ", "Ji ", "Nie ", "Man ", "Liu ", "Zhan ", "Bi ", "Chong ", "Lu ", "Liao ", "Cu ", "Tang ", "Dai ", "Suo ", "Xi ", "Kui ", "Ji ", "Zhi ", "Qiang ", "Di ", "Man ", "Zong ", "Lian ", "Beng ", "Zao ", "Nian ", "Bie ", "Tui ", "Ju ", "Deng ", "Ceng ", "Xian ", "Fan ", "Chu ", "Zhong ", "Dun ", "Bo ", "Cu ", "Zu ", "Jue ", "Jue ", "Lin ", "Ta ", "Qiao ", "Qiao ", "Pu ", "Liao ", "Dun ", "Cuan ", "Kuang ", "Zao ", "Ta ", "Bi ", "Bi ", "Zhu ", "Ju ", "Chu ", "Qiao ", "Dun ", "Chou ", "Ji ", "Wu ", "Yue ", "Nian ", "Lin ", "Lie ", "Zhi ", "Li ", "Zhi ", "Chan ", "Chu ", "Duan ", "Wei ", "Long ", "Lin ", "Xian ", "Wei ", "Zuan ", "Lan ", "Xie ", "Rang ", "Xie ", "Nie ", "Ta ", "Qu ", "Jie ", "Cuan ", "Zuan ", "Xi ", "Kui ", "Jue ", "Lin ", "Shen ", "Gong ", "Dan ", "Segare ", "Qu ", "Ti ", "Duo ", "Duo ", "Gong ", "Lang ", "Nerau ", "Luo ", "Ai ", "Ji ", "Ju ", "Tang ", "Utsuke ", "[?] ", "Yan ", "Shitsuke ", "Kang ", "Qu ", "Lou ", "Lao ", "Tuo ", "Zhi ", "Yagate ", "Ti ", "Dao ", "Yagate ", "Yu ", "Che ", "Ya ", "Gui ", "Jun ", "Wei ", "Yue ", "Xin ", "Di ", "Xuan ", "Fan ", "Ren ", "Shan ", "Qiang ", "Shu ", "Tun ", "Chen ", "Dai ", "E ", "Na ", "Qi ", "Mao ", "Ruan ", "Ren ", "Fan ", "Zhuan ", "Hong ", "Hu ", "Qu ", "Huang ", "Di ", "Ling ", "Dai ", "Ao ", "Zhen ", "Fan ", "Kuang ", "Ang ", "Peng ", "Bei ", "Gu ", "Ku ", "Pao ", "Zhu ", "Rong ", "E ", "Ba ", "Zhou ", "Zhi ", "Yao ", "Ke ", "Yi ", "Qing ", "Shi ", "Ping "},
- {"Er ", "Qiong ", "Ju ", "Jiao ", "Guang ", "Lu ", "Kai ", "Quan ", "Zhou ", "Zai ", "Zhi ", "She ", "Liang ", "Yu ", "Shao ", "You ", "Huan ", "Yun ", "Zhe ", "Wan ", "Fu ", "Qing ", "Zhou ", "Ni ", "Ling ", "Zhe ", "Zhan ", "Liang ", "Zi ", "Hui ", "Wang ", "Chuo ", "Guo ", "Kan ", "Yi ", "Peng ", "Qian ", "Gun ", "Nian ", "Pian ", "Guan ", "Bei ", "Lun ", "Pai ", "Liang ", "Ruan ", "Rou ", "Ji ", "Yang ", "Xian ", "Chuan ", "Cou ", "Qun ", "Ge ", "You ", "Hong ", "Shu ", "Fu ", "Zi ", "Fu ", "Wen ", "Ben ", "Zhan ", "Yu ", "Wen ", "Tao ", "Gu ", "Zhen ", "Xia ", "Yuan ", "Lu ", "Jiu ", "Chao ", "Zhuan ", "Wei ", "Hun ", "Sori ", "Che ", "Jiao ", "Zhan ", "Pu ", "Lao ", "Fen ", "Fan ", "Lin ", "Ge ", "Se ", "Kan ", "Huan ", "Yi ", "Ji ", "Dui ", "Er ", "Yu ", "Xian ", "Hong ", "Lei ", "Pei ", "Li ", "Li ", "Lu ", "Lin ", "Che ", "Ya ", "Gui ", "Xuan ", "Di ", "Ren ", "Zhuan ", "E ", "Lun ", "Ruan ", "Hong ", "Ku ", "Ke ", "Lu ", "Zhou ", "Zhi ", "Yi ", "Hu ", "Zhen ", "Li ", "Yao ", "Qing ", "Shi ", "Zai ", "Zhi ", "Jiao ", "Zhou ", "Quan ", "Lu ", "Jiao ", "Zhe ", "Fu ", "Liang ", "Nian ", "Bei ", "Hui ", "Gun ", "Wang ", "Liang ", "Chuo ", "Zi ", "Cou ", "Fu ", "Ji ", "Wen ", "Shu ", "Pei ", "Yuan ", "Xia ", "Zhan ", "Lu ", "Che ", "Lin ", "Xin ", "Gu ", "Ci ", "Ci ", "Pi ", "Zui ", "Bian ", "La ", "La ", "Ci ", "Xue ", "Ban ", "Bian ", "Bian ", "Bian ", "[?] ", "Bian ", "Ban ", "Ci ", "Bian ", "Bian ", "Chen ", "Ru ", "Nong ", "Nong ", "Zhen ", "Chuo ", "Chuo ", "Suberu ", "Reng ", "Bian ", "Bian ", "Sip ", "Ip ", "Liao ", "Da ", "Chan ", "Gan ", "Qian ", "Yu ", "Yu ", "Qi ", "Xun ", "Yi ", "Guo ", "Mai ", "Qi ", "Za ", "Wang ", "Jia ", "Zhun ", "Ying ", "Ti ", "Yun ", "Jin ", "Hang ", "Ya ", "Fan ", "Wu ", "Da ", "E ", "Huan ", "Zhe ", "Totemo ", "Jin ", "Yuan ", "Wei ", "Lian ", "Chi ", "Che ", "Ni ", "Tiao ", "Zhi ", "Yi ", "Jiong ", "Jia ", "Chen ", "Dai ", "Er ", "Di ", "Po ", "Wang ", "Die ", "Ze ", "Tao ", "Shu ", "Tuo ", "Kep ", "Jing ", "Hui ", "Tong ", "You ", "Mi ", "Beng ", "Ji ", "Nai ", "Yi ", "Jie ", "Zhui ", "Lie ", "Xun "},
- {"Tui ", "Song ", "Gua ", "Tao ", "Pang ", "Hou ", "Ni ", "Dun ", "Jiong ", "Xuan ", "Xun ", "Bu ", "You ", "Xiao ", "Qiu ", "Tou ", "Zhu ", "Qiu ", "Di ", "Di ", "Tu ", "Jing ", "Ti ", "Dou ", "Yi ", "Zhe ", "Tong ", "Guang ", "Wu ", "Shi ", "Cheng ", "Su ", "Zao ", "Qun ", "Feng ", "Lian ", "Suo ", "Hui ", "Li ", "Sako ", "Lai ", "Ben ", "Cuo ", "Jue ", "Beng ", "Huan ", "Dai ", "Lu ", "You ", "Zhou ", "Jin ", "Yu ", "Chuo ", "Kui ", "Wei ", "Ti ", "Yi ", "Da ", "Yuan ", "Luo ", "Bi ", "Nuo ", "Yu ", "Dang ", "Sui ", "Dun ", "Sui ", "Yan ", "Chuan ", "Chi ", "Ti ", "Yu ", "Shi ", "Zhen ", "You ", "Yun ", "E ", "Bian ", "Guo ", "E ", "Xia ", "Huang ", "Qiu ", "Dao ", "Da ", "Wei ", "Appare ", "Yi ", "Gou ", "Yao ", "Chu ", "Liu ", "Xun ", "Ta ", "Di ", "Chi ", "Yuan ", "Su ", "Ta ", "Qian ", "[?] ", "Yao ", "Guan ", "Zhang ", "Ao ", "Shi ", "Ce ", "Chi ", "Su ", "Zao ", "Zhe ", "Dun ", "Di ", "Lou ", "Chi ", "Cuo ", "Lin ", "Zun ", "Rao ", "Qian ", "Xuan ", "Yu ", "Yi ", "Wu ", "Liao ", "Ju ", "Shi ", "Bi ", "Yao ", "Mai ", "Xie ", "Sui ", "Huan ", "Zhan ", "Teng ", "Er ", "Miao ", "Bian ", "Bian ", "La ", "Li ", "Yuan ", "Yao ", "Luo ", "Li ", "Yi ", "Ting ", "Deng ", "Qi ", "Yong ", "Shan ", "Han ", "Yu ", "Mang ", "Ru ", "Qiong ", "[?] ", "Kuang ", "Fu ", "Kang ", "Bin ", "Fang ", "Xing ", "Na ", "Xin ", "Shen ", "Bang ", "Yuan ", "Cun ", "Huo ", "Xie ", "Bang ", "Wu ", "Ju ", "You ", "Han ", "Tai ", "Qiu ", "Bi ", "Pei ", "Bing ", "Shao ", "Bei ", "Wa ", "Di ", "Zou ", "Ye ", "Lin ", "Kuang ", "Gui ", "Zhu ", "Shi ", "Ku ", "Yu ", "Gai ", "Ge ", "Xi ", "Zhi ", "Ji ", "Xun ", "Hou ", "Xing ", "Jiao ", "Xi ", "Gui ", "Nuo ", "Lang ", "Jia ", "Kuai ", "Zheng ", "Otoko ", "Yun ", "Yan ", "Cheng ", "Dou ", "Chi ", "Lu ", "Fu ", "Wu ", "Fu ", "Gao ", "Hao ", "Lang ", "Jia ", "Geng ", "Jun ", "Ying ", "Bo ", "Xi ", "Bei ", "Li ", "Yun ", "Bu ", "Xiao ", "Qi ", "Pi ", "Qing ", "Guo ", "Zhou ", "Tan ", "Zou ", "Ping ", "Lai ", "Ni ", "Chen ", "You ", "Bu ", "Xiang ", "Dan ", "Ju ", "Yong ", "Qiao ", "Yi ", "Du ", "Yan ", "Mei "},
- {"Ruo ", "Bei ", "E ", "Yu ", "Juan ", "Yu ", "Yun ", "Hou ", "Kui ", "Xiang ", "Xiang ", "Sou ", "Tang ", "Ming ", "Xi ", "Ru ", "Chu ", "Zi ", "Zou ", "Ju ", "Wu ", "Xiang ", "Yun ", "Hao ", "Yong ", "Bi ", "Mo ", "Chao ", "Fu ", "Liao ", "Yin ", "Zhuan ", "Hu ", "Qiao ", "Yan ", "Zhang ", "Fan ", "Qiao ", "Xu ", "Deng ", "Bi ", "Xin ", "Bi ", "Ceng ", "Wei ", "Zheng ", "Mao ", "Shan ", "Lin ", "Po ", "Dan ", "Meng ", "Ye ", "Cao ", "Kuai ", "Feng ", "Meng ", "Zou ", "Kuang ", "Lian ", "Zan ", "Chan ", "You ", "Qi ", "Yan ", "Chan ", "Zan ", "Ling ", "Huan ", "Xi ", "Feng ", "Zan ", "Li ", "You ", "Ding ", "Qiu ", "Zhuo ", "Pei ", "Zhou ", "Yi ", "Hang ", "Yu ", "Jiu ", "Yan ", "Zui ", "Mao ", "Dan ", "Xu ", "Tou ", "Zhen ", "Fen ", "Sakenomoto ", "[?] ", "Yun ", "Tai ", "Tian ", "Qia ", "Tuo ", "Zuo ", "Han ", "Gu ", "Su ", "Po ", "Chou ", "Zai ", "Ming ", "Luo ", "Chuo ", "Chou ", "You ", "Tong ", "Zhi ", "Xian ", "Jiang ", "Cheng ", "Yin ", "Tu ", "Xiao ", "Mei ", "Ku ", "Suan ", "Lei ", "Pu ", "Zui ", "Hai ", "Yan ", "Xi ", "Niang ", "Wei ", "Lu ", "Lan ", "Yan ", "Tao ", "Pei ", "Zhan ", "Chun ", "Tan ", "Zui ", "Chuo ", "Cu ", "Kun ", "Ti ", "Mian ", "Du ", "Hu ", "Xu ", "Xing ", "Tan ", "Jiu ", "Chun ", "Yun ", "Po ", "Ke ", "Sou ", "Mi ", "Quan ", "Chou ", "Cuo ", "Yun ", "Yong ", "Ang ", "Zha ", "Hai ", "Tang ", "Jiang ", "Piao ", "Shan ", "Yu ", "Li ", "Zao ", "Lao ", "Yi ", "Jiang ", "Pu ", "Jiao ", "Xi ", "Tan ", "Po ", "Nong ", "Yi ", "Li ", "Ju ", "Jiao ", "Yi ", "Niang ", "Ru ", "Xun ", "Chou ", "Yan ", "Ling ", "Mi ", "Mi ", "Niang ", "Xin ", "Jiao ", "Xi ", "Mi ", "Yan ", "Bian ", "Cai ", "Shi ", "You ", "Shi ", "Shi ", "Li ", "Zhong ", "Ye ", "Liang ", "Li ", "Jin ", "Jin ", "Qiu ", "Yi ", "Diao ", "Dao ", "Zhao ", "Ding ", "Po ", "Qiu ", "He ", "Fu ", "Zhen ", "Zhi ", "Ba ", "Luan ", "Fu ", "Nai ", "Diao ", "Shan ", "Qiao ", "Kou ", "Chuan ", "Zi ", "Fan ", "Yu ", "Hua ", "Han ", "Gong ", "Qi ", "Mang ", "Ri ", "Di ", "Si ", "Xi ", "Yi ", "Chai ", "Shi ", "Tu ", "Xi ", "Nu ", "Qian ", "Ishiyumi ", "Jian ", "Pi ", "Ye ", "Yin "},
- {"Ba ", "Fang ", "Chen ", "Xing ", "Tou ", "Yue ", "Yan ", "Fu ", "Pi ", "Na ", "Xin ", "E ", "Jue ", "Dun ", "Gou ", "Yin ", "Qian ", "Ban ", "Ji ", "Ren ", "Chao ", "Niu ", "Fen ", "Yun ", "Ji ", "Qin ", "Pi ", "Guo ", "Hong ", "Yin ", "Jun ", "Shi ", "Yi ", "Zhong ", "Nie ", "Gai ", "Ri ", "Huo ", "Tai ", "Kang ", "Habaki ", "Irori ", "Ngaak ", "[?] ", "Duo ", "Zi ", "Ni ", "Tu ", "Shi ", "Min ", "Gu ", "E ", "Ling ", "Bing ", "Yi ", "Gu ", "Ba ", "Pi ", "Yu ", "Si ", "Zuo ", "Bu ", "You ", "Dian ", "Jia ", "Zhen ", "Shi ", "Shi ", "Tie ", "Ju ", "Zhan ", "Shi ", "She ", "Xuan ", "Zhao ", "Bao ", "He ", "Bi ", "Sheng ", "Chu ", "Shi ", "Bo ", "Zhu ", "Chi ", "Za ", "Po ", "Tong ", "Qian ", "Fu ", "Zhai ", "Liu ", "Qian ", "Fu ", "Li ", "Yue ", "Pi ", "Yang ", "Ban ", "Bo ", "Jie ", "Gou ", "Shu ", "Zheng ", "Mu ", "Ni ", "Nie ", "Di ", "Jia ", "Mu ", "Dan ", "Shen ", "Yi ", "Si ", "Kuang ", "Ka ", "Bei ", "Jian ", "Tong ", "Xing ", "Hong ", "Jiao ", "Chi ", "Er ", "Ge ", "Bing ", "Shi ", "Mou ", "Jia ", "Yin ", "Jun ", "Zhou ", "Chong ", "Shang ", "Tong ", "Mo ", "Lei ", "Ji ", "Yu ", "Xu ", "Ren ", "Zun ", "Zhi ", "Qiong ", "Shan ", "Chi ", "Xian ", "Xing ", "Quan ", "Pi ", "Tie ", "Zhu ", "Hou ", "Ming ", "Kua ", "Yao ", "Xian ", "Xian ", "Xiu ", "Jun ", "Cha ", "Lao ", "Ji ", "Pi ", "Ru ", "Mi ", "Yi ", "Yin ", "Guang ", "An ", "Diou ", "You ", "Se ", "Kao ", "Qian ", "Luan ", "Kasugai ", "Ai ", "Diao ", "Han ", "Rui ", "Shi ", "Keng ", "Qiu ", "Xiao ", "Zhe ", "Xiu ", "Zang ", "Ti ", "Cuo ", "Gua ", "Gong ", "Zhong ", "Dou ", "Lu ", "Mei ", "Lang ", "Wan ", "Xin ", "Yun ", "Bei ", "Wu ", "Su ", "Yu ", "Chan ", "Ting ", "Bo ", "Han ", "Jia ", "Hong ", "Cuan ", "Feng ", "Chan ", "Wan ", "Zhi ", "Si ", "Xuan ", "Wu ", "Wu ", "Tiao ", "Gong ", "Zhuo ", "Lue ", "Xing ", "Qian ", "Shen ", "Han ", "Lue ", "Xie ", "Chu ", "Zheng ", "Ju ", "Xian ", "Tie ", "Mang ", "Pu ", "Li ", "Pan ", "Rui ", "Cheng ", "Gao ", "Li ", "Te ", "Pyeng ", "Zhu ", "[?] ", "Tu ", "Liu ", "Zui ", "Ju ", "Chang ", "Yuan ", "Jian ", "Gang ", "Diao ", "Tao ", "Chang "},
- {"Lun ", "Kua ", "Ling ", "Bei ", "Lu ", "Li ", "Qiang ", "Pou ", "Juan ", "Min ", "Zui ", "Peng ", "An ", "Pi ", "Xian ", "Ya ", "Zhui ", "Lei ", "A ", "Kong ", "Ta ", "Kun ", "Du ", "Wei ", "Chui ", "Zi ", "Zheng ", "Ben ", "Nie ", "Cong ", "Qun ", "Tan ", "Ding ", "Qi ", "Qian ", "Zhuo ", "Qi ", "Yu ", "Jin ", "Guan ", "Mao ", "Chang ", "Tian ", "Xi ", "Lian ", "Tao ", "Gu ", "Cuo ", "Shu ", "Zhen ", "Lu ", "Meng ", "Lu ", "Hua ", "Biao ", "Ga ", "Lai ", "Ken ", "Kazari ", "Bu ", "Nai ", "Wan ", "Zan ", "[?] ", "De ", "Xian ", "[?] ", "Huo ", "Liang ", "[?] ", "Men ", "Kai ", "Ying ", "Di ", "Lian ", "Guo ", "Xian ", "Du ", "Tu ", "Wei ", "Cong ", "Fu ", "Rou ", "Ji ", "E ", "Rou ", "Chen ", "Ti ", "Zha ", "Hong ", "Yang ", "Duan ", "Xia ", "Yu ", "Keng ", "Xing ", "Huang ", "Wei ", "Fu ", "Zhao ", "Cha ", "Qie ", "She ", "Hong ", "Kui ", "Tian ", "Mou ", "Qiao ", "Qiao ", "Hou ", "Tou ", "Cong ", "Huan ", "Ye ", "Min ", "Jian ", "Duan ", "Jian ", "Song ", "Kui ", "Hu ", "Xuan ", "Duo ", "Jie ", "Zhen ", "Bian ", "Zhong ", "Zi ", "Xiu ", "Ye ", "Mei ", "Pai ", "Ai ", "Jie ", "[?] ", "Mei ", "Chuo ", "Ta ", "Bang ", "Xia ", "Lian ", "Suo ", "Xi ", "Liu ", "Zu ", "Ye ", "Nou ", "Weng ", "Rong ", "Tang ", "Suo ", "Qiang ", "Ge ", "Shuo ", "Chui ", "Bo ", "Pan ", "Sa ", "Bi ", "Sang ", "Gang ", "Zi ", "Wu ", "Ying ", "Huang ", "Tiao ", "Liu ", "Kai ", "Sun ", "Sha ", "Sou ", "Wan ", "Hao ", "Zhen ", "Zhen ", "Luo ", "Yi ", "Yuan ", "Tang ", "Nie ", "Xi ", "Jia ", "Ge ", "Ma ", "Juan ", "Kasugai ", "Habaki ", "Suo ", "[?] ", "[?] ", "[?] ", "Na ", "Lu ", "Suo ", "Ou ", "Zu ", "Tuan ", "Xiu ", "Guan ", "Xuan ", "Lian ", "Shou ", "Ao ", "Man ", "Mo ", "Luo ", "Bi ", "Wei ", "Liu ", "Di ", "Qiao ", "Cong ", "Yi ", "Lu ", "Ao ", "Keng ", "Qiang ", "Cui ", "Qi ", "Chang ", "Tang ", "Man ", "Yong ", "Chan ", "Feng ", "Jing ", "Biao ", "Shu ", "Lou ", "Xiu ", "Cong ", "Long ", "Zan ", "Jian ", "Cao ", "Li ", "Xia ", "Xi ", "Kang ", "[?] ", "Beng ", "[?] ", "[?] ", "Zheng ", "Lu ", "Hua ", "Ji ", "Pu ", "Hui ", "Qiang ", "Po ", "Lin ", "Suo ", "Xiu ", "San ", "Cheng "},
- {"Kui ", "Si ", "Liu ", "Nao ", "Heng ", "Pie ", "Sui ", "Fan ", "Qiao ", "Quan ", "Yang ", "Tang ", "Xiang ", "Jue ", "Jiao ", "Zun ", "Liao ", "Jie ", "Lao ", "Dui ", "Tan ", "Zan ", "Ji ", "Jian ", "Zhong ", "Deng ", "Ya ", "Ying ", "Dui ", "Jue ", "Nou ", "Ti ", "Pu ", "Tie ", "[?] ", "[?] ", "Ding ", "Shan ", "Kai ", "Jian ", "Fei ", "Sui ", "Lu ", "Juan ", "Hui ", "Yu ", "Lian ", "Zhuo ", "Qiao ", "Qian ", "Zhuo ", "Lei ", "Bi ", "Tie ", "Huan ", "Ye ", "Duo ", "Guo ", "Dang ", "Ju ", "Fen ", "Da ", "Bei ", "Yi ", "Ai ", "Zong ", "Xun ", "Diao ", "Zhu ", "Heng ", "Zhui ", "Ji ", "Nie ", "Ta ", "Huo ", "Qing ", "Bin ", "Ying ", "Kui ", "Ning ", "Xu ", "Jian ", "Jian ", "Yari ", "Cha ", "Zhi ", "Mie ", "Li ", "Lei ", "Ji ", "Zuan ", "Kuang ", "Shang ", "Peng ", "La ", "Du ", "Shuo ", "Chuo ", "Lu ", "Biao ", "Bao ", "Lu ", "[?] ", "[?] ", "Long ", "E ", "Lu ", "Xin ", "Jian ", "Lan ", "Bo ", "Jian ", "Yao ", "Chan ", "Xiang ", "Jian ", "Xi ", "Guan ", "Cang ", "Nie ", "Lei ", "Cuan ", "Qu ", "Pan ", "Luo ", "Zuan ", "Luan ", "Zao ", "Nie ", "Jue ", "Tang ", "Shu ", "Lan ", "Jin ", "Qiu ", "Yi ", "Zhen ", "Ding ", "Zhao ", "Po ", "Diao ", "Tu ", "Qian ", "Chuan ", "Shan ", "Ji ", "Fan ", "Diao ", "Men ", "Nu ", "Xi ", "Chai ", "Xing ", "Gai ", "Bu ", "Tai ", "Ju ", "Dun ", "Chao ", "Zhong ", "Na ", "Bei ", "Gang ", "Ban ", "Qian ", "Yao ", "Qin ", "Jun ", "Wu ", "Gou ", "Kang ", "Fang ", "Huo ", "Tou ", "Niu ", "Ba ", "Yu ", "Qian ", "Zheng ", "Qian ", "Gu ", "Bo ", "E ", "Po ", "Bu ", "Ba ", "Yue ", "Zuan ", "Mu ", "Dan ", "Jia ", "Dian ", "You ", "Tie ", "Bo ", "Ling ", "Shuo ", "Qian ", "Liu ", "Bao ", "Shi ", "Xuan ", "She ", "Bi ", "Ni ", "Pi ", "Duo ", "Xing ", "Kao ", "Lao ", "Er ", "Mang ", "Ya ", "You ", "Cheng ", "Jia ", "Ye ", "Nao ", "Zhi ", "Dang ", "Tong ", "Lu ", "Diao ", "Yin ", "Kai ", "Zha ", "Zhu ", "Xian ", "Ting ", "Diu ", "Xian ", "Hua ", "Quan ", "Sha ", "Jia ", "Yao ", "Ge ", "Ming ", "Zheng ", "Se ", "Jiao ", "Yi ", "Chan ", "Chong ", "Tang ", "An ", "Yin ", "Ru ", "Zhu ", "Lao ", "Pu ", "Wu ", "Lai ", "Te ", "Lian ", "Keng "},
- {"Xiao ", "Suo ", "Li ", "Zheng ", "Chu ", "Guo ", "Gao ", "Tie ", "Xiu ", "Cuo ", "Lue ", "Feng ", "Xin ", "Liu ", "Kai ", "Jian ", "Rui ", "Ti ", "Lang ", "Qian ", "Ju ", "A ", "Qiang ", "Duo ", "Tian ", "Cuo ", "Mao ", "Ben ", "Qi ", "De ", "Kua ", "Kun ", "Chang ", "Xi ", "Gu ", "Luo ", "Chui ", "Zhui ", "Jin ", "Zhi ", "Xian ", "Juan ", "Huo ", "Pou ", "Tan ", "Ding ", "Jian ", "Ju ", "Meng ", "Zi ", "Qie ", "Ying ", "Kai ", "Qiang ", "Song ", "E ", "Cha ", "Qiao ", "Zhong ", "Duan ", "Sou ", "Huang ", "Huan ", "Ai ", "Du ", "Mei ", "Lou ", "Zi ", "Fei ", "Mei ", "Mo ", "Zhen ", "Bo ", "Ge ", "Nie ", "Tang ", "Juan ", "Nie ", "Na ", "Liu ", "Hao ", "Bang ", "Yi ", "Jia ", "Bin ", "Rong ", "Biao ", "Tang ", "Man ", "Luo ", "Beng ", "Yong ", "Jing ", "Di ", "Zu ", "Xuan ", "Liu ", "Tan ", "Jue ", "Liao ", "Pu ", "Lu ", "Dui ", "Lan ", "Pu ", "Cuan ", "Qiang ", "Deng ", "Huo ", "Lei ", "Huan ", "Zhuo ", "Lian ", "Yi ", "Cha ", "Biao ", "La ", "Chan ", "Xiang ", "Chang ", "Chang ", "Jiu ", "Ao ", "Die ", "Qu ", "Liao ", "Mi ", "Chang ", "Men ", "Ma ", "Shuan ", "Shan ", "Huo ", "Men ", "Yan ", "Bi ", "Han ", "Bi ", "San ", "Kai ", "Kang ", "Beng ", "Hong ", "Run ", "San ", "Xian ", "Xian ", "Jian ", "Min ", "Xia ", "Yuru ", "Dou ", "Zha ", "Nao ", "Jian ", "Peng ", "Xia ", "Ling ", "Bian ", "Bi ", "Run ", "He ", "Guan ", "Ge ", "Ge ", "Fa ", "Chu ", "Hong ", "Gui ", "Min ", "Se ", "Kun ", "Lang ", "Lu ", "Ting ", "Sha ", "Ju ", "Yue ", "Yue ", "Chan ", "Qu ", "Lin ", "Chang ", "Shai ", "Kun ", "Yan ", "Min ", "Yan ", "E ", "Hun ", "Yu ", "Wen ", "Xiang ", "Bao ", "Xiang ", "Qu ", "Yao ", "Wen ", "Ban ", "An ", "Wei ", "Yin ", "Kuo ", "Que ", "Lan ", "Du ", "[?] ", "Phwung ", "Tian ", "Nie ", "Ta ", "Kai ", "He ", "Que ", "Chuang ", "Guan ", "Dou ", "Qi ", "Kui ", "Tang ", "Guan ", "Piao ", "Kan ", "Xi ", "Hui ", "Chan ", "Pi ", "Dang ", "Huan ", "Ta ", "Wen ", "[?] ", "Men ", "Shuan ", "Shan ", "Yan ", "Han ", "Bi ", "Wen ", "Chuang ", "Run ", "Wei ", "Xian ", "Hong ", "Jian ", "Min ", "Kang ", "Men ", "Zha ", "Nao ", "Gui ", "Wen ", "Ta ", "Min ", "Lu ", "Kai "},
- {"Fa ", "Ge ", "He ", "Kun ", "Jiu ", "Yue ", "Lang ", "Du ", "Yu ", "Yan ", "Chang ", "Xi ", "Wen ", "Hun ", "Yan ", "E ", "Chan ", "Lan ", "Qu ", "Hui ", "Kuo ", "Que ", "Ge ", "Tian ", "Ta ", "Que ", "Kan ", "Huan ", "Fu ", "Fu ", "Le ", "Dui ", "Xin ", "Qian ", "Wu ", "Yi ", "Tuo ", "Yin ", "Yang ", "Dou ", "E ", "Sheng ", "Ban ", "Pei ", "Keng ", "Yun ", "Ruan ", "Zhi ", "Pi ", "Jing ", "Fang ", "Yang ", "Yin ", "Zhen ", "Jie ", "Cheng ", "E ", "Qu ", "Di ", "Zu ", "Zuo ", "Dian ", "Ling ", "A ", "Tuo ", "Tuo ", "Po ", "Bing ", "Fu ", "Ji ", "Lu ", "Long ", "Chen ", "Xing ", "Duo ", "Lou ", "Mo ", "Jiang ", "Shu ", "Duo ", "Xian ", "Er ", "Gui ", "Yu ", "Gai ", "Shan ", "Xun ", "Qiao ", "Xing ", "Chun ", "Fu ", "Bi ", "Xia ", "Shan ", "Sheng ", "Zhi ", "Pu ", "Dou ", "Yuan ", "Zhen ", "Chu ", "Xian ", "Tou ", "Nie ", "Yun ", "Xian ", "Pei ", "Pei ", "Zou ", "Yi ", "Dui ", "Lun ", "Yin ", "Ju ", "Chui ", "Chen ", "Pi ", "Ling ", "Tao ", "Xian ", "Lu ", "Sheng ", "Xian ", "Yin ", "Zhu ", "Yang ", "Reng ", "Shan ", "Chong ", "Yan ", "Yin ", "Yu ", "Ti ", "Yu ", "Long ", "Wei ", "Wei ", "Nie ", "Dui ", "Sui ", "An ", "Huang ", "Jie ", "Sui ", "Yin ", "Gai ", "Yan ", "Hui ", "Ge ", "Yun ", "Wu ", "Wei ", "Ai ", "Xi ", "Tang ", "Ji ", "Zhang ", "Dao ", "Ao ", "Xi ", "Yin ", "[?] ", "Rao ", "Lin ", "Tui ", "Deng ", "Pi ", "Sui ", "Sui ", "Yu ", "Xian ", "Fen ", "Ni ", "Er ", "Ji ", "Dao ", "Xi ", "Yin ", "E ", "Hui ", "Long ", "Xi ", "Li ", "Li ", "Li ", "Zhui ", "He ", "Zhi ", "Zhun ", "Jun ", "Nan ", "Yi ", "Que ", "Yan ", "Qian ", "Ya ", "Xiong ", "Ya ", "Ji ", "Gu ", "Huan ", "Zhi ", "Gou ", "Jun ", "Ci ", "Yong ", "Ju ", "Chu ", "Hu ", "Za ", "Luo ", "Yu ", "Chou ", "Diao ", "Sui ", "Han ", "Huo ", "Shuang ", "Guan ", "Chu ", "Za ", "Yong ", "Ji ", "Xi ", "Chou ", "Liu ", "Li ", "Nan ", "Xue ", "Za ", "Ji ", "Ji ", "Yu ", "Yu ", "Xue ", "Na ", "Fou ", "Se ", "Mu ", "Wen ", "Fen ", "Pang ", "Yun ", "Li ", "Li ", "Ang ", "Ling ", "Lei ", "An ", "Bao ", "Meng ", "Dian ", "Dang ", "Xing ", "Wu ", "Zhao "},
- {"Xu ", "Ji ", "Mu ", "Chen ", "Xiao ", "Zha ", "Ting ", "Zhen ", "Pei ", "Mei ", "Ling ", "Qi ", "Chou ", "Huo ", "Sha ", "Fei ", "Weng ", "Zhan ", "Yin ", "Ni ", "Chou ", "Tun ", "Lin ", "[?] ", "Dong ", "Ying ", "Wu ", "Ling ", "Shuang ", "Ling ", "Xia ", "Hong ", "Yin ", "Mo ", "Mai ", "Yun ", "Liu ", "Meng ", "Bin ", "Wu ", "Wei ", "Huo ", "Yin ", "Xi ", "Yi ", "Ai ", "Dan ", "Deng ", "Xian ", "Yu ", "Lu ", "Long ", "Dai ", "Ji ", "Pang ", "Yang ", "Ba ", "Pi ", "Wei ", "[?] ", "Xi ", "Ji ", "Mai ", "Meng ", "Meng ", "Lei ", "Li ", "Huo ", "Ai ", "Fei ", "Dai ", "Long ", "Ling ", "Ai ", "Feng ", "Li ", "Bao ", "[?] ", "He ", "He ", "Bing ", "Qing ", "Qing ", "Jing ", "Tian ", "Zhen ", "Jing ", "Cheng ", "Qing ", "Jing ", "Jing ", "Dian ", "Jing ", "Tian ", "Fei ", "Fei ", "Kao ", "Mi ", "Mian ", "Mian ", "Pao ", "Ye ", "Tian ", "Hui ", "Ye ", "Ge ", "Ding ", "Cha ", "Jian ", "Ren ", "Di ", "Du ", "Wu ", "Ren ", "Qin ", "Jin ", "Xue ", "Niu ", "Ba ", "Yin ", "Sa ", "Na ", "Mo ", "Zu ", "Da ", "Ban ", "Yi ", "Yao ", "Tao ", "Tuo ", "Jia ", "Hong ", "Pao ", "Yang ", "Tomo ", "Yin ", "Jia ", "Tao ", "Ji ", "Xie ", "An ", "An ", "Hen ", "Gong ", "Kohaze ", "Da ", "Qiao ", "Ting ", "Wan ", "Ying ", "Sui ", "Tiao ", "Qiao ", "Xuan ", "Kong ", "Beng ", "Ta ", "Zhang ", "Bing ", "Kuo ", "Ju ", "La ", "Xie ", "Rou ", "Bang ", "Yi ", "Qiu ", "Qiu ", "He ", "Xiao ", "Mu ", "Ju ", "Jian ", "Bian ", "Di ", "Jian ", "On ", "Tao ", "Gou ", "Ta ", "Bei ", "Xie ", "Pan ", "Ge ", "Bi ", "Kuo ", "Tang ", "Lou ", "Gui ", "Qiao ", "Xue ", "Ji ", "Jian ", "Jiang ", "Chan ", "Da ", "Huo ", "Xian ", "Qian ", "Du ", "Wa ", "Jian ", "Lan ", "Wei ", "Ren ", "Fu ", "Mei ", "Juan ", "Ge ", "Wei ", "Qiao ", "Han ", "Chang ", "[?] ", "Rou ", "Xun ", "She ", "Wei ", "Ge ", "Bei ", "Tao ", "Gou ", "Yun ", "[?] ", "Bi ", "Wei ", "Hui ", "Du ", "Wa ", "Du ", "Wei ", "Ren ", "Fu ", "Han ", "Wei ", "Yun ", "Tao ", "Jiu ", "Jiu ", "Xian ", "Xie ", "Xian ", "Ji ", "Yin ", "Za ", "Yun ", "Shao ", "Le ", "Peng ", "Heng ", "Ying ", "Yun ", "Peng ", "Yin ", "Yin ", "Xiang "},
- {"Hu ", "Ye ", "Ding ", "Qing ", "Pan ", "Xiang ", "Shun ", "Han ", "Xu ", "Yi ", "Xu ", "Gu ", "Song ", "Kui ", "Qi ", "Hang ", "Yu ", "Wan ", "Ban ", "Dun ", "Di ", "Dan ", "Pan ", "Po ", "Ling ", "Ce ", "Jing ", "Lei ", "He ", "Qiao ", "E ", "E ", "Wei ", "Jie ", "Gua ", "Shen ", "Yi ", "Shen ", "Hai ", "Dui ", "Pian ", "Ping ", "Lei ", "Fu ", "Jia ", "Tou ", "Hui ", "Kui ", "Jia ", "Le ", "Tian ", "Cheng ", "Ying ", "Jun ", "Hu ", "Han ", "Jing ", "Tui ", "Tui ", "Pin ", "Lai ", "Tui ", "Zi ", "Zi ", "Chui ", "Ding ", "Lai ", "Yan ", "Han ", "Jian ", "Ke ", "Cui ", "Jiong ", "Qin ", "Yi ", "Sai ", "Ti ", "E ", "E ", "Yan ", "Hun ", "Kan ", "Yong ", "Zhuan ", "Yan ", "Xian ", "Xin ", "Yi ", "Yuan ", "Sang ", "Dian ", "Dian ", "Jiang ", "Ku ", "Lei ", "Liao ", "Piao ", "Yi ", "Man ", "Qi ", "Rao ", "Hao ", "Qiao ", "Gu ", "Xun ", "Qian ", "Hui ", "Zhan ", "Ru ", "Hong ", "Bin ", "Xian ", "Pin ", "Lu ", "Lan ", "Nie ", "Quan ", "Ye ", "Ding ", "Qing ", "Han ", "Xiang ", "Shun ", "Xu ", "Xu ", "Wan ", "Gu ", "Dun ", "Qi ", "Ban ", "Song ", "Hang ", "Yu ", "Lu ", "Ling ", "Po ", "Jing ", "Jie ", "Jia ", "Tian ", "Han ", "Ying ", "Jiong ", "Hai ", "Yi ", "Pin ", "Hui ", "Tui ", "Han ", "Ying ", "Ying ", "Ke ", "Ti ", "Yong ", "E ", "Zhuan ", "Yan ", "E ", "Nie ", "Man ", "Dian ", "Sang ", "Hao ", "Lei ", "Zhan ", "Ru ", "Pin ", "Quan ", "Feng ", "Biao ", "Oroshi ", "Fu ", "Xia ", "Zhan ", "Biao ", "Sa ", "Ba ", "Tai ", "Lie ", "Gua ", "Xuan ", "Shao ", "Ju ", "Bi ", "Si ", "Wei ", "Yang ", "Yao ", "Sou ", "Kai ", "Sao ", "Fan ", "Liu ", "Xi ", "Liao ", "Piao ", "Piao ", "Liu ", "Biao ", "Biao ", "Biao ", "Liao ", "[?] ", "Se ", "Feng ", "Biao ", "Feng ", "Yang ", "Zhan ", "Biao ", "Sa ", "Ju ", "Si ", "Sou ", "Yao ", "Liu ", "Piao ", "Biao ", "Biao ", "Fei ", "Fan ", "Fei ", "Fei ", "Shi ", "Shi ", "Can ", "Ji ", "Ding ", "Si ", "Tuo ", "Zhan ", "Sun ", "Xiang ", "Tun ", "Ren ", "Yu ", "Juan ", "Chi ", "Yin ", "Fan ", "Fan ", "Sun ", "Yin ", "Zhu ", "Yi ", "Zhai ", "Bi ", "Jie ", "Tao ", "Liu ", "Ci ", "Tie ", "Si ", "Bao ", "Shi ", "Duo "},
- {"Hai ", "Ren ", "Tian ", "Jiao ", "Jia ", "Bing ", "Yao ", "Tong ", "Ci ", "Xiang ", "Yang ", "Yang ", "Er ", "Yan ", "Le ", "Yi ", "Can ", "Bo ", "Nei ", "E ", "Bu ", "Jun ", "Dou ", "Su ", "Yu ", "Shi ", "Yao ", "Hun ", "Guo ", "Shi ", "Jian ", "Zhui ", "Bing ", "Xian ", "Bu ", "Ye ", "Tan ", "Fei ", "Zhang ", "Wei ", "Guan ", "E ", "Nuan ", "Hun ", "Hu ", "Huang ", "Tie ", "Hui ", "Jian ", "Hou ", "He ", "Xing ", "Fen ", "Wei ", "Gu ", "Cha ", "Song ", "Tang ", "Bo ", "Gao ", "Xi ", "Kui ", "Liu ", "Sou ", "Tao ", "Ye ", "Yun ", "Mo ", "Tang ", "Man ", "Bi ", "Yu ", "Xiu ", "Jin ", "San ", "Kui ", "Zhuan ", "Shan ", "Chi ", "Dan ", "Yi ", "Ji ", "Rao ", "Cheng ", "Yong ", "Tao ", "Hui ", "Xiang ", "Zhan ", "Fen ", "Hai ", "Meng ", "Yan ", "Mo ", "Chan ", "Xiang ", "Luo ", "Zuan ", "Nang ", "Shi ", "Ding ", "Ji ", "Tuo ", "Xing ", "Tun ", "Xi ", "Ren ", "Yu ", "Chi ", "Fan ", "Yin ", "Jian ", "Shi ", "Bao ", "Si ", "Duo ", "Yi ", "Er ", "Rao ", "Xiang ", "Jia ", "Le ", "Jiao ", "Yi ", "Bing ", "Bo ", "Dou ", "E ", "Yu ", "Nei ", "Jun ", "Guo ", "Hun ", "Xian ", "Guan ", "Cha ", "Kui ", "Gu ", "Sou ", "Chan ", "Ye ", "Mo ", "Bo ", "Liu ", "Xiu ", "Jin ", "Man ", "San ", "Zhuan ", "Nang ", "Shou ", "Kui ", "Guo ", "Xiang ", "Fen ", "Ba ", "Ni ", "Bi ", "Bo ", "Tu ", "Han ", "Fei ", "Jian ", "An ", "Ai ", "Fu ", "Xian ", "Wen ", "Xin ", "Fen ", "Bin ", "Xing ", "Ma ", "Yu ", "Feng ", "Han ", "Di ", "Tuo ", "Tuo ", "Chi ", "Xun ", "Zhu ", "Zhi ", "Pei ", "Xin ", "Ri ", "Sa ", "Yin ", "Wen ", "Zhi ", "Dan ", "Lu ", "You ", "Bo ", "Bao ", "Kuai ", "Tuo ", "Yi ", "Qu ", "[?] ", "Qu ", "Jiong ", "Bo ", "Zhao ", "Yuan ", "Peng ", "Zhou ", "Ju ", "Zhu ", "Nu ", "Ju ", "Pi ", "Zang ", "Jia ", "Ling ", "Zhen ", "Tai ", "Fu ", "Yang ", "Shi ", "Bi ", "Tuo ", "Tuo ", "Si ", "Liu ", "Ma ", "Pian ", "Tao ", "Zhi ", "Rong ", "Teng ", "Dong ", "Xun ", "Quan ", "Shen ", "Jiong ", "Er ", "Hai ", "Bo ", "Zhu ", "Yin ", "Luo ", "Shuu ", "Dan ", "Xie ", "Liu ", "Ju ", "Song ", "Qin ", "Mang ", "Liang ", "Han ", "Tu ", "Xuan ", "Tui ", "Jun "},
- {"E ", "Cheng ", "Xin ", "Ai ", "Lu ", "Zhui ", "Zhou ", "She ", "Pian ", "Kun ", "Tao ", "Lai ", "Zong ", "Ke ", "Qi ", "Qi ", "Yan ", "Fei ", "Sao ", "Yan ", "Jie ", "Yao ", "Wu ", "Pian ", "Cong ", "Pian ", "Qian ", "Fei ", "Huang ", "Jian ", "Huo ", "Yu ", "Ti ", "Quan ", "Xia ", "Zong ", "Kui ", "Rou ", "Si ", "Gua ", "Tuo ", "Kui ", "Sou ", "Qian ", "Cheng ", "Zhi ", "Liu ", "Pang ", "Teng ", "Xi ", "Cao ", "Du ", "Yan ", "Yuan ", "Zou ", "Sao ", "Shan ", "Li ", "Zhi ", "Shuang ", "Lu ", "Xi ", "Luo ", "Zhang ", "Mo ", "Ao ", "Can ", "Piao ", "Cong ", "Qu ", "Bi ", "Zhi ", "Yu ", "Xu ", "Hua ", "Bo ", "Su ", "Xiao ", "Lin ", "Chan ", "Dun ", "Liu ", "Tuo ", "Zeng ", "Tan ", "Jiao ", "Tie ", "Yan ", "Luo ", "Zhan ", "Jing ", "Yi ", "Ye ", "Tuo ", "Bin ", "Zou ", "Yan ", "Peng ", "Lu ", "Teng ", "Xiang ", "Ji ", "Shuang ", "Ju ", "Xi ", "Huan ", "Li ", "Biao ", "Ma ", "Yu ", "Tuo ", "Xun ", "Chi ", "Qu ", "Ri ", "Bo ", "Lu ", "Zang ", "Shi ", "Si ", "Fu ", "Ju ", "Zou ", "Zhu ", "Tuo ", "Nu ", "Jia ", "Yi ", "Tai ", "Xiao ", "Ma ", "Yin ", "Jiao ", "Hua ", "Luo ", "Hai ", "Pian ", "Biao ", "Li ", "Cheng ", "Yan ", "Xin ", "Qin ", "Jun ", "Qi ", "Qi ", "Ke ", "Zhui ", "Zong ", "Su ", "Can ", "Pian ", "Zhi ", "Kui ", "Sao ", "Wu ", "Ao ", "Liu ", "Qian ", "Shan ", "Piao ", "Luo ", "Cong ", "Chan ", "Zou ", "Ji ", "Shuang ", "Xiang ", "Gu ", "Wei ", "Wei ", "Wei ", "Yu ", "Gan ", "Yi ", "Ang ", "Tou ", "Xie ", "Bao ", "Bi ", "Chi ", "Ti ", "Di ", "Ku ", "Hai ", "Qiao ", "Gou ", "Kua ", "Ge ", "Tui ", "Geng ", "Pian ", "Bi ", "Ke ", "Ka ", "Yu ", "Sui ", "Lou ", "Bo ", "Xiao ", "Pang ", "Bo ", "Ci ", "Kuan ", "Bin ", "Mo ", "Liao ", "Lou ", "Nao ", "Du ", "Zang ", "Sui ", "Ti ", "Bin ", "Kuan ", "Lu ", "Gao ", "Gao ", "Qiao ", "Kao ", "Qiao ", "Lao ", "Zao ", "Biao ", "Kun ", "Kun ", "Ti ", "Fang ", "Xiu ", "Ran ", "Mao ", "Dan ", "Kun ", "Bin ", "Fa ", "Tiao ", "Peng ", "Zi ", "Fa ", "Ran ", "Ti ", "Pao ", "Pi ", "Mao ", "Fu ", "Er ", "Rong ", "Qu ", "Gong ", "Xiu ", "Gua ", "Ji ", "Peng ", "Zhua ", "Shao ", "Sha "},
- {"Ti ", "Li ", "Bin ", "Zong ", "Ti ", "Peng ", "Song ", "Zheng ", "Quan ", "Zong ", "Shun ", "Jian ", "Duo ", "Hu ", "La ", "Jiu ", "Qi ", "Lian ", "Zhen ", "Bin ", "Peng ", "Mo ", "San ", "Man ", "Man ", "Seng ", "Xu ", "Lie ", "Qian ", "Qian ", "Nong ", "Huan ", "Kuai ", "Ning ", "Bin ", "Lie ", "Rang ", "Dou ", "Dou ", "Nao ", "Hong ", "Xi ", "Dou ", "Han ", "Dou ", "Dou ", "Jiu ", "Chang ", "Yu ", "Yu ", "Li ", "Juan ", "Fu ", "Qian ", "Gui ", "Zong ", "Liu ", "Gui ", "Shang ", "Yu ", "Gui ", "Mei ", "Ji ", "Qi ", "Jie ", "Kui ", "Hun ", "Ba ", "Po ", "Mei ", "Xu ", "Yan ", "Xiao ", "Liang ", "Yu ", "Tui ", "Qi ", "Wang ", "Liang ", "Wei ", "Jian ", "Chi ", "Piao ", "Bi ", "Mo ", "Ji ", "Xu ", "Chou ", "Yan ", "Zhan ", "Yu ", "Dao ", "Ren ", "Ji ", "Eri ", "Gong ", "Tuo ", "Diao ", "Ji ", "Xu ", "E ", "E ", "Sha ", "Hang ", "Tun ", "Mo ", "Jie ", "Shen ", "Fan ", "Yuan ", "Bi ", "Lu ", "Wen ", "Hu ", "Lu ", "Za ", "Fang ", "Fen ", "Na ", "You ", "Namazu ", "Todo ", "He ", "Xia ", "Qu ", "Han ", "Pi ", "Ling ", "Tuo ", "Bo ", "Qiu ", "Ping ", "Fu ", "Bi ", "Ji ", "Wei ", "Ju ", "Diao ", "Bo ", "You ", "Gun ", "Pi ", "Nian ", "Xing ", "Tai ", "Bao ", "Fu ", "Zha ", "Ju ", "Gu ", "Kajika ", "Tong ", "[?] ", "Ta ", "Jie ", "Shu ", "Hou ", "Xiang ", "Er ", "An ", "Wei ", "Tiao ", "Zhu ", "Yin ", "Lie ", "Luo ", "Tong ", "Yi ", "Qi ", "Bing ", "Wei ", "Jiao ", "Bu ", "Gui ", "Xian ", "Ge ", "Hui ", "Bora ", "Mate ", "Kao ", "Gori ", "Duo ", "Jun ", "Ti ", "Man ", "Xiao ", "Za ", "Sha ", "Qin ", "Yu ", "Nei ", "Zhe ", "Gun ", "Geng ", "Su ", "Wu ", "Qiu ", "Ting ", "Fu ", "Wan ", "You ", "Li ", "Sha ", "Sha ", "Gao ", "Meng ", "Ugui ", "Asari ", "Subashiri ", "Kazunoko ", "Yong ", "Ni ", "Zi ", "Qi ", "Qing ", "Xiang ", "Nei ", "Chun ", "Ji ", "Diao ", "Qie ", "Gu ", "Zhou ", "Dong ", "Lai ", "Fei ", "Ni ", "Yi ", "Kun ", "Lu ", "Jiu ", "Chang ", "Jing ", "Lun ", "Ling ", "Zou ", "Li ", "Meng ", "Zong ", "Zhi ", "Nian ", "Shachi ", "Dojou ", "Sukesou ", "Shi ", "Shen ", "Hun ", "Shi ", "Hou ", "Xing ", "Zhu ", "La ", "Zong ", "Ji ", "Bian ", "Bian "},
- {"Huan ", "Quan ", "Ze ", "Wei ", "Wei ", "Yu ", "Qun ", "Rou ", "Die ", "Huang ", "Lian ", "Yan ", "Qiu ", "Qiu ", "Jian ", "Bi ", "E ", "Yang ", "Fu ", "Sai ", "Jian ", "Xia ", "Tuo ", "Hu ", "Muroaji ", "Ruo ", "Haraka ", "Wen ", "Jian ", "Hao ", "Wu ", "Fang ", "Sao ", "Liu ", "Ma ", "Shi ", "Shi ", "Yin ", "Z ", "Teng ", "Ta ", "Yao ", "Ge ", "Rong ", "Qian ", "Qi ", "Wen ", "Ruo ", "Hatahata ", "Lian ", "Ao ", "Le ", "Hui ", "Min ", "Ji ", "Tiao ", "Qu ", "Jian ", "Sao ", "Man ", "Xi ", "Qiu ", "Biao ", "Ji ", "Ji ", "Zhu ", "Jiang ", "Qiu ", "Zhuan ", "Yong ", "Zhang ", "Kang ", "Xue ", "Bie ", "Jue ", "Qu ", "Xiang ", "Bo ", "Jiao ", "Xun ", "Su ", "Huang ", "Zun ", "Shan ", "Shan ", "Fan ", "Jue ", "Lin ", "Xun ", "Miao ", "Xi ", "Eso ", "Kyou ", "Fen ", "Guan ", "Hou ", "Kuai ", "Zei ", "Sao ", "Zhan ", "Gan ", "Gui ", "Sheng ", "Li ", "Chang ", "Hatahata ", "Shiira ", "Mutsu ", "Ru ", "Ji ", "Xu ", "Huo ", "Shiira ", "Li ", "Lie ", "Li ", "Mie ", "Zhen ", "Xiang ", "E ", "Lu ", "Guan ", "Li ", "Xian ", "Yu ", "Dao ", "Ji ", "You ", "Tun ", "Lu ", "Fang ", "Ba ", "He ", "Bo ", "Ping ", "Nian ", "Lu ", "You ", "Zha ", "Fu ", "Bo ", "Bao ", "Hou ", "Pi ", "Tai ", "Gui ", "Jie ", "Kao ", "Wei ", "Er ", "Tong ", "Ze ", "Hou ", "Kuai ", "Ji ", "Jiao ", "Xian ", "Za ", "Xiang ", "Xun ", "Geng ", "Li ", "Lian ", "Jian ", "Li ", "Shi ", "Tiao ", "Gun ", "Sha ", "Wan ", "Jun ", "Ji ", "Yong ", "Qing ", "Ling ", "Qi ", "Zou ", "Fei ", "Kun ", "Chang ", "Gu ", "Ni ", "Nian ", "Diao ", "Jing ", "Shen ", "Shi ", "Zi ", "Fen ", "Die ", "Bi ", "Chang ", "Shi ", "Wen ", "Wei ", "Sai ", "E ", "Qiu ", "Fu ", "Huang ", "Quan ", "Jiang ", "Bian ", "Sao ", "Ao ", "Qi ", "Ta ", "Yin ", "Yao ", "Fang ", "Jian ", "Le ", "Biao ", "Xue ", "Bie ", "Man ", "Min ", "Yong ", "Wei ", "Xi ", "Jue ", "Shan ", "Lin ", "Zun ", "Huo ", "Gan ", "Li ", "Zhan ", "Guan ", "Niao ", "Yi ", "Fu ", "Li ", "Jiu ", "Bu ", "Yan ", "Fu ", "Diao ", "Ji ", "Feng ", "Nio ", "Gan ", "Shi ", "Feng ", "Ming ", "Bao ", "Yuan ", "Zhi ", "Hu ", "Qin ", "Fu ", "Fen ", "Wen ", "Jian ", "Shi ", "Yu "},
- {"Fou ", "Yiao ", "Jue ", "Jue ", "Pi ", "Huan ", "Zhen ", "Bao ", "Yan ", "Ya ", "Zheng ", "Fang ", "Feng ", "Wen ", "Ou ", "Te ", "Jia ", "Nu ", "Ling ", "Mie ", "Fu ", "Tuo ", "Wen ", "Li ", "Bian ", "Zhi ", "Ge ", "Yuan ", "Zi ", "Qu ", "Xiao ", "Zhi ", "Dan ", "Ju ", "You ", "Gu ", "Zhong ", "Yu ", "Yang ", "Rong ", "Ya ", "Tie ", "Yu ", "Shigi ", "Ying ", "Zhui ", "Wu ", "Er ", "Gua ", "Ai ", "Zhi ", "Yan ", "Heng ", "Jiao ", "Ji ", "Lie ", "Zhu ", "Ren ", "Yi ", "Hong ", "Luo ", "Ru ", "Mou ", "Ge ", "Ren ", "Jiao ", "Xiu ", "Zhou ", "Zhi ", "Luo ", "Chidori ", "Toki ", "Ten ", "Luan ", "Jia ", "Ji ", "Yu ", "Huan ", "Tuo ", "Bu ", "Wu ", "Juan ", "Yu ", "Bo ", "Xun ", "Xun ", "Bi ", "Xi ", "Jun ", "Ju ", "Tu ", "Jing ", "Ti ", "E ", "E ", "Kuang ", "Hu ", "Wu ", "Shen ", "Lai ", "Ikaruga ", "Kakesu ", "Lu ", "Ping ", "Shu ", "Fu ", "An ", "Zhao ", "Peng ", "Qin ", "Qian ", "Bei ", "Diao ", "Lu ", "Que ", "Jian ", "Ju ", "Tu ", "Ya ", "Yuan ", "Qi ", "Li ", "Ye ", "Zhui ", "Kong ", "Zhui ", "Kun ", "Sheng ", "Qi ", "Jing ", "Yi ", "Yi ", "Jing ", "Zi ", "Lai ", "Dong ", "Qi ", "Chun ", "Geng ", "Ju ", "Qu ", "Isuka ", "Kikuitadaki ", "Ji ", "Shu ", "[?] ", "Chi ", "Miao ", "Rou ", "An ", "Qiu ", "Ti ", "Hu ", "Ti ", "E ", "Jie ", "Mao ", "Fu ", "Chun ", "Tu ", "Yan ", "He ", "Yuan ", "Pian ", "Yun ", "Mei ", "Hu ", "Ying ", "Dun ", "Mu ", "Ju ", "Tsugumi ", "Cang ", "Fang ", "Gu ", "Ying ", "Yuan ", "Xuan ", "Weng ", "Shi ", "He ", "Chu ", "Tang ", "Xia ", "Ruo ", "Liu ", "Ji ", "Gu ", "Jian ", "Zhun ", "Han ", "Zi ", "Zi ", "Ni ", "Yao ", "Yan ", "Ji ", "Li ", "Tian ", "Kou ", "Ti ", "Ti ", "Ni ", "Tu ", "Ma ", "Jiao ", "Gao ", "Tian ", "Chen ", "Li ", "Zhuan ", "Zhe ", "Ao ", "Yao ", "Yi ", "Ou ", "Chi ", "Zhi ", "Liao ", "Rong ", "Lou ", "Bi ", "Shuang ", "Zhuo ", "Yu ", "Wu ", "Jue ", "Yin ", "Quan ", "Si ", "Jiao ", "Yi ", "Hua ", "Bi ", "Ying ", "Su ", "Huang ", "Fan ", "Jiao ", "Liao ", "Yan ", "Kao ", "Jiu ", "Xian ", "Xian ", "Tu ", "Mai ", "Zun ", "Yu ", "Ying ", "Lu ", "Tuan ", "Xian ", "Xue ", "Yi ", "Pi "},
- {"Shu ", "Luo ", "Qi ", "Yi ", "Ji ", "Zhe ", "Yu ", "Zhan ", "Ye ", "Yang ", "Pi ", "Ning ", "Huo ", "Mi ", "Ying ", "Meng ", "Di ", "Yue ", "Yu ", "Lei ", "Bao ", "Lu ", "He ", "Long ", "Shuang ", "Yue ", "Ying ", "Guan ", "Qu ", "Li ", "Luan ", "Niao ", "Jiu ", "Ji ", "Yuan ", "Ming ", "Shi ", "Ou ", "Ya ", "Cang ", "Bao ", "Zhen ", "Gu ", "Dong ", "Lu ", "Ya ", "Xiao ", "Yang ", "Ling ", "Zhi ", "Qu ", "Yuan ", "Xue ", "Tuo ", "Si ", "Zhi ", "Er ", "Gua ", "Xiu ", "Heng ", "Zhou ", "Ge ", "Luan ", "Hong ", "Wu ", "Bo ", "Li ", "Juan ", "Hu ", "E ", "Yu ", "Xian ", "Ti ", "Wu ", "Que ", "Miao ", "An ", "Kun ", "Bei ", "Peng ", "Qian ", "Chun ", "Geng ", "Yuan ", "Su ", "Hu ", "He ", "E ", "Gu ", "Qiu ", "Zi ", "Mei ", "Mu ", "Ni ", "Yao ", "Weng ", "Liu ", "Ji ", "Ni ", "Jian ", "He ", "Yi ", "Ying ", "Zhe ", "Liao ", "Liao ", "Jiao ", "Jiu ", "Yu ", "Lu ", "Xuan ", "Zhan ", "Ying ", "Huo ", "Meng ", "Guan ", "Shuang ", "Lu ", "Jin ", "Ling ", "Jian ", "Xian ", "Cuo ", "Jian ", "Jian ", "Yan ", "Cuo ", "Lu ", "You ", "Cu ", "Ji ", "Biao ", "Cu ", "Biao ", "Zhu ", "Jun ", "Zhu ", "Jian ", "Mi ", "Mi ", "Wu ", "Liu ", "Chen ", "Jun ", "Lin ", "Ni ", "Qi ", "Lu ", "Jiu ", "Jun ", "Jing ", "Li ", "Xiang ", "Yan ", "Jia ", "Mi ", "Li ", "She ", "Zhang ", "Lin ", "Jing ", "Ji ", "Ling ", "Yan ", "Cu ", "Mai ", "Mai ", "Ge ", "Chao ", "Fu ", "Mian ", "Mian ", "Fu ", "Pao ", "Qu ", "Qu ", "Mou ", "Fu ", "Xian ", "Lai ", "Qu ", "Mian ", "[?] ", "Feng ", "Fu ", "Qu ", "Mian ", "Ma ", "Mo ", "Mo ", "Hui ", "Ma ", "Zou ", "Nen ", "Fen ", "Huang ", "Huang ", "Jin ", "Guang ", "Tian ", "Tou ", "Heng ", "Xi ", "Kuang ", "Heng ", "Shu ", "Li ", "Nian ", "Chi ", "Hei ", "Hei ", "Yi ", "Qian ", "Dan ", "Xi ", "Tuan ", "Mo ", "Mo ", "Qian ", "Dai ", "Chu ", "You ", "Dian ", "Yi ", "Xia ", "Yan ", "Qu ", "Mei ", "Yan ", "Jing ", "Yu ", "Li ", "Dang ", "Du ", "Can ", "Yin ", "An ", "Yan ", "Tan ", "An ", "Zhen ", "Dai ", "Can ", "Yi ", "Mei ", "Dan ", "Yan ", "Du ", "Lu ", "Zhi ", "Fen ", "Fu ", "Fu ", "Min ", "Min ", "Yuan "},
- {"Cu ", "Qu ", "Chao ", "Wa ", "Zhu ", "Zhi ", "Mang ", "Ao ", "Bie ", "Tuo ", "Bi ", "Yuan ", "Chao ", "Tuo ", "Ding ", "Mi ", "Nai ", "Ding ", "Zi ", "Gu ", "Gu ", "Dong ", "Fen ", "Tao ", "Yuan ", "Pi ", "Chang ", "Gao ", "Qi ", "Yuan ", "Tang ", "Teng ", "Shu ", "Shu ", "Fen ", "Fei ", "Wen ", "Ba ", "Diao ", "Tuo ", "Tong ", "Qu ", "Sheng ", "Shi ", "You ", "Shi ", "Ting ", "Wu ", "Nian ", "Jing ", "Hun ", "Ju ", "Yan ", "Tu ", "Ti ", "Xi ", "Xian ", "Yan ", "Lei ", "Bi ", "Yao ", "Qiu ", "Han ", "Wu ", "Wu ", "Hou ", "Xi ", "Ge ", "Zha ", "Xiu ", "Weng ", "Zha ", "Nong ", "Nang ", "Qi ", "Zhai ", "Ji ", "Zi ", "Ji ", "Ji ", "Qi ", "Ji ", "Chi ", "Chen ", "Chen ", "He ", "Ya ", "Ken ", "Xie ", "Pao ", "Cuo ", "Shi ", "Zi ", "Chi ", "Nian ", "Ju ", "Tiao ", "Ling ", "Ling ", "Chu ", "Quan ", "Xie ", "Ken ", "Nie ", "Jiu ", "Yao ", "Chuo ", "Kun ", "Yu ", "Chu ", "Yi ", "Ni ", "Cuo ", "Zou ", "Qu ", "Nen ", "Xian ", "Ou ", "E ", "Wo ", "Yi ", "Chuo ", "Zou ", "Dian ", "Chu ", "Jin ", "Ya ", "Chi ", "Chen ", "He ", "Ken ", "Ju ", "Ling ", "Pao ", "Tiao ", "Zi ", "Ken ", "Yu ", "Chuo ", "Qu ", "Wo ", "Long ", "Pang ", "Gong ", "Pang ", "Yan ", "Long ", "Long ", "Gong ", "Kan ", "Ta ", "Ling ", "Ta ", "Long ", "Gong ", "Kan ", "Gui ", "Qiu ", "Bie ", "Gui ", "Yue ", "Chui ", "He ", "Jue ", "Xie ", "Yu ", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"it", "ix", "i", "ip", "iet", "iex", "ie", "iep", "at", "ax", "a", "ap", "uox", "uo", "uop", "ot", "ox", "o", "op", "ex", "e", "wu", "bit", "bix", "bi", "bip", "biet", "biex", "bie", "biep", "bat", "bax", "ba", "bap", "buox", "buo", "buop", "bot", "box", "bo", "bop", "bex", "be", "bep", "but", "bux", "bu", "bup", "burx", "bur", "byt", "byx", "by", "byp", "byrx", "byr", "pit", "pix", "pi", "pip", "piex", "pie", "piep", "pat", "pax", "pa", "pap", "puox", "puo", "puop", "pot", "pox", "po", "pop", "put", "pux", "pu", "pup", "purx", "pur", "pyt", "pyx", "py", "pyp", "pyrx", "pyr", "bbit", "bbix", "bbi", "bbip", "bbiet", "bbiex", "bbie", "bbiep", "bbat", "bbax", "bba", "bbap", "bbuox", "bbuo", "bbuop", "bbot", "bbox", "bbo", "bbop", "bbex", "bbe", "bbep", "bbut", "bbux", "bbu", "bbup", "bburx", "bbur", "bbyt", "bbyx", "bby", "bbyp", "nbit", "nbix", "nbi", "nbip", "nbiex", "nbie", "nbiep", "nbat", "nbax", "nba", "nbap", "nbot", "nbox", "nbo", "nbop", "nbut", "nbux", "nbu", "nbup", "nburx", "nbur", "nbyt", "nbyx", "nby", "nbyp", "nbyrx", "nbyr", "hmit", "hmix", "hmi", "hmip", "hmiex", "hmie", "hmiep", "hmat", "hmax", "hma", "hmap", "hmuox", "hmuo", "hmuop", "hmot", "hmox", "hmo", "hmop", "hmut", "hmux", "hmu", "hmup", "hmurx", "hmur", "hmyx", "hmy", "hmyp", "hmyrx", "hmyr", "mit", "mix", "mi", "mip", "miex", "mie", "miep", "mat", "max", "ma", "map", "muot", "muox", "muo", "muop", "mot", "mox", "mo", "mop", "mex", "me", "mut", "mux", "mu", "mup", "murx", "mur", "myt", "myx", "my", "myp", "fit", "fix", "fi", "fip", "fat", "fax", "fa", "fap", "fox", "fo", "fop", "fut", "fux", "fu", "fup", "furx", "fur", "fyt", "fyx", "fy", "fyp", "vit", "vix", "vi", "vip", "viet", "viex", "vie", "viep", "vat", "vax", "va", "vap", "vot", "vox", "vo", "vop", "vex", "vep", "vut", "vux", "vu", "vup", "vurx", "vur", "vyt", "vyx", "vy", "vyp", "vyrx", "vyr"},
- {"dit", "dix", "di", "dip", "diex", "die", "diep", "dat", "dax", "da", "dap", "duox", "duo", "dot", "dox", "do", "dop", "dex", "de", "dep", "dut", "dux", "du", "dup", "durx", "dur", "tit", "tix", "ti", "tip", "tiex", "tie", "tiep", "tat", "tax", "ta", "tap", "tuot", "tuox", "tuo", "tuop", "tot", "tox", "to", "top", "tex", "te", "tep", "tut", "tux", "tu", "tup", "turx", "tur", "ddit", "ddix", "ddi", "ddip", "ddiex", "ddie", "ddiep", "ddat", "ddax", "dda", "ddap", "dduox", "dduo", "dduop", "ddot", "ddox", "ddo", "ddop", "ddex", "dde", "ddep", "ddut", "ddux", "ddu", "ddup", "ddurx", "ddur", "ndit", "ndix", "ndi", "ndip", "ndiex", "ndie", "ndat", "ndax", "nda", "ndap", "ndot", "ndox", "ndo", "ndop", "ndex", "nde", "ndep", "ndut", "ndux", "ndu", "ndup", "ndurx", "ndur", "hnit", "hnix", "hni", "hnip", "hniet", "hniex", "hnie", "hniep", "hnat", "hnax", "hna", "hnap", "hnuox", "hnuo", "hnot", "hnox", "hnop", "hnex", "hne", "hnep", "hnut", "nit", "nix", "ni", "nip", "niex", "nie", "niep", "nax", "na", "nap", "nuox", "nuo", "nuop", "not", "nox", "no", "nop", "nex", "ne", "nep", "nut", "nux", "nu", "nup", "nurx", "nur", "hlit", "hlix", "hli", "hlip", "hliex", "hlie", "hliep", "hlat", "hlax", "hla", "hlap", "hluox", "hluo", "hluop", "hlox", "hlo", "hlop", "hlex", "hle", "hlep", "hlut", "hlux", "hlu", "hlup", "hlurx", "hlur", "hlyt", "hlyx", "hly", "hlyp", "hlyrx", "hlyr", "lit", "lix", "li", "lip", "liet", "liex", "lie", "liep", "lat", "lax", "la", "lap", "luot", "luox", "luo", "luop", "lot", "lox", "lo", "lop", "lex", "le", "lep", "lut", "lux", "lu", "lup", "lurx", "lur", "lyt", "lyx", "ly", "lyp", "lyrx", "lyr", "git", "gix", "gi", "gip", "giet", "giex", "gie", "giep", "gat", "gax", "ga", "gap", "guot", "guox", "guo", "guop", "got", "gox", "go", "gop", "get", "gex", "ge", "gep", "gut", "gux", "gu", "gup", "gurx", "gur", "kit", "kix", "ki", "kip", "kiex", "kie", "kiep", "kat"},
- {"kax", "ka", "kap", "kuox", "kuo", "kuop", "kot", "kox", "ko", "kop", "ket", "kex", "ke", "kep", "kut", "kux", "ku", "kup", "kurx", "kur", "ggit", "ggix", "ggi", "ggiex", "ggie", "ggiep", "ggat", "ggax", "gga", "ggap", "gguot", "gguox", "gguo", "gguop", "ggot", "ggox", "ggo", "ggop", "gget", "ggex", "gge", "ggep", "ggut", "ggux", "ggu", "ggup", "ggurx", "ggur", "mgiex", "mgie", "mgat", "mgax", "mga", "mgap", "mguox", "mguo", "mguop", "mgot", "mgox", "mgo", "mgop", "mgex", "mge", "mgep", "mgut", "mgux", "mgu", "mgup", "mgurx", "mgur", "hxit", "hxix", "hxi", "hxip", "hxiet", "hxiex", "hxie", "hxiep", "hxat", "hxax", "hxa", "hxap", "hxuot", "hxuox", "hxuo", "hxuop", "hxot", "hxox", "hxo", "hxop", "hxex", "hxe", "hxep", "ngiex", "ngie", "ngiep", "ngat", "ngax", "nga", "ngap", "nguot", "nguox", "nguo", "ngot", "ngox", "ngo", "ngop", "ngex", "nge", "ngep", "hit", "hiex", "hie", "hat", "hax", "ha", "hap", "huot", "huox", "huo", "huop", "hot", "hox", "ho", "hop", "hex", "he", "hep", "wat", "wax", "wa", "wap", "wuox", "wuo", "wuop", "wox", "wo", "wop", "wex", "we", "wep", "zit", "zix", "zi", "zip", "ziex", "zie", "ziep", "zat", "zax", "za", "zap", "zuox", "zuo", "zuop", "zot", "zox", "zo", "zop", "zex", "ze", "zep", "zut", "zux", "zu", "zup", "zurx", "zur", "zyt", "zyx", "zy", "zyp", "zyrx", "zyr", "cit", "cix", "ci", "cip", "ciet", "ciex", "cie", "ciep", "cat", "cax", "ca", "cap", "cuox", "cuo", "cuop", "cot", "cox", "co", "cop", "cex", "ce", "cep", "cut", "cux", "cu", "cup", "curx", "cur", "cyt", "cyx", "cy", "cyp", "cyrx", "cyr", "zzit", "zzix", "zzi", "zzip", "zziet", "zziex", "zzie", "zziep", "zzat", "zzax", "zza", "zzap", "zzox", "zzo", "zzop", "zzex", "zze", "zzep", "zzux", "zzu", "zzup", "zzurx", "zzur", "zzyt", "zzyx", "zzy", "zzyp", "zzyrx", "zzyr", "nzit", "nzix", "nzi", "nzip", "nziex", "nzie", "nziep", "nzat", "nzax", "nza", "nzap", "nzuox", "nzuo", "nzox", "nzop", "nzex", "nze", "nzux", "nzu"},
- {"nzup", "nzurx", "nzur", "nzyt", "nzyx", "nzy", "nzyp", "nzyrx", "nzyr", "sit", "six", "si", "sip", "siex", "sie", "siep", "sat", "sax", "sa", "sap", "suox", "suo", "suop", "sot", "sox", "so", "sop", "sex", "se", "sep", "sut", "sux", "su", "sup", "surx", "sur", "syt", "syx", "sy", "syp", "syrx", "syr", "ssit", "ssix", "ssi", "ssip", "ssiex", "ssie", "ssiep", "ssat", "ssax", "ssa", "ssap", "ssot", "ssox", "sso", "ssop", "ssex", "sse", "ssep", "ssut", "ssux", "ssu", "ssup", "ssyt", "ssyx", "ssy", "ssyp", "ssyrx", "ssyr", "zhat", "zhax", "zha", "zhap", "zhuox", "zhuo", "zhuop", "zhot", "zhox", "zho", "zhop", "zhet", "zhex", "zhe", "zhep", "zhut", "zhux", "zhu", "zhup", "zhurx", "zhur", "zhyt", "zhyx", "zhy", "zhyp", "zhyrx", "zhyr", "chat", "chax", "cha", "chap", "chuot", "chuox", "chuo", "chuop", "chot", "chox", "cho", "chop", "chet", "chex", "che", "chep", "chux", "chu", "chup", "churx", "chur", "chyt", "chyx", "chy", "chyp", "chyrx", "chyr", "rrax", "rra", "rruox", "rruo", "rrot", "rrox", "rro", "rrop", "rret", "rrex", "rre", "rrep", "rrut", "rrux", "rru", "rrup", "rrurx", "rrur", "rryt", "rryx", "rry", "rryp", "rryrx", "rryr", "nrat", "nrax", "nra", "nrap", "nrox", "nro", "nrop", "nret", "nrex", "nre", "nrep", "nrut", "nrux", "nru", "nrup", "nrurx", "nrur", "nryt", "nryx", "nry", "nryp", "nryrx", "nryr", "shat", "shax", "sha", "shap", "shuox", "shuo", "shuop", "shot", "shox", "sho", "shop", "shet", "shex", "she", "shep", "shut", "shux", "shu", "shup", "shurx", "shur", "shyt", "shyx", "shy", "shyp", "shyrx", "shyr", "rat", "rax", "ra", "rap", "ruox", "ruo", "ruop", "rot", "rox", "ro", "rop", "rex", "re", "rep", "rut", "rux", "ru", "rup", "rurx", "rur", "ryt", "ryx", "ry", "ryp", "ryrx", "ryr", "jit", "jix", "ji", "jip", "jiet", "jiex", "jie", "jiep", "juot", "juox", "juo", "juop", "jot", "jox", "jo", "jop", "jut", "jux", "ju", "jup", "jurx", "jur", "jyt", "jyx", "jy", "jyp", "jyrx", "jyr", "qit", "qix", "qi", "qip"},
- {"qiet", "qiex", "qie", "qiep", "quot", "quox", "quo", "quop", "qot", "qox", "qo", "qop", "qut", "qux", "qu", "qup", "qurx", "qur", "qyt", "qyx", "qy", "qyp", "qyrx", "qyr", "jjit", "jjix", "jji", "jjip", "jjiet", "jjiex", "jjie", "jjiep", "jjuox", "jjuo", "jjuop", "jjot", "jjox", "jjo", "jjop", "jjut", "jjux", "jju", "jjup", "jjurx", "jjur", "jjyt", "jjyx", "jjy", "jjyp", "njit", "njix", "nji", "njip", "njiet", "njiex", "njie", "njiep", "njuox", "njuo", "njot", "njox", "njo", "njop", "njux", "nju", "njup", "njurx", "njur", "njyt", "njyx", "njy", "njyp", "njyrx", "njyr", "nyit", "nyix", "nyi", "nyip", "nyiet", "nyiex", "nyie", "nyiep", "nyuox", "nyuo", "nyuop", "nyot", "nyox", "nyo", "nyop", "nyut", "nyux", "nyu", "nyup", "xit", "xix", "xi", "xip", "xiet", "xiex", "xie", "xiep", "xuox", "xuo", "xot", "xox", "xo", "xop", "xyt", "xyx", "xy", "xyp", "xyrx", "xyr", "yit", "yix", "yi", "yip", "yiet", "yiex", "yie", "yiep", "yuot", "yuox", "yuo", "yuop", "yot", "yox", "yo", "yop", "yut", "yux", "yu", "yup", "yurx", "yur", "yyt", "yyx", "yy", "yyp", "yyrx", "yyr", "[?]", "[?]", "[?]", "Qot", "Li", "Kit", "Nyip", "Cyp", "Ssi", "Ggop", "Gep", "Mi", "Hxit", "Lyr", "Bbut", "Mop", "Yo", "Put", "Hxuo", "Tat", "Ga", "[?]", "[?]", "Ddur", "Bur", "Gguo", "Nyop", "Tu", "Op", "Jjut", "Zot", "Pyt", "Hmo", "Yit", "Vur", "Shy", "Vep", "Za", "Jo", "[?]", "Jjy", "Got", "Jjie", "Wo", "Du", "Shur", "Lie", "Cy", "Cuop", "Cip", "Hxop", "Shat", "[?]", "Shop", "Che", "Zziet", "[?]", "Ke", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"ga", "gag", "gagg", "gags", "gan", "ganj", "ganh", "gad", "gal", "galg", "galm", "galb", "gals", "galt", "galp", "galh", "gam", "gab", "gabs", "gas", "gass", "gang", "gaj", "gac", "gak", "gat", "gap", "gah", "gae", "gaeg", "gaegg", "gaegs", "gaen", "gaenj", "gaenh", "gaed", "gael", "gaelg", "gaelm", "gaelb", "gaels", "gaelt", "gaelp", "gaelh", "gaem", "gaeb", "gaebs", "gaes", "gaess", "gaeng", "gaej", "gaec", "gaek", "gaet", "gaep", "gaeh", "gya", "gyag", "gyagg", "gyags", "gyan", "gyanj", "gyanh", "gyad", "gyal", "gyalg", "gyalm", "gyalb", "gyals", "gyalt", "gyalp", "gyalh", "gyam", "gyab", "gyabs", "gyas", "gyass", "gyang", "gyaj", "gyac", "gyak", "gyat", "gyap", "gyah", "gyae", "gyaeg", "gyaegg", "gyaegs", "gyaen", "gyaenj", "gyaenh", "gyaed", "gyael", "gyaelg", "gyaelm", "gyaelb", "gyaels", "gyaelt", "gyaelp", "gyaelh", "gyaem", "gyaeb", "gyaebs", "gyaes", "gyaess", "gyaeng", "gyaej", "gyaec", "gyaek", "gyaet", "gyaep", "gyaeh", "geo", "geog", "geogg", "geogs", "geon", "geonj", "geonh", "geod", "geol", "geolg", "geolm", "geolb", "geols", "geolt", "geolp", "geolh", "geom", "geob", "geobs", "geos", "geoss", "geong", "geoj", "geoc", "geok", "geot", "geop", "geoh", "ge", "geg", "gegg", "gegs", "gen", "genj", "genh", "ged", "gel", "gelg", "gelm", "gelb", "gels", "gelt", "gelp", "gelh", "gem", "geb", "gebs", "ges", "gess", "geng", "gej", "gec", "gek", "get", "gep", "geh", "gyeo", "gyeog", "gyeogg", "gyeogs", "gyeon", "gyeonj", "gyeonh", "gyeod", "gyeol", "gyeolg", "gyeolm", "gyeolb", "gyeols", "gyeolt", "gyeolp", "gyeolh", "gyeom", "gyeob", "gyeobs", "gyeos", "gyeoss", "gyeong", "gyeoj", "gyeoc", "gyeok", "gyeot", "gyeop", "gyeoh", "gye", "gyeg", "gyegg", "gyegs", "gyen", "gyenj", "gyenh", "gyed", "gyel", "gyelg", "gyelm", "gyelb", "gyels", "gyelt", "gyelp", "gyelh", "gyem", "gyeb", "gyebs", "gyes", "gyess", "gyeng", "gyej", "gyec", "gyek", "gyet", "gyep", "gyeh", "go", "gog", "gogg", "gogs", "gon", "gonj", "gonh", "god", "gol", "golg", "golm", "golb", "gols", "golt", "golp", "golh", "gom", "gob", "gobs", "gos", "goss", "gong", "goj", "goc", "gok", "got", "gop", "goh", "gwa", "gwag", "gwagg", "gwags"},
- {"gwan", "gwanj", "gwanh", "gwad", "gwal", "gwalg", "gwalm", "gwalb", "gwals", "gwalt", "gwalp", "gwalh", "gwam", "gwab", "gwabs", "gwas", "gwass", "gwang", "gwaj", "gwac", "gwak", "gwat", "gwap", "gwah", "gwae", "gwaeg", "gwaegg", "gwaegs", "gwaen", "gwaenj", "gwaenh", "gwaed", "gwael", "gwaelg", "gwaelm", "gwaelb", "gwaels", "gwaelt", "gwaelp", "gwaelh", "gwaem", "gwaeb", "gwaebs", "gwaes", "gwaess", "gwaeng", "gwaej", "gwaec", "gwaek", "gwaet", "gwaep", "gwaeh", "goe", "goeg", "goegg", "goegs", "goen", "goenj", "goenh", "goed", "goel", "goelg", "goelm", "goelb", "goels", "goelt", "goelp", "goelh", "goem", "goeb", "goebs", "goes", "goess", "goeng", "goej", "goec", "goek", "goet", "goep", "goeh", "gyo", "gyog", "gyogg", "gyogs", "gyon", "gyonj", "gyonh", "gyod", "gyol", "gyolg", "gyolm", "gyolb", "gyols", "gyolt", "gyolp", "gyolh", "gyom", "gyob", "gyobs", "gyos", "gyoss", "gyong", "gyoj", "gyoc", "gyok", "gyot", "gyop", "gyoh", "gu", "gug", "gugg", "gugs", "gun", "gunj", "gunh", "gud", "gul", "gulg", "gulm", "gulb", "guls", "gult", "gulp", "gulh", "gum", "gub", "gubs", "gus", "guss", "gung", "guj", "guc", "guk", "gut", "gup", "guh", "gweo", "gweog", "gweogg", "gweogs", "gweon", "gweonj", "gweonh", "gweod", "gweol", "gweolg", "gweolm", "gweolb", "gweols", "gweolt", "gweolp", "gweolh", "gweom", "gweob", "gweobs", "gweos", "gweoss", "gweong", "gweoj", "gweoc", "gweok", "gweot", "gweop", "gweoh", "gwe", "gweg", "gwegg", "gwegs", "gwen", "gwenj", "gwenh", "gwed", "gwel", "gwelg", "gwelm", "gwelb", "gwels", "gwelt", "gwelp", "gwelh", "gwem", "gweb", "gwebs", "gwes", "gwess", "gweng", "gwej", "gwec", "gwek", "gwet", "gwep", "gweh", "gwi", "gwig", "gwigg", "gwigs", "gwin", "gwinj", "gwinh", "gwid", "gwil", "gwilg", "gwilm", "gwilb", "gwils", "gwilt", "gwilp", "gwilh", "gwim", "gwib", "gwibs", "gwis", "gwiss", "gwing", "gwij", "gwic", "gwik", "gwit", "gwip", "gwih", "gyu", "gyug", "gyugg", "gyugs", "gyun", "gyunj", "gyunh", "gyud", "gyul", "gyulg", "gyulm", "gyulb", "gyuls", "gyult", "gyulp", "gyulh", "gyum", "gyub", "gyubs", "gyus", "gyuss", "gyung", "gyuj", "gyuc", "gyuk", "gyut", "gyup", "gyuh", "geu", "geug", "geugg", "geugs", "geun", "geunj", "geunh", "geud"},
- {"geul", "geulg", "geulm", "geulb", "geuls", "geult", "geulp", "geulh", "geum", "geub", "geubs", "geus", "geuss", "geung", "geuj", "geuc", "geuk", "geut", "geup", "geuh", "gyi", "gyig", "gyigg", "gyigs", "gyin", "gyinj", "gyinh", "gyid", "gyil", "gyilg", "gyilm", "gyilb", "gyils", "gyilt", "gyilp", "gyilh", "gyim", "gyib", "gyibs", "gyis", "gyiss", "gying", "gyij", "gyic", "gyik", "gyit", "gyip", "gyih", "gi", "gig", "gigg", "gigs", "gin", "ginj", "ginh", "gid", "gil", "gilg", "gilm", "gilb", "gils", "gilt", "gilp", "gilh", "gim", "gib", "gibs", "gis", "giss", "ging", "gij", "gic", "gik", "git", "gip", "gih", "gga", "ggag", "ggagg", "ggags", "ggan", "gganj", "gganh", "ggad", "ggal", "ggalg", "ggalm", "ggalb", "ggals", "ggalt", "ggalp", "ggalh", "ggam", "ggab", "ggabs", "ggas", "ggass", "ggang", "ggaj", "ggac", "ggak", "ggat", "ggap", "ggah", "ggae", "ggaeg", "ggaegg", "ggaegs", "ggaen", "ggaenj", "ggaenh", "ggaed", "ggael", "ggaelg", "ggaelm", "ggaelb", "ggaels", "ggaelt", "ggaelp", "ggaelh", "ggaem", "ggaeb", "ggaebs", "ggaes", "ggaess", "ggaeng", "ggaej", "ggaec", "ggaek", "ggaet", "ggaep", "ggaeh", "ggya", "ggyag", "ggyagg", "ggyags", "ggyan", "ggyanj", "ggyanh", "ggyad", "ggyal", "ggyalg", "ggyalm", "ggyalb", "ggyals", "ggyalt", "ggyalp", "ggyalh", "ggyam", "ggyab", "ggyabs", "ggyas", "ggyass", "ggyang", "ggyaj", "ggyac", "ggyak", "ggyat", "ggyap", "ggyah", "ggyae", "ggyaeg", "ggyaegg", "ggyaegs", "ggyaen", "ggyaenj", "ggyaenh", "ggyaed", "ggyael", "ggyaelg", "ggyaelm", "ggyaelb", "ggyaels", "ggyaelt", "ggyaelp", "ggyaelh", "ggyaem", "ggyaeb", "ggyaebs", "ggyaes", "ggyaess", "ggyaeng", "ggyaej", "ggyaec", "ggyaek", "ggyaet", "ggyaep", "ggyaeh", "ggeo", "ggeog", "ggeogg", "ggeogs", "ggeon", "ggeonj", "ggeonh", "ggeod", "ggeol", "ggeolg", "ggeolm", "ggeolb", "ggeols", "ggeolt", "ggeolp", "ggeolh", "ggeom", "ggeob", "ggeobs", "ggeos", "ggeoss", "ggeong", "ggeoj", "ggeoc", "ggeok", "ggeot", "ggeop", "ggeoh", "gge", "ggeg", "ggegg", "ggegs", "ggen", "ggenj", "ggenh", "gged", "ggel", "ggelg", "ggelm", "ggelb", "ggels", "ggelt", "ggelp", "ggelh", "ggem", "ggeb", "ggebs", "gges", "ggess", "ggeng", "ggej", "ggec", "ggek", "gget", "ggep", "ggeh", "ggyeo", "ggyeog", "ggyeogg", "ggyeogs", "ggyeon", "ggyeonj", "ggyeonh", "ggyeod", "ggyeol", "ggyeolg", "ggyeolm", "ggyeolb"},
- {"ggyeols", "ggyeolt", "ggyeolp", "ggyeolh", "ggyeom", "ggyeob", "ggyeobs", "ggyeos", "ggyeoss", "ggyeong", "ggyeoj", "ggyeoc", "ggyeok", "ggyeot", "ggyeop", "ggyeoh", "ggye", "ggyeg", "ggyegg", "ggyegs", "ggyen", "ggyenj", "ggyenh", "ggyed", "ggyel", "ggyelg", "ggyelm", "ggyelb", "ggyels", "ggyelt", "ggyelp", "ggyelh", "ggyem", "ggyeb", "ggyebs", "ggyes", "ggyess", "ggyeng", "ggyej", "ggyec", "ggyek", "ggyet", "ggyep", "ggyeh", "ggo", "ggog", "ggogg", "ggogs", "ggon", "ggonj", "ggonh", "ggod", "ggol", "ggolg", "ggolm", "ggolb", "ggols", "ggolt", "ggolp", "ggolh", "ggom", "ggob", "ggobs", "ggos", "ggoss", "ggong", "ggoj", "ggoc", "ggok", "ggot", "ggop", "ggoh", "ggwa", "ggwag", "ggwagg", "ggwags", "ggwan", "ggwanj", "ggwanh", "ggwad", "ggwal", "ggwalg", "ggwalm", "ggwalb", "ggwals", "ggwalt", "ggwalp", "ggwalh", "ggwam", "ggwab", "ggwabs", "ggwas", "ggwass", "ggwang", "ggwaj", "ggwac", "ggwak", "ggwat", "ggwap", "ggwah", "ggwae", "ggwaeg", "ggwaegg", "ggwaegs", "ggwaen", "ggwaenj", "ggwaenh", "ggwaed", "ggwael", "ggwaelg", "ggwaelm", "ggwaelb", "ggwaels", "ggwaelt", "ggwaelp", "ggwaelh", "ggwaem", "ggwaeb", "ggwaebs", "ggwaes", "ggwaess", "ggwaeng", "ggwaej", "ggwaec", "ggwaek", "ggwaet", "ggwaep", "ggwaeh", "ggoe", "ggoeg", "ggoegg", "ggoegs", "ggoen", "ggoenj", "ggoenh", "ggoed", "ggoel", "ggoelg", "ggoelm", "ggoelb", "ggoels", "ggoelt", "ggoelp", "ggoelh", "ggoem", "ggoeb", "ggoebs", "ggoes", "ggoess", "ggoeng", "ggoej", "ggoec", "ggoek", "ggoet", "ggoep", "ggoeh", "ggyo", "ggyog", "ggyogg", "ggyogs", "ggyon", "ggyonj", "ggyonh", "ggyod", "ggyol", "ggyolg", "ggyolm", "ggyolb", "ggyols", "ggyolt", "ggyolp", "ggyolh", "ggyom", "ggyob", "ggyobs", "ggyos", "ggyoss", "ggyong", "ggyoj", "ggyoc", "ggyok", "ggyot", "ggyop", "ggyoh", "ggu", "ggug", "ggugg", "ggugs", "ggun", "ggunj", "ggunh", "ggud", "ggul", "ggulg", "ggulm", "ggulb", "gguls", "ggult", "ggulp", "ggulh", "ggum", "ggub", "ggubs", "ggus", "gguss", "ggung", "gguj", "gguc", "gguk", "ggut", "ggup", "gguh", "ggweo", "ggweog", "ggweogg", "ggweogs", "ggweon", "ggweonj", "ggweonh", "ggweod", "ggweol", "ggweolg", "ggweolm", "ggweolb", "ggweols", "ggweolt", "ggweolp", "ggweolh", "ggweom", "ggweob", "ggweobs", "ggweos", "ggweoss", "ggweong", "ggweoj", "ggweoc", "ggweok", "ggweot", "ggweop", "ggweoh", "ggwe", "ggweg", "ggwegg", "ggwegs", "ggwen", "ggwenj", "ggwenh", "ggwed", "ggwel", "ggwelg", "ggwelm", "ggwelb", "ggwels", "ggwelt", "ggwelp", "ggwelh"},
- {"ggwem", "ggweb", "ggwebs", "ggwes", "ggwess", "ggweng", "ggwej", "ggwec", "ggwek", "ggwet", "ggwep", "ggweh", "ggwi", "ggwig", "ggwigg", "ggwigs", "ggwin", "ggwinj", "ggwinh", "ggwid", "ggwil", "ggwilg", "ggwilm", "ggwilb", "ggwils", "ggwilt", "ggwilp", "ggwilh", "ggwim", "ggwib", "ggwibs", "ggwis", "ggwiss", "ggwing", "ggwij", "ggwic", "ggwik", "ggwit", "ggwip", "ggwih", "ggyu", "ggyug", "ggyugg", "ggyugs", "ggyun", "ggyunj", "ggyunh", "ggyud", "ggyul", "ggyulg", "ggyulm", "ggyulb", "ggyuls", "ggyult", "ggyulp", "ggyulh", "ggyum", "ggyub", "ggyubs", "ggyus", "ggyuss", "ggyung", "ggyuj", "ggyuc", "ggyuk", "ggyut", "ggyup", "ggyuh", "ggeu", "ggeug", "ggeugg", "ggeugs", "ggeun", "ggeunj", "ggeunh", "ggeud", "ggeul", "ggeulg", "ggeulm", "ggeulb", "ggeuls", "ggeult", "ggeulp", "ggeulh", "ggeum", "ggeub", "ggeubs", "ggeus", "ggeuss", "ggeung", "ggeuj", "ggeuc", "ggeuk", "ggeut", "ggeup", "ggeuh", "ggyi", "ggyig", "ggyigg", "ggyigs", "ggyin", "ggyinj", "ggyinh", "ggyid", "ggyil", "ggyilg", "ggyilm", "ggyilb", "ggyils", "ggyilt", "ggyilp", "ggyilh", "ggyim", "ggyib", "ggyibs", "ggyis", "ggyiss", "ggying", "ggyij", "ggyic", "ggyik", "ggyit", "ggyip", "ggyih", "ggi", "ggig", "ggigg", "ggigs", "ggin", "gginj", "gginh", "ggid", "ggil", "ggilg", "ggilm", "ggilb", "ggils", "ggilt", "ggilp", "ggilh", "ggim", "ggib", "ggibs", "ggis", "ggiss", "gging", "ggij", "ggic", "ggik", "ggit", "ggip", "ggih", "na", "nag", "nagg", "nags", "nan", "nanj", "nanh", "nad", "nal", "nalg", "nalm", "nalb", "nals", "nalt", "nalp", "nalh", "nam", "nab", "nabs", "nas", "nass", "nang", "naj", "nac", "nak", "nat", "nap", "nah", "nae", "naeg", "naegg", "naegs", "naen", "naenj", "naenh", "naed", "nael", "naelg", "naelm", "naelb", "naels", "naelt", "naelp", "naelh", "naem", "naeb", "naebs", "naes", "naess", "naeng", "naej", "naec", "naek", "naet", "naep", "naeh", "nya", "nyag", "nyagg", "nyags", "nyan", "nyanj", "nyanh", "nyad", "nyal", "nyalg", "nyalm", "nyalb", "nyals", "nyalt", "nyalp", "nyalh", "nyam", "nyab", "nyabs", "nyas", "nyass", "nyang", "nyaj", "nyac", "nyak", "nyat", "nyap", "nyah", "nyae", "nyaeg", "nyaegg", "nyaegs", "nyaen", "nyaenj", "nyaenh", "nyaed", "nyael", "nyaelg", "nyaelm", "nyaelb", "nyaels", "nyaelt", "nyaelp", "nyaelh", "nyaem", "nyaeb", "nyaebs", "nyaes"},
- {"nyaess", "nyaeng", "nyaej", "nyaec", "nyaek", "nyaet", "nyaep", "nyaeh", "neo", "neog", "neogg", "neogs", "neon", "neonj", "neonh", "neod", "neol", "neolg", "neolm", "neolb", "neols", "neolt", "neolp", "neolh", "neom", "neob", "neobs", "neos", "neoss", "neong", "neoj", "neoc", "neok", "neot", "neop", "neoh", "ne", "neg", "negg", "negs", "nen", "nenj", "nenh", "ned", "nel", "nelg", "nelm", "nelb", "nels", "nelt", "nelp", "nelh", "nem", "neb", "nebs", "nes", "ness", "neng", "nej", "nec", "nek", "net", "nep", "neh", "nyeo", "nyeog", "nyeogg", "nyeogs", "nyeon", "nyeonj", "nyeonh", "nyeod", "nyeol", "nyeolg", "nyeolm", "nyeolb", "nyeols", "nyeolt", "nyeolp", "nyeolh", "nyeom", "nyeob", "nyeobs", "nyeos", "nyeoss", "nyeong", "nyeoj", "nyeoc", "nyeok", "nyeot", "nyeop", "nyeoh", "nye", "nyeg", "nyegg", "nyegs", "nyen", "nyenj", "nyenh", "nyed", "nyel", "nyelg", "nyelm", "nyelb", "nyels", "nyelt", "nyelp", "nyelh", "nyem", "nyeb", "nyebs", "nyes", "nyess", "nyeng", "nyej", "nyec", "nyek", "nyet", "nyep", "nyeh", "no", "nog", "nogg", "nogs", "non", "nonj", "nonh", "nod", "nol", "nolg", "nolm", "nolb", "nols", "nolt", "nolp", "nolh", "nom", "nob", "nobs", "nos", "noss", "nong", "noj", "noc", "nok", "not", "nop", "noh", "nwa", "nwag", "nwagg", "nwags", "nwan", "nwanj", "nwanh", "nwad", "nwal", "nwalg", "nwalm", "nwalb", "nwals", "nwalt", "nwalp", "nwalh", "nwam", "nwab", "nwabs", "nwas", "nwass", "nwang", "nwaj", "nwac", "nwak", "nwat", "nwap", "nwah", "nwae", "nwaeg", "nwaegg", "nwaegs", "nwaen", "nwaenj", "nwaenh", "nwaed", "nwael", "nwaelg", "nwaelm", "nwaelb", "nwaels", "nwaelt", "nwaelp", "nwaelh", "nwaem", "nwaeb", "nwaebs", "nwaes", "nwaess", "nwaeng", "nwaej", "nwaec", "nwaek", "nwaet", "nwaep", "nwaeh", "noe", "noeg", "noegg", "noegs", "noen", "noenj", "noenh", "noed", "noel", "noelg", "noelm", "noelb", "noels", "noelt", "noelp", "noelh", "noem", "noeb", "noebs", "noes", "noess", "noeng", "noej", "noec", "noek", "noet", "noep", "noeh", "nyo", "nyog", "nyogg", "nyogs", "nyon", "nyonj", "nyonh", "nyod", "nyol", "nyolg", "nyolm", "nyolb", "nyols", "nyolt", "nyolp", "nyolh", "nyom", "nyob", "nyobs", "nyos", "nyoss", "nyong", "nyoj", "nyoc"},
- {"nyok", "nyot", "nyop", "nyoh", "nu", "nug", "nugg", "nugs", "nun", "nunj", "nunh", "nud", "nul", "nulg", "nulm", "nulb", "nuls", "nult", "nulp", "nulh", "num", "nub", "nubs", "nus", "nuss", "nung", "nuj", "nuc", "nuk", "nut", "nup", "nuh", "nweo", "nweog", "nweogg", "nweogs", "nweon", "nweonj", "nweonh", "nweod", "nweol", "nweolg", "nweolm", "nweolb", "nweols", "nweolt", "nweolp", "nweolh", "nweom", "nweob", "nweobs", "nweos", "nweoss", "nweong", "nweoj", "nweoc", "nweok", "nweot", "nweop", "nweoh", "nwe", "nweg", "nwegg", "nwegs", "nwen", "nwenj", "nwenh", "nwed", "nwel", "nwelg", "nwelm", "nwelb", "nwels", "nwelt", "nwelp", "nwelh", "nwem", "nweb", "nwebs", "nwes", "nwess", "nweng", "nwej", "nwec", "nwek", "nwet", "nwep", "nweh", "nwi", "nwig", "nwigg", "nwigs", "nwin", "nwinj", "nwinh", "nwid", "nwil", "nwilg", "nwilm", "nwilb", "nwils", "nwilt", "nwilp", "nwilh", "nwim", "nwib", "nwibs", "nwis", "nwiss", "nwing", "nwij", "nwic", "nwik", "nwit", "nwip", "nwih", "nyu", "nyug", "nyugg", "nyugs", "nyun", "nyunj", "nyunh", "nyud", "nyul", "nyulg", "nyulm", "nyulb", "nyuls", "nyult", "nyulp", "nyulh", "nyum", "nyub", "nyubs", "nyus", "nyuss", "nyung", "nyuj", "nyuc", "nyuk", "nyut", "nyup", "nyuh", "neu", "neug", "neugg", "neugs", "neun", "neunj", "neunh", "neud", "neul", "neulg", "neulm", "neulb", "neuls", "neult", "neulp", "neulh", "neum", "neub", "neubs", "neus", "neuss", "neung", "neuj", "neuc", "neuk", "neut", "neup", "neuh", "nyi", "nyig", "nyigg", "nyigs", "nyin", "nyinj", "nyinh", "nyid", "nyil", "nyilg", "nyilm", "nyilb", "nyils", "nyilt", "nyilp", "nyilh", "nyim", "nyib", "nyibs", "nyis", "nyiss", "nying", "nyij", "nyic", "nyik", "nyit", "nyip", "nyih", "ni", "nig", "nigg", "nigs", "nin", "ninj", "ninh", "nid", "nil", "nilg", "nilm", "nilb", "nils", "nilt", "nilp", "nilh", "nim", "nib", "nibs", "nis", "niss", "ning", "nij", "nic", "nik", "nit", "nip", "nih", "da", "dag", "dagg", "dags", "dan", "danj", "danh", "dad", "dal", "dalg", "dalm", "dalb", "dals", "dalt", "dalp", "dalh", "dam", "dab", "dabs", "das", "dass", "dang", "daj", "dac", "dak", "dat", "dap", "dah"},
- {"dae", "daeg", "daegg", "daegs", "daen", "daenj", "daenh", "daed", "dael", "daelg", "daelm", "daelb", "daels", "daelt", "daelp", "daelh", "daem", "daeb", "daebs", "daes", "daess", "daeng", "daej", "daec", "daek", "daet", "daep", "daeh", "dya", "dyag", "dyagg", "dyags", "dyan", "dyanj", "dyanh", "dyad", "dyal", "dyalg", "dyalm", "dyalb", "dyals", "dyalt", "dyalp", "dyalh", "dyam", "dyab", "dyabs", "dyas", "dyass", "dyang", "dyaj", "dyac", "dyak", "dyat", "dyap", "dyah", "dyae", "dyaeg", "dyaegg", "dyaegs", "dyaen", "dyaenj", "dyaenh", "dyaed", "dyael", "dyaelg", "dyaelm", "dyaelb", "dyaels", "dyaelt", "dyaelp", "dyaelh", "dyaem", "dyaeb", "dyaebs", "dyaes", "dyaess", "dyaeng", "dyaej", "dyaec", "dyaek", "dyaet", "dyaep", "dyaeh", "deo", "deog", "deogg", "deogs", "deon", "deonj", "deonh", "deod", "deol", "deolg", "deolm", "deolb", "deols", "deolt", "deolp", "deolh", "deom", "deob", "deobs", "deos", "deoss", "deong", "deoj", "deoc", "deok", "deot", "deop", "deoh", "de", "deg", "degg", "degs", "den", "denj", "denh", "ded", "del", "delg", "delm", "delb", "dels", "delt", "delp", "delh", "dem", "deb", "debs", "des", "dess", "deng", "dej", "dec", "dek", "det", "dep", "deh", "dyeo", "dyeog", "dyeogg", "dyeogs", "dyeon", "dyeonj", "dyeonh", "dyeod", "dyeol", "dyeolg", "dyeolm", "dyeolb", "dyeols", "dyeolt", "dyeolp", "dyeolh", "dyeom", "dyeob", "dyeobs", "dyeos", "dyeoss", "dyeong", "dyeoj", "dyeoc", "dyeok", "dyeot", "dyeop", "dyeoh", "dye", "dyeg", "dyegg", "dyegs", "dyen", "dyenj", "dyenh", "dyed", "dyel", "dyelg", "dyelm", "dyelb", "dyels", "dyelt", "dyelp", "dyelh", "dyem", "dyeb", "dyebs", "dyes", "dyess", "dyeng", "dyej", "dyec", "dyek", "dyet", "dyep", "dyeh", "do", "dog", "dogg", "dogs", "don", "donj", "donh", "dod", "dol", "dolg", "dolm", "dolb", "dols", "dolt", "dolp", "dolh", "dom", "dob", "dobs", "dos", "doss", "dong", "doj", "doc", "dok", "dot", "dop", "doh", "dwa", "dwag", "dwagg", "dwags", "dwan", "dwanj", "dwanh", "dwad", "dwal", "dwalg", "dwalm", "dwalb", "dwals", "dwalt", "dwalp", "dwalh", "dwam", "dwab", "dwabs", "dwas", "dwass", "dwang", "dwaj", "dwac", "dwak", "dwat", "dwap", "dwah", "dwae", "dwaeg", "dwaegg", "dwaegs"},
- {"dwaen", "dwaenj", "dwaenh", "dwaed", "dwael", "dwaelg", "dwaelm", "dwaelb", "dwaels", "dwaelt", "dwaelp", "dwaelh", "dwaem", "dwaeb", "dwaebs", "dwaes", "dwaess", "dwaeng", "dwaej", "dwaec", "dwaek", "dwaet", "dwaep", "dwaeh", "doe", "doeg", "doegg", "doegs", "doen", "doenj", "doenh", "doed", "doel", "doelg", "doelm", "doelb", "doels", "doelt", "doelp", "doelh", "doem", "doeb", "doebs", "does", "doess", "doeng", "doej", "doec", "doek", "doet", "doep", "doeh", "dyo", "dyog", "dyogg", "dyogs", "dyon", "dyonj", "dyonh", "dyod", "dyol", "dyolg", "dyolm", "dyolb", "dyols", "dyolt", "dyolp", "dyolh", "dyom", "dyob", "dyobs", "dyos", "dyoss", "dyong", "dyoj", "dyoc", "dyok", "dyot", "dyop", "dyoh", "du", "dug", "dugg", "dugs", "dun", "dunj", "dunh", "dud", "dul", "dulg", "dulm", "dulb", "duls", "dult", "dulp", "dulh", "dum", "dub", "dubs", "dus", "duss", "dung", "duj", "duc", "duk", "dut", "dup", "duh", "dweo", "dweog", "dweogg", "dweogs", "dweon", "dweonj", "dweonh", "dweod", "dweol", "dweolg", "dweolm", "dweolb", "dweols", "dweolt", "dweolp", "dweolh", "dweom", "dweob", "dweobs", "dweos", "dweoss", "dweong", "dweoj", "dweoc", "dweok", "dweot", "dweop", "dweoh", "dwe", "dweg", "dwegg", "dwegs", "dwen", "dwenj", "dwenh", "dwed", "dwel", "dwelg", "dwelm", "dwelb", "dwels", "dwelt", "dwelp", "dwelh", "dwem", "dweb", "dwebs", "dwes", "dwess", "dweng", "dwej", "dwec", "dwek", "dwet", "dwep", "dweh", "dwi", "dwig", "dwigg", "dwigs", "dwin", "dwinj", "dwinh", "dwid", "dwil", "dwilg", "dwilm", "dwilb", "dwils", "dwilt", "dwilp", "dwilh", "dwim", "dwib", "dwibs", "dwis", "dwiss", "dwing", "dwij", "dwic", "dwik", "dwit", "dwip", "dwih", "dyu", "dyug", "dyugg", "dyugs", "dyun", "dyunj", "dyunh", "dyud", "dyul", "dyulg", "dyulm", "dyulb", "dyuls", "dyult", "dyulp", "dyulh", "dyum", "dyub", "dyubs", "dyus", "dyuss", "dyung", "dyuj", "dyuc", "dyuk", "dyut", "dyup", "dyuh", "deu", "deug", "deugg", "deugs", "deun", "deunj", "deunh", "deud", "deul", "deulg", "deulm", "deulb", "deuls", "deult", "deulp", "deulh", "deum", "deub", "deubs", "deus", "deuss", "deung", "deuj", "deuc", "deuk", "deut", "deup", "deuh", "dyi", "dyig", "dyigg", "dyigs", "dyin", "dyinj", "dyinh", "dyid"},
- {"dyil", "dyilg", "dyilm", "dyilb", "dyils", "dyilt", "dyilp", "dyilh", "dyim", "dyib", "dyibs", "dyis", "dyiss", "dying", "dyij", "dyic", "dyik", "dyit", "dyip", "dyih", "di", "dig", "digg", "digs", "din", "dinj", "dinh", "did", "dil", "dilg", "dilm", "dilb", "dils", "dilt", "dilp", "dilh", "dim", "dib", "dibs", "dis", "diss", "ding", "dij", "dic", "dik", "dit", "dip", "dih", "dda", "ddag", "ddagg", "ddags", "ddan", "ddanj", "ddanh", "ddad", "ddal", "ddalg", "ddalm", "ddalb", "ddals", "ddalt", "ddalp", "ddalh", "ddam", "ddab", "ddabs", "ddas", "ddass", "ddang", "ddaj", "ddac", "ddak", "ddat", "ddap", "ddah", "ddae", "ddaeg", "ddaegg", "ddaegs", "ddaen", "ddaenj", "ddaenh", "ddaed", "ddael", "ddaelg", "ddaelm", "ddaelb", "ddaels", "ddaelt", "ddaelp", "ddaelh", "ddaem", "ddaeb", "ddaebs", "ddaes", "ddaess", "ddaeng", "ddaej", "ddaec", "ddaek", "ddaet", "ddaep", "ddaeh", "ddya", "ddyag", "ddyagg", "ddyags", "ddyan", "ddyanj", "ddyanh", "ddyad", "ddyal", "ddyalg", "ddyalm", "ddyalb", "ddyals", "ddyalt", "ddyalp", "ddyalh", "ddyam", "ddyab", "ddyabs", "ddyas", "ddyass", "ddyang", "ddyaj", "ddyac", "ddyak", "ddyat", "ddyap", "ddyah", "ddyae", "ddyaeg", "ddyaegg", "ddyaegs", "ddyaen", "ddyaenj", "ddyaenh", "ddyaed", "ddyael", "ddyaelg", "ddyaelm", "ddyaelb", "ddyaels", "ddyaelt", "ddyaelp", "ddyaelh", "ddyaem", "ddyaeb", "ddyaebs", "ddyaes", "ddyaess", "ddyaeng", "ddyaej", "ddyaec", "ddyaek", "ddyaet", "ddyaep", "ddyaeh", "ddeo", "ddeog", "ddeogg", "ddeogs", "ddeon", "ddeonj", "ddeonh", "ddeod", "ddeol", "ddeolg", "ddeolm", "ddeolb", "ddeols", "ddeolt", "ddeolp", "ddeolh", "ddeom", "ddeob", "ddeobs", "ddeos", "ddeoss", "ddeong", "ddeoj", "ddeoc", "ddeok", "ddeot", "ddeop", "ddeoh", "dde", "ddeg", "ddegg", "ddegs", "dden", "ddenj", "ddenh", "dded", "ddel", "ddelg", "ddelm", "ddelb", "ddels", "ddelt", "ddelp", "ddelh", "ddem", "ddeb", "ddebs", "ddes", "ddess", "ddeng", "ddej", "ddec", "ddek", "ddet", "ddep", "ddeh", "ddyeo", "ddyeog", "ddyeogg", "ddyeogs", "ddyeon", "ddyeonj", "ddyeonh", "ddyeod", "ddyeol", "ddyeolg", "ddyeolm", "ddyeolb", "ddyeols", "ddyeolt", "ddyeolp", "ddyeolh", "ddyeom", "ddyeob", "ddyeobs", "ddyeos", "ddyeoss", "ddyeong", "ddyeoj", "ddyeoc", "ddyeok", "ddyeot", "ddyeop", "ddyeoh", "ddye", "ddyeg", "ddyegg", "ddyegs", "ddyen", "ddyenj", "ddyenh", "ddyed", "ddyel", "ddyelg", "ddyelm", "ddyelb"},
- {"ddyels", "ddyelt", "ddyelp", "ddyelh", "ddyem", "ddyeb", "ddyebs", "ddyes", "ddyess", "ddyeng", "ddyej", "ddyec", "ddyek", "ddyet", "ddyep", "ddyeh", "ddo", "ddog", "ddogg", "ddogs", "ddon", "ddonj", "ddonh", "ddod", "ddol", "ddolg", "ddolm", "ddolb", "ddols", "ddolt", "ddolp", "ddolh", "ddom", "ddob", "ddobs", "ddos", "ddoss", "ddong", "ddoj", "ddoc", "ddok", "ddot", "ddop", "ddoh", "ddwa", "ddwag", "ddwagg", "ddwags", "ddwan", "ddwanj", "ddwanh", "ddwad", "ddwal", "ddwalg", "ddwalm", "ddwalb", "ddwals", "ddwalt", "ddwalp", "ddwalh", "ddwam", "ddwab", "ddwabs", "ddwas", "ddwass", "ddwang", "ddwaj", "ddwac", "ddwak", "ddwat", "ddwap", "ddwah", "ddwae", "ddwaeg", "ddwaegg", "ddwaegs", "ddwaen", "ddwaenj", "ddwaenh", "ddwaed", "ddwael", "ddwaelg", "ddwaelm", "ddwaelb", "ddwaels", "ddwaelt", "ddwaelp", "ddwaelh", "ddwaem", "ddwaeb", "ddwaebs", "ddwaes", "ddwaess", "ddwaeng", "ddwaej", "ddwaec", "ddwaek", "ddwaet", "ddwaep", "ddwaeh", "ddoe", "ddoeg", "ddoegg", "ddoegs", "ddoen", "ddoenj", "ddoenh", "ddoed", "ddoel", "ddoelg", "ddoelm", "ddoelb", "ddoels", "ddoelt", "ddoelp", "ddoelh", "ddoem", "ddoeb", "ddoebs", "ddoes", "ddoess", "ddoeng", "ddoej", "ddoec", "ddoek", "ddoet", "ddoep", "ddoeh", "ddyo", "ddyog", "ddyogg", "ddyogs", "ddyon", "ddyonj", "ddyonh", "ddyod", "ddyol", "ddyolg", "ddyolm", "ddyolb", "ddyols", "ddyolt", "ddyolp", "ddyolh", "ddyom", "ddyob", "ddyobs", "ddyos", "ddyoss", "ddyong", "ddyoj", "ddyoc", "ddyok", "ddyot", "ddyop", "ddyoh", "ddu", "ddug", "ddugg", "ddugs", "ddun", "ddunj", "ddunh", "ddud", "ddul", "ddulg", "ddulm", "ddulb", "dduls", "ddult", "ddulp", "ddulh", "ddum", "ddub", "ddubs", "ddus", "dduss", "ddung", "dduj", "dduc", "dduk", "ddut", "ddup", "dduh", "ddweo", "ddweog", "ddweogg", "ddweogs", "ddweon", "ddweonj", "ddweonh", "ddweod", "ddweol", "ddweolg", "ddweolm", "ddweolb", "ddweols", "ddweolt", "ddweolp", "ddweolh", "ddweom", "ddweob", "ddweobs", "ddweos", "ddweoss", "ddweong", "ddweoj", "ddweoc", "ddweok", "ddweot", "ddweop", "ddweoh", "ddwe", "ddweg", "ddwegg", "ddwegs", "ddwen", "ddwenj", "ddwenh", "ddwed", "ddwel", "ddwelg", "ddwelm", "ddwelb", "ddwels", "ddwelt", "ddwelp", "ddwelh", "ddwem", "ddweb", "ddwebs", "ddwes", "ddwess", "ddweng", "ddwej", "ddwec", "ddwek", "ddwet", "ddwep", "ddweh", "ddwi", "ddwig", "ddwigg", "ddwigs", "ddwin", "ddwinj", "ddwinh", "ddwid", "ddwil", "ddwilg", "ddwilm", "ddwilb", "ddwils", "ddwilt", "ddwilp", "ddwilh"},
- {"ddwim", "ddwib", "ddwibs", "ddwis", "ddwiss", "ddwing", "ddwij", "ddwic", "ddwik", "ddwit", "ddwip", "ddwih", "ddyu", "ddyug", "ddyugg", "ddyugs", "ddyun", "ddyunj", "ddyunh", "ddyud", "ddyul", "ddyulg", "ddyulm", "ddyulb", "ddyuls", "ddyult", "ddyulp", "ddyulh", "ddyum", "ddyub", "ddyubs", "ddyus", "ddyuss", "ddyung", "ddyuj", "ddyuc", "ddyuk", "ddyut", "ddyup", "ddyuh", "ddeu", "ddeug", "ddeugg", "ddeugs", "ddeun", "ddeunj", "ddeunh", "ddeud", "ddeul", "ddeulg", "ddeulm", "ddeulb", "ddeuls", "ddeult", "ddeulp", "ddeulh", "ddeum", "ddeub", "ddeubs", "ddeus", "ddeuss", "ddeung", "ddeuj", "ddeuc", "ddeuk", "ddeut", "ddeup", "ddeuh", "ddyi", "ddyig", "ddyigg", "ddyigs", "ddyin", "ddyinj", "ddyinh", "ddyid", "ddyil", "ddyilg", "ddyilm", "ddyilb", "ddyils", "ddyilt", "ddyilp", "ddyilh", "ddyim", "ddyib", "ddyibs", "ddyis", "ddyiss", "ddying", "ddyij", "ddyic", "ddyik", "ddyit", "ddyip", "ddyih", "ddi", "ddig", "ddigg", "ddigs", "ddin", "ddinj", "ddinh", "ddid", "ddil", "ddilg", "ddilm", "ddilb", "ddils", "ddilt", "ddilp", "ddilh", "ddim", "ddib", "ddibs", "ddis", "ddiss", "dding", "ddij", "ddic", "ddik", "ddit", "ddip", "ddih", "ra", "rag", "ragg", "rags", "ran", "ranj", "ranh", "rad", "ral", "ralg", "ralm", "ralb", "rals", "ralt", "ralp", "ralh", "ram", "rab", "rabs", "ras", "rass", "rang", "raj", "rac", "rak", "rat", "rap", "rah", "rae", "raeg", "raegg", "raegs", "raen", "raenj", "raenh", "raed", "rael", "raelg", "raelm", "raelb", "raels", "raelt", "raelp", "raelh", "raem", "raeb", "raebs", "raes", "raess", "raeng", "raej", "raec", "raek", "raet", "raep", "raeh", "rya", "ryag", "ryagg", "ryags", "ryan", "ryanj", "ryanh", "ryad", "ryal", "ryalg", "ryalm", "ryalb", "ryals", "ryalt", "ryalp", "ryalh", "ryam", "ryab", "ryabs", "ryas", "ryass", "ryang", "ryaj", "ryac", "ryak", "ryat", "ryap", "ryah", "ryae", "ryaeg", "ryaegg", "ryaegs", "ryaen", "ryaenj", "ryaenh", "ryaed", "ryael", "ryaelg", "ryaelm", "ryaelb", "ryaels", "ryaelt", "ryaelp", "ryaelh", "ryaem", "ryaeb", "ryaebs", "ryaes", "ryaess", "ryaeng", "ryaej", "ryaec", "ryaek", "ryaet", "ryaep", "ryaeh", "reo", "reog", "reogg", "reogs", "reon", "reonj", "reonh", "reod", "reol", "reolg", "reolm", "reolb", "reols", "reolt", "reolp", "reolh", "reom", "reob", "reobs", "reos"},
- {"reoss", "reong", "reoj", "reoc", "reok", "reot", "reop", "reoh", "re", "reg", "regg", "regs", "ren", "renj", "renh", "red", "rel", "relg", "relm", "relb", "rels", "relt", "relp", "relh", "rem", "reb", "rebs", "res", "ress", "reng", "rej", "rec", "rek", "ret", "rep", "reh", "ryeo", "ryeog", "ryeogg", "ryeogs", "ryeon", "ryeonj", "ryeonh", "ryeod", "ryeol", "ryeolg", "ryeolm", "ryeolb", "ryeols", "ryeolt", "ryeolp", "ryeolh", "ryeom", "ryeob", "ryeobs", "ryeos", "ryeoss", "ryeong", "ryeoj", "ryeoc", "ryeok", "ryeot", "ryeop", "ryeoh", "rye", "ryeg", "ryegg", "ryegs", "ryen", "ryenj", "ryenh", "ryed", "ryel", "ryelg", "ryelm", "ryelb", "ryels", "ryelt", "ryelp", "ryelh", "ryem", "ryeb", "ryebs", "ryes", "ryess", "ryeng", "ryej", "ryec", "ryek", "ryet", "ryep", "ryeh", "ro", "rog", "rogg", "rogs", "ron", "ronj", "ronh", "rod", "rol", "rolg", "rolm", "rolb", "rols", "rolt", "rolp", "rolh", "rom", "rob", "robs", "ros", "ross", "rong", "roj", "roc", "rok", "rot", "rop", "roh", "rwa", "rwag", "rwagg", "rwags", "rwan", "rwanj", "rwanh", "rwad", "rwal", "rwalg", "rwalm", "rwalb", "rwals", "rwalt", "rwalp", "rwalh", "rwam", "rwab", "rwabs", "rwas", "rwass", "rwang", "rwaj", "rwac", "rwak", "rwat", "rwap", "rwah", "rwae", "rwaeg", "rwaegg", "rwaegs", "rwaen", "rwaenj", "rwaenh", "rwaed", "rwael", "rwaelg", "rwaelm", "rwaelb", "rwaels", "rwaelt", "rwaelp", "rwaelh", "rwaem", "rwaeb", "rwaebs", "rwaes", "rwaess", "rwaeng", "rwaej", "rwaec", "rwaek", "rwaet", "rwaep", "rwaeh", "roe", "roeg", "roegg", "roegs", "roen", "roenj", "roenh", "roed", "roel", "roelg", "roelm", "roelb", "roels", "roelt", "roelp", "roelh", "roem", "roeb", "roebs", "roes", "roess", "roeng", "roej", "roec", "roek", "roet", "roep", "roeh", "ryo", "ryog", "ryogg", "ryogs", "ryon", "ryonj", "ryonh", "ryod", "ryol", "ryolg", "ryolm", "ryolb", "ryols", "ryolt", "ryolp", "ryolh", "ryom", "ryob", "ryobs", "ryos", "ryoss", "ryong", "ryoj", "ryoc", "ryok", "ryot", "ryop", "ryoh", "ru", "rug", "rugg", "rugs", "run", "runj", "runh", "rud", "rul", "rulg", "rulm", "rulb", "ruls", "rult", "rulp", "rulh", "rum", "rub", "rubs", "rus", "russ", "rung", "ruj", "ruc"},
- {"ruk", "rut", "rup", "ruh", "rweo", "rweog", "rweogg", "rweogs", "rweon", "rweonj", "rweonh", "rweod", "rweol", "rweolg", "rweolm", "rweolb", "rweols", "rweolt", "rweolp", "rweolh", "rweom", "rweob", "rweobs", "rweos", "rweoss", "rweong", "rweoj", "rweoc", "rweok", "rweot", "rweop", "rweoh", "rwe", "rweg", "rwegg", "rwegs", "rwen", "rwenj", "rwenh", "rwed", "rwel", "rwelg", "rwelm", "rwelb", "rwels", "rwelt", "rwelp", "rwelh", "rwem", "rweb", "rwebs", "rwes", "rwess", "rweng", "rwej", "rwec", "rwek", "rwet", "rwep", "rweh", "rwi", "rwig", "rwigg", "rwigs", "rwin", "rwinj", "rwinh", "rwid", "rwil", "rwilg", "rwilm", "rwilb", "rwils", "rwilt", "rwilp", "rwilh", "rwim", "rwib", "rwibs", "rwis", "rwiss", "rwing", "rwij", "rwic", "rwik", "rwit", "rwip", "rwih", "ryu", "ryug", "ryugg", "ryugs", "ryun", "ryunj", "ryunh", "ryud", "ryul", "ryulg", "ryulm", "ryulb", "ryuls", "ryult", "ryulp", "ryulh", "ryum", "ryub", "ryubs", "ryus", "ryuss", "ryung", "ryuj", "ryuc", "ryuk", "ryut", "ryup", "ryuh", "reu", "reug", "reugg", "reugs", "reun", "reunj", "reunh", "reud", "reul", "reulg", "reulm", "reulb", "reuls", "reult", "reulp", "reulh", "reum", "reub", "reubs", "reus", "reuss", "reung", "reuj", "reuc", "reuk", "reut", "reup", "reuh", "ryi", "ryig", "ryigg", "ryigs", "ryin", "ryinj", "ryinh", "ryid", "ryil", "ryilg", "ryilm", "ryilb", "ryils", "ryilt", "ryilp", "ryilh", "ryim", "ryib", "ryibs", "ryis", "ryiss", "rying", "ryij", "ryic", "ryik", "ryit", "ryip", "ryih", "ri", "rig", "rigg", "rigs", "rin", "rinj", "rinh", "rid", "ril", "rilg", "rilm", "rilb", "rils", "rilt", "rilp", "rilh", "rim", "rib", "ribs", "ris", "riss", "ring", "rij", "ric", "rik", "rit", "rip", "rih", "ma", "mag", "magg", "mags", "man", "manj", "manh", "mad", "mal", "malg", "malm", "malb", "mals", "malt", "malp", "malh", "mam", "mab", "mabs", "mas", "mass", "mang", "maj", "mac", "mak", "mat", "map", "mah", "mae", "maeg", "maegg", "maegs", "maen", "maenj", "maenh", "maed", "mael", "maelg", "maelm", "maelb", "maels", "maelt", "maelp", "maelh", "maem", "maeb", "maebs", "maes", "maess", "maeng", "maej", "maec", "maek", "maet", "maep", "maeh"},
- {"mya", "myag", "myagg", "myags", "myan", "myanj", "myanh", "myad", "myal", "myalg", "myalm", "myalb", "myals", "myalt", "myalp", "myalh", "myam", "myab", "myabs", "myas", "myass", "myang", "myaj", "myac", "myak", "myat", "myap", "myah", "myae", "myaeg", "myaegg", "myaegs", "myaen", "myaenj", "myaenh", "myaed", "myael", "myaelg", "myaelm", "myaelb", "myaels", "myaelt", "myaelp", "myaelh", "myaem", "myaeb", "myaebs", "myaes", "myaess", "myaeng", "myaej", "myaec", "myaek", "myaet", "myaep", "myaeh", "meo", "meog", "meogg", "meogs", "meon", "meonj", "meonh", "meod", "meol", "meolg", "meolm", "meolb", "meols", "meolt", "meolp", "meolh", "meom", "meob", "meobs", "meos", "meoss", "meong", "meoj", "meoc", "meok", "meot", "meop", "meoh", "me", "meg", "megg", "megs", "men", "menj", "menh", "med", "mel", "melg", "melm", "melb", "mels", "melt", "melp", "melh", "mem", "meb", "mebs", "mes", "mess", "meng", "mej", "mec", "mek", "met", "mep", "meh", "myeo", "myeog", "myeogg", "myeogs", "myeon", "myeonj", "myeonh", "myeod", "myeol", "myeolg", "myeolm", "myeolb", "myeols", "myeolt", "myeolp", "myeolh", "myeom", "myeob", "myeobs", "myeos", "myeoss", "myeong", "myeoj", "myeoc", "myeok", "myeot", "myeop", "myeoh", "mye", "myeg", "myegg", "myegs", "myen", "myenj", "myenh", "myed", "myel", "myelg", "myelm", "myelb", "myels", "myelt", "myelp", "myelh", "myem", "myeb", "myebs", "myes", "myess", "myeng", "myej", "myec", "myek", "myet", "myep", "myeh", "mo", "mog", "mogg", "mogs", "mon", "monj", "monh", "mod", "mol", "molg", "molm", "molb", "mols", "molt", "molp", "molh", "mom", "mob", "mobs", "mos", "moss", "mong", "moj", "moc", "mok", "mot", "mop", "moh", "mwa", "mwag", "mwagg", "mwags", "mwan", "mwanj", "mwanh", "mwad", "mwal", "mwalg", "mwalm", "mwalb", "mwals", "mwalt", "mwalp", "mwalh", "mwam", "mwab", "mwabs", "mwas", "mwass", "mwang", "mwaj", "mwac", "mwak", "mwat", "mwap", "mwah", "mwae", "mwaeg", "mwaegg", "mwaegs", "mwaen", "mwaenj", "mwaenh", "mwaed", "mwael", "mwaelg", "mwaelm", "mwaelb", "mwaels", "mwaelt", "mwaelp", "mwaelh", "mwaem", "mwaeb", "mwaebs", "mwaes", "mwaess", "mwaeng", "mwaej", "mwaec", "mwaek", "mwaet", "mwaep", "mwaeh", "moe", "moeg", "moegg", "moegs"},
- {"moen", "moenj", "moenh", "moed", "moel", "moelg", "moelm", "moelb", "moels", "moelt", "moelp", "moelh", "moem", "moeb", "moebs", "moes", "moess", "moeng", "moej", "moec", "moek", "moet", "moep", "moeh", "myo", "myog", "myogg", "myogs", "myon", "myonj", "myonh", "myod", "myol", "myolg", "myolm", "myolb", "myols", "myolt", "myolp", "myolh", "myom", "myob", "myobs", "myos", "myoss", "myong", "myoj", "myoc", "myok", "myot", "myop", "myoh", "mu", "mug", "mugg", "mugs", "mun", "munj", "munh", "mud", "mul", "mulg", "mulm", "mulb", "muls", "mult", "mulp", "mulh", "mum", "mub", "mubs", "mus", "muss", "mung", "muj", "muc", "muk", "mut", "mup", "muh", "mweo", "mweog", "mweogg", "mweogs", "mweon", "mweonj", "mweonh", "mweod", "mweol", "mweolg", "mweolm", "mweolb", "mweols", "mweolt", "mweolp", "mweolh", "mweom", "mweob", "mweobs", "mweos", "mweoss", "mweong", "mweoj", "mweoc", "mweok", "mweot", "mweop", "mweoh", "mwe", "mweg", "mwegg", "mwegs", "mwen", "mwenj", "mwenh", "mwed", "mwel", "mwelg", "mwelm", "mwelb", "mwels", "mwelt", "mwelp", "mwelh", "mwem", "mweb", "mwebs", "mwes", "mwess", "mweng", "mwej", "mwec", "mwek", "mwet", "mwep", "mweh", "mwi", "mwig", "mwigg", "mwigs", "mwin", "mwinj", "mwinh", "mwid", "mwil", "mwilg", "mwilm", "mwilb", "mwils", "mwilt", "mwilp", "mwilh", "mwim", "mwib", "mwibs", "mwis", "mwiss", "mwing", "mwij", "mwic", "mwik", "mwit", "mwip", "mwih", "myu", "myug", "myugg", "myugs", "myun", "myunj", "myunh", "myud", "myul", "myulg", "myulm", "myulb", "myuls", "myult", "myulp", "myulh", "myum", "myub", "myubs", "myus", "myuss", "myung", "myuj", "myuc", "myuk", "myut", "myup", "myuh", "meu", "meug", "meugg", "meugs", "meun", "meunj", "meunh", "meud", "meul", "meulg", "meulm", "meulb", "meuls", "meult", "meulp", "meulh", "meum", "meub", "meubs", "meus", "meuss", "meung", "meuj", "meuc", "meuk", "meut", "meup", "meuh", "myi", "myig", "myigg", "myigs", "myin", "myinj", "myinh", "myid", "myil", "myilg", "myilm", "myilb", "myils", "myilt", "myilp", "myilh", "myim", "myib", "myibs", "myis", "myiss", "mying", "myij", "myic", "myik", "myit", "myip", "myih", "mi", "mig", "migg", "migs", "min", "minj", "minh", "mid"},
- {"mil", "milg", "milm", "milb", "mils", "milt", "milp", "milh", "mim", "mib", "mibs", "mis", "miss", "ming", "mij", "mic", "mik", "mit", "mip", "mih", "ba", "bag", "bagg", "bags", "ban", "banj", "banh", "bad", "bal", "balg", "balm", "balb", "bals", "balt", "balp", "balh", "bam", "bab", "babs", "bas", "bass", "bang", "baj", "bac", "bak", "bat", "bap", "bah", "bae", "baeg", "baegg", "baegs", "baen", "baenj", "baenh", "baed", "bael", "baelg", "baelm", "baelb", "baels", "baelt", "baelp", "baelh", "baem", "baeb", "baebs", "baes", "baess", "baeng", "baej", "baec", "baek", "baet", "baep", "baeh", "bya", "byag", "byagg", "byags", "byan", "byanj", "byanh", "byad", "byal", "byalg", "byalm", "byalb", "byals", "byalt", "byalp", "byalh", "byam", "byab", "byabs", "byas", "byass", "byang", "byaj", "byac", "byak", "byat", "byap", "byah", "byae", "byaeg", "byaegg", "byaegs", "byaen", "byaenj", "byaenh", "byaed", "byael", "byaelg", "byaelm", "byaelb", "byaels", "byaelt", "byaelp", "byaelh", "byaem", "byaeb", "byaebs", "byaes", "byaess", "byaeng", "byaej", "byaec", "byaek", "byaet", "byaep", "byaeh", "beo", "beog", "beogg", "beogs", "beon", "beonj", "beonh", "beod", "beol", "beolg", "beolm", "beolb", "beols", "beolt", "beolp", "beolh", "beom", "beob", "beobs", "beos", "beoss", "beong", "beoj", "beoc", "beok", "beot", "beop", "beoh", "be", "beg", "begg", "begs", "ben", "benj", "benh", "bed", "bel", "belg", "belm", "belb", "bels", "belt", "belp", "belh", "bem", "beb", "bebs", "bes", "bess", "beng", "bej", "bec", "bek", "bet", "bep", "beh", "byeo", "byeog", "byeogg", "byeogs", "byeon", "byeonj", "byeonh", "byeod", "byeol", "byeolg", "byeolm", "byeolb", "byeols", "byeolt", "byeolp", "byeolh", "byeom", "byeob", "byeobs", "byeos", "byeoss", "byeong", "byeoj", "byeoc", "byeok", "byeot", "byeop", "byeoh", "bye", "byeg", "byegg", "byegs", "byen", "byenj", "byenh", "byed", "byel", "byelg", "byelm", "byelb", "byels", "byelt", "byelp", "byelh", "byem", "byeb", "byebs", "byes", "byess", "byeng", "byej", "byec", "byek", "byet", "byep", "byeh", "bo", "bog", "bogg", "bogs", "bon", "bonj", "bonh", "bod", "bol", "bolg", "bolm", "bolb"},
- {"bols", "bolt", "bolp", "bolh", "bom", "bob", "bobs", "bos", "boss", "bong", "boj", "boc", "bok", "bot", "bop", "boh", "bwa", "bwag", "bwagg", "bwags", "bwan", "bwanj", "bwanh", "bwad", "bwal", "bwalg", "bwalm", "bwalb", "bwals", "bwalt", "bwalp", "bwalh", "bwam", "bwab", "bwabs", "bwas", "bwass", "bwang", "bwaj", "bwac", "bwak", "bwat", "bwap", "bwah", "bwae", "bwaeg", "bwaegg", "bwaegs", "bwaen", "bwaenj", "bwaenh", "bwaed", "bwael", "bwaelg", "bwaelm", "bwaelb", "bwaels", "bwaelt", "bwaelp", "bwaelh", "bwaem", "bwaeb", "bwaebs", "bwaes", "bwaess", "bwaeng", "bwaej", "bwaec", "bwaek", "bwaet", "bwaep", "bwaeh", "boe", "boeg", "boegg", "boegs", "boen", "boenj", "boenh", "boed", "boel", "boelg", "boelm", "boelb", "boels", "boelt", "boelp", "boelh", "boem", "boeb", "boebs", "boes", "boess", "boeng", "boej", "boec", "boek", "boet", "boep", "boeh", "byo", "byog", "byogg", "byogs", "byon", "byonj", "byonh", "byod", "byol", "byolg", "byolm", "byolb", "byols", "byolt", "byolp", "byolh", "byom", "byob", "byobs", "byos", "byoss", "byong", "byoj", "byoc", "byok", "byot", "byop", "byoh", "bu", "bug", "bugg", "bugs", "bun", "bunj", "bunh", "bud", "bul", "bulg", "bulm", "bulb", "buls", "bult", "bulp", "bulh", "bum", "bub", "bubs", "bus", "buss", "bung", "buj", "buc", "buk", "but", "bup", "buh", "bweo", "bweog", "bweogg", "bweogs", "bweon", "bweonj", "bweonh", "bweod", "bweol", "bweolg", "bweolm", "bweolb", "bweols", "bweolt", "bweolp", "bweolh", "bweom", "bweob", "bweobs", "bweos", "bweoss", "bweong", "bweoj", "bweoc", "bweok", "bweot", "bweop", "bweoh", "bwe", "bweg", "bwegg", "bwegs", "bwen", "bwenj", "bwenh", "bwed", "bwel", "bwelg", "bwelm", "bwelb", "bwels", "bwelt", "bwelp", "bwelh", "bwem", "bweb", "bwebs", "bwes", "bwess", "bweng", "bwej", "bwec", "bwek", "bwet", "bwep", "bweh", "bwi", "bwig", "bwigg", "bwigs", "bwin", "bwinj", "bwinh", "bwid", "bwil", "bwilg", "bwilm", "bwilb", "bwils", "bwilt", "bwilp", "bwilh", "bwim", "bwib", "bwibs", "bwis", "bwiss", "bwing", "bwij", "bwic", "bwik", "bwit", "bwip", "bwih", "byu", "byug", "byugg", "byugs", "byun", "byunj", "byunh", "byud", "byul", "byulg", "byulm", "byulb", "byuls", "byult", "byulp", "byulh"},
- {"byum", "byub", "byubs", "byus", "byuss", "byung", "byuj", "byuc", "byuk", "byut", "byup", "byuh", "beu", "beug", "beugg", "beugs", "beun", "beunj", "beunh", "beud", "beul", "beulg", "beulm", "beulb", "beuls", "beult", "beulp", "beulh", "beum", "beub", "beubs", "beus", "beuss", "beung", "beuj", "beuc", "beuk", "beut", "beup", "beuh", "byi", "byig", "byigg", "byigs", "byin", "byinj", "byinh", "byid", "byil", "byilg", "byilm", "byilb", "byils", "byilt", "byilp", "byilh", "byim", "byib", "byibs", "byis", "byiss", "bying", "byij", "byic", "byik", "byit", "byip", "byih", "bi", "big", "bigg", "bigs", "bin", "binj", "binh", "bid", "bil", "bilg", "bilm", "bilb", "bils", "bilt", "bilp", "bilh", "bim", "bib", "bibs", "bis", "biss", "bing", "bij", "bic", "bik", "bit", "bip", "bih", "bba", "bbag", "bbagg", "bbags", "bban", "bbanj", "bbanh", "bbad", "bbal", "bbalg", "bbalm", "bbalb", "bbals", "bbalt", "bbalp", "bbalh", "bbam", "bbab", "bbabs", "bbas", "bbass", "bbang", "bbaj", "bbac", "bbak", "bbat", "bbap", "bbah", "bbae", "bbaeg", "bbaegg", "bbaegs", "bbaen", "bbaenj", "bbaenh", "bbaed", "bbael", "bbaelg", "bbaelm", "bbaelb", "bbaels", "bbaelt", "bbaelp", "bbaelh", "bbaem", "bbaeb", "bbaebs", "bbaes", "bbaess", "bbaeng", "bbaej", "bbaec", "bbaek", "bbaet", "bbaep", "bbaeh", "bbya", "bbyag", "bbyagg", "bbyags", "bbyan", "bbyanj", "bbyanh", "bbyad", "bbyal", "bbyalg", "bbyalm", "bbyalb", "bbyals", "bbyalt", "bbyalp", "bbyalh", "bbyam", "bbyab", "bbyabs", "bbyas", "bbyass", "bbyang", "bbyaj", "bbyac", "bbyak", "bbyat", "bbyap", "bbyah", "bbyae", "bbyaeg", "bbyaegg", "bbyaegs", "bbyaen", "bbyaenj", "bbyaenh", "bbyaed", "bbyael", "bbyaelg", "bbyaelm", "bbyaelb", "bbyaels", "bbyaelt", "bbyaelp", "bbyaelh", "bbyaem", "bbyaeb", "bbyaebs", "bbyaes", "bbyaess", "bbyaeng", "bbyaej", "bbyaec", "bbyaek", "bbyaet", "bbyaep", "bbyaeh", "bbeo", "bbeog", "bbeogg", "bbeogs", "bbeon", "bbeonj", "bbeonh", "bbeod", "bbeol", "bbeolg", "bbeolm", "bbeolb", "bbeols", "bbeolt", "bbeolp", "bbeolh", "bbeom", "bbeob", "bbeobs", "bbeos", "bbeoss", "bbeong", "bbeoj", "bbeoc", "bbeok", "bbeot", "bbeop", "bbeoh", "bbe", "bbeg", "bbegg", "bbegs", "bben", "bbenj", "bbenh", "bbed", "bbel", "bbelg", "bbelm", "bbelb", "bbels", "bbelt", "bbelp", "bbelh", "bbem", "bbeb", "bbebs", "bbes"},
- {"bbess", "bbeng", "bbej", "bbec", "bbek", "bbet", "bbep", "bbeh", "bbyeo", "bbyeog", "bbyeogg", "bbyeogs", "bbyeon", "bbyeonj", "bbyeonh", "bbyeod", "bbyeol", "bbyeolg", "bbyeolm", "bbyeolb", "bbyeols", "bbyeolt", "bbyeolp", "bbyeolh", "bbyeom", "bbyeob", "bbyeobs", "bbyeos", "bbyeoss", "bbyeong", "bbyeoj", "bbyeoc", "bbyeok", "bbyeot", "bbyeop", "bbyeoh", "bbye", "bbyeg", "bbyegg", "bbyegs", "bbyen", "bbyenj", "bbyenh", "bbyed", "bbyel", "bbyelg", "bbyelm", "bbyelb", "bbyels", "bbyelt", "bbyelp", "bbyelh", "bbyem", "bbyeb", "bbyebs", "bbyes", "bbyess", "bbyeng", "bbyej", "bbyec", "bbyek", "bbyet", "bbyep", "bbyeh", "bbo", "bbog", "bbogg", "bbogs", "bbon", "bbonj", "bbonh", "bbod", "bbol", "bbolg", "bbolm", "bbolb", "bbols", "bbolt", "bbolp", "bbolh", "bbom", "bbob", "bbobs", "bbos", "bboss", "bbong", "bboj", "bboc", "bbok", "bbot", "bbop", "bboh", "bbwa", "bbwag", "bbwagg", "bbwags", "bbwan", "bbwanj", "bbwanh", "bbwad", "bbwal", "bbwalg", "bbwalm", "bbwalb", "bbwals", "bbwalt", "bbwalp", "bbwalh", "bbwam", "bbwab", "bbwabs", "bbwas", "bbwass", "bbwang", "bbwaj", "bbwac", "bbwak", "bbwat", "bbwap", "bbwah", "bbwae", "bbwaeg", "bbwaegg", "bbwaegs", "bbwaen", "bbwaenj", "bbwaenh", "bbwaed", "bbwael", "bbwaelg", "bbwaelm", "bbwaelb", "bbwaels", "bbwaelt", "bbwaelp", "bbwaelh", "bbwaem", "bbwaeb", "bbwaebs", "bbwaes", "bbwaess", "bbwaeng", "bbwaej", "bbwaec", "bbwaek", "bbwaet", "bbwaep", "bbwaeh", "bboe", "bboeg", "bboegg", "bboegs", "bboen", "bboenj", "bboenh", "bboed", "bboel", "bboelg", "bboelm", "bboelb", "bboels", "bboelt", "bboelp", "bboelh", "bboem", "bboeb", "bboebs", "bboes", "bboess", "bboeng", "bboej", "bboec", "bboek", "bboet", "bboep", "bboeh", "bbyo", "bbyog", "bbyogg", "bbyogs", "bbyon", "bbyonj", "bbyonh", "bbyod", "bbyol", "bbyolg", "bbyolm", "bbyolb", "bbyols", "bbyolt", "bbyolp", "bbyolh", "bbyom", "bbyob", "bbyobs", "bbyos", "bbyoss", "bbyong", "bbyoj", "bbyoc", "bbyok", "bbyot", "bbyop", "bbyoh", "bbu", "bbug", "bbugg", "bbugs", "bbun", "bbunj", "bbunh", "bbud", "bbul", "bbulg", "bbulm", "bbulb", "bbuls", "bbult", "bbulp", "bbulh", "bbum", "bbub", "bbubs", "bbus", "bbuss", "bbung", "bbuj", "bbuc", "bbuk", "bbut", "bbup", "bbuh", "bbweo", "bbweog", "bbweogg", "bbweogs", "bbweon", "bbweonj", "bbweonh", "bbweod", "bbweol", "bbweolg", "bbweolm", "bbweolb", "bbweols", "bbweolt", "bbweolp", "bbweolh", "bbweom", "bbweob", "bbweobs", "bbweos", "bbweoss", "bbweong", "bbweoj", "bbweoc"},
- {"bbweok", "bbweot", "bbweop", "bbweoh", "bbwe", "bbweg", "bbwegg", "bbwegs", "bbwen", "bbwenj", "bbwenh", "bbwed", "bbwel", "bbwelg", "bbwelm", "bbwelb", "bbwels", "bbwelt", "bbwelp", "bbwelh", "bbwem", "bbweb", "bbwebs", "bbwes", "bbwess", "bbweng", "bbwej", "bbwec", "bbwek", "bbwet", "bbwep", "bbweh", "bbwi", "bbwig", "bbwigg", "bbwigs", "bbwin", "bbwinj", "bbwinh", "bbwid", "bbwil", "bbwilg", "bbwilm", "bbwilb", "bbwils", "bbwilt", "bbwilp", "bbwilh", "bbwim", "bbwib", "bbwibs", "bbwis", "bbwiss", "bbwing", "bbwij", "bbwic", "bbwik", "bbwit", "bbwip", "bbwih", "bbyu", "bbyug", "bbyugg", "bbyugs", "bbyun", "bbyunj", "bbyunh", "bbyud", "bbyul", "bbyulg", "bbyulm", "bbyulb", "bbyuls", "bbyult", "bbyulp", "bbyulh", "bbyum", "bbyub", "bbyubs", "bbyus", "bbyuss", "bbyung", "bbyuj", "bbyuc", "bbyuk", "bbyut", "bbyup", "bbyuh", "bbeu", "bbeug", "bbeugg", "bbeugs", "bbeun", "bbeunj", "bbeunh", "bbeud", "bbeul", "bbeulg", "bbeulm", "bbeulb", "bbeuls", "bbeult", "bbeulp", "bbeulh", "bbeum", "bbeub", "bbeubs", "bbeus", "bbeuss", "bbeung", "bbeuj", "bbeuc", "bbeuk", "bbeut", "bbeup", "bbeuh", "bbyi", "bbyig", "bbyigg", "bbyigs", "bbyin", "bbyinj", "bbyinh", "bbyid", "bbyil", "bbyilg", "bbyilm", "bbyilb", "bbyils", "bbyilt", "bbyilp", "bbyilh", "bbyim", "bbyib", "bbyibs", "bbyis", "bbyiss", "bbying", "bbyij", "bbyic", "bbyik", "bbyit", "bbyip", "bbyih", "bbi", "bbig", "bbigg", "bbigs", "bbin", "bbinj", "bbinh", "bbid", "bbil", "bbilg", "bbilm", "bbilb", "bbils", "bbilt", "bbilp", "bbilh", "bbim", "bbib", "bbibs", "bbis", "bbiss", "bbing", "bbij", "bbic", "bbik", "bbit", "bbip", "bbih", "sa", "sag", "sagg", "sags", "san", "sanj", "sanh", "sad", "sal", "salg", "salm", "salb", "sals", "salt", "salp", "salh", "sam", "sab", "sabs", "sas", "sass", "sang", "saj", "sac", "sak", "sat", "sap", "sah", "sae", "saeg", "saegg", "saegs", "saen", "saenj", "saenh", "saed", "sael", "saelg", "saelm", "saelb", "saels", "saelt", "saelp", "saelh", "saem", "saeb", "saebs", "saes", "saess", "saeng", "saej", "saec", "saek", "saet", "saep", "saeh", "sya", "syag", "syagg", "syags", "syan", "syanj", "syanh", "syad", "syal", "syalg", "syalm", "syalb", "syals", "syalt", "syalp", "syalh", "syam", "syab", "syabs", "syas", "syass", "syang", "syaj", "syac", "syak", "syat", "syap", "syah"},
- {"syae", "syaeg", "syaegg", "syaegs", "syaen", "syaenj", "syaenh", "syaed", "syael", "syaelg", "syaelm", "syaelb", "syaels", "syaelt", "syaelp", "syaelh", "syaem", "syaeb", "syaebs", "syaes", "syaess", "syaeng", "syaej", "syaec", "syaek", "syaet", "syaep", "syaeh", "seo", "seog", "seogg", "seogs", "seon", "seonj", "seonh", "seod", "seol", "seolg", "seolm", "seolb", "seols", "seolt", "seolp", "seolh", "seom", "seob", "seobs", "seos", "seoss", "seong", "seoj", "seoc", "seok", "seot", "seop", "seoh", "se", "seg", "segg", "segs", "sen", "senj", "senh", "sed", "sel", "selg", "selm", "selb", "sels", "selt", "selp", "selh", "sem", "seb", "sebs", "ses", "sess", "seng", "sej", "sec", "sek", "set", "sep", "seh", "syeo", "syeog", "syeogg", "syeogs", "syeon", "syeonj", "syeonh", "syeod", "syeol", "syeolg", "syeolm", "syeolb", "syeols", "syeolt", "syeolp", "syeolh", "syeom", "syeob", "syeobs", "syeos", "syeoss", "syeong", "syeoj", "syeoc", "syeok", "syeot", "syeop", "syeoh", "sye", "syeg", "syegg", "syegs", "syen", "syenj", "syenh", "syed", "syel", "syelg", "syelm", "syelb", "syels", "syelt", "syelp", "syelh", "syem", "syeb", "syebs", "syes", "syess", "syeng", "syej", "syec", "syek", "syet", "syep", "syeh", "so", "sog", "sogg", "sogs", "son", "sonj", "sonh", "sod", "sol", "solg", "solm", "solb", "sols", "solt", "solp", "solh", "som", "sob", "sobs", "sos", "soss", "song", "soj", "soc", "sok", "sot", "sop", "soh", "swa", "swag", "swagg", "swags", "swan", "swanj", "swanh", "swad", "swal", "swalg", "swalm", "swalb", "swals", "swalt", "swalp", "swalh", "swam", "swab", "swabs", "swas", "swass", "swang", "swaj", "swac", "swak", "swat", "swap", "swah", "swae", "swaeg", "swaegg", "swaegs", "swaen", "swaenj", "swaenh", "swaed", "swael", "swaelg", "swaelm", "swaelb", "swaels", "swaelt", "swaelp", "swaelh", "swaem", "swaeb", "swaebs", "swaes", "swaess", "swaeng", "swaej", "swaec", "swaek", "swaet", "swaep", "swaeh", "soe", "soeg", "soegg", "soegs", "soen", "soenj", "soenh", "soed", "soel", "soelg", "soelm", "soelb", "soels", "soelt", "soelp", "soelh", "soem", "soeb", "soebs", "soes", "soess", "soeng", "soej", "soec", "soek", "soet", "soep", "soeh", "syo", "syog", "syogg", "syogs"},
- {"syon", "syonj", "syonh", "syod", "syol", "syolg", "syolm", "syolb", "syols", "syolt", "syolp", "syolh", "syom", "syob", "syobs", "syos", "syoss", "syong", "syoj", "syoc", "syok", "syot", "syop", "syoh", "su", "sug", "sugg", "sugs", "sun", "sunj", "sunh", "sud", "sul", "sulg", "sulm", "sulb", "suls", "sult", "sulp", "sulh", "sum", "sub", "subs", "sus", "suss", "sung", "suj", "suc", "suk", "sut", "sup", "suh", "sweo", "sweog", "sweogg", "sweogs", "sweon", "sweonj", "sweonh", "sweod", "sweol", "sweolg", "sweolm", "sweolb", "sweols", "sweolt", "sweolp", "sweolh", "sweom", "sweob", "sweobs", "sweos", "sweoss", "sweong", "sweoj", "sweoc", "sweok", "sweot", "sweop", "sweoh", "swe", "sweg", "swegg", "swegs", "swen", "swenj", "swenh", "swed", "swel", "swelg", "swelm", "swelb", "swels", "swelt", "swelp", "swelh", "swem", "sweb", "swebs", "swes", "swess", "sweng", "swej", "swec", "swek", "swet", "swep", "sweh", "swi", "swig", "swigg", "swigs", "swin", "swinj", "swinh", "swid", "swil", "swilg", "swilm", "swilb", "swils", "swilt", "swilp", "swilh", "swim", "swib", "swibs", "swis", "swiss", "swing", "swij", "swic", "swik", "swit", "swip", "swih", "syu", "syug", "syugg", "syugs", "syun", "syunj", "syunh", "syud", "syul", "syulg", "syulm", "syulb", "syuls", "syult", "syulp", "syulh", "syum", "syub", "syubs", "syus", "syuss", "syung", "syuj", "syuc", "syuk", "syut", "syup", "syuh", "seu", "seug", "seugg", "seugs", "seun", "seunj", "seunh", "seud", "seul", "seulg", "seulm", "seulb", "seuls", "seult", "seulp", "seulh", "seum", "seub", "seubs", "seus", "seuss", "seung", "seuj", "seuc", "seuk", "seut", "seup", "seuh", "syi", "syig", "syigg", "syigs", "syin", "syinj", "syinh", "syid", "syil", "syilg", "syilm", "syilb", "syils", "syilt", "syilp", "syilh", "syim", "syib", "syibs", "syis", "syiss", "sying", "syij", "syic", "syik", "syit", "syip", "syih", "si", "sig", "sigg", "sigs", "sin", "sinj", "sinh", "sid", "sil", "silg", "silm", "silb", "sils", "silt", "silp", "silh", "sim", "sib", "sibs", "sis", "siss", "sing", "sij", "sic", "sik", "sit", "sip", "sih", "ssa", "ssag", "ssagg", "ssags", "ssan", "ssanj", "ssanh", "ssad"},
- {"ssal", "ssalg", "ssalm", "ssalb", "ssals", "ssalt", "ssalp", "ssalh", "ssam", "ssab", "ssabs", "ssas", "ssass", "ssang", "ssaj", "ssac", "ssak", "ssat", "ssap", "ssah", "ssae", "ssaeg", "ssaegg", "ssaegs", "ssaen", "ssaenj", "ssaenh", "ssaed", "ssael", "ssaelg", "ssaelm", "ssaelb", "ssaels", "ssaelt", "ssaelp", "ssaelh", "ssaem", "ssaeb", "ssaebs", "ssaes", "ssaess", "ssaeng", "ssaej", "ssaec", "ssaek", "ssaet", "ssaep", "ssaeh", "ssya", "ssyag", "ssyagg", "ssyags", "ssyan", "ssyanj", "ssyanh", "ssyad", "ssyal", "ssyalg", "ssyalm", "ssyalb", "ssyals", "ssyalt", "ssyalp", "ssyalh", "ssyam", "ssyab", "ssyabs", "ssyas", "ssyass", "ssyang", "ssyaj", "ssyac", "ssyak", "ssyat", "ssyap", "ssyah", "ssyae", "ssyaeg", "ssyaegg", "ssyaegs", "ssyaen", "ssyaenj", "ssyaenh", "ssyaed", "ssyael", "ssyaelg", "ssyaelm", "ssyaelb", "ssyaels", "ssyaelt", "ssyaelp", "ssyaelh", "ssyaem", "ssyaeb", "ssyaebs", "ssyaes", "ssyaess", "ssyaeng", "ssyaej", "ssyaec", "ssyaek", "ssyaet", "ssyaep", "ssyaeh", "sseo", "sseog", "sseogg", "sseogs", "sseon", "sseonj", "sseonh", "sseod", "sseol", "sseolg", "sseolm", "sseolb", "sseols", "sseolt", "sseolp", "sseolh", "sseom", "sseob", "sseobs", "sseos", "sseoss", "sseong", "sseoj", "sseoc", "sseok", "sseot", "sseop", "sseoh", "sse", "sseg", "ssegg", "ssegs", "ssen", "ssenj", "ssenh", "ssed", "ssel", "sselg", "sselm", "sselb", "ssels", "sselt", "sselp", "sselh", "ssem", "sseb", "ssebs", "sses", "ssess", "sseng", "ssej", "ssec", "ssek", "sset", "ssep", "sseh", "ssyeo", "ssyeog", "ssyeogg", "ssyeogs", "ssyeon", "ssyeonj", "ssyeonh", "ssyeod", "ssyeol", "ssyeolg", "ssyeolm", "ssyeolb", "ssyeols", "ssyeolt", "ssyeolp", "ssyeolh", "ssyeom", "ssyeob", "ssyeobs", "ssyeos", "ssyeoss", "ssyeong", "ssyeoj", "ssyeoc", "ssyeok", "ssyeot", "ssyeop", "ssyeoh", "ssye", "ssyeg", "ssyegg", "ssyegs", "ssyen", "ssyenj", "ssyenh", "ssyed", "ssyel", "ssyelg", "ssyelm", "ssyelb", "ssyels", "ssyelt", "ssyelp", "ssyelh", "ssyem", "ssyeb", "ssyebs", "ssyes", "ssyess", "ssyeng", "ssyej", "ssyec", "ssyek", "ssyet", "ssyep", "ssyeh", "sso", "ssog", "ssogg", "ssogs", "sson", "ssonj", "ssonh", "ssod", "ssol", "ssolg", "ssolm", "ssolb", "ssols", "ssolt", "ssolp", "ssolh", "ssom", "ssob", "ssobs", "ssos", "ssoss", "ssong", "ssoj", "ssoc", "ssok", "ssot", "ssop", "ssoh", "sswa", "sswag", "sswagg", "sswags", "sswan", "sswanj", "sswanh", "sswad", "sswal", "sswalg", "sswalm", "sswalb"},
- {"sswals", "sswalt", "sswalp", "sswalh", "sswam", "sswab", "sswabs", "sswas", "sswass", "sswang", "sswaj", "sswac", "sswak", "sswat", "sswap", "sswah", "sswae", "sswaeg", "sswaegg", "sswaegs", "sswaen", "sswaenj", "sswaenh", "sswaed", "sswael", "sswaelg", "sswaelm", "sswaelb", "sswaels", "sswaelt", "sswaelp", "sswaelh", "sswaem", "sswaeb", "sswaebs", "sswaes", "sswaess", "sswaeng", "sswaej", "sswaec", "sswaek", "sswaet", "sswaep", "sswaeh", "ssoe", "ssoeg", "ssoegg", "ssoegs", "ssoen", "ssoenj", "ssoenh", "ssoed", "ssoel", "ssoelg", "ssoelm", "ssoelb", "ssoels", "ssoelt", "ssoelp", "ssoelh", "ssoem", "ssoeb", "ssoebs", "ssoes", "ssoess", "ssoeng", "ssoej", "ssoec", "ssoek", "ssoet", "ssoep", "ssoeh", "ssyo", "ssyog", "ssyogg", "ssyogs", "ssyon", "ssyonj", "ssyonh", "ssyod", "ssyol", "ssyolg", "ssyolm", "ssyolb", "ssyols", "ssyolt", "ssyolp", "ssyolh", "ssyom", "ssyob", "ssyobs", "ssyos", "ssyoss", "ssyong", "ssyoj", "ssyoc", "ssyok", "ssyot", "ssyop", "ssyoh", "ssu", "ssug", "ssugg", "ssugs", "ssun", "ssunj", "ssunh", "ssud", "ssul", "ssulg", "ssulm", "ssulb", "ssuls", "ssult", "ssulp", "ssulh", "ssum", "ssub", "ssubs", "ssus", "ssuss", "ssung", "ssuj", "ssuc", "ssuk", "ssut", "ssup", "ssuh", "ssweo", "ssweog", "ssweogg", "ssweogs", "ssweon", "ssweonj", "ssweonh", "ssweod", "ssweol", "ssweolg", "ssweolm", "ssweolb", "ssweols", "ssweolt", "ssweolp", "ssweolh", "ssweom", "ssweob", "ssweobs", "ssweos", "ssweoss", "ssweong", "ssweoj", "ssweoc", "ssweok", "ssweot", "ssweop", "ssweoh", "sswe", "ssweg", "sswegg", "sswegs", "sswen", "sswenj", "sswenh", "sswed", "sswel", "sswelg", "sswelm", "sswelb", "sswels", "sswelt", "sswelp", "sswelh", "sswem", "ssweb", "sswebs", "sswes", "sswess", "ssweng", "sswej", "sswec", "sswek", "sswet", "sswep", "ssweh", "sswi", "sswig", "sswigg", "sswigs", "sswin", "sswinj", "sswinh", "sswid", "sswil", "sswilg", "sswilm", "sswilb", "sswils", "sswilt", "sswilp", "sswilh", "sswim", "sswib", "sswibs", "sswis", "sswiss", "sswing", "sswij", "sswic", "sswik", "sswit", "sswip", "sswih", "ssyu", "ssyug", "ssyugg", "ssyugs", "ssyun", "ssyunj", "ssyunh", "ssyud", "ssyul", "ssyulg", "ssyulm", "ssyulb", "ssyuls", "ssyult", "ssyulp", "ssyulh", "ssyum", "ssyub", "ssyubs", "ssyus", "ssyuss", "ssyung", "ssyuj", "ssyuc", "ssyuk", "ssyut", "ssyup", "ssyuh", "sseu", "sseug", "sseugg", "sseugs", "sseun", "sseunj", "sseunh", "sseud", "sseul", "sseulg", "sseulm", "sseulb", "sseuls", "sseult", "sseulp", "sseulh"},
- {"sseum", "sseub", "sseubs", "sseus", "sseuss", "sseung", "sseuj", "sseuc", "sseuk", "sseut", "sseup", "sseuh", "ssyi", "ssyig", "ssyigg", "ssyigs", "ssyin", "ssyinj", "ssyinh", "ssyid", "ssyil", "ssyilg", "ssyilm", "ssyilb", "ssyils", "ssyilt", "ssyilp", "ssyilh", "ssyim", "ssyib", "ssyibs", "ssyis", "ssyiss", "ssying", "ssyij", "ssyic", "ssyik", "ssyit", "ssyip", "ssyih", "ssi", "ssig", "ssigg", "ssigs", "ssin", "ssinj", "ssinh", "ssid", "ssil", "ssilg", "ssilm", "ssilb", "ssils", "ssilt", "ssilp", "ssilh", "ssim", "ssib", "ssibs", "ssis", "ssiss", "ssing", "ssij", "ssic", "ssik", "ssit", "ssip", "ssih", "a", "ag", "agg", "ags", "an", "anj", "anh", "ad", "al", "alg", "alm", "alb", "als", "alt", "alp", "alh", "am", "ab", "abs", "as", "ass", "ang", "aj", "ac", "ak", "at", "ap", "ah", "ae", "aeg", "aegg", "aegs", "aen", "aenj", "aenh", "aed", "ael", "aelg", "aelm", "aelb", "aels", "aelt", "aelp", "aelh", "aem", "aeb", "aebs", "aes", "aess", "aeng", "aej", "aec", "aek", "aet", "aep", "aeh", "ya", "yag", "yagg", "yags", "yan", "yanj", "yanh", "yad", "yal", "yalg", "yalm", "yalb", "yals", "yalt", "yalp", "yalh", "yam", "yab", "yabs", "yas", "yass", "yang", "yaj", "yac", "yak", "yat", "yap", "yah", "yae", "yaeg", "yaegg", "yaegs", "yaen", "yaenj", "yaenh", "yaed", "yael", "yaelg", "yaelm", "yaelb", "yaels", "yaelt", "yaelp", "yaelh", "yaem", "yaeb", "yaebs", "yaes", "yaess", "yaeng", "yaej", "yaec", "yaek", "yaet", "yaep", "yaeh", "eo", "eog", "eogg", "eogs", "eon", "eonj", "eonh", "eod", "eol", "eolg", "eolm", "eolb", "eols", "eolt", "eolp", "eolh", "eom", "eob", "eobs", "eos", "eoss", "eong", "eoj", "eoc", "eok", "eot", "eop", "eoh", "e", "eg", "egg", "egs", "en", "enj", "enh", "ed", "el", "elg", "elm", "elb", "els", "elt", "elp", "elh", "em", "eb", "ebs", "es", "ess", "eng", "ej", "ec", "ek", "et", "ep", "eh", "yeo", "yeog", "yeogg", "yeogs", "yeon", "yeonj", "yeonh", "yeod", "yeol", "yeolg", "yeolm", "yeolb", "yeols", "yeolt", "yeolp", "yeolh", "yeom", "yeob", "yeobs", "yeos"},
- {"yeoss", "yeong", "yeoj", "yeoc", "yeok", "yeot", "yeop", "yeoh", "ye", "yeg", "yegg", "yegs", "yen", "yenj", "yenh", "yed", "yel", "yelg", "yelm", "yelb", "yels", "yelt", "yelp", "yelh", "yem", "yeb", "yebs", "yes", "yess", "yeng", "yej", "yec", "yek", "yet", "yep", "yeh", "o", "og", "ogg", "ogs", "on", "onj", "onh", "od", "ol", "olg", "olm", "olb", "ols", "olt", "olp", "olh", "om", "ob", "obs", "os", "oss", "ong", "oj", "oc", "ok", "ot", "op", "oh", "wa", "wag", "wagg", "wags", "wan", "wanj", "wanh", "wad", "wal", "walg", "walm", "walb", "wals", "walt", "walp", "walh", "wam", "wab", "wabs", "was", "wass", "wang", "waj", "wac", "wak", "wat", "wap", "wah", "wae", "waeg", "waegg", "waegs", "waen", "waenj", "waenh", "waed", "wael", "waelg", "waelm", "waelb", "waels", "waelt", "waelp", "waelh", "waem", "waeb", "waebs", "waes", "waess", "waeng", "waej", "waec", "waek", "waet", "waep", "waeh", "oe", "oeg", "oegg", "oegs", "oen", "oenj", "oenh", "oed", "oel", "oelg", "oelm", "oelb", "oels", "oelt", "oelp", "oelh", "oem", "oeb", "oebs", "oes", "oess", "oeng", "oej", "oec", "oek", "oet", "oep", "oeh", "yo", "yog", "yogg", "yogs", "yon", "yonj", "yonh", "yod", "yol", "yolg", "yolm", "yolb", "yols", "yolt", "yolp", "yolh", "yom", "yob", "yobs", "yos", "yoss", "yong", "yoj", "yoc", "yok", "yot", "yop", "yoh", "u", "ug", "ugg", "ugs", "un", "unj", "unh", "ud", "ul", "ulg", "ulm", "ulb", "uls", "ult", "ulp", "ulh", "um", "ub", "ubs", "us", "uss", "ung", "uj", "uc", "uk", "ut", "up", "uh", "weo", "weog", "weogg", "weogs", "weon", "weonj", "weonh", "weod", "weol", "weolg", "weolm", "weolb", "weols", "weolt", "weolp", "weolh", "weom", "weob", "weobs", "weos", "weoss", "weong", "weoj", "weoc", "weok", "weot", "weop", "weoh", "we", "weg", "wegg", "wegs", "wen", "wenj", "wenh", "wed", "wel", "welg", "welm", "welb", "wels", "welt", "welp", "welh", "wem", "web", "webs", "wes", "wess", "weng", "wej", "wec"},
- {"wek", "wet", "wep", "weh", "wi", "wig", "wigg", "wigs", "win", "winj", "winh", "wid", "wil", "wilg", "wilm", "wilb", "wils", "wilt", "wilp", "wilh", "wim", "wib", "wibs", "wis", "wiss", "wing", "wij", "wic", "wik", "wit", "wip", "wih", "yu", "yug", "yugg", "yugs", "yun", "yunj", "yunh", "yud", "yul", "yulg", "yulm", "yulb", "yuls", "yult", "yulp", "yulh", "yum", "yub", "yubs", "yus", "yuss", "yung", "yuj", "yuc", "yuk", "yut", "yup", "yuh", "eu", "eug", "eugg", "eugs", "eun", "eunj", "eunh", "eud", "eul", "eulg", "eulm", "eulb", "euls", "eult", "eulp", "eulh", "eum", "eub", "eubs", "eus", "euss", "eung", "euj", "euc", "euk", "eut", "eup", "euh", "yi", "yig", "yigg", "yigs", "yin", "yinj", "yinh", "yid", "yil", "yilg", "yilm", "yilb", "yils", "yilt", "yilp", "yilh", "yim", "yib", "yibs", "yis", "yiss", "ying", "yij", "yic", "yik", "yit", "yip", "yih", "i", "ig", "igg", "igs", "in", "inj", "inh", "id", "il", "ilg", "ilm", "ilb", "ils", "ilt", "ilp", "ilh", "im", "ib", "ibs", "is", "iss", "ing", "ij", "ic", "ik", "it", "ip", "ih", "ja", "jag", "jagg", "jags", "jan", "janj", "janh", "jad", "jal", "jalg", "jalm", "jalb", "jals", "jalt", "jalp", "jalh", "jam", "jab", "jabs", "jas", "jass", "jang", "jaj", "jac", "jak", "jat", "jap", "jah", "jae", "jaeg", "jaegg", "jaegs", "jaen", "jaenj", "jaenh", "jaed", "jael", "jaelg", "jaelm", "jaelb", "jaels", "jaelt", "jaelp", "jaelh", "jaem", "jaeb", "jaebs", "jaes", "jaess", "jaeng", "jaej", "jaec", "jaek", "jaet", "jaep", "jaeh", "jya", "jyag", "jyagg", "jyags", "jyan", "jyanj", "jyanh", "jyad", "jyal", "jyalg", "jyalm", "jyalb", "jyals", "jyalt", "jyalp", "jyalh", "jyam", "jyab", "jyabs", "jyas", "jyass", "jyang", "jyaj", "jyac", "jyak", "jyat", "jyap", "jyah", "jyae", "jyaeg", "jyaegg", "jyaegs", "jyaen", "jyaenj", "jyaenh", "jyaed", "jyael", "jyaelg", "jyaelm", "jyaelb", "jyaels", "jyaelt", "jyaelp", "jyaelh", "jyaem", "jyaeb", "jyaebs", "jyaes", "jyaess", "jyaeng", "jyaej", "jyaec", "jyaek", "jyaet", "jyaep", "jyaeh"},
- {"jeo", "jeog", "jeogg", "jeogs", "jeon", "jeonj", "jeonh", "jeod", "jeol", "jeolg", "jeolm", "jeolb", "jeols", "jeolt", "jeolp", "jeolh", "jeom", "jeob", "jeobs", "jeos", "jeoss", "jeong", "jeoj", "jeoc", "jeok", "jeot", "jeop", "jeoh", "je", "jeg", "jegg", "jegs", "jen", "jenj", "jenh", "jed", "jel", "jelg", "jelm", "jelb", "jels", "jelt", "jelp", "jelh", "jem", "jeb", "jebs", "jes", "jess", "jeng", "jej", "jec", "jek", "jet", "jep", "jeh", "jyeo", "jyeog", "jyeogg", "jyeogs", "jyeon", "jyeonj", "jyeonh", "jyeod", "jyeol", "jyeolg", "jyeolm", "jyeolb", "jyeols", "jyeolt", "jyeolp", "jyeolh", "jyeom", "jyeob", "jyeobs", "jyeos", "jyeoss", "jyeong", "jyeoj", "jyeoc", "jyeok", "jyeot", "jyeop", "jyeoh", "jye", "jyeg", "jyegg", "jyegs", "jyen", "jyenj", "jyenh", "jyed", "jyel", "jyelg", "jyelm", "jyelb", "jyels", "jyelt", "jyelp", "jyelh", "jyem", "jyeb", "jyebs", "jyes", "jyess", "jyeng", "jyej", "jyec", "jyek", "jyet", "jyep", "jyeh", "jo", "jog", "jogg", "jogs", "jon", "jonj", "jonh", "jod", "jol", "jolg", "jolm", "jolb", "jols", "jolt", "jolp", "jolh", "jom", "job", "jobs", "jos", "joss", "jong", "joj", "joc", "jok", "jot", "jop", "joh", "jwa", "jwag", "jwagg", "jwags", "jwan", "jwanj", "jwanh", "jwad", "jwal", "jwalg", "jwalm", "jwalb", "jwals", "jwalt", "jwalp", "jwalh", "jwam", "jwab", "jwabs", "jwas", "jwass", "jwang", "jwaj", "jwac", "jwak", "jwat", "jwap", "jwah", "jwae", "jwaeg", "jwaegg", "jwaegs", "jwaen", "jwaenj", "jwaenh", "jwaed", "jwael", "jwaelg", "jwaelm", "jwaelb", "jwaels", "jwaelt", "jwaelp", "jwaelh", "jwaem", "jwaeb", "jwaebs", "jwaes", "jwaess", "jwaeng", "jwaej", "jwaec", "jwaek", "jwaet", "jwaep", "jwaeh", "joe", "joeg", "joegg", "joegs", "joen", "joenj", "joenh", "joed", "joel", "joelg", "joelm", "joelb", "joels", "joelt", "joelp", "joelh", "joem", "joeb", "joebs", "joes", "joess", "joeng", "joej", "joec", "joek", "joet", "joep", "joeh", "jyo", "jyog", "jyogg", "jyogs", "jyon", "jyonj", "jyonh", "jyod", "jyol", "jyolg", "jyolm", "jyolb", "jyols", "jyolt", "jyolp", "jyolh", "jyom", "jyob", "jyobs", "jyos", "jyoss", "jyong", "jyoj", "jyoc", "jyok", "jyot", "jyop", "jyoh", "ju", "jug", "jugg", "jugs"},
- {"jun", "junj", "junh", "jud", "jul", "julg", "julm", "julb", "juls", "jult", "julp", "julh", "jum", "jub", "jubs", "jus", "juss", "jung", "juj", "juc", "juk", "jut", "jup", "juh", "jweo", "jweog", "jweogg", "jweogs", "jweon", "jweonj", "jweonh", "jweod", "jweol", "jweolg", "jweolm", "jweolb", "jweols", "jweolt", "jweolp", "jweolh", "jweom", "jweob", "jweobs", "jweos", "jweoss", "jweong", "jweoj", "jweoc", "jweok", "jweot", "jweop", "jweoh", "jwe", "jweg", "jwegg", "jwegs", "jwen", "jwenj", "jwenh", "jwed", "jwel", "jwelg", "jwelm", "jwelb", "jwels", "jwelt", "jwelp", "jwelh", "jwem", "jweb", "jwebs", "jwes", "jwess", "jweng", "jwej", "jwec", "jwek", "jwet", "jwep", "jweh", "jwi", "jwig", "jwigg", "jwigs", "jwin", "jwinj", "jwinh", "jwid", "jwil", "jwilg", "jwilm", "jwilb", "jwils", "jwilt", "jwilp", "jwilh", "jwim", "jwib", "jwibs", "jwis", "jwiss", "jwing", "jwij", "jwic", "jwik", "jwit", "jwip", "jwih", "jyu", "jyug", "jyugg", "jyugs", "jyun", "jyunj", "jyunh", "jyud", "jyul", "jyulg", "jyulm", "jyulb", "jyuls", "jyult", "jyulp", "jyulh", "jyum", "jyub", "jyubs", "jyus", "jyuss", "jyung", "jyuj", "jyuc", "jyuk", "jyut", "jyup", "jyuh", "jeu", "jeug", "jeugg", "jeugs", "jeun", "jeunj", "jeunh", "jeud", "jeul", "jeulg", "jeulm", "jeulb", "jeuls", "jeult", "jeulp", "jeulh", "jeum", "jeub", "jeubs", "jeus", "jeuss", "jeung", "jeuj", "jeuc", "jeuk", "jeut", "jeup", "jeuh", "jyi", "jyig", "jyigg", "jyigs", "jyin", "jyinj", "jyinh", "jyid", "jyil", "jyilg", "jyilm", "jyilb", "jyils", "jyilt", "jyilp", "jyilh", "jyim", "jyib", "jyibs", "jyis", "jyiss", "jying", "jyij", "jyic", "jyik", "jyit", "jyip", "jyih", "ji", "jig", "jigg", "jigs", "jin", "jinj", "jinh", "jid", "jil", "jilg", "jilm", "jilb", "jils", "jilt", "jilp", "jilh", "jim", "jib", "jibs", "jis", "jiss", "jing", "jij", "jic", "jik", "jit", "jip", "jih", "jja", "jjag", "jjagg", "jjags", "jjan", "jjanj", "jjanh", "jjad", "jjal", "jjalg", "jjalm", "jjalb", "jjals", "jjalt", "jjalp", "jjalh", "jjam", "jjab", "jjabs", "jjas", "jjass", "jjang", "jjaj", "jjac", "jjak", "jjat", "jjap", "jjah", "jjae", "jjaeg", "jjaegg", "jjaegs", "jjaen", "jjaenj", "jjaenh", "jjaed"},
- {"jjael", "jjaelg", "jjaelm", "jjaelb", "jjaels", "jjaelt", "jjaelp", "jjaelh", "jjaem", "jjaeb", "jjaebs", "jjaes", "jjaess", "jjaeng", "jjaej", "jjaec", "jjaek", "jjaet", "jjaep", "jjaeh", "jjya", "jjyag", "jjyagg", "jjyags", "jjyan", "jjyanj", "jjyanh", "jjyad", "jjyal", "jjyalg", "jjyalm", "jjyalb", "jjyals", "jjyalt", "jjyalp", "jjyalh", "jjyam", "jjyab", "jjyabs", "jjyas", "jjyass", "jjyang", "jjyaj", "jjyac", "jjyak", "jjyat", "jjyap", "jjyah", "jjyae", "jjyaeg", "jjyaegg", "jjyaegs", "jjyaen", "jjyaenj", "jjyaenh", "jjyaed", "jjyael", "jjyaelg", "jjyaelm", "jjyaelb", "jjyaels", "jjyaelt", "jjyaelp", "jjyaelh", "jjyaem", "jjyaeb", "jjyaebs", "jjyaes", "jjyaess", "jjyaeng", "jjyaej", "jjyaec", "jjyaek", "jjyaet", "jjyaep", "jjyaeh", "jjeo", "jjeog", "jjeogg", "jjeogs", "jjeon", "jjeonj", "jjeonh", "jjeod", "jjeol", "jjeolg", "jjeolm", "jjeolb", "jjeols", "jjeolt", "jjeolp", "jjeolh", "jjeom", "jjeob", "jjeobs", "jjeos", "jjeoss", "jjeong", "jjeoj", "jjeoc", "jjeok", "jjeot", "jjeop", "jjeoh", "jje", "jjeg", "jjegg", "jjegs", "jjen", "jjenj", "jjenh", "jjed", "jjel", "jjelg", "jjelm", "jjelb", "jjels", "jjelt", "jjelp", "jjelh", "jjem", "jjeb", "jjebs", "jjes", "jjess", "jjeng", "jjej", "jjec", "jjek", "jjet", "jjep", "jjeh", "jjyeo", "jjyeog", "jjyeogg", "jjyeogs", "jjyeon", "jjyeonj", "jjyeonh", "jjyeod", "jjyeol", "jjyeolg", "jjyeolm", "jjyeolb", "jjyeols", "jjyeolt", "jjyeolp", "jjyeolh", "jjyeom", "jjyeob", "jjyeobs", "jjyeos", "jjyeoss", "jjyeong", "jjyeoj", "jjyeoc", "jjyeok", "jjyeot", "jjyeop", "jjyeoh", "jjye", "jjyeg", "jjyegg", "jjyegs", "jjyen", "jjyenj", "jjyenh", "jjyed", "jjyel", "jjyelg", "jjyelm", "jjyelb", "jjyels", "jjyelt", "jjyelp", "jjyelh", "jjyem", "jjyeb", "jjyebs", "jjyes", "jjyess", "jjyeng", "jjyej", "jjyec", "jjyek", "jjyet", "jjyep", "jjyeh", "jjo", "jjog", "jjogg", "jjogs", "jjon", "jjonj", "jjonh", "jjod", "jjol", "jjolg", "jjolm", "jjolb", "jjols", "jjolt", "jjolp", "jjolh", "jjom", "jjob", "jjobs", "jjos", "jjoss", "jjong", "jjoj", "jjoc", "jjok", "jjot", "jjop", "jjoh", "jjwa", "jjwag", "jjwagg", "jjwags", "jjwan", "jjwanj", "jjwanh", "jjwad", "jjwal", "jjwalg", "jjwalm", "jjwalb", "jjwals", "jjwalt", "jjwalp", "jjwalh", "jjwam", "jjwab", "jjwabs", "jjwas", "jjwass", "jjwang", "jjwaj", "jjwac", "jjwak", "jjwat", "jjwap", "jjwah", "jjwae", "jjwaeg", "jjwaegg", "jjwaegs", "jjwaen", "jjwaenj", "jjwaenh", "jjwaed", "jjwael", "jjwaelg", "jjwaelm", "jjwaelb"},
- {"jjwaels", "jjwaelt", "jjwaelp", "jjwaelh", "jjwaem", "jjwaeb", "jjwaebs", "jjwaes", "jjwaess", "jjwaeng", "jjwaej", "jjwaec", "jjwaek", "jjwaet", "jjwaep", "jjwaeh", "jjoe", "jjoeg", "jjoegg", "jjoegs", "jjoen", "jjoenj", "jjoenh", "jjoed", "jjoel", "jjoelg", "jjoelm", "jjoelb", "jjoels", "jjoelt", "jjoelp", "jjoelh", "jjoem", "jjoeb", "jjoebs", "jjoes", "jjoess", "jjoeng", "jjoej", "jjoec", "jjoek", "jjoet", "jjoep", "jjoeh", "jjyo", "jjyog", "jjyogg", "jjyogs", "jjyon", "jjyonj", "jjyonh", "jjyod", "jjyol", "jjyolg", "jjyolm", "jjyolb", "jjyols", "jjyolt", "jjyolp", "jjyolh", "jjyom", "jjyob", "jjyobs", "jjyos", "jjyoss", "jjyong", "jjyoj", "jjyoc", "jjyok", "jjyot", "jjyop", "jjyoh", "jju", "jjug", "jjugg", "jjugs", "jjun", "jjunj", "jjunh", "jjud", "jjul", "jjulg", "jjulm", "jjulb", "jjuls", "jjult", "jjulp", "jjulh", "jjum", "jjub", "jjubs", "jjus", "jjuss", "jjung", "jjuj", "jjuc", "jjuk", "jjut", "jjup", "jjuh", "jjweo", "jjweog", "jjweogg", "jjweogs", "jjweon", "jjweonj", "jjweonh", "jjweod", "jjweol", "jjweolg", "jjweolm", "jjweolb", "jjweols", "jjweolt", "jjweolp", "jjweolh", "jjweom", "jjweob", "jjweobs", "jjweos", "jjweoss", "jjweong", "jjweoj", "jjweoc", "jjweok", "jjweot", "jjweop", "jjweoh", "jjwe", "jjweg", "jjwegg", "jjwegs", "jjwen", "jjwenj", "jjwenh", "jjwed", "jjwel", "jjwelg", "jjwelm", "jjwelb", "jjwels", "jjwelt", "jjwelp", "jjwelh", "jjwem", "jjweb", "jjwebs", "jjwes", "jjwess", "jjweng", "jjwej", "jjwec", "jjwek", "jjwet", "jjwep", "jjweh", "jjwi", "jjwig", "jjwigg", "jjwigs", "jjwin", "jjwinj", "jjwinh", "jjwid", "jjwil", "jjwilg", "jjwilm", "jjwilb", "jjwils", "jjwilt", "jjwilp", "jjwilh", "jjwim", "jjwib", "jjwibs", "jjwis", "jjwiss", "jjwing", "jjwij", "jjwic", "jjwik", "jjwit", "jjwip", "jjwih", "jjyu", "jjyug", "jjyugg", "jjyugs", "jjyun", "jjyunj", "jjyunh", "jjyud", "jjyul", "jjyulg", "jjyulm", "jjyulb", "jjyuls", "jjyult", "jjyulp", "jjyulh", "jjyum", "jjyub", "jjyubs", "jjyus", "jjyuss", "jjyung", "jjyuj", "jjyuc", "jjyuk", "jjyut", "jjyup", "jjyuh", "jjeu", "jjeug", "jjeugg", "jjeugs", "jjeun", "jjeunj", "jjeunh", "jjeud", "jjeul", "jjeulg", "jjeulm", "jjeulb", "jjeuls", "jjeult", "jjeulp", "jjeulh", "jjeum", "jjeub", "jjeubs", "jjeus", "jjeuss", "jjeung", "jjeuj", "jjeuc", "jjeuk", "jjeut", "jjeup", "jjeuh", "jjyi", "jjyig", "jjyigg", "jjyigs", "jjyin", "jjyinj", "jjyinh", "jjyid", "jjyil", "jjyilg", "jjyilm", "jjyilb", "jjyils", "jjyilt", "jjyilp", "jjyilh"},
- {"jjyim", "jjyib", "jjyibs", "jjyis", "jjyiss", "jjying", "jjyij", "jjyic", "jjyik", "jjyit", "jjyip", "jjyih", "jji", "jjig", "jjigg", "jjigs", "jjin", "jjinj", "jjinh", "jjid", "jjil", "jjilg", "jjilm", "jjilb", "jjils", "jjilt", "jjilp", "jjilh", "jjim", "jjib", "jjibs", "jjis", "jjiss", "jjing", "jjij", "jjic", "jjik", "jjit", "jjip", "jjih", "ca", "cag", "cagg", "cags", "can", "canj", "canh", "cad", "cal", "calg", "calm", "calb", "cals", "calt", "calp", "calh", "cam", "cab", "cabs", "cas", "cass", "cang", "caj", "cac", "cak", "cat", "cap", "cah", "cae", "caeg", "caegg", "caegs", "caen", "caenj", "caenh", "caed", "cael", "caelg", "caelm", "caelb", "caels", "caelt", "caelp", "caelh", "caem", "caeb", "caebs", "caes", "caess", "caeng", "caej", "caec", "caek", "caet", "caep", "caeh", "cya", "cyag", "cyagg", "cyags", "cyan", "cyanj", "cyanh", "cyad", "cyal", "cyalg", "cyalm", "cyalb", "cyals", "cyalt", "cyalp", "cyalh", "cyam", "cyab", "cyabs", "cyas", "cyass", "cyang", "cyaj", "cyac", "cyak", "cyat", "cyap", "cyah", "cyae", "cyaeg", "cyaegg", "cyaegs", "cyaen", "cyaenj", "cyaenh", "cyaed", "cyael", "cyaelg", "cyaelm", "cyaelb", "cyaels", "cyaelt", "cyaelp", "cyaelh", "cyaem", "cyaeb", "cyaebs", "cyaes", "cyaess", "cyaeng", "cyaej", "cyaec", "cyaek", "cyaet", "cyaep", "cyaeh", "ceo", "ceog", "ceogg", "ceogs", "ceon", "ceonj", "ceonh", "ceod", "ceol", "ceolg", "ceolm", "ceolb", "ceols", "ceolt", "ceolp", "ceolh", "ceom", "ceob", "ceobs", "ceos", "ceoss", "ceong", "ceoj", "ceoc", "ceok", "ceot", "ceop", "ceoh", "ce", "ceg", "cegg", "cegs", "cen", "cenj", "cenh", "ced", "cel", "celg", "celm", "celb", "cels", "celt", "celp", "celh", "cem", "ceb", "cebs", "ces", "cess", "ceng", "cej", "cec", "cek", "cet", "cep", "ceh", "cyeo", "cyeog", "cyeogg", "cyeogs", "cyeon", "cyeonj", "cyeonh", "cyeod", "cyeol", "cyeolg", "cyeolm", "cyeolb", "cyeols", "cyeolt", "cyeolp", "cyeolh", "cyeom", "cyeob", "cyeobs", "cyeos", "cyeoss", "cyeong", "cyeoj", "cyeoc", "cyeok", "cyeot", "cyeop", "cyeoh", "cye", "cyeg", "cyegg", "cyegs", "cyen", "cyenj", "cyenh", "cyed", "cyel", "cyelg", "cyelm", "cyelb", "cyels", "cyelt", "cyelp", "cyelh", "cyem", "cyeb", "cyebs", "cyes"},
- {"cyess", "cyeng", "cyej", "cyec", "cyek", "cyet", "cyep", "cyeh", "co", "cog", "cogg", "cogs", "con", "conj", "conh", "cod", "col", "colg", "colm", "colb", "cols", "colt", "colp", "colh", "com", "cob", "cobs", "cos", "coss", "cong", "coj", "coc", "cok", "cot", "cop", "coh", "cwa", "cwag", "cwagg", "cwags", "cwan", "cwanj", "cwanh", "cwad", "cwal", "cwalg", "cwalm", "cwalb", "cwals", "cwalt", "cwalp", "cwalh", "cwam", "cwab", "cwabs", "cwas", "cwass", "cwang", "cwaj", "cwac", "cwak", "cwat", "cwap", "cwah", "cwae", "cwaeg", "cwaegg", "cwaegs", "cwaen", "cwaenj", "cwaenh", "cwaed", "cwael", "cwaelg", "cwaelm", "cwaelb", "cwaels", "cwaelt", "cwaelp", "cwaelh", "cwaem", "cwaeb", "cwaebs", "cwaes", "cwaess", "cwaeng", "cwaej", "cwaec", "cwaek", "cwaet", "cwaep", "cwaeh", "coe", "coeg", "coegg", "coegs", "coen", "coenj", "coenh", "coed", "coel", "coelg", "coelm", "coelb", "coels", "coelt", "coelp", "coelh", "coem", "coeb", "coebs", "coes", "coess", "coeng", "coej", "coec", "coek", "coet", "coep", "coeh", "cyo", "cyog", "cyogg", "cyogs", "cyon", "cyonj", "cyonh", "cyod", "cyol", "cyolg", "cyolm", "cyolb", "cyols", "cyolt", "cyolp", "cyolh", "cyom", "cyob", "cyobs", "cyos", "cyoss", "cyong", "cyoj", "cyoc", "cyok", "cyot", "cyop", "cyoh", "cu", "cug", "cugg", "cugs", "cun", "cunj", "cunh", "cud", "cul", "culg", "culm", "culb", "culs", "cult", "culp", "culh", "cum", "cub", "cubs", "cus", "cuss", "cung", "cuj", "cuc", "cuk", "cut", "cup", "cuh", "cweo", "cweog", "cweogg", "cweogs", "cweon", "cweonj", "cweonh", "cweod", "cweol", "cweolg", "cweolm", "cweolb", "cweols", "cweolt", "cweolp", "cweolh", "cweom", "cweob", "cweobs", "cweos", "cweoss", "cweong", "cweoj", "cweoc", "cweok", "cweot", "cweop", "cweoh", "cwe", "cweg", "cwegg", "cwegs", "cwen", "cwenj", "cwenh", "cwed", "cwel", "cwelg", "cwelm", "cwelb", "cwels", "cwelt", "cwelp", "cwelh", "cwem", "cweb", "cwebs", "cwes", "cwess", "cweng", "cwej", "cwec", "cwek", "cwet", "cwep", "cweh", "cwi", "cwig", "cwigg", "cwigs", "cwin", "cwinj", "cwinh", "cwid", "cwil", "cwilg", "cwilm", "cwilb", "cwils", "cwilt", "cwilp", "cwilh", "cwim", "cwib", "cwibs", "cwis", "cwiss", "cwing", "cwij", "cwic"},
- {"cwik", "cwit", "cwip", "cwih", "cyu", "cyug", "cyugg", "cyugs", "cyun", "cyunj", "cyunh", "cyud", "cyul", "cyulg", "cyulm", "cyulb", "cyuls", "cyult", "cyulp", "cyulh", "cyum", "cyub", "cyubs", "cyus", "cyuss", "cyung", "cyuj", "cyuc", "cyuk", "cyut", "cyup", "cyuh", "ceu", "ceug", "ceugg", "ceugs", "ceun", "ceunj", "ceunh", "ceud", "ceul", "ceulg", "ceulm", "ceulb", "ceuls", "ceult", "ceulp", "ceulh", "ceum", "ceub", "ceubs", "ceus", "ceuss", "ceung", "ceuj", "ceuc", "ceuk", "ceut", "ceup", "ceuh", "cyi", "cyig", "cyigg", "cyigs", "cyin", "cyinj", "cyinh", "cyid", "cyil", "cyilg", "cyilm", "cyilb", "cyils", "cyilt", "cyilp", "cyilh", "cyim", "cyib", "cyibs", "cyis", "cyiss", "cying", "cyij", "cyic", "cyik", "cyit", "cyip", "cyih", "ci", "cig", "cigg", "cigs", "cin", "cinj", "cinh", "cid", "cil", "cilg", "cilm", "cilb", "cils", "cilt", "cilp", "cilh", "cim", "cib", "cibs", "cis", "ciss", "cing", "cij", "cic", "cik", "cit", "cip", "cih", "ka", "kag", "kagg", "kags", "kan", "kanj", "kanh", "kad", "kal", "kalg", "kalm", "kalb", "kals", "kalt", "kalp", "kalh", "kam", "kab", "kabs", "kas", "kass", "kang", "kaj", "kac", "kak", "kat", "kap", "kah", "kae", "kaeg", "kaegg", "kaegs", "kaen", "kaenj", "kaenh", "kaed", "kael", "kaelg", "kaelm", "kaelb", "kaels", "kaelt", "kaelp", "kaelh", "kaem", "kaeb", "kaebs", "kaes", "kaess", "kaeng", "kaej", "kaec", "kaek", "kaet", "kaep", "kaeh", "kya", "kyag", "kyagg", "kyags", "kyan", "kyanj", "kyanh", "kyad", "kyal", "kyalg", "kyalm", "kyalb", "kyals", "kyalt", "kyalp", "kyalh", "kyam", "kyab", "kyabs", "kyas", "kyass", "kyang", "kyaj", "kyac", "kyak", "kyat", "kyap", "kyah", "kyae", "kyaeg", "kyaegg", "kyaegs", "kyaen", "kyaenj", "kyaenh", "kyaed", "kyael", "kyaelg", "kyaelm", "kyaelb", "kyaels", "kyaelt", "kyaelp", "kyaelh", "kyaem", "kyaeb", "kyaebs", "kyaes", "kyaess", "kyaeng", "kyaej", "kyaec", "kyaek", "kyaet", "kyaep", "kyaeh", "keo", "keog", "keogg", "keogs", "keon", "keonj", "keonh", "keod", "keol", "keolg", "keolm", "keolb", "keols", "keolt", "keolp", "keolh", "keom", "keob", "keobs", "keos", "keoss", "keong", "keoj", "keoc", "keok", "keot", "keop", "keoh"},
- {"ke", "keg", "kegg", "kegs", "ken", "kenj", "kenh", "ked", "kel", "kelg", "kelm", "kelb", "kels", "kelt", "kelp", "kelh", "kem", "keb", "kebs", "kes", "kess", "keng", "kej", "kec", "kek", "ket", "kep", "keh", "kyeo", "kyeog", "kyeogg", "kyeogs", "kyeon", "kyeonj", "kyeonh", "kyeod", "kyeol", "kyeolg", "kyeolm", "kyeolb", "kyeols", "kyeolt", "kyeolp", "kyeolh", "kyeom", "kyeob", "kyeobs", "kyeos", "kyeoss", "kyeong", "kyeoj", "kyeoc", "kyeok", "kyeot", "kyeop", "kyeoh", "kye", "kyeg", "kyegg", "kyegs", "kyen", "kyenj", "kyenh", "kyed", "kyel", "kyelg", "kyelm", "kyelb", "kyels", "kyelt", "kyelp", "kyelh", "kyem", "kyeb", "kyebs", "kyes", "kyess", "kyeng", "kyej", "kyec", "kyek", "kyet", "kyep", "kyeh", "ko", "kog", "kogg", "kogs", "kon", "konj", "konh", "kod", "kol", "kolg", "kolm", "kolb", "kols", "kolt", "kolp", "kolh", "kom", "kob", "kobs", "kos", "koss", "kong", "koj", "koc", "kok", "kot", "kop", "koh", "kwa", "kwag", "kwagg", "kwags", "kwan", "kwanj", "kwanh", "kwad", "kwal", "kwalg", "kwalm", "kwalb", "kwals", "kwalt", "kwalp", "kwalh", "kwam", "kwab", "kwabs", "kwas", "kwass", "kwang", "kwaj", "kwac", "kwak", "kwat", "kwap", "kwah", "kwae", "kwaeg", "kwaegg", "kwaegs", "kwaen", "kwaenj", "kwaenh", "kwaed", "kwael", "kwaelg", "kwaelm", "kwaelb", "kwaels", "kwaelt", "kwaelp", "kwaelh", "kwaem", "kwaeb", "kwaebs", "kwaes", "kwaess", "kwaeng", "kwaej", "kwaec", "kwaek", "kwaet", "kwaep", "kwaeh", "koe", "koeg", "koegg", "koegs", "koen", "koenj", "koenh", "koed", "koel", "koelg", "koelm", "koelb", "koels", "koelt", "koelp", "koelh", "koem", "koeb", "koebs", "koes", "koess", "koeng", "koej", "koec", "koek", "koet", "koep", "koeh", "kyo", "kyog", "kyogg", "kyogs", "kyon", "kyonj", "kyonh", "kyod", "kyol", "kyolg", "kyolm", "kyolb", "kyols", "kyolt", "kyolp", "kyolh", "kyom", "kyob", "kyobs", "kyos", "kyoss", "kyong", "kyoj", "kyoc", "kyok", "kyot", "kyop", "kyoh", "ku", "kug", "kugg", "kugs", "kun", "kunj", "kunh", "kud", "kul", "kulg", "kulm", "kulb", "kuls", "kult", "kulp", "kulh", "kum", "kub", "kubs", "kus", "kuss", "kung", "kuj", "kuc", "kuk", "kut", "kup", "kuh", "kweo", "kweog", "kweogg", "kweogs"},
- {"kweon", "kweonj", "kweonh", "kweod", "kweol", "kweolg", "kweolm", "kweolb", "kweols", "kweolt", "kweolp", "kweolh", "kweom", "kweob", "kweobs", "kweos", "kweoss", "kweong", "kweoj", "kweoc", "kweok", "kweot", "kweop", "kweoh", "kwe", "kweg", "kwegg", "kwegs", "kwen", "kwenj", "kwenh", "kwed", "kwel", "kwelg", "kwelm", "kwelb", "kwels", "kwelt", "kwelp", "kwelh", "kwem", "kweb", "kwebs", "kwes", "kwess", "kweng", "kwej", "kwec", "kwek", "kwet", "kwep", "kweh", "kwi", "kwig", "kwigg", "kwigs", "kwin", "kwinj", "kwinh", "kwid", "kwil", "kwilg", "kwilm", "kwilb", "kwils", "kwilt", "kwilp", "kwilh", "kwim", "kwib", "kwibs", "kwis", "kwiss", "kwing", "kwij", "kwic", "kwik", "kwit", "kwip", "kwih", "kyu", "kyug", "kyugg", "kyugs", "kyun", "kyunj", "kyunh", "kyud", "kyul", "kyulg", "kyulm", "kyulb", "kyuls", "kyult", "kyulp", "kyulh", "kyum", "kyub", "kyubs", "kyus", "kyuss", "kyung", "kyuj", "kyuc", "kyuk", "kyut", "kyup", "kyuh", "keu", "keug", "keugg", "keugs", "keun", "keunj", "keunh", "keud", "keul", "keulg", "keulm", "keulb", "keuls", "keult", "keulp", "keulh", "keum", "keub", "keubs", "keus", "keuss", "keung", "keuj", "keuc", "keuk", "keut", "keup", "keuh", "kyi", "kyig", "kyigg", "kyigs", "kyin", "kyinj", "kyinh", "kyid", "kyil", "kyilg", "kyilm", "kyilb", "kyils", "kyilt", "kyilp", "kyilh", "kyim", "kyib", "kyibs", "kyis", "kyiss", "kying", "kyij", "kyic", "kyik", "kyit", "kyip", "kyih", "ki", "kig", "kigg", "kigs", "kin", "kinj", "kinh", "kid", "kil", "kilg", "kilm", "kilb", "kils", "kilt", "kilp", "kilh", "kim", "kib", "kibs", "kis", "kiss", "king", "kij", "kic", "kik", "kit", "kip", "kih", "ta", "tag", "tagg", "tags", "tan", "tanj", "tanh", "tad", "tal", "talg", "talm", "talb", "tals", "talt", "talp", "talh", "tam", "tab", "tabs", "tas", "tass", "tang", "taj", "tac", "tak", "tat", "tap", "tah", "tae", "taeg", "taegg", "taegs", "taen", "taenj", "taenh", "taed", "tael", "taelg", "taelm", "taelb", "taels", "taelt", "taelp", "taelh", "taem", "taeb", "taebs", "taes", "taess", "taeng", "taej", "taec", "taek", "taet", "taep", "taeh", "tya", "tyag", "tyagg", "tyags", "tyan", "tyanj", "tyanh", "tyad"},
- {"tyal", "tyalg", "tyalm", "tyalb", "tyals", "tyalt", "tyalp", "tyalh", "tyam", "tyab", "tyabs", "tyas", "tyass", "tyang", "tyaj", "tyac", "tyak", "tyat", "tyap", "tyah", "tyae", "tyaeg", "tyaegg", "tyaegs", "tyaen", "tyaenj", "tyaenh", "tyaed", "tyael", "tyaelg", "tyaelm", "tyaelb", "tyaels", "tyaelt", "tyaelp", "tyaelh", "tyaem", "tyaeb", "tyaebs", "tyaes", "tyaess", "tyaeng", "tyaej", "tyaec", "tyaek", "tyaet", "tyaep", "tyaeh", "teo", "teog", "teogg", "teogs", "teon", "teonj", "teonh", "teod", "teol", "teolg", "teolm", "teolb", "teols", "teolt", "teolp", "teolh", "teom", "teob", "teobs", "teos", "teoss", "teong", "teoj", "teoc", "teok", "teot", "teop", "teoh", "te", "teg", "tegg", "tegs", "ten", "tenj", "tenh", "ted", "tel", "telg", "telm", "telb", "tels", "telt", "telp", "telh", "tem", "teb", "tebs", "tes", "tess", "teng", "tej", "tec", "tek", "tet", "tep", "teh", "tyeo", "tyeog", "tyeogg", "tyeogs", "tyeon", "tyeonj", "tyeonh", "tyeod", "tyeol", "tyeolg", "tyeolm", "tyeolb", "tyeols", "tyeolt", "tyeolp", "tyeolh", "tyeom", "tyeob", "tyeobs", "tyeos", "tyeoss", "tyeong", "tyeoj", "tyeoc", "tyeok", "tyeot", "tyeop", "tyeoh", "tye", "tyeg", "tyegg", "tyegs", "tyen", "tyenj", "tyenh", "tyed", "tyel", "tyelg", "tyelm", "tyelb", "tyels", "tyelt", "tyelp", "tyelh", "tyem", "tyeb", "tyebs", "tyes", "tyess", "tyeng", "tyej", "tyec", "tyek", "tyet", "tyep", "tyeh", "to", "tog", "togg", "togs", "ton", "tonj", "tonh", "tod", "tol", "tolg", "tolm", "tolb", "tols", "tolt", "tolp", "tolh", "tom", "tob", "tobs", "tos", "toss", "tong", "toj", "toc", "tok", "tot", "top", "toh", "twa", "twag", "twagg", "twags", "twan", "twanj", "twanh", "twad", "twal", "twalg", "twalm", "twalb", "twals", "twalt", "twalp", "twalh", "twam", "twab", "twabs", "twas", "twass", "twang", "twaj", "twac", "twak", "twat", "twap", "twah", "twae", "twaeg", "twaegg", "twaegs", "twaen", "twaenj", "twaenh", "twaed", "twael", "twaelg", "twaelm", "twaelb", "twaels", "twaelt", "twaelp", "twaelh", "twaem", "twaeb", "twaebs", "twaes", "twaess", "twaeng", "twaej", "twaec", "twaek", "twaet", "twaep", "twaeh", "toe", "toeg", "toegg", "toegs", "toen", "toenj", "toenh", "toed", "toel", "toelg", "toelm", "toelb"},
- {"toels", "toelt", "toelp", "toelh", "toem", "toeb", "toebs", "toes", "toess", "toeng", "toej", "toec", "toek", "toet", "toep", "toeh", "tyo", "tyog", "tyogg", "tyogs", "tyon", "tyonj", "tyonh", "tyod", "tyol", "tyolg", "tyolm", "tyolb", "tyols", "tyolt", "tyolp", "tyolh", "tyom", "tyob", "tyobs", "tyos", "tyoss", "tyong", "tyoj", "tyoc", "tyok", "tyot", "tyop", "tyoh", "tu", "tug", "tugg", "tugs", "tun", "tunj", "tunh", "tud", "tul", "tulg", "tulm", "tulb", "tuls", "tult", "tulp", "tulh", "tum", "tub", "tubs", "tus", "tuss", "tung", "tuj", "tuc", "tuk", "tut", "tup", "tuh", "tweo", "tweog", "tweogg", "tweogs", "tweon", "tweonj", "tweonh", "tweod", "tweol", "tweolg", "tweolm", "tweolb", "tweols", "tweolt", "tweolp", "tweolh", "tweom", "tweob", "tweobs", "tweos", "tweoss", "tweong", "tweoj", "tweoc", "tweok", "tweot", "tweop", "tweoh", "twe", "tweg", "twegg", "twegs", "twen", "twenj", "twenh", "twed", "twel", "twelg", "twelm", "twelb", "twels", "twelt", "twelp", "twelh", "twem", "tweb", "twebs", "twes", "twess", "tweng", "twej", "twec", "twek", "twet", "twep", "tweh", "twi", "twig", "twigg", "twigs", "twin", "twinj", "twinh", "twid", "twil", "twilg", "twilm", "twilb", "twils", "twilt", "twilp", "twilh", "twim", "twib", "twibs", "twis", "twiss", "twing", "twij", "twic", "twik", "twit", "twip", "twih", "tyu", "tyug", "tyugg", "tyugs", "tyun", "tyunj", "tyunh", "tyud", "tyul", "tyulg", "tyulm", "tyulb", "tyuls", "tyult", "tyulp", "tyulh", "tyum", "tyub", "tyubs", "tyus", "tyuss", "tyung", "tyuj", "tyuc", "tyuk", "tyut", "tyup", "tyuh", "teu", "teug", "teugg", "teugs", "teun", "teunj", "teunh", "teud", "teul", "teulg", "teulm", "teulb", "teuls", "teult", "teulp", "teulh", "teum", "teub", "teubs", "teus", "teuss", "teung", "teuj", "teuc", "teuk", "teut", "teup", "teuh", "tyi", "tyig", "tyigg", "tyigs", "tyin", "tyinj", "tyinh", "tyid", "tyil", "tyilg", "tyilm", "tyilb", "tyils", "tyilt", "tyilp", "tyilh", "tyim", "tyib", "tyibs", "tyis", "tyiss", "tying", "tyij", "tyic", "tyik", "tyit", "tyip", "tyih", "ti", "tig", "tigg", "tigs", "tin", "tinj", "tinh", "tid", "til", "tilg", "tilm", "tilb", "tils", "tilt", "tilp", "tilh"},
- {"tim", "tib", "tibs", "tis", "tiss", "ting", "tij", "tic", "tik", "tit", "tip", "tih", "pa", "pag", "pagg", "pags", "pan", "panj", "panh", "pad", "pal", "palg", "palm", "palb", "pals", "palt", "palp", "palh", "pam", "pab", "pabs", "pas", "pass", "pang", "paj", "pac", "pak", "pat", "pap", "pah", "pae", "paeg", "paegg", "paegs", "paen", "paenj", "paenh", "paed", "pael", "paelg", "paelm", "paelb", "paels", "paelt", "paelp", "paelh", "paem", "paeb", "paebs", "paes", "paess", "paeng", "paej", "paec", "paek", "paet", "paep", "paeh", "pya", "pyag", "pyagg", "pyags", "pyan", "pyanj", "pyanh", "pyad", "pyal", "pyalg", "pyalm", "pyalb", "pyals", "pyalt", "pyalp", "pyalh", "pyam", "pyab", "pyabs", "pyas", "pyass", "pyang", "pyaj", "pyac", "pyak", "pyat", "pyap", "pyah", "pyae", "pyaeg", "pyaegg", "pyaegs", "pyaen", "pyaenj", "pyaenh", "pyaed", "pyael", "pyaelg", "pyaelm", "pyaelb", "pyaels", "pyaelt", "pyaelp", "pyaelh", "pyaem", "pyaeb", "pyaebs", "pyaes", "pyaess", "pyaeng", "pyaej", "pyaec", "pyaek", "pyaet", "pyaep", "pyaeh", "peo", "peog", "peogg", "peogs", "peon", "peonj", "peonh", "peod", "peol", "peolg", "peolm", "peolb", "peols", "peolt", "peolp", "peolh", "peom", "peob", "peobs", "peos", "peoss", "peong", "peoj", "peoc", "peok", "peot", "peop", "peoh", "pe", "peg", "pegg", "pegs", "pen", "penj", "penh", "ped", "pel", "pelg", "pelm", "pelb", "pels", "pelt", "pelp", "pelh", "pem", "peb", "pebs", "pes", "pess", "peng", "pej", "pec", "pek", "pet", "pep", "peh", "pyeo", "pyeog", "pyeogg", "pyeogs", "pyeon", "pyeonj", "pyeonh", "pyeod", "pyeol", "pyeolg", "pyeolm", "pyeolb", "pyeols", "pyeolt", "pyeolp", "pyeolh", "pyeom", "pyeob", "pyeobs", "pyeos", "pyeoss", "pyeong", "pyeoj", "pyeoc", "pyeok", "pyeot", "pyeop", "pyeoh", "pye", "pyeg", "pyegg", "pyegs", "pyen", "pyenj", "pyenh", "pyed", "pyel", "pyelg", "pyelm", "pyelb", "pyels", "pyelt", "pyelp", "pyelh", "pyem", "pyeb", "pyebs", "pyes", "pyess", "pyeng", "pyej", "pyec", "pyek", "pyet", "pyep", "pyeh", "po", "pog", "pogg", "pogs", "pon", "ponj", "ponh", "pod", "pol", "polg", "polm", "polb", "pols", "polt", "polp", "polh", "pom", "pob", "pobs", "pos"},
- {"poss", "pong", "poj", "poc", "pok", "pot", "pop", "poh", "pwa", "pwag", "pwagg", "pwags", "pwan", "pwanj", "pwanh", "pwad", "pwal", "pwalg", "pwalm", "pwalb", "pwals", "pwalt", "pwalp", "pwalh", "pwam", "pwab", "pwabs", "pwas", "pwass", "pwang", "pwaj", "pwac", "pwak", "pwat", "pwap", "pwah", "pwae", "pwaeg", "pwaegg", "pwaegs", "pwaen", "pwaenj", "pwaenh", "pwaed", "pwael", "pwaelg", "pwaelm", "pwaelb", "pwaels", "pwaelt", "pwaelp", "pwaelh", "pwaem", "pwaeb", "pwaebs", "pwaes", "pwaess", "pwaeng", "pwaej", "pwaec", "pwaek", "pwaet", "pwaep", "pwaeh", "poe", "poeg", "poegg", "poegs", "poen", "poenj", "poenh", "poed", "poel", "poelg", "poelm", "poelb", "poels", "poelt", "poelp", "poelh", "poem", "poeb", "poebs", "poes", "poess", "poeng", "poej", "poec", "poek", "poet", "poep", "poeh", "pyo", "pyog", "pyogg", "pyogs", "pyon", "pyonj", "pyonh", "pyod", "pyol", "pyolg", "pyolm", "pyolb", "pyols", "pyolt", "pyolp", "pyolh", "pyom", "pyob", "pyobs", "pyos", "pyoss", "pyong", "pyoj", "pyoc", "pyok", "pyot", "pyop", "pyoh", "pu", "pug", "pugg", "pugs", "pun", "punj", "punh", "pud", "pul", "pulg", "pulm", "pulb", "puls", "pult", "pulp", "pulh", "pum", "pub", "pubs", "pus", "puss", "pung", "puj", "puc", "puk", "put", "pup", "puh", "pweo", "pweog", "pweogg", "pweogs", "pweon", "pweonj", "pweonh", "pweod", "pweol", "pweolg", "pweolm", "pweolb", "pweols", "pweolt", "pweolp", "pweolh", "pweom", "pweob", "pweobs", "pweos", "pweoss", "pweong", "pweoj", "pweoc", "pweok", "pweot", "pweop", "pweoh", "pwe", "pweg", "pwegg", "pwegs", "pwen", "pwenj", "pwenh", "pwed", "pwel", "pwelg", "pwelm", "pwelb", "pwels", "pwelt", "pwelp", "pwelh", "pwem", "pweb", "pwebs", "pwes", "pwess", "pweng", "pwej", "pwec", "pwek", "pwet", "pwep", "pweh", "pwi", "pwig", "pwigg", "pwigs", "pwin", "pwinj", "pwinh", "pwid", "pwil", "pwilg", "pwilm", "pwilb", "pwils", "pwilt", "pwilp", "pwilh", "pwim", "pwib", "pwibs", "pwis", "pwiss", "pwing", "pwij", "pwic", "pwik", "pwit", "pwip", "pwih", "pyu", "pyug", "pyugg", "pyugs", "pyun", "pyunj", "pyunh", "pyud", "pyul", "pyulg", "pyulm", "pyulb", "pyuls", "pyult", "pyulp", "pyulh", "pyum", "pyub", "pyubs", "pyus", "pyuss", "pyung", "pyuj", "pyuc"},
- {"pyuk", "pyut", "pyup", "pyuh", "peu", "peug", "peugg", "peugs", "peun", "peunj", "peunh", "peud", "peul", "peulg", "peulm", "peulb", "peuls", "peult", "peulp", "peulh", "peum", "peub", "peubs", "peus", "peuss", "peung", "peuj", "peuc", "peuk", "peut", "peup", "peuh", "pyi", "pyig", "pyigg", "pyigs", "pyin", "pyinj", "pyinh", "pyid", "pyil", "pyilg", "pyilm", "pyilb", "pyils", "pyilt", "pyilp", "pyilh", "pyim", "pyib", "pyibs", "pyis", "pyiss", "pying", "pyij", "pyic", "pyik", "pyit", "pyip", "pyih", "pi", "pig", "pigg", "pigs", "pin", "pinj", "pinh", "pid", "pil", "pilg", "pilm", "pilb", "pils", "pilt", "pilp", "pilh", "pim", "pib", "pibs", "pis", "piss", "ping", "pij", "pic", "pik", "pit", "pip", "pih", "ha", "hag", "hagg", "hags", "han", "hanj", "hanh", "had", "hal", "halg", "halm", "halb", "hals", "halt", "halp", "halh", "ham", "hab", "habs", "has", "hass", "hang", "haj", "hac", "hak", "hat", "hap", "hah", "hae", "haeg", "haegg", "haegs", "haen", "haenj", "haenh", "haed", "hael", "haelg", "haelm", "haelb", "haels", "haelt", "haelp", "haelh", "haem", "haeb", "haebs", "haes", "haess", "haeng", "haej", "haec", "haek", "haet", "haep", "haeh", "hya", "hyag", "hyagg", "hyags", "hyan", "hyanj", "hyanh", "hyad", "hyal", "hyalg", "hyalm", "hyalb", "hyals", "hyalt", "hyalp", "hyalh", "hyam", "hyab", "hyabs", "hyas", "hyass", "hyang", "hyaj", "hyac", "hyak", "hyat", "hyap", "hyah", "hyae", "hyaeg", "hyaegg", "hyaegs", "hyaen", "hyaenj", "hyaenh", "hyaed", "hyael", "hyaelg", "hyaelm", "hyaelb", "hyaels", "hyaelt", "hyaelp", "hyaelh", "hyaem", "hyaeb", "hyaebs", "hyaes", "hyaess", "hyaeng", "hyaej", "hyaec", "hyaek", "hyaet", "hyaep", "hyaeh", "heo", "heog", "heogg", "heogs", "heon", "heonj", "heonh", "heod", "heol", "heolg", "heolm", "heolb", "heols", "heolt", "heolp", "heolh", "heom", "heob", "heobs", "heos", "heoss", "heong", "heoj", "heoc", "heok", "heot", "heop", "heoh", "he", "heg", "hegg", "hegs", "hen", "henj", "henh", "hed", "hel", "helg", "helm", "helb", "hels", "helt", "help", "helh", "hem", "heb", "hebs", "hes", "hess", "heng", "hej", "hec", "hek", "het", "hep", "heh"},
- {"hyeo", "hyeog", "hyeogg", "hyeogs", "hyeon", "hyeonj", "hyeonh", "hyeod", "hyeol", "hyeolg", "hyeolm", "hyeolb", "hyeols", "hyeolt", "hyeolp", "hyeolh", "hyeom", "hyeob", "hyeobs", "hyeos", "hyeoss", "hyeong", "hyeoj", "hyeoc", "hyeok", "hyeot", "hyeop", "hyeoh", "hye", "hyeg", "hyegg", "hyegs", "hyen", "hyenj", "hyenh", "hyed", "hyel", "hyelg", "hyelm", "hyelb", "hyels", "hyelt", "hyelp", "hyelh", "hyem", "hyeb", "hyebs", "hyes", "hyess", "hyeng", "hyej", "hyec", "hyek", "hyet", "hyep", "hyeh", "ho", "hog", "hogg", "hogs", "hon", "honj", "honh", "hod", "hol", "holg", "holm", "holb", "hols", "holt", "holp", "holh", "hom", "hob", "hobs", "hos", "hoss", "hong", "hoj", "hoc", "hok", "hot", "hop", "hoh", "hwa", "hwag", "hwagg", "hwags", "hwan", "hwanj", "hwanh", "hwad", "hwal", "hwalg", "hwalm", "hwalb", "hwals", "hwalt", "hwalp", "hwalh", "hwam", "hwab", "hwabs", "hwas", "hwass", "hwang", "hwaj", "hwac", "hwak", "hwat", "hwap", "hwah", "hwae", "hwaeg", "hwaegg", "hwaegs", "hwaen", "hwaenj", "hwaenh", "hwaed", "hwael", "hwaelg", "hwaelm", "hwaelb", "hwaels", "hwaelt", "hwaelp", "hwaelh", "hwaem", "hwaeb", "hwaebs", "hwaes", "hwaess", "hwaeng", "hwaej", "hwaec", "hwaek", "hwaet", "hwaep", "hwaeh", "hoe", "hoeg", "hoegg", "hoegs", "hoen", "hoenj", "hoenh", "hoed", "hoel", "hoelg", "hoelm", "hoelb", "hoels", "hoelt", "hoelp", "hoelh", "hoem", "hoeb", "hoebs", "hoes", "hoess", "hoeng", "hoej", "hoec", "hoek", "hoet", "hoep", "hoeh", "hyo", "hyog", "hyogg", "hyogs", "hyon", "hyonj", "hyonh", "hyod", "hyol", "hyolg", "hyolm", "hyolb", "hyols", "hyolt", "hyolp", "hyolh", "hyom", "hyob", "hyobs", "hyos", "hyoss", "hyong", "hyoj", "hyoc", "hyok", "hyot", "hyop", "hyoh", "hu", "hug", "hugg", "hugs", "hun", "hunj", "hunh", "hud", "hul", "hulg", "hulm", "hulb", "huls", "hult", "hulp", "hulh", "hum", "hub", "hubs", "hus", "huss", "hung", "huj", "huc", "huk", "hut", "hup", "huh", "hweo", "hweog", "hweogg", "hweogs", "hweon", "hweonj", "hweonh", "hweod", "hweol", "hweolg", "hweolm", "hweolb", "hweols", "hweolt", "hweolp", "hweolh", "hweom", "hweob", "hweobs", "hweos", "hweoss", "hweong", "hweoj", "hweoc", "hweok", "hweot", "hweop", "hweoh", "hwe", "hweg", "hwegg", "hwegs"},
- {"hwen", "hwenj", "hwenh", "hwed", "hwel", "hwelg", "hwelm", "hwelb", "hwels", "hwelt", "hwelp", "hwelh", "hwem", "hweb", "hwebs", "hwes", "hwess", "hweng", "hwej", "hwec", "hwek", "hwet", "hwep", "hweh", "hwi", "hwig", "hwigg", "hwigs", "hwin", "hwinj", "hwinh", "hwid", "hwil", "hwilg", "hwilm", "hwilb", "hwils", "hwilt", "hwilp", "hwilh", "hwim", "hwib", "hwibs", "hwis", "hwiss", "hwing", "hwij", "hwic", "hwik", "hwit", "hwip", "hwih", "hyu", "hyug", "hyugg", "hyugs", "hyun", "hyunj", "hyunh", "hyud", "hyul", "hyulg", "hyulm", "hyulb", "hyuls", "hyult", "hyulp", "hyulh", "hyum", "hyub", "hyubs", "hyus", "hyuss", "hyung", "hyuj", "hyuc", "hyuk", "hyut", "hyup", "hyuh", "heu", "heug", "heugg", "heugs", "heun", "heunj", "heunh", "heud", "heul", "heulg", "heulm", "heulb", "heuls", "heult", "heulp", "heulh", "heum", "heub", "heubs", "heus", "heuss", "heung", "heuj", "heuc", "heuk", "heut", "heup", "heuh", "hyi", "hyig", "hyigg", "hyigs", "hyin", "hyinj", "hyinh", "hyid", "hyil", "hyilg", "hyilm", "hyilb", "hyils", "hyilt", "hyilp", "hyilh", "hyim", "hyib", "hyibs", "hyis", "hyiss", "hying", "hyij", "hyic", "hyik", "hyit", "hyip", "hyih", "hi", "hig", "higg", "higs", "hin", "hinj", "hinh", "hid", "hil", "hilg", "hilm", "hilb", "hils", "hilt", "hilp", "hilh", "him", "hib", "hibs", "his", "hiss", "hing", "hij", "hic", "hik", "hit", "hip", "hih", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] ", "[?] "},
- {"Kay ", "Kayng ", "Ke ", "Ko ", "Kol ", "Koc ", "Kwi ", "Kwi ", "Kyun ", "Kul ", "Kum ", "Na ", "Na ", "Na ", "La ", "Na ", "Na ", "Na ", "Na ", "Na ", "Nak ", "Nak ", "Nak ", "Nak ", "Nak ", "Nak ", "Nak ", "Nan ", "Nan ", "Nan ", "Nan ", "Nan ", "Nan ", "Nam ", "Nam ", "Nam ", "Nam ", "Nap ", "Nap ", "Nap ", "Nang ", "Nang ", "Nang ", "Nang ", "Nang ", "Nay ", "Nayng ", "No ", "No ", "No ", "No ", "No ", "No ", "No ", "No ", "No ", "No ", "No ", "No ", "Nok ", "Nok ", "Nok ", "Nok ", "Nok ", "Nok ", "Non ", "Nong ", "Nong ", "Nong ", "Nong ", "Noy ", "Noy ", "Noy ", "Noy ", "Nwu ", "Nwu ", "Nwu ", "Nwu ", "Nwu ", "Nwu ", "Nwu ", "Nwu ", "Nuk ", "Nuk ", "Num ", "Nung ", "Nung ", "Nung ", "Nung ", "Nung ", "Twu ", "La ", "Lak ", "Lak ", "Lan ", "Lyeng ", "Lo ", "Lyul ", "Li ", "Pey ", "Pen ", "Pyen ", "Pwu ", "Pwul ", "Pi ", "Sak ", "Sak ", "Sam ", "Sayk ", "Sayng ", "Sep ", "Sey ", "Sway ", "Sin ", "Sim ", "Sip ", "Ya ", "Yak ", "Yak ", "Yang ", "Yang ", "Yang ", "Yang ", "Yang ", "Yang ", "Yang ", "Yang ", "Ye ", "Ye ", "Ye ", "Ye ", "Ye ", "Ye ", "Ye ", "Ye ", "Ye ", "Ye ", "Ye ", "Yek ", "Yek ", "Yek ", "Yek ", "Yen ", "Yen ", "Yen ", "Yen ", "Yen ", "Yen ", "Yen ", "Yen ", "Yen ", "Yen ", "Yen ", "Yen ", "Yen ", "Yen ", "Yel ", "Yel ", "Yel ", "Yel ", "Yel ", "Yel ", "Yem ", "Yem ", "Yem ", "Yem ", "Yem ", "Yep ", "Yeng ", "Yeng ", "Yeng ", "Yeng ", "Yeng ", "Yeng ", "Yeng ", "Yeng ", "Yeng ", "Yeng ", "Yeng ", "Yeng ", "Yeng ", "Yey ", "Yey ", "Yey ", "Yey ", "O ", "Yo ", "Yo ", "Yo ", "Yo ", "Yo ", "Yo ", "Yo ", "Yo ", "Yo ", "Yo ", "Yong ", "Wun ", "Wen ", "Yu ", "Yu ", "Yu ", "Yu ", "Yu ", "Yu ", "Yu ", "Yu ", "Yu ", "Yu ", "Yuk ", "Yuk ", "Yuk ", "Yun ", "Yun ", "Yun ", "Yun ", "Yul ", "Yul ", "Yul ", "Yul ", "Yung ", "I ", "I ", "I ", "I ", "I ", "I ", "I ", "I ", "I ", "I ", "I ", "I ", "I ", "I ", "Ik ", "Ik ", "In ", "In ", "In ", "In ", "In ", "In ", "In ", "Im ", "Im ", "Im ", "Ip ", "Ip ", "Ip ", "Cang ", "Cek ", "Ci ", "Cip ", "Cha ", "Chek "},
- {"Chey ", "Thak ", "Thak ", "Thang ", "Thayk ", "Thong ", "Pho ", "Phok ", "Hang ", "Hang ", "Hyen ", "Hwak ", "Wu ", "Huo ", "[?] ", "[?] ", "Zhong ", "[?] ", "Qing ", "[?] ", "[?] ", "Xi ", "Zhu ", "Yi ", "Li ", "Shen ", "Xiang ", "Fu ", "Jing ", "Jing ", "Yu ", "[?] ", "Hagi ", "[?] ", "Zhu ", "[?] ", "[?] ", "Yi ", "Du ", "[?] ", "[?] ", "[?] ", "Fan ", "Si ", "Guan ", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]"},
- {"ff", "fi", "fl", "ffi", "ffl", "st", "st", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "mn", "me", "mi", "vn", "mkh", "[?]", "[?]", "[?]", "[?]", "[?]", "yi", "", "ay", "`", "", "d", "h", "k", "l", "m", "m", "t", "+", "sh", "s", "sh", "s", "a", "a", "", "b", "g", "d", "h", "v", "z", "[?]", "t", "y", "k", "k", "l", "[?]", "l", "[?]", "n", "n", "[?]", "p", "p", "[?]", "ts", "ts", "r", "sh", "t", "vo", "b", "k", "p", "l", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
- {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""},
- {"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "{Salla}", "{Qala}", "Allah", "Akbar", "Mohammed", "SL`M", "Rasul", "{Alayhi}", "{WaSallam}", "{Salla}", "{Salla Llahu Alayhi WaSallam}", "{Jalla Jalalahu}", "Rial ", "{Bismillah Ar-Rahman Ar-Rahimi}", "[?]", "[?]"},
- {"[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "", "", "", "~", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "..", "--", "-", "_", "_", "(", ") ", "{", "} ", "[", "] ", "[(", ")] ", "<<", ">> ", "<", "> ", "[", "] ", "{", "}", "[?]", "[?]", "[?]", "[?]", "", "", "", "", "", "", "", ",", ",", ".", "", ";", ":", "?", "!", "-", "(", ")", "{", "}", "{", "}", "#", "&", "*", "+", "-", "<", ">", "=", "", "\\", "$", "%", "@", "[?]", "[?]", "[?]", "[?]", "", "", "", "[?]", "", "[?]", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "[?]", "[?]", ""},
- {"[?]", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "[?]", "[?]", ".", "[", "]", ",", "*", "wo", "a", "i", "u", "e", "o", "ya", "yu", "yo", "tu", "+", "a", "i", "u", "e", "o", "ka", "ki", "ku", "ke", "ko", "sa", "si", "su", "se", "so", "ta", "ti", "tu", "te", "to", "na", "ni", "nu", "ne", "no", "ha", "hi", "hu", "he", "ho", "ma", "mi", "mu", "me", "mo", "ya", "yu", "yo", "ra", "ri", "ru", "re", "ro", "wa", "n", ":", ";", "", "g", "gg", "gs", "n", "nj", "nh", "d", "dd", "r", "lg", "lm", "lb", "ls", "lt", "lp", "rh", "m", "b", "bb", "bs", "s", "ss", "", "j", "jj", "c", "k", "t", "p", "h", "[?]", "[?]", "[?]", "a", "ae", "ya", "yae", "eo", "e", "[?]", "[?]", "yeo", "ye", "o", "wa", "wae", "oe", "[?]", "[?]", "yo", "u", "weo", "we", "wi", "yu", "[?]", "[?]", "eu", "yi", "i", "[?]", "[?]", "[?]", "/C", "PS", "!", "-", "|", "Y=", "W=", "[?]", "|", "-", "|", "-", "|", "#", "O", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "[?]", "{", "|", "}", "", "", "", ""},
-}
-
-data[0] = {" ", "", "", "", "", "", "", "", "", " ", "\n", "", "", "\r", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "", "EUR", "", ",", "f", ",,", "...", "+", "++", "^", "%0", "S", "<", "OE", "", "Z", "", "", "'", "'", "\"", "\"", "*", "-", "--", "~", "tm", "s", ">", "oe", "", "z", "Y", " ", "!", "C/", "PS", "$?", "Y=", "|", "SS", "\"", "(c)", "a", "<<", "!", "", "(r)", "-", "deg", "+-", "2", "3", "'", "u", "P", "*", ",", "1", "o", ">>", "1/4", "1/2", "3/4", "?", "A", "A", "A", "A", "A", "A", "AE", "C", "E", "E", "E", "E", "I", "I", "I", "I", "D", "N", "O", "O", "O", "O", "O", "x", "O", "U", "U", "U", "U", "Y", "Th", "ss", "a", "a", "a", "a", "a", "a", "ae", "c", "e", "e", "e", "e", "i", "i", "i", "i", "d", "n", "o", "o", "o", "o", "o", "/", "o", "u", "u", "u", "u", "y", "th", "y"}
-
-return data;
diff --git a/lib/voicechat.lua b/lib/voicechat.lua
deleted file mode 100644
index 6ff22f9..0000000
--- a/lib/voicechat.lua
+++ /dev/null
@@ -1,485 +0,0 @@
-local ffi = require("ffi")
-local bit = require("bit")
-
-local smallfolk = dofile_once("mods/evaisa.mp/lib/smallfolk.lua")
-
-pcall(ffi.cdef, [[
-typedef uint32_t SDL_AudioDeviceID;
-typedef uint16_t SDL_AudioFormat_vc;
-typedef void (*SDL_AudioCallback_vc)(void *userdata, uint8_t *stream, int len);
-typedef struct SDL_AudioSpec_vc {
- int freq;
- SDL_AudioFormat_vc format;
- uint8_t channels;
- uint8_t silence;
- uint16_t samples;
- uint16_t padding;
- uint32_t size;
- SDL_AudioCallback_vc callback;
- void *userdata;
-} SDL_AudioSpec_vc;
-int SDL_InitSubSystem(uint32_t flags);
-int SDL_GetNumAudioDevices(int iscapture);
-const char *SDL_GetAudioDeviceName(int index, int iscapture);
-SDL_AudioDeviceID SDL_OpenAudioDevice(const char *device, int iscapture,
- const SDL_AudioSpec_vc *desired, SDL_AudioSpec_vc *obtained, int allowed_changes);
-void SDL_PauseAudioDevice(SDL_AudioDeviceID dev, int pause_on);
-uint32_t SDL_DequeueAudio(SDL_AudioDeviceID dev, void *data, uint32_t len);
-uint32_t SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev);
-void SDL_ClearQueuedAudio(SDL_AudioDeviceID dev);
-void SDL_CloseAudioDevice(SDL_AudioDeviceID dev);
-const char *SDL_GetError(void);
-]])
-
-pcall(ffi.cdef, [[
-typedef int FMOD_RESULT;
-typedef struct FMOD_SYSTEM FMOD_SYSTEM;
-typedef struct FMOD_SOUND FMOD_SOUND;
-typedef struct FMOD_CHANNEL FMOD_CHANNEL;
-typedef struct FMOD_CHANNELGROUP FMOD_CHANNELGROUP;
-typedef struct FMOD_VECTOR {
- float x; float y; float z;
-} FMOD_VECTOR;
-typedef struct FMOD_EXINFO_VOICE {
- int cbsize;
- unsigned int length;
- unsigned int fileoffset;
- int numchannels;
- int defaultfrequency;
- int format;
-} FMOD_EXINFO_VOICE;
-static const int FMOD_OK_VC = 0;
-static const unsigned int FMOD_DEFAULT_VC = 0x00000000;
-static const unsigned int FMOD_LOOP_OFF_VC = 0x00000001;
-static const unsigned int FMOD_3D_VC = 0x00000010;
-static const unsigned int FMOD_OPENMEMORY_VC = 0x00000800;
-static const unsigned int FMOD_OPENRAW_VC = 0x00001000;
-static const unsigned int FMOD_INIT_NORMAL_VC = 0x00000000;
-FMOD_RESULT FMOD_System_Create(FMOD_SYSTEM **system);
-FMOD_RESULT FMOD_System_Init(FMOD_SYSTEM *system, int maxchannels, unsigned int flags, void *extradriverdata);
-FMOD_RESULT FMOD_System_CreateSound(FMOD_SYSTEM *system, const char *name_or_data, unsigned int mode, FMOD_EXINFO_VOICE *exinfo, FMOD_SOUND **sound);
-FMOD_RESULT FMOD_System_PlaySound(FMOD_SYSTEM *system, FMOD_SOUND *sound, FMOD_CHANNELGROUP *channelgroup, int paused, FMOD_CHANNEL **channel);
-FMOD_RESULT FMOD_System_Set3DListenerAttributes(FMOD_SYSTEM *system, int listener, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel, const FMOD_VECTOR *forward, const FMOD_VECTOR *up);
-FMOD_RESULT FMOD_System_Update(FMOD_SYSTEM *system);
-FMOD_RESULT FMOD_System_Close(FMOD_SYSTEM *system);
-FMOD_RESULT FMOD_System_Release(FMOD_SYSTEM *system);
-FMOD_RESULT FMOD_Sound_Release(FMOD_SOUND *sound);
-FMOD_RESULT FMOD_Channel_Set3DAttributes(FMOD_CHANNEL *channel, const FMOD_VECTOR *pos, const FMOD_VECTOR *vel);
-FMOD_RESULT FMOD_Channel_SetPaused(FMOD_CHANNEL *channel, int paused);
-FMOD_RESULT FMOD_Channel_Stop(FMOD_CHANNEL *channel);
-FMOD_RESULT FMOD_Channel_Set3DMinMaxDistance(FMOD_CHANNEL *channel, float min, float max);
-FMOD_RESULT FMOD_Channel_SetVolume(FMOD_CHANNEL *channel, float volume);
-FMOD_RESULT FMOD_Channel_IsPlaying(FMOD_CHANNEL *channel, int *isplaying);
-typedef struct FMOD_DSP FMOD_DSP;
-FMOD_RESULT FMOD_System_CreateDSPByType(FMOD_SYSTEM *system, int type, FMOD_DSP **dsp);
-FMOD_RESULT FMOD_Channel_AddDSP(FMOD_CHANNEL *channel, int index, FMOD_DSP *dsp);
-FMOD_RESULT FMOD_DSP_SetParameterFloat(FMOD_DSP *dsp, int index, float value);
-FMOD_RESULT FMOD_DSP_Release(FMOD_DSP *dsp);
-]])
-
-local sdl = ffi.load("SDL2")
-local fmod = ffi.load("fmod")
-
-local SDL_INIT_AUDIO = 0x00000010
-local FMOD_SOUND_FORMAT_PCM16 = 2
-
-local SAMPLE_RATE = 48000
-local CHANNELS = 1
-local BYTES_PER_SAMPLE = 2
-local CHUNK_FRAMES = 9
-local CHUNK_BYTES = SAMPLE_RATE * CHANNELS * BYTES_PER_SAMPLE * CHUNK_FRAMES / 60
-
-local M = {}
-
-local capture_dev = 0
-local playback_dev = 0
-local pcm_accum = {}
-local pcm_accum_bytes = 0
-
-local listener_x = 0
-local listener_y = 0
-
-local VOICE_MIN_DIST = 50.0
-local VOICE_MAX_DIST = 3000.0
-
-local fmod_system = nil
-local playing_voices = {}
-local pending_voices = {}
-local update_tick = 0
-
-local function resample_pcm(pcm_data, target_rate)
- if target_rate == SAMPLE_RATE then return pcm_data end
- local factor = SAMPLE_RATE / target_rate
- local n_in = #pcm_data / 2
- local n_out = math.max(1, math.floor(n_in / factor))
- local in_buf = ffi.new("int16_t[?]", n_in)
- ffi.copy(in_buf, pcm_data, #pcm_data)
- local out_buf = ffi.new("int16_t[?]", n_out)
- for i = 0, n_out - 1 do
- out_buf[i] = in_buf[math.floor(i * factor)]
- end
- return ffi.string(out_buf, n_out * 2)
-end
-
-local last_mic_level = 0.0
-local gate_gain = 0.0
-local GATE_RAMP_RATE = 1.0 / 480
-
-M.get_mic_level = function()
- return last_mic_level
-end
-
-local function init_sdl_audio()
- sdl.SDL_InitSubSystem(SDL_INIT_AUDIO)
-end
-
-local function init_fmod_voice_system()
- if fmod_system ~= nil then return true end
- local sys_ptr = ffi.new("FMOD_SYSTEM*[1]")
- if fmod.FMOD_System_Create(sys_ptr) ~= 0 then return false end
- fmod_system = sys_ptr[0]
- if fmod.FMOD_System_Init(fmod_system, 32, fmod.FMOD_INIT_NORMAL_VC, nil) ~= 0 then
- fmod_system = nil
- return false
- end
- local pos = ffi.new("FMOD_VECTOR", { x = 0, y = 0, z = 0 })
- local vel = ffi.new("FMOD_VECTOR", { x = 0, y = 0, z = 0 })
- local fwd = ffi.new("FMOD_VECTOR", { x = 0, y = 0, z = 1 })
- local up = ffi.new("FMOD_VECTOR", { x = 0, y = 1, z = 0 })
- fmod.FMOD_System_Set3DListenerAttributes(fmod_system, 0, pos, vel, fwd, up)
- return true
-end
-
-local function open_playback()
- if playback_dev ~= 0 then return true end
- init_sdl_audio()
- local desired = ffi.new("SDL_AudioSpec_vc")
- desired.freq = SAMPLE_RATE
- desired.format = 0x8010
- desired.channels = CHANNELS
- desired.samples = 1024
- desired.callback = nil
- local obtained = ffi.new("SDL_AudioSpec_vc")
- local dev = sdl.SDL_OpenAudioDevice(nil, 0, desired, obtained, 0)
- if dev == 0 then
- print("[voicechat] SDL playback open failed: " .. ffi.string(sdl.SDL_GetError()))
- return false
- end
- playback_dev = dev
- sdl.SDL_PauseAudioDevice(playback_dev, 0)
- return true
-end
-
-local function queue_pcm_with_gain(pcm_data, gain)
- if not open_playback() then return end
- local pcm_len = #pcm_data
- local n = pcm_len / 2
- local buf = ffi.new("int16_t[?]", n)
- ffi.copy(buf, pcm_data, pcm_len)
- if gain < 0.999 then
- for i = 0, n - 1 do
- local s = buf[i] * gain
- if s > 32767 then s = 32767 elseif s < -32768 then s = -32768 end
- buf[i] = s
- end
- end
- sdl.SDL_QueueAudio(playback_dev, buf, pcm_len)
-end
-
-local cached_devices = nil
-
-M.enumerate_devices = function()
- init_sdl_audio()
- local count = sdl.SDL_GetNumAudioDevices(1)
- local devices = {}
- for i = 0, count - 1 do
- local name = ffi.string(sdl.SDL_GetAudioDeviceName(i, 1))
- table.insert(devices, name)
- end
- cached_devices = devices
- pcall(GlobalsSetValue, "evaisa.mp.audio_devices", smallfolk.dumps(devices))
- return devices
-end
-
-M.get_devices = function()
- if cached_devices ~= nil then return cached_devices end
- local ok, raw = pcall(GlobalsGetValue, "evaisa.mp.audio_devices", "")
- if not ok or raw == "" then return {} end
- return smallfolk.loads(raw)
-end
-
-M.open_capture = function(device_name)
- if capture_dev ~= 0 then
- sdl.SDL_CloseAudioDevice(capture_dev)
- capture_dev = 0
- end
-
- init_sdl_audio()
-
- local desired = ffi.new("SDL_AudioSpec_vc")
- desired.freq = SAMPLE_RATE
- desired.format = 0x8010
- desired.channels = CHANNELS
- desired.samples = 512
- desired.callback = nil
-
- local obtained = ffi.new("SDL_AudioSpec_vc")
-
- local dev_name_ptr = nil
- if device_name and device_name ~= "" then
- dev_name_ptr = device_name
- end
-
- local dev = sdl.SDL_OpenAudioDevice(dev_name_ptr, 1, desired, obtained, 0)
- if dev == 0 then
- print("[voicechat] SDL_OpenAudioDevice failed: " .. ffi.string(sdl.SDL_GetError()))
- return false
- end
-
- capture_dev = dev
- sdl.SDL_PauseAudioDevice(capture_dev, 0)
- return true
-end
-
-M.close_capture = function()
- if capture_dev ~= 0 then
- sdl.SDL_CloseAudioDevice(capture_dev)
- capture_dev = 0
- end
-end
-
-M.capture_tick = function(ptt_held)
- if capture_dev == 0 then return nil end
-
- local buf_size = 4096
- local buf = ffi.new("uint8_t[?]", buf_size)
- local got = sdl.SDL_DequeueAudio(capture_dev, buf, buf_size)
-
- local target_gain = ptt_held and 1.0 or 0.0
-
- if got > 0 then
- local n_samples = got / 2
- local samples = ffi.cast("int16_t*", buf)
- local sum_sq = 0.0
- for i = 0, n_samples - 1 do
- local s = samples[i] / 32768.0
- sum_sq = sum_sq + s * s
- end
- last_mic_level = math.sqrt(sum_sq / n_samples) * (tonumber(ModSettingGet("evaisa.mp.voicechat_mic_volume")) or 1.0)
- else
- last_mic_level = last_mic_level * 0.85
- end
-
- if target_gain == 0.0 and gate_gain == 0.0 then
- sdl.SDL_ClearQueuedAudio(capture_dev)
- pcm_accum = {}
- pcm_accum_bytes = 0
- return nil
- end
-
- if got == 0 then
- if target_gain == 0.0 then
- gate_gain = 0.0
- sdl.SDL_ClearQueuedAudio(capture_dev)
- pcm_accum = {}
- pcm_accum_bytes = 0
- end
- return nil
- end
-
- local n_samples = got / 2
- local samples = ffi.cast("int16_t*", buf)
- local mic_vol = tonumber(ModSettingGet("evaisa.mp.voicechat_mic_volume")) or 1.0
- for i = 0, n_samples - 1 do
- if target_gain > gate_gain then
- gate_gain = math.min(1.0, gate_gain + GATE_RAMP_RATE)
- elseif target_gain < gate_gain then
- gate_gain = math.max(0.0, gate_gain - GATE_RAMP_RATE)
- end
- local s = samples[i] * gate_gain * mic_vol
- if s > 32767 then s = 32767 elseif s < -32768 then s = -32768 end
- samples[i] = s
- end
-
- if gate_gain == 0.0 then
- pcm_accum = {}
- pcm_accum_bytes = 0
- return nil
- end
-
- table.insert(pcm_accum, ffi.string(buf, got))
- pcm_accum_bytes = pcm_accum_bytes + got
-
- if pcm_accum_bytes >= CHUNK_BYTES then
- local chunk = table.concat(pcm_accum)
- pcm_accum = {}
- pcm_accum_bytes = 0
- return chunk
- end
-
- return nil
-end
-
-M.update_listener = function(x, y)
- listener_x = x
- listener_y = y
- if not init_fmod_voice_system() then return end
- local pos = ffi.new("FMOD_VECTOR", { x = x, y = y, z = 0 })
- local vel = ffi.new("FMOD_VECTOR", { x = 0, y = 0, z = 0 })
- local fwd = ffi.new("FMOD_VECTOR", { x = 0, y = 0, z = 1 })
- local up = ffi.new("FMOD_VECTOR", { x = 0, y = 1, z = 0 })
- fmod.FMOD_System_Set3DListenerAttributes(fmod_system, 0, pos, vel, fwd, up)
-end
-
-M.play_voice = function(pcm_data, x, y, global_vol, player_vol, opts)
- opts = opts or {}
- local delay = opts.delay_frames or 0
- if delay > 0 then
- table.insert(pending_voices, {
- pcm = pcm_data, x = x, y = y,
- global_vol = global_vol, player_vol = player_vol,
- opts = opts,
- play_at = update_tick + delay
- })
- return
- end
-
- if not init_fmod_voice_system() then return end
-
- local sample_rate = opts.sample_rate or SAMPLE_RATE
- local actual_pcm = (sample_rate ~= SAMPLE_RATE) and resample_pcm(pcm_data, sample_rate) or pcm_data
- local data_len = #actual_pcm
- local c_buf = ffi.new("uint8_t[?]", data_len)
- ffi.copy(c_buf, actual_pcm, data_len)
-
- local exinfo = ffi.new("FMOD_EXINFO_VOICE")
- exinfo.cbsize = ffi.sizeof("FMOD_EXINFO_VOICE")
- exinfo.length = data_len
- exinfo.fileoffset = 0
- exinfo.numchannels = CHANNELS
- exinfo.defaultfrequency = sample_rate
- exinfo.format = FMOD_SOUND_FORMAT_PCM16
-
- local mode = bit.bor(fmod.FMOD_LOOP_OFF_VC, fmod.FMOD_OPENMEMORY_VC, fmod.FMOD_OPENRAW_VC, fmod.FMOD_3D_VC)
-
- local sound_ptr = ffi.new("FMOD_SOUND*[1]")
- if fmod.FMOD_System_CreateSound(fmod_system, c_buf, mode, exinfo, sound_ptr) ~= 0 then return end
-
- local ch_ptr = ffi.new("FMOD_CHANNEL*[1]")
- if fmod.FMOD_System_PlaySound(fmod_system, sound_ptr[0], nil, 1, ch_ptr) ~= 0 then
- fmod.FMOD_Sound_Release(sound_ptr[0])
- return
- end
-
- local ch = ch_ptr[0]
- local spos = ffi.new("FMOD_VECTOR", { x = x, y = y, z = 0 })
- local vel = ffi.new("FMOD_VECTOR", { x = 0, y = 0, z = 0 })
- fmod.FMOD_Channel_Set3DAttributes(ch, spos, vel)
- fmod.FMOD_Channel_Set3DMinMaxDistance(ch, VOICE_MIN_DIST, VOICE_MAX_DIST)
- fmod.FMOD_Channel_SetVolume(ch, (global_vol or 1.0) * (player_vol or 1.0))
-
- local entry = { sound = sound_ptr[0], channel = ch }
-
- if opts.reverb then
- local dsp_ptr = ffi.new("FMOD_DSP*[1]")
- if fmod.FMOD_System_CreateDSPByType(fmod_system, 18, dsp_ptr) == 0 then
- local dsp = dsp_ptr[0]
- fmod.FMOD_DSP_SetParameterFloat(dsp, 0, opts.reverb_decay or 1200.0)
- fmod.FMOD_DSP_SetParameterFloat(dsp, 1, opts.reverb_early or 15.0)
- fmod.FMOD_DSP_SetParameterFloat(dsp, 2, opts.reverb_late or 30.0)
- fmod.FMOD_DSP_SetParameterFloat(dsp, 9, opts.reverb_hicut or 4000.0)
- fmod.FMOD_DSP_SetParameterFloat(dsp, 11, opts.reverb_wet or -3.0)
- fmod.FMOD_DSP_SetParameterFloat(dsp, 12, opts.reverb_dry or 0.0)
- fmod.FMOD_Channel_AddDSP(ch, 0, dsp)
- entry.dsp = dsp
- end
- end
-
- fmod.FMOD_Channel_SetPaused(ch, 0)
- table.insert(playing_voices, entry)
-end
-
-M.update = function()
- if fmod_system == nil then return end
-
- update_tick = update_tick + 1
-
- local pi = 1
- while pi <= #pending_voices do
- local pv = pending_voices[pi]
- if update_tick >= pv.play_at then
- local fire_opts = {}
- for k, v in pairs(pv.opts) do fire_opts[k] = v end
- fire_opts.delay_frames = 0
- M.play_voice(pv.pcm, pv.x, pv.y, pv.global_vol, pv.player_vol, fire_opts)
- table.remove(pending_voices, pi)
- else
- pi = pi + 1
- end
- end
-
- local i = 1
- while i <= #playing_voices do
- local v = playing_voices[i]
- local is_playing = ffi.new("int[1]")
- fmod.FMOD_Channel_IsPlaying(v.channel, is_playing)
- if is_playing[0] == 0 then
- if v.dsp then fmod.FMOD_DSP_Release(v.dsp) end
- fmod.FMOD_Sound_Release(v.sound)
- table.remove(playing_voices, i)
- else
- i = i + 1
- end
- end
-
- fmod.FMOD_System_Update(fmod_system)
-end
-
-local recording_buffer = nil
-
-M.start_recording = function()
- recording_buffer = {}
-end
-
-M.stop_recording = function()
- if recording_buffer == nil then return nil end
- local result = table.concat(recording_buffer)
- recording_buffer = nil
- return result
-end
-
-M.record_chunk = function(pcm_chunk)
- if recording_buffer ~= nil then
- table.insert(recording_buffer, pcm_chunk)
- end
-end
-
-M.is_recording = function()
- return recording_buffer ~= nil
-end
-
-M.play_direct = function(pcm_data)
- queue_pcm_with_gain(pcm_data, 1.0)
-end
-
-M.cleanup = function()
- M.close_capture()
- pending_voices = {}
- for _, v in ipairs(playing_voices) do
- fmod.FMOD_Channel_Stop(v.channel)
- if v.dsp then fmod.FMOD_DSP_Release(v.dsp) end
- fmod.FMOD_Sound_Release(v.sound)
- end
- playing_voices = {}
- if fmod_system ~= nil then
- fmod.FMOD_System_Close(fmod_system)
- fmod.FMOD_System_Release(fmod_system)
- fmod_system = nil
- end
- if playback_dev ~= 0 then
- sdl.SDL_CloseAudioDevice(playback_dev)
- playback_dev = 0
- end
-end
-
-return M
diff --git a/lib/zstd.lua b/lib/zstd.lua
deleted file mode 100644
index cdb4288..0000000
--- a/lib/zstd.lua
+++ /dev/null
@@ -1,321 +0,0 @@
-
--- facebook zstandard ffi binding
--- Written by Soojin Nam. Public Domain.
-
-
-local ffi = require "ffi"
-local C = ffi.C
-local ffi_new = ffi.new
-local ffi_load = ffi.load
-local ffi_str = ffi.string
-local ffi_typeof = ffi.typeof
-local assert = assert
-local tonumber = tonumber
-local fopen = io.open
-local gsub = string.gsub
-local tinsert = table.insert
-local tconcat = table.concat
-
-
-ffi.cdef[[
-typedef struct ZSTD_CCtx_s ZSTD_CCtx;
-ZSTD_CCtx* ZSTD_createCCtx(void);
-size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx);
-
-typedef struct ZSTD_DCtx_s ZSTD_DCtx;
-ZSTD_DCtx* ZSTD_createDCtx(void);
-size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx);
-
-unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize);
-size_t ZSTD_compressBound(size_t srcSize);
-int ZSTD_maxCLevel(void);
-unsigned ZSTD_isError(size_t code);
-const char* ZSTD_getErrorName(size_t code);
-
-typedef struct ZSTD_inBuffer_s {
- const void* src;
- size_t size;
- size_t pos;
-} ZSTD_inBuffer;
-
-typedef struct ZSTD_outBuffer_s {
- void* dst;
- size_t size;
- size_t pos;
-} ZSTD_outBuffer;
-
-typedef struct ZSTD_CStream_s ZSTD_CStream;
-ZSTD_CStream* ZSTD_createCStream(void);
-size_t ZSTD_freeCStream(ZSTD_CStream* zcs);
-size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel);
-size_t ZSTD_compressStream(ZSTD_CStream* zcs,
- ZSTD_outBuffer* output, ZSTD_inBuffer* input);
-size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output);
-size_t ZSTD_CStreamInSize(void);
-size_t ZSTD_CStreamOutSize(void);
-
-typedef struct ZSTD_DStream_s ZSTD_DStream;
-ZSTD_DStream* ZSTD_createDStream(void);
-size_t ZSTD_freeDStream(ZSTD_DStream* zds);
-size_t ZSTD_initDStream(ZSTD_DStream* zds);
-size_t ZSTD_decompressStream(ZSTD_DStream* zds,
- ZSTD_outBuffer* output, ZSTD_inBuffer* input);
-size_t ZSTD_DStreamInSize(void);
-size_t ZSTD_DStreamOutSize(void);
-
-typedef struct ZSTD_CDict_s ZSTD_CDict;
-ZSTD_CDict* ZSTD_createCDict(const void* dictBuffer, size_t dictSize,
- int compressionLevel);
-size_t ZSTD_freeCDict(ZSTD_CDict* CDict);
-size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const ZSTD_CDict* cdict);
-
-typedef struct ZSTD_DDict_s ZSTD_DDict;
-ZSTD_DDict* ZSTD_createDDict(const void* dictBuffer, size_t dictSize);
-size_t ZSTD_freeDDict(ZSTD_DDict* ddict);
-size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
- void* dst, size_t dstCapacity,
- const void* src, size_t srcSize,
- const ZSTD_DDict* ddict);
-unsigned ZSTD_getDictID_fromDDict(const ZSTD_DDict* ddict);
-unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize);
-]]
-
-
-local arr_utint8_t = ffi_typeof "uint8_t[?]"
-local ptr_zstd_inbuffer_t = ffi_typeof "ZSTD_inBuffer[1]"
-local ptr_zstd_outbuffer_t = ffi_typeof "ZSTD_outBuffer[1]"
-
-
-local zstd = ffi.load(package.searchpath("libzstd", package.cpath))
-
-
-local _M = {
- version = '0.2.3'
-}
-
-
-local function init_cstream (cstream, cLevel)
- local res = zstd.ZSTD_initCStream(cstream, cLevel or 1);
- if zstd.ZSTD_isError(res) ~= 0 then
- return "ZSTD_initCStream() error: "..ffi_str(zstd.ZSTD_getErrorName(res))
- end
-end
-
-
-local function init_dstream (dstream)
- local res = zstd.ZSTD_initDStream(dstream)
- if zstd.ZSTD_isError(res) ~= 0 then
- return "ZSTD_initDStream() error: "..ffi_str(zstd.ZSTD_getErrorName(res))
- end
-end
-
-
-local function end_frame (cstream)
- local olen = zstd.ZSTD_CStreamOutSize();
- local obuf = ffi_new(arr_utint8_t, olen);
- local output = ffi_new(ptr_zstd_outbuffer_t)
- output[0] = { obuf, olen, 0 }
- if zstd.ZSTD_endStream(cstream, output) ~= 0 then
- return nil, "not fully flushed"
- end
- return ffi_str(obuf, output[0].pos)
-end
-
-
-function _M.new (self)
- local cstream = zstd.ZSTD_createCStream();
- if not cstream then
- return nil, "ZSTD_createCStream() error"
- end
- local dstream = zstd.ZSTD_createDStream();
- if not dstream then
- return nil, "ZSTD_createDStream() error"
- end
- return setmetatable({cstream = cstream, dstream = dstream}, {__index = _M})
-end
-
-
-function _M.free (self)
- zstd.ZSTD_freeCStream(self.cstream)
- zstd.ZSTD_freeDStream(self.dstream)
-end
-
-
-function _M.maxCLevel (self)
- return tonumber(zstd.ZSTD_maxCLevel())
-end
-
-
-local function compress_stream (cstream, inbuf, cLevel)
- local cLevel = cLevel or 1
- local insize = #inbuf
- local olen = zstd.ZSTD_CStreamOutSize();
- local obuf = ffi_new(arr_utint8_t, olen);
- local input = ffi_new(ptr_zstd_inbuffer_t)
- local output = ffi_new(ptr_zstd_outbuffer_t)
- local rlen = insize;
- local result = {}
- input[0] = { inbuf, rlen, 0 }
- while input[0].pos < input[0].size do
- output[0] = { obuf, olen, 0 }
- rlen = zstd.ZSTD_compressStream(cstream, output, input);
- if zstd.ZSTD_isError(rlen) ~= 0 then
- return nil, "ZSTD_compressStream() error: "
- .. ffi_str(zstd.ZSTD_getErrorName(rlen))
- end
- if rlen > insize then
- rlen = insize
- end
- tinsert(result, ffi_str(obuf, output[0].pos))
- end
- return tconcat(result)
-end
-
-
-local function decompress_stream (dstream, inbuf)
- local rlen = #inbuf
- local olen = zstd.ZSTD_DStreamOutSize()
- local obuf = ffi_new(arr_utint8_t, olen)
- local input = ffi_new(ptr_zstd_inbuffer_t)
- local output = ffi_new(ptr_zstd_outbuffer_t)
- local decompressed = {}
- input[0] = { inbuf, rlen, 0 }
- while input[0].pos < input[0].size do
- output[0] = { obuf, olen, 0 }
- rlen = zstd.ZSTD_decompressStream(dstream, output, input);
- if zstd.ZSTD_isError(rlen) ~= 0 then
- return nil, "ZSTD_decompressStream() error: "
- .. ffi_str(zstd.ZSTD_getErrorName(rlen))
- end
- tinsert(decompressed, ffi_str(obuf, output[0].pos))
- end
- return tconcat(decompressed)
-end
-
-
-function _M:compress (fBuff, cLevel)
- local cstream = self.cstream
- local err = init_cstream(cstream, cLevel)
- if err then
- return nil, err
- end
- return compress_stream(cstream, fBuff, cLevel) .. end_frame(cstream)
-end
-
-
-function _M:decompress (cBuff)
- local dstream = self.dstream
- local err = init_dstream(dstream)
- if err then
- return nil, err
- end
- return decompress_stream(dstream, cBuff)
-end
-
-
-function _M:compressFile (fname, cLevel)
- local cstream = self.cstream
- local fin = assert(fopen(fname, "rb"))
- local fout = assert(fopen(fname..".zst", "wb"))
- local err = init_cstream(cstream, cLevel)
- if err then
- return nil, err
- end
- local rlen = tonumber(zstd.ZSTD_CStreamInSize());
- local buff = fin:read(rlen)
- while buff do
- local obuff = compress_stream(cstream, buff, cLevel)
- fout:write(obuff)
- buff = fin:read(rlen)
- end
- fout:write(end_frame(cstream))
- fout:close()
- fin:close()
- return true
-end
-
-
-function _M:decompressFile (fname, oname)
- local dstream = self.dstream
- local fin = assert(fopen(fname, "rb"))
- local fout = assert(fopen(oname or gsub(fname, "%.zst", ""), "wb"))
- local err = init_dstream(dstream)
- if err then
- return nil, err
- end
- local rlen = tonumber(zstd.ZSTD_DStreamInSize())
- local buff = fin:read(rlen)
- while buff do
- local obuff = decompress_stream(dstream, buff)
- fout:write(obuff)
- buff = fin:read(rlen)
- end
- fout:close()
- fin:close()
- return true
-end
-
-
-local function create_dict (iscompress, fname, cLevel)
- local fd = assert(fopen(fname, "rb"))
- local current = fd:seek()
- local dictSize = fd:seek("end")
- fd:seek("set", current)
- local dictBuffer = ffi_new("char[?]", dictSize, fd:read("*a"))
- fd:close()
- return iscompress
- and zstd.ZSTD_createCDict(dictBuffer, dictSize, cLevel)
- or zstd.ZSTD_createDDict(dictBuffer, dictSize)
-end
-
-
-function _M:compressFileUsingDictionary (fname, dname, cLevel)
- local cdict = create_dict(true, dname, cLevel or 1)
-
- local fin = assert(fopen(fname, "rb"))
- local current = fin:seek()
- local fSize = fin:seek("end")
- fin:seek("set", current)
- local fBuff = ffi_new("char[?]", fSize, fin:read("*a"))
- fin:close()
-
- local cBuffSize = zstd.ZSTD_compressBound(fSize)
- local cBuff = ffi_new("char[?]", cBuffSize)
- local cctx = zstd.ZSTD_createCCtx()
- local cSize = zstd.ZSTD_compress_usingCDict(cctx, cBuff, cBuffSize,
- fBuff, fSize, cdict)
- local fout = assert(fopen(fname..".zst", "wb"))
- fout:write(ffi_str(cBuff, cSize))
- fout:close()
- zstd.ZSTD_freeCCtx(cctx)
- return true
-end
-
-
-function _M:decompressFileUsingDictionary (fname, oname, dname)
- local ddict = create_dict(false, dname)
-
- local fin = assert(fopen(fname, "rb"))
- local current = fin:seek()
- local cSize = fin:seek("end")
- fin:seek("set", current)
- local cBuff = ffi_new("char[?]", cSize, fin:read("*a"))
- fin:close()
-
- local rSize = zstd.ZSTD_getFrameContentSize(cBuff, cSize)
- local rBuff = ffi_new("char[?]", rSize)
- local dctx = zstd.ZSTD_createDCtx()
- local dSize = zstd.ZSTD_decompress_usingDDict(dctx, rBuff, rSize,
- cBuff, cSize, ddict)
- local fout = assert(fopen(oname or gsub(fname, "%.zst", ""), "wb"))
- fout:write(ffi_str(rBuff, rSize))
- fout:close()
- zstd.ZSTD_freeDCtx(dctx)
- return true
-end
-
-
-return _M
\ No newline at end of file
diff --git a/magic_numbers_trailer.xml b/magic_numbers_trailer.xml
deleted file mode 100644
index 83ea07c..0000000
--- a/magic_numbers_trailer.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
\ No newline at end of file
diff --git a/menu_banner_background.png b/menu_banner_background.png
deleted file mode 100644
index 6d26fe6..0000000
Binary files a/menu_banner_background.png and /dev/null differ
diff --git a/menu_banner_overlay.png b/menu_banner_overlay.png
deleted file mode 100644
index 2bd93f0..0000000
Binary files a/menu_banner_overlay.png and /dev/null differ
diff --git a/mod.xml b/mod.xml
deleted file mode 100644
index 8758910..0000000
--- a/mod.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/online.bank b/online.bank
deleted file mode 100644
index fad0797..0000000
Binary files a/online.bank and /dev/null differ
diff --git a/settings.lua b/settings.lua
deleted file mode 100644
index 442c1f2..0000000
--- a/settings.lua
+++ /dev/null
@@ -1,511 +0,0 @@
-dofile("data/scripts/lib/mod_settings.lua")
-
-
-
-local mod_id = "evaisa.mp" -- This should match the name of your mod's folder.
-mod_settings_version = 1 -- This is a magic global that can be used to migrate settings to new mod versions. call mod_settings_get_version() before mod_settings_update() to get the old value.
-mod_settings =
-{
-
- --[[{
- id = "artificial_lag",
- ui_name = "Artificial Lag",
- ui_description = "Adds a delay to all network traffic. Useful for testing network code.",
- value_default = 1,
- value_min = 1,
- value_max = 60,
- value_display_multiplier = 1,
- value_display_formatting = " $0",
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },]]
- {
- id = "hide_lobby_code",
- ui_name = "Hide Lobby Code",
- ui_description = "Censor lobby code in join lobby menu.",
- value_default = false,
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },
- {
- id = "presets_as_json",
- ui_name = "Presets as JSON",
- ui_description = "Save presets as plain text JSON files.\nThis allows you to edit presets outside of the game. \nIssues caused by doing so will not be supported.",
- value_default = false,
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },
- {
- id = "streamer_mode",
- ui_name = "Streamer Mode",
- ui_description = "Disable avatars and other stuff.",
- value_default = false,
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },
- {
- id = "streamer_mode_detection",
- ui_name = "Streaming App Detection",
- ui_description = "Show popup asking if you want to enable streamer mode if a streaming app is detected, and streamer mode is disabled.",
- value_default = true,
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },
- {
- id = "flip_chat_direction",
- ui_name = "Flip chat direction",
- ui_description = "Make new messages appear on the top of the chat box.",
- value_default = false,
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },
- {
- id = "profiler_rate",
- ui_name = "Profiler Rate",
- ui_description = "The rate at which the debugging profiler runs, in frames.",
- value_default = 1,
- value_min = 1,
- value_max = 300,
- value_display_multiplier = 1,
- value_display_formatting = " $0",
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },
- {
- category_id = "keybinds",
- ui_name = "Keybindings",
- ui_description = "You can edit keybinds here.",
- foldable = true,
- _folded = true,
- settings = {
- }
- },
- {
- category_id = "voicechat",
- ui_name = "Voice Chat",
- ui_description = "Configure voice chat settings.",
- foldable = true,
- _folded = true,
- settings = {
- {
- id = "voicechat_enabled",
- ui_name = "Enable Voice Chat",
- ui_description = "Enable proximity voice chat.",
- value_default = true,
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },
- {
- id = "voicechat_volume",
- ui_name = "Voice Chat Volume",
- ui_description = "Global volume multiplier for received voice chat.",
- value_default = 1.0,
- value_min = 0.0,
- value_max = 2.0,
- value_display_multiplier = 100,
- value_display_formatting = " $0%",
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },
- {
- id = "voicechat_mic_volume",
- ui_name = "Microphone Volume",
- ui_description = "Amplify or reduce your microphone output volume.",
- value_default = 1.0,
- value_min = 0.0,
- value_max = 2.0,
- value_display_multiplier = 100,
- value_display_formatting = " $0%",
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },
- {
- id = "voicechat_vad_mode",
- ui_name = "Voice Activation",
- ui_description = "Use voice activation instead of push-to-talk.\nWhen enabled, your mic activates automatically when you speak.",
- value_default = false,
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },
- {
- id = "voicechat_vad_threshold",
- ui_name = "Activation Threshold",
- ui_description = "How loud you need to speak to trigger voice activation.\nLower = more sensitive.",
- value_default = 0.01,
- value_min = 0,
- value_max = 0.1,
- value_display_multiplier = 1000,
- value_display_formatting = " $0%",
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },
- {
- id = "voicechat_intercom_monitor",
- ui_name = "Intercom Monitor",
- ui_description = "Hear your own voice through the speakers when speaking into an intercom.",
- value_default = false,
- scope = MOD_SETTING_SCOPE_RUNTIME,
- },
- }
- }
-
-}
-
-local bindings = nil
-
-function ModSettingsUpdate(init_scope)
- local old_version = mod_settings_get_version(mod_id)
- mod_settings_update(mod_id, mod_settings, init_scope)
-
-
-end
-
-
-function settings_count( mod_id, settings )
- local result = 0
-
- for i,setting in ipairs(settings) do
- if setting.category_id ~= nil then
- local visible = not setting._folded
- if visible then
- result = result + settings_count( mod_id, setting.settings )
- end
- else
- local visible = not setting.hidden or setting.hidden == nil
- if visible then
- result = result + 1
- end
- end
- end
-
- return result
-end
-
-function ModSettingsGuiCount()
- local count = settings_count(mod_id, mod_settings)
- --print("settings count: " .. count)
- return count
-end
-
-
-function mod_setting_button( mod_id, gui, in_main_menu, im_id, setting )
- local value = setting.handler_callback( mod_id, setting )
-
- if(value == "[Unbound]")then
- GuiColorSetForNextWidget( gui, 0.5, 0.5, 0.5, 1 )
- end
-
- local text = setting.ui_name .. ": " .. value
-
- local clicked,right_clicked = GuiButton( gui, im_id, mod_setting_group_x_offset, 0, text )
- if clicked then
- setting.clicked_callback( mod_id, setting, value )
- end
- if right_clicked then
- setting.right_clicked_callback( mod_id, setting, value )
- end
-
- mod_setting_tooltip( mod_id, gui, in_main_menu, setting )
-end
-
-
-local function ToID (str)
- str = str:gsub("[^%w]", "_")
- -- lowercase
- str = str:lower()
- return str
-end
-
-local old_mod_setting_title = mod_setting_title
-mod_setting_title = function ( mod_id, gui, in_main_menu, im_id, setting )
- if(setting.color)then
- GuiColorSetForNextWidget( gui, setting.color[1], setting.color[2], setting.color[3], setting.color[4] )
- end
- old_mod_setting_title(mod_id, gui, in_main_menu, im_id, setting)
-end
-
-mod_setting_number = function( mod_id, gui, in_main_menu, im_id, setting )
- local value = ModSettingGetNextValue( mod_setting_get_id(mod_id,setting) )
- if type(value) ~= "number" then value = setting.value_default or 0.0 end
-
- local value_new = GuiSlider( gui, im_id, mod_setting_group_x_offset, 0, setting.ui_name, value, setting.value_min, setting.value_max, setting.value_default, setting.value_display_multiplier or 1, setting.value_display_formatting or "", 160 )
- if value ~= value_new then
- ModSettingSetNextValue( mod_setting_get_id(mod_id,setting), value_new, false )
- mod_setting_handle_change_callback( mod_id, gui, in_main_menu, setting, value, value_new )
- end
-
- mod_setting_tooltip( mod_id, gui, in_main_menu, setting )
-end
-
-local function GenerateDisplayName(id)
- -- if id starts with "Key_", remove it
- if(id:sub(1, 4) == "Key_")then
- id = id:sub(5)
- end
-
- -- if starts with "JOY_BUTTON", replace with "Gamepad"
- if(id:sub(1, 11) == "JOY_BUTTON_")then
- id = "Gamepad " .. id:sub(12)
- end
-
- -- replace underscores with spaces
- id = id:gsub("_", " ")
- -- lowercase, then capitalize first letter
- id = id:sub(1, 1):upper() .. id:sub(2):lower()
-
- -- trim
- id = id:match("^%s*(.-)%s*$")
-
- if(id == "")then
- id = "Unbound"
- end
-
- return id
-end
-
-function ImageClip(gui, id, x, y, width, height, fn, ...)
- GuiAnimateBegin(gui)
- GuiAnimateAlphaFadeIn(gui, id * 620, 0, 0, true)
- GuiBeginAutoBox(gui)
-
- GuiZSetForNextWidget(gui, 1000)
- GuiBeginScrollContainer(gui, id * 630, x, y, width, height, false, 0, 0)
- GuiEndAutoBoxNinePiece(gui)
- GuiAnimateEnd(gui)
- fn(gui, width, height, ...)
- GuiEndScrollContainer(gui)
-end
-
-function ModSettingsGui(gui, in_main_menu)
- last_gui_frame = last_gui_frame or GameGetFrameNum()
-
- if(last_gui_frame ~= GameGetFrameNum() - 1)then
- bindings = nil
- end
-
- last_gui_frame = GameGetFrameNum()
-
- if(bindings == nil and not in_main_menu)then
- bindings = dofile_once("mods/evaisa.mp/lib/keybinds.lua")
- bindings:Load()
-
- local settings_cat = nil
- local all_bindings = {}
- -- sort bindings by category
- for _, id in pairs(bindings._binding_order)do
- if(bindings._bindings[id])then
- local bindy = bindings._bindings[id]
- bindy.id = id
- table.insert(all_bindings, bindy)
- end
- end
-
- table.sort(all_bindings, function(a, b)
- return a.category < b.category
- end)
-
- for k, v in ipairs(mod_settings)do
- if(v.category_id == "keybinds")then
- settings_cat = v
- break
- end
- end
- local last_cat = nil
- for _, bind in pairs(all_bindings)do
- if(bind.category ~= last_cat)then
- last_cat = bind.category
- local cat = {
- id = "cat_" .. ToID(bind.category),
- ui_name = bind.category,
- ui_description = "Edit your keybinds here.",
- offset_x = -4,
- color = {219 / 255, 156 / 255, 79 / 255, 1},
- not_setting = true,
- }
- table.insert(settings_cat.settings, cat)
- end
-
- local id = bind.id
- local setting = {
- id = id,
- ui_name = bind.name,
- ui_description = "",
- value_default = bind.default,
- ui_fn = mod_setting_button,
- clicked_callback = function(mod_id, setting, value)
- bindings._bindings[setting.id].being_set = true
- end,
- right_clicked_callback = function(mod_id, setting, value)
- ModSettingSet("keybind."..bindings._bindings[setting.id].category .. "." .. setting.id, bindings._bindings[setting.id].default)
- ModSettingSet("keybind."..bindings._bindings[setting.id].category .. "." .. setting.id .. ".type", bindings._bindings[setting.id].default_type)
- bindings._bindings[setting.id].value = bindings._bindings[setting.id].default
- bindings._bindings[setting.id].type = bindings._bindings[setting.id].default_type
-
- bindings._bindings[setting.id].being_set = false
- end,
- handler_callback = function(mod_id, setting)
-
- if(bindings._bindings == nil)then
- print("bindings._bindings is nil")
- return "[Error]"
- end
-
- if(bindings._bindings[setting.id] == nil)then
- print("bindings._bindings[setting.id] is nil")
- return "[Error]"
- end
-
- if(bindings._bindings[setting.id].being_set)then
- return "[...]"
- end
- return "["..GenerateDisplayName(bindings._bindings[setting.id].value).."]"
- end
- }
-
- print("Adding keybind: " .. id)
-
- table.insert(settings_cat.settings, setting)
- end
- end
-
- local vc_cat = nil
- for k, v in ipairs(mod_settings) do
- if v.category_id == "voicechat" then
- vc_cat = v
- break
- end
- end
-
- if vc_cat ~= nil and not in_main_menu then
- local raw_devices = GlobalsGetValue("evaisa.mp.audio_devices", "")
- local smallfolk = dofile_once("mods/evaisa.mp/lib/smallfolk.lua")
- local devices = (raw_devices ~= "" and smallfolk.loads(raw_devices)) or {}
-
- local saved_name = ModSettingGet("evaisa.mp.mic_device_name") or ""
- local display_name = saved_name ~= "" and saved_name or "Default"
-
- local mic_device_exists = false
- local mic_level_exists = false
- local mic_test_exists = false
- for _, s in ipairs(vc_cat.settings) do
- if s.id == "mic_device" then mic_device_exists = true end
- if s.id == "mic_level_display" then mic_level_exists = true end
- if s.id == "mic_test_button" then mic_test_exists = true end
- end
-
- if not mic_device_exists then
- table.insert(vc_cat.settings, {
- id = "mic_device",
- ui_name = "Microphone",
- ui_description = "Select the microphone to use for voice chat.",
- ui_fn = mod_setting_button,
- clicked_callback = function(mod_id, setting, value)
- local raw = GlobalsGetValue("evaisa.mp.audio_devices", "")
- local sf = dofile_once("mods/evaisa.mp/lib/smallfolk.lua")
- local devs = (raw ~= "" and sf.loads(raw)) or {}
- local cur_name = ModSettingGet("evaisa.mp.mic_device_name") or ""
- local cur_idx = 0
- for i, name in ipairs(devs) do
- if name == cur_name then
- cur_idx = i
- break
- end
- end
- local next_idx = cur_idx + 1
- if next_idx > #devs then
- next_idx = 0
- end
- if next_idx == 0 then
- ModSettingSet("evaisa.mp.mic_device_name", "")
- GlobalsSetValue("evaisa.mp.mic_device_changed", "1")
- else
- ModSettingSet("evaisa.mp.mic_device_name", devs[next_idx])
- GlobalsSetValue("evaisa.mp.mic_device_changed", "1")
- end
- end,
- right_clicked_callback = function(mod_id, setting, value)
- ModSettingSet("evaisa.mp.mic_device_name", "")
- GlobalsSetValue("evaisa.mp.mic_device_changed", "1")
- end,
- handler_callback = function(mod_id, setting)
- local name = ModSettingGet("evaisa.mp.mic_device_name") or ""
- return "[" .. (name ~= "" and name or "Default") .. "]"
- end,
- })
- end
-
- if not mic_level_exists then
- table.insert(vc_cat.settings, {
- id = "mic_level_display",
- ui_name = "Mic Level",
- ui_description = "Live microphone input level. Use this to tune the activation threshold.",
- not_setting = true,
- ui_fn = function(mod_id, gui, in_main_menu, im_id, setting)
- local level = tonumber(GlobalsGetValue("evaisa.mp.mic_level", "0")) or 0
- local threshold = tonumber(ModSettingGet("evaisa.mp.voicechat_vad_threshold")) or 0.04
- local max_level = 0.1
- local bar_w = 120
- local bar_h = 6
- local ox = mod_setting_group_x_offset
- local above = level >= threshold
-
- local filled_w = math.max(1, math.floor(math.min(level / max_level, 1.0) * bar_w))
- local empty_w = bar_w - filled_w
- local threshold_x = math.min(math.floor(math.min(threshold / max_level, 1.0) * bar_w), bar_w - 1)
-
- local pre_filled = math.min(filled_w, threshold_x)
- local pre_empty = math.max(0, threshold_x - filled_w)
- local post_filled = math.max(0, filled_w - threshold_x - 1)
- local post_empty = bar_w - threshold_x - 1 - post_filled
-
- ImageClip(gui, 32512396, 0, 0, bar_w, bar_h, function(gui, width, height)
- GuiLayoutBeginHorizontal(gui, ox, 0, true, 0, 0)
-
- if pre_filled > 0 then
- if above then
- GuiColorSetForNextWidget(gui, 0.3, 0.9, 0.4, 1)
- else
- GuiColorSetForNextWidget(gui, 0.5, 0.7, 0.9, 1)
- end
- GuiImage(gui, 3185122, 0, 0, "mods/evaisa.mp/files/gfx/ui/1pixel.png", 1, pre_filled, bar_h, 0)
- end
- if pre_empty > 0 then
- GuiColorSetForNextWidget(gui, 0.15, 0.15, 0.15, 1)
- GuiImage(gui, 3185123, 0, 0, "mods/evaisa.mp/files/gfx/ui/1pixel.png", 1, pre_empty, bar_h, 0)
- end
-
- GuiColorSetForNextWidget(gui, 1, 0.2, 0.2, 1)
- GuiImage(gui, 3185124, 0, 0, "mods/evaisa.mp/files/gfx/ui/1pixel.png", 1, 1, bar_h, 0)
-
- if post_filled > 0 then
- if above then
- GuiColorSetForNextWidget(gui, 0.3, 0.9, 0.4, 1)
- else
- GuiColorSetForNextWidget(gui, 0.5, 0.7, 0.9, 1)
- end
- GuiImage(gui, 3185125, 0, 0, "mods/evaisa.mp/files/gfx/ui/1pixel.png", 1, post_filled, bar_h, 0)
- end
- if post_empty > 0 then
- GuiColorSetForNextWidget(gui, 0.15, 0.15, 0.15, 1)
- GuiImage(gui, 3185126, 0, 0, "mods/evaisa.mp/files/gfx/ui/1pixel.png", 1, post_empty, bar_h, 0)
- end
-
- GuiLayoutEnd(gui)
- end)
- end,
- })
- end
-
- if not mic_test_exists then
- table.insert(vc_cat.settings, {
- id = "mic_test_button",
- ui_name = "Test Microphone",
- ui_description = "Toggle microphone loopback test. You will hear yourself with a short delay.",
- ui_fn = mod_setting_button,
- clicked_callback = function(mod_id, setting, value)
- GlobalsSetValue("evaisa.mp.request_mic_test_toggle", "1")
- end,
- right_clicked_callback = function(mod_id, setting, value)
- GlobalsSetValue("evaisa.mp.request_mic_test_toggle", "1")
- end,
- handler_callback = function(mod_id, setting)
- return GlobalsGetValue("evaisa.mp.mic_test_active", "0") == "1" and "[Active]" or "[Off]"
- end,
- })
- end
- end
-
- mod_settings_gui(mod_id, mod_settings, gui, in_main_menu)
-
- if(bindings ~= nil)then
- bindings:Update()
- end
-end
diff --git a/translations.csv b/translations.csv
index c845241..17bd1f8 100644
--- a/translations.csv
+++ b/translations.csv
@@ -1,154 +1,154 @@
-,en,ru,pt-br,es-es,de,fr-fr,it,pl,zh-cn,jp,ko,,NOTES – use \n for newline,max length
-current_language,English,Русский,Português [Brasil],Español,Deutsch,Francais,Italiano,Polski,简体中文,日本語,한국어,,,
-mp_create_lobby,Create Lobby,Создать комнату,,,Erstelle Raum,,,Stwórz pokój,创建房间,,,,,
-mp_lobby_list_header,Create or Join Lobby,Создать или присоединиться к комнате,,,Erstelle oder Betrete Raum,,,Stwórz lub dołącz do pokoju,创建或加入房间,,,,,
-mp_join_with_code,Join lobby with code,Присоединиться используя код,,,Betrete Raum mit Code,,,Dołącz do pokoju za pomocą kodu,加入密钥房间,,,,,
-mp_refresh_lobby_list,Refresh lobby list,Обновить список комнат,,,Aktualisiere Raum Liste,,,Odśwież listę pokoi,刷新房间列表,,,,,
-mp_friend_lobbies,Friend Lobbies,Комнаты друзей,,,Räume von Freunden,,,Pokoje znajomych,好 友 房 间,,,,,
-mp_public_lobbies,Public Lobbies,Общие комнаты,,,Öffentliche Räume,,,Publiczne pokoje,公 开 房 间,,,,,
-mp_no_lobbies_found,No lobbies found,Комнат не найдено,,,Keine Räume gefunden,,,Nie znaleziono żadnych pokoi,好像没有房间诶(创建一个吧?),,,,,
-mp_lobby_type,Lobby type,Тип комнаты,,,Raum Typ,,,Rodzaj pokoju,房间类型,,,,,
-mp_public,Public,Общая,,,Öffentlich,,,Publiczny,公开,,,,,
-mp_private,Private,Приватная,,,Privat,,,Prywatny,私人密钥,,,,,
-mp_friends_only,Friends Only,Только для друзей,,,Nur Freunde,,,Tylko znajomi,仅限好友,,,,,
-mp_gamemode,Gamemode,Режим игры,,,Spielmodus,,,Tryb gry,游戏模式,,,,,
-mp_lobby_name,Lobby name,Имя комнаты,,,Raum Name,,,Nazwa pokoju,房间名字,,,,,
-mp_max_players,Max players,Максимум игроков,,,Maximale Spieler,,,Maksymalna ilośc graczy,玩家数量,,,,,
-mp_world_seed,World seed,Семя мира,,,Welt Seed,,,Ziarno świata,世界种子,,,,,
-mp_join_lobby,Join lobby,Присоединиться к комнате,,,Betrete Raum,,,Dołącz do pokoju za pomocą kodu,加入房间,,,,,
-mp_return_menu,Return to menu,Вернуться в меню,,,Kehre zum Menü zurück,,,Wróć do menu,返回主界面,,,,,
-mp_paste_code,Paste code from clipboard,Вставить код из буфера обмена,,,Füge Code vom Clipboard ein,,,Wklej kod,从剪贴板粘贴密钥,,,,,
-mp_lobby_code,Lobby code,Код комнаты,,,Raum Code,,,Kod pokoju,房间密钥,,,,,
-mp_lobby,Lobby,Комната,,,Raum,,,Pokój,房间,,,,,
-mp_show,Show,Показать,,,Zeigen,,,Pokaż,显示,,,,,
-mp_show_tooltip,Show the lobby code,Показать код комнаты,,,Zeige Raum Code,,,Pokaż kod pokoju,显示房间密钥,,,,,
-mp_copy,Copy,Копировать,,,kopieren,,,Kopiuj,复制,,,,,
-mp_copy_tooltip,Copy the lobby code to your clipboard,Копировать код комнаты в буфер обмена,,,Kopiere den Raum Code,,,Kopiuj kod pokoju do schowka,复制房间密钥,,,,,
-mp_hide,Hide,Спрятать,,,verstecken,,,Ukryj,隐藏,,,,,
-mp_hide_tooltip,Hide the lobby code,Спрятать код комнаты,,,verstecke den Raum Code,,,Ukryj kod pokoju,隐藏房间密钥,,,,,
-mp_leave_lobby,Leave lobby,Покинуть комнату,,,Raum verlassen,,,Wyjdź z pokoju,离开房间,,,,,
-mp_invite_players,Invite players,Пригласить игроков,,,Spieler einladen,,,Zaproś znajomych,邀请好友,,,,,
-mp_lobby_settings,Lobby settings,Настройки комнаты,,,Raum einstellungen,,,Ustawienia pokoju,房间设置,,,,,
-mp_start_game,Start game,Начать игру,,,Spiel starten,,,Rozpocznij grę,开始游戏,,,,,
-mp_restart_game,Restart game,Перезапустить игру,,,Spiel neustarten,,,Uruchom ponownie grę,重新开始游戏,,,,,
-mp_enter_game,Enter game,Присоединиться к игре,,,Spiel betreten,,,Wejdź do gry,加入游戏,,,,,
-mp_invite_only_ingame,Show only in-game,Показать только в игре,,,Zeige nur im Spiel,,,Pokaż tylko w trakcie rozgrywki,仅Noita游戏中,,,,,
-mp_invite_in_lobby,Show in lobby,Показать игроков уже в лобби,,,Zeige nur Räume,,,Pokaż nierozpoczęte,显示此房间,,,,,
-mp_invite_offline,Show offline,Показать оффлайн,,,Zeige offline,,,Pokaż offline,显示离线,,,,,
-mp_invite_busy,Show busy,Показать не беспокоить,,,Zeige beschäftigt,,,Pokaż nie przeszkadzać,显示忙碌,,,,,
-mp_invite_away,Show away,Показать нет на месте,,,Zeige abwesend,,,Pokaż zaraz wracam,显示在线,,,,,
-mp_friends,Friends,Друзья,,,Freunde,,,Znajomi,好友,,,,,
-mp_invite,[Invite],[Пригласить],,,[Einladen],,,[Zaproś],[邀请],,,,,
-mp_update_settings,Update lobby settings,Обновить настройки комнаты,,,Aktualisiere Raum Einstellungen,,,Aktualizuj ustawienia pokoju,更新房间设置,,,,,
-mp_lobby_settings,Lobby settings,Настройки комнаты,,,Raum Einstellungen,,,Ustawienia pokoju,房间设置,,,,,
-mp_chat,Chat,Чат,,,Chat,,,Chat,聊天,,,,,
-mp_open_steam_url_warning,Are you sure you want to open the workshop page for this mod in steam?,"Вы уверены, что хотите открыть страницу мастерской Steam для этого мода?",,,"Sind sie sich sicher, dass Sie die Workhshop Liste im Browser öffnen möchten?",,,Czy na pewno chcesz otworzyć stronę tego dodatku w Warsztacie Steam?,您确定要在 Steam 中打开此模组的创意工坊页面吗?,,,,,
-mp_open_download_page_warning,Are you sure you want to open this URL?\n%s,"Вы уверены, что хотите перейти по этой ссылке?\n%s",,,"Sind sie sich sicher, dass Sie die URL öffnen möchten?",,,Czy na pewno chcesz otworzyć ten link?\n%s,你确定要打开这个 链接 吗?\n%s,,,,,
-mp_open_steam_url_tooltip,Press to go to workshop page.,"Нажмите, что бы открыть страницу в мастерской.",,,Drücke um die Workshop Seite zu öffnen ,,,Naciśnij aby przejść do strony Warsztatu.,进入创意工坊页面,,,,,
-mp_open_download_page_tooltip,Press to go to download page.,"Нажмите, что бы перейти на страницу загрузки.",,,Drücke um zur Download Seite zu gehen,,,Naciśnij aby przejść do strony z pobieraniem.,转到下载页面 ,,,,,
-mp_outdated_warning_title,Noita Online Outdated,Мод Noita Online устарел,,,Noita Online veraltet,,,Dodatek Noita Online jest nieaktualny,Noita Online已过时,,,,,
-mp_outdated_warning_description,The Noita Online version you are running is outdated or invalid,Используемая вами версия Noita Online устарела или неисправна,,,Die momentane Noita Online Version ist veraltet oder ungültig,,,Wersja dodatku Noita Online z której korzystasz jest nieaktualna lub niepoprawna,您运行的Noita Online版本已过时或无效,,,,,
-mp_spectator_mode_enabled,Stop spectating,Выйти из режима наблюдателя,,,Zuschauen abbrechen,,,Przestań oglądać,停止旁观,,,,,
-mp_spectator_mode_disabled,Spectator Mode,Режим наблюдателя,,,Zuschauermodus,,,Tryb widza,旁观者模式,,,,,
-mp_kick,[Kick],[Выкинуть],,,[Kick],,,[Wyrzuć],[踢出],,,,,
-mp_kick_notification,You were kicked from the lobby,Вас выкинули из комнаты,,,Du wurdest aus dem Raum gekickt,,,Zostałeś wyrzucony z pokoju,你被踢出房间!(如果是网络问题被踢出,可以重复加入尝试),,,,,
-mp_ban,[Ban],[Забанить],,,[Bann],,,[Zablokuj],[禁入],,,,,
-mp_ban_notification,You were banned from the lobby,Вы были забанены в этой комнате,,,du wurdest aus dem Raum verbannt,,,Zostałeś zbanowany z pokoju,你被禁止加入!,,,,,
-mp_owner,[Owner],[Владелец],,,[Inhaber],,,[Właściciel],[房主],,,,,
-mp_banned_warning,You are banned from this lobby,Вы забанены в этой комнате,,,Du bist von dieser Lobby gebannt,,,Jesteś zbanowany z tego pokoju,您已被禁止进入该房间,,,,,
-mp_client_outdated,You are using an outdated version of Noita Online,Вы используете устаревшую версию Noita Online,,,Du benutzt eine veraltete Version von Noita Online,,,Korzystasz z nieaktualnej wersji dodatku Noita Online,您使用的是旧版 Noita Online,,,,,
-mp_host_outdated,The host is using an outdated version of Noita Online,Хост использует устаревшую версию Noita Online,,,Der Raumbesitzer benutzt eine veraltete Version von Noita Online,,,Właściciel pokoju korzysta z nieaktualnej wersji dodatku Noita Online,主机使用的是旧版 Noita Online,,,,,
-mp_client_gamemode_outdated,You are using an outdated version of the gamemode: %s,Вы используете устаревшую версию игрового режима: %s,,,du benutzt eine veraltete Version von diesem Spielmodus,,,Korzystasz z nieaktualnej wersji dodatku trybu gry: %s,您正在使用旧版本的游戏模式:%s,,,,,
-mp_host_gamemode_outdated,The host is using an outdated version of the gamemode: %s,Хост использует устаревшую версию игрового режима: %s,,,Der Raumbesitzer benutzt eine veraltete Version vom Spielmodus,,,Właściciel pokoju korzysta z nieaktualnej wersji dodatku trybu gry: %s,主机正在使用旧版本的游戏模式:%s,,,,,
-mp_gamemode_missing,Gamemode missing: %s,Игровой режим отсутствует: %s,,,Spielmodus nicht vorhanden,,,Brakuje trybu pokoju: %s,缺少游戏模式:%s,,,,,
-mp_mod_twitch_integration_name,[Vanilla] Twitch Integration,[Ванила] Twitch интеграция,,,[Vanilla] Twitch Integration,,,[Wanilia] Integracja z Twitch, Twitch 整合,,,,,
-mp_mod_twitch_integration_description,Noita's built-in Twitch integration.,Встроенная интеграция Twitch,,,Noita's eingebaute Twitch Integration,,,Wbudowana w grę integracja z Twitch,Noita 的内置 Twitch 整合。,,,,,
-mp_flip_chat_direction_name,Flip Chat Direction,Перевернуть направление чата,,,drehe Chat Richtung um,,,Odwróć kierunek chatu,翻转聊天方向,,,,,
-mp_flip_chat_direction_description,Makes up for the lack of auto scrolling by putting new messages at the top.,Компенсирует отсутствие автопрокрутки отображением новых сообщений сверху.,,,Setze neue Textnachrichten nach oben,,,"Naprawia problem braku automatycznego przesuwania czatu, wyświetlając nowe wiadomości na górze okna.",通过将新消息放在顶部来弥补自动滚动的不足。,,,,,
-mp_no_gamemodes,No gamemodes enabled!,Игровые режимы не установлены!,,,Keine Spielmodies installiert!,,,Nie wykryto żadnych zainstalowanych trybów gry,未安装任何游戏模式!,,,,,
-mp_steam_connection_failed_title,Failed to connect to steam,Не удалось подключиться к steam,,,Kann keine Verbindung zu Steam herstellen!,,,Nie udało połączyć się do steam,连接steam失败,,,,,
-mp_steam_connection_failed_description,"Noita Online failed to connect to steam, are you logged in to the steam friends list?\n*If it is tuesday there may be steam maintenance.","Noita Online не удалось подключиться к steam, убедитесь что список друзей стим активен.\n*По вторникам сервера steam могут быть отключены для технического обслуживания.", ,,"Noita Online kann keine Verbindung zu Steam herstellen, Sind Sie in ihre Steam Freundesliste eingeloggt?",,,Dodatek Noita Online nie mógł połączyć się ze Steam. Czy jesteś podłączony do listy znajomych Steam?\n*We wtorki serwery Steam przechodzą przerwy techniczne.*,Noita Online 连接steam失败,请问您登录steam好友列表了吗?\n*如果是星期二可能有steam维护。,,,,,
-mp_close_popup,Close,Закрыть,,,Schließen,,,Zamknij,关闭,,,,,
-mp_get_updated_version,Get updated version,Скачать новую версию,,,erhalte die aktualisierte Version,,,Pobierz aktualną wersję,获取更新,,,,,
-mp_version_mismatch,[Version Mismatch],[Несоответствие Версий],,,[Version Nichtübereinstimmung],,,[Niezgodnośc wersji],[版本不符],,,,,
-mp_missing,[Missing],[Отсутствует],,,[fehlen],,,[Brakujący],[移交房主],,,,,
-mp_mods,Mods,Моды,,,Mods,,,Dodatki,模组列表,,,,,
-mp_cannot_change_mode_in_lobby,Can not change gamemode while in a lobby,Изменение режима игры невозможно внутри комнаты,,,Kann Spielmodus nicht im Raum ändern,,,Nie można zmienić trybu gry w pokoju,在大厅时无法更改游戏模式,,,,,
-mp_setting_enabled,Enabled,Включено,,,aktiviert,,,Włączony,启用,,,,,
-mp_setting_disabled,Disabled,Выключено,,,deaktiviert,,,Wyłączony,禁用,,,,,
-mp_default_lobby_name,%s's Lobby,Комната %s,,,%s's Raum,,,Pokój %s,%s 的房间 (zh-cn),,,,,
-mp_default_lobby_name_s,%s' Lobby,Комната %s,,,%s' Raum,,,Pokój %s,%s 的房间 (zh-cn),,,,,
-mp_disconnected,Disconnected,Отключено,,,Verbindung getrennt,,,Rozłączono,断开连接,,,,,
-mp_reason,Reason,Причина,,,Begründung,,,Powód,由于,,,,,
-mp_alpha,Alpha,Alpha,,,Alpha,,,Alfa,,,,,,
-mp_beta,Beta,Beta,,,Beta,,,Beta,,,,,,
-mp_release,Release,Release,,,Freigabe,,,Produkcyjna,公开版,,,,,
-mp_required,[Required],[Необходим],,,[benötigt],,,[Wymagane],[必要],,,,,
-mp_not_required,[Not required],[Опционален],,,[nicht benötigt],,,[Nie wymagane],[非必要],,,,,
-mp_client_missing_mods,You are missing the following required mods: \n%s,У вас отсутствуют необходимые моды: \n%s,,,Dir fehlen die folgenden erforderlichen Mods,,,Nie posiadasz wymaganych dodatków: \n%s,您缺少以下必需的模组:\n%s,,,,,
-mp_lobby_presets,Lobby Presets,Сохраненные настройки лобби,,,Raum Voreinstellungen,,,Zapisane ustawienia,房间预设,,,,,
-mp_save_preset,Save Lobby Preset,Сохранить настройки лобби,,,Speichere Raum Voreinstellung,,,Zapisz ustawienia pokoju,保存房间预设,,,,,
-mp_open_preset_folder,Open Preset Folder,Открыть папку сохраненных лобби,,,Öffne Voreinstellungs Ordner,,,Otwórz folder z zapisanymi ustawieniami,打开预设文件夹,,,,,
-mp_refresh_presets,Refresh Lobby Presets,Обновить сохраненные настройки лобби,,,Aktualisiere Raum Voreinstellungen,,,Odśwież zapisane ustawienia pokojów,刷新房间预设,,,,,
-mp_preset_name,Preset Name:,Название сохраненных настроек:,,,Voreinstellung Name:,,,Nazwa ustawienia:,预设名称:,,,,,
-mp_remove_preset,[Remove],[Удалить],,,[entfernen],,,[Usuń],[删除],,,,,
-mp_default_preset_name,Default,По умолчанию,,,Standart,,,Domyślne,默认,,,,,
-mp_laa_message,Do you want to enable LAA?,Вы хотите включить LAA?,,,,,,Czy chcesz uruchomić LAA?,是否要启用 LAA?,,,,,
-mp_laa_description,Enabling Large Address Aware lets noita use up to 4GB of memory. \nWhich helps prevent crashes.,Включение LAA позволяет игре использовать до 4ГБ ОЗУ\n что помогает избежать крашей,,,,,,"Włączenie LAA pozwoli grze na wykorzystanie 4 GB pamięci, co zmniejsza szansę wystąpienia błędów.",启用 Large Address Aware (LAA)可让 noita 使用高达 4GB 的内存。 \n这有助于防止崩溃。,,,,,
-mp_laa_patch,Patch,Патч,,,,,,Łatka,补丁,,,,,
-mp_laa_warning,This patch is permanent until Noita is updated or reinstalled.,Этот патчи перманентен пока игра не обновится или переустановится,,,,,,Ta łatka jest trwała do momentu aktualizacji lub reinstalacji gry.,在更新或重新安装 Noita 之前,此补丁是永久性的。,,,,,
-mp_in_progress,Game In Progress,Игра в процессе,,,,,,Gra w toku,游戏正在进行中,,,,,
-mp_in_progress_warning,The lobby you attemped to join is in progress,"Лобби, в которое вы пытались зайти, в процессе игры",,,,,,Pokój do którego próbujesz dołączyć jest w trakcie rozgrywki,您试图加入的房间正在游戏中。,,,,,
-mp_in_progress_warning_description,The gamemode does not allow for mid-game joining.,Этот режим игры не позволяет заходить посреди игры,,,,,,Tryb gry nie pozwala na dołączenie w trakcie rozgrywki,游戏模式不允许在游戏中加入。,,,,,
-mp_in_progress_warning_description_2,The lobby host has disabled mid-game joining.,Хост этого лобби отключил заход посреди игры,,,,,,Właściciel pokoju wyłączył możliwość dołączenia w trakcie rozgrywki,房间主机已禁用游戏中加入。,,,,,
-mp_invalid_version,The version of Noita you are running is not compatible with this Noita Online version.,Ваша версия игры несовместима с этой версией Noita Arena,,,,,,Wersja Noity nie jest kompatybilna z tą wersją dodatku Noita Online,您正在运行的 Noita 版本与此 Noita Online 版本不兼容。,,,,,
-mp_invalid_version_description,Try Beta branch?,"Может быть, Бета сработает?",,,,,,Spróbować wersję beta?,使用 Beta 版本吗?,,,,,
-mp_delete_preset_confirm,Delete Preset %s,Удалить шаблон %s,,,,,,Usuń zapisane ustawienia %s,,,,,,
-mp_delete_preset_confirm_description,Are you sure you want to delete this preset?,Вы действительно хотите удалить этот шаблон?,,,,,,Czy na pewno chcesz usunąc te zapisane ustawienia?,,,,,,
-mp_delete_preset_confirm_delete,Delete,Удалить,,,,,,Usuń,,,,,,
-mp_delete_preset_confirm_cancel,Cancel,Отменить,,,,,,Anuluj,,,,,,
-mp_blacklist_player,Ban Player,Заблокировать игрока,,,,,,Zbanuj gracza,,,,,,
-mp_blacklist_player_description,Do you wish to ban or blacklist this player?,Вы хотите заблокировать этого игрока или поместить его в чёрный список?,,,,,,Czy chcesz zbanować czy zablokować gracza?,,,,,,
-mp_blacklist_player_description_2,Blacklist will ban the player in any future lobby you make.,Игрок в чёрном списке не сможет заходить во все ваши будущие лобби,,,,,,Zablokowanie gracza zbanuje go z każdego lobby jakie utworzysz.,,,,,,
-mp_blacklist_player_option_1,Ban,Заблокировать игрока,,,,,,Zbanuj,,,,,,
-mp_blacklist_player_option_2,Blacklist,В чёрный список,,,,,,Zablokuj,,,,,,
-mp_blacklist_player_option_3,Cancel,Отменить,,,,,,Anuluj,,,,,,
-mp_lobby_info_host_older,The host is running an older version of Noita Online: %s ,У хоста установлена более старая версия Noita Online: %s,,,,,,Host gry korzysta ze starszej wersji Noita Online: %s,,,,,,
-mp_lobby_info_host_newer,The host is running a newer version of Noita Online: %s,У хоста установлена более новая версия Noita Online: %s,,,,,,Host gry korzysta z nowszej wersji Noita Online: %s,,,,,,
-mp_lobby_info_same_version,You are running the same version of Noita Online,У вас одинаковая версия Noita Online,,,,,,Korzystasz z tej samej wersji Noita Online,,,,,,
-mp_lobby_info_you_using,(You are running version %s),(Ваша версия: %s),,,,,,(Korzystasz z wersji %s),,,,,,
-mp_lobby_info_gm_host_older,The host is running an older version of %s: %s,У хоста установлена более старая версия %s: %s,,,,,,Host gry korzysta ze starszej wersji %s: %s,,,,,,
-mp_lobby_info_gm_host_newer,The host is running a newer version of %s: %s,У хоста установлена более новая версия %s: %s,,,,,,Host gry korzysta z nowszej wersji %s: %s,,,,,,
-mp_lobby_info_gm_same_version,You are running the same version of %s,У вас одинаковая версия %s,,,,,,Korzystasz z tej samej wersji %s,,,,,,
-mp_lobby_info_gm_missing,You are missing the gamemode: %s (version %s),У вас отсутствует режим игры %s (версия %s),,,,,,Brakuje trybu gry: %s (wersja %s),,,,,,
-mp_lobby_info_missing_mods,Missing Mods,Отсутствующие модификации,,,,,,Brakuje dodatków,,,,,,
-mp_lobby_info_missing_mods_list,You are missing the following mods: %s,У вас отсутствуют модификации: %s,,,,,,Brakuje następujących dodatków: %s,,,,,,
-mp_streamer_mode_popup,Streaming App Detected!,Обнаружено приложение для стриминга!,,,,,,Wykryto aplikacje do Streaming'u!,,,,,,
-mp_streamer_mode_popup_detected,"Noita Online has detected that you are running ""%s"".","У вас открыто приложение ""%s"".",,,,,,"Noita Online wykryła, że masz uruchomione ""%s"".",,,,,,
-mp_streamer_mode_popup_desc,Do you wish to turn on Streamer Mode? This can be disabled from mod settings.,Хотите ли вы включить режим стримера? Может быть выключено в настройках мода,,,,,,Czy chcesz uruchomić tryb Streamer'a? Możesz go wyłączyć w opcjach dodatków.,,,,,,
-mp_streamer_mode_popup_desc2,Streamer mode disables profile pictures and hides usernames.,Режим стримера скрывает картинку профиля и скрывает имена игроков,,,,,,Tryb Streamer'a ukrywa obrazki profilowe i nazwy użytkowników.,,,,,,
-mp_streamer_mode_popup_enable,Enable Streamer Mode,Включить режим стримера,,,,,,Uruchom tryb Streamer'a,,,,,,
-mp_spectator_hover,"This player is in spectator mode, they will not partake in the game.","Этот игрок в режиме наблюдателя, он не учавствует в игре",,,,,,"Ten gracz jest widzem, nie bierze udziału w grze.",,,,,,
-mp_game_version_mismatch,You are using a different version of Noita,Вы используете другую версию Noita,,,,,,Korzystasz z innej wersji Noita'y.,,,,,,
-mp_lobby_info_game_host_diff,The host is running a different version of Noita: %s ,Хост использует другую версию Noita: %s,,,,,,Host korzysta z innej wersji Noita'y.,,,,,,
-mp_lobby_info_game_same_version,You are running the same version of Noita,Вы используете одинаковую версию Noita,,,,,,Korzystasz z tej samej wersji Noita'y.,,,,,,
-mp_msvcp140_missing,MSVCP140.dll Missing,MSVCP140.dll Не найден,,,,,,Brakuje MSVCP140.dll,,,,,,
-mp_msvcp140_missing_description,MSVCP140.dll is required for Noita Online to work.,MSVCP140.dll нужен для работы Noita Online,,,,,,MSVCP140.dll jest wymagane do działania Noita Online.,,,,,,
-mp_msvcp140_missing_description_2,Please install it and restart the game.,"Пожалуйста, установите MSVCP140.dll и перезапустите игру",,,,,,Proszę zainstaluj go i zrestartuj grę.,,,,,,
-mp_msvcp140_install,Download,Загрузить,,,,,,Pobierz,,,,,,
-lobby_error_doesnt_exist,Lobby code doesn't exist,Такого кода лобби не существует,,,,,,Kod pokoju nie istnieje,,,,,,
-lobby_error_no_permissions,You don't have permission to join the lobby,У вас нет разрешения на присоединение к данному лобби,,,,,,Nie masz uprawnień by dołączyć do tego pokoju,,,,,,
-lobby_error_full,Lobby is full,Лобби переполнено,,,,,,Pokój jest pełny,,,,,,
-lobby_error_unexpected,Unexpected error,Неожиданная ошибка,,,,,,Nieoczekiwany błąd,,,,,,
-lobby_error_banned,You are banned from this lobby,Вы были заблокированы в этом лобби,,,,,,Zostałeś zbanowany z tego pokoju,,,,,,
-lobby_error_limited,Joining this lobby is not allowed because you are a limited user,"Присоединение к данному лоби невозможно, потому что вы ограничены.",,,,,,"Dołączenie do pokoju jest niemożliwe, bo jesteś limitowanym użytkownikiem",,,,,,
-lobby_error_clan_disabled,Attempt to join a clan lobby when the clan is locked or disabled,Попытка зайти в закрытое или отключённое лобби клана,,,,,,Próba dołączenia do pokoju klanu kiedy klan jest zablokowany lub wyłączony,,,,,,
-lobby_error_community_ban,Attempt to join a lobby when the user has a community lock on their account,Попытка присоедениться в лобби когда пользователь закрыл свой аккаунт,,,,,,Próba dołączenia do pokoju kiedy użytkownik ma blokadę społecznościową,,,,,,
-lobby_error_member_blocked_you,Join failed - a user that is in the lobby has blocked you from joining,Не удалось присоедениться - пользователь в лобби вас заблокировал,,,,,,Połączenie nieudane - użytkownik z tego pokoju cię zablokował,,,,,,
-lobby_error_you_blocked_member,Join failed - you have blocked a user that is already in the chat. ,Не удалось присоединиться - вы заблокировали пользователя в лобби,,,,,,"Połączenie nieudane - zablokowałeś użytkownika, który jest już w czacie.",,,,,,
-lobby_error_ratelimit_exceeded,Join failed - too many join attempts in a very short period of time,Не удалось присоединиться - слишком много попыток войти в короткий период времени,,,,,,Połączenie nieudane - zbyt dużo prób w krótkim czasie,,,,,,
-mp_preset_default,This is a default lobby preset.,Стандартный шаблон лобби,,,,,,To są domyślne ustawienia pokoju.,,,,,,
-mp_preset_corrupt,This preset was corrupted.,Этот шаблон испорчен,,,,,,Plik z ustawieniami jest uszkodzony.,,,,,,
-mp_preset_outdated,This preset file was made on an older version.,Этот шаблон была создан для более старой версии,,,,,,Te ustawienia zostały stworzone w starszej wersji.,,,,,,
-mp_player_left,%s left the game.,Игрок %s покинул игру.,,,Spieler %s hat das Spiel verlassen.,,,Gracz %s opuścił grę.,,,,,,
-mp_player_joined,%s has joined the game,,,,,,,Gracz %s dołączył do gry.,,,,,,
\ No newline at end of file
+,en,ru,pt-br,es-es,de,fr-fr,it,pl,zh-cn,jp,ko,,NOTES – use \n for newline,max length
+current_language,English,Русский,Português [Brasil],Español,Deutsch,Francais,Italiano,Polski,简体中文,日本語,한국어,,,
+mp_create_lobby,Create Lobby,Создать комнату,,,Erstelle Raum,,,Stwórz pokój,创建房间,,,,,
+mp_lobby_list_header,Create or Join Lobby,Создать или присоединиться к комнате,,,Erstelle oder Betrete Raum,,,Stwórz lub dołącz do pokoju,创建或加入房间,,,,,
+mp_join_with_code,Join lobby with code,Присоединиться используя код,,,Betrete Raum mit Code,,,Dołącz do pokoju za pomocą kodu,加入密钥房间,,,,,
+mp_refresh_lobby_list,Refresh lobby list,Обновить список комнат,,,Aktualisiere Raum Liste,,,Odśwież listę pokoi,刷新房间列表,,,,,
+mp_friend_lobbies,Friend Lobbies,Комнаты друзей,,,Räume von Freunden,,,Pokoje znajomych,好 友 房 间,,,,,
+mp_public_lobbies,Public Lobbies,Общие комнаты,,,Öffentliche Räume,,,Publiczne pokoje,公 开 房 间,,,,,
+mp_no_lobbies_found,No lobbies found,Комнат не найдено,,,Keine Räume gefunden,,,Nie znaleziono żadnych pokoi,好像没有房间诶(创建一个吧?),,,,,
+mp_lobby_type,Lobby type,Тип комнаты,,,Raum Typ,,,Rodzaj pokoju,房间类型,,,,,
+mp_public,Public,Общая,,,Öffentlich,,,Publiczny,公开,,,,,
+mp_private,Private,Приватная,,,Privat,,,Prywatny,私人密钥,,,,,
+mp_friends_only,Friends Only,Только для друзей,,,Nur Freunde,,,Tylko znajomi,仅限好友,,,,,
+mp_gamemode,Gamemode,Режим игры,,,Spielmodus,,,Tryb gry,游戏模式,,,,,
+mp_lobby_name,Lobby name,Имя комнаты,,,Raum Name,,,Nazwa pokoju,房间名字,,,,,
+mp_max_players,Max players,Максимум игроков,,,Maximale Spieler,,,Maksymalna ilośc graczy,玩家数量,,,,,
+mp_world_seed,World seed,Семя мира,,,Welt Seed,,,Ziarno świata,世界种子,,,,,
+mp_join_lobby,Join lobby,Присоединиться к комнате,,,Betrete Raum,,,Dołącz do pokoju za pomocą kodu,加入房间,,,,,
+mp_return_menu,Return to menu,Вернуться в меню,,,Kehre zum Menü zurück,,,Wróć do menu,返回主界面,,,,,
+mp_paste_code,Paste code from clipboard,Вставить код из буфера обмена,,,Füge Code vom Clipboard ein,,,Wklej kod,从剪贴板粘贴密钥,,,,,
+mp_lobby_code,Lobby code,Код комнаты,,,Raum Code,,,Kod pokoju,房间密钥,,,,,
+mp_lobby,Lobby,Комната,,,Raum,,,Pokój,房间,,,,,
+mp_show,Show,Показать,,,Zeigen,,,Pokaż,显示,,,,,
+mp_show_tooltip,Show the lobby code,Показать код комнаты,,,Zeige Raum Code,,,Pokaż kod pokoju,显示房间密钥,,,,,
+mp_copy,Copy,Копировать,,,kopieren,,,Kopiuj,复制,,,,,
+mp_copy_tooltip,Copy the lobby code to your clipboard,Копировать код комнаты в буфер обмена,,,Kopiere den Raum Code,,,Kopiuj kod pokoju do schowka,复制房间密钥,,,,,
+mp_hide,Hide,Спрятать,,,verstecken,,,Ukryj,隐藏,,,,,
+mp_hide_tooltip,Hide the lobby code,Спрятать код комнаты,,,verstecke den Raum Code,,,Ukryj kod pokoju,隐藏房间密钥,,,,,
+mp_leave_lobby,Leave lobby,Покинуть комнату,,,Raum verlassen,,,Wyjdź z pokoju,离开房间,,,,,
+mp_invite_players,Invite players,Пригласить игроков,,,Spieler einladen,,,Zaproś znajomych,邀请好友,,,,,
+mp_lobby_settings,Lobby settings,Настройки комнаты,,,Raum einstellungen,,,Ustawienia pokoju,房间设置,,,,,
+mp_start_game,Start game,Начать игру,,,Spiel starten,,,Rozpocznij grę,开始游戏,,,,,
+mp_restart_game,Restart game,Перезапустить игру,,,Spiel neustarten,,,Uruchom ponownie grę,重新开始游戏,,,,,
+mp_enter_game,Enter game,Присоединиться к игре,,,Spiel betreten,,,Wejdź do gry,加入游戏,,,,,
+mp_invite_only_ingame,Show only in-game,Показать только в игре,,,Zeige nur im Spiel,,,Pokaż tylko w trakcie rozgrywki,仅Noita游戏中,,,,,
+mp_invite_in_lobby,Show in lobby,Показать игроков уже в лобби,,,Zeige nur Räume,,,Pokaż nierozpoczęte,显示此房间,,,,,
+mp_invite_offline,Show offline,Показать оффлайн,,,Zeige offline,,,Pokaż offline,显示离线,,,,,
+mp_invite_busy,Show busy,Показать не беспокоить,,,Zeige beschäftigt,,,Pokaż nie przeszkadzać,显示忙碌,,,,,
+mp_invite_away,Show away,Показать нет на месте,,,Zeige abwesend,,,Pokaż zaraz wracam,显示在线,,,,,
+mp_friends,Friends,Друзья,,,Freunde,,,Znajomi,好友,,,,,
+mp_invite,[Invite],[Пригласить],,,[Einladen],,,[Zaproś],[邀请],,,,,
+mp_update_settings,Update lobby settings,Обновить настройки комнаты,,,Aktualisiere Raum Einstellungen,,,Aktualizuj ustawienia pokoju,更新房间设置,,,,,
+mp_lobby_settings,Lobby settings,Настройки комнаты,,,Raum Einstellungen,,,Ustawienia pokoju,房间设置,,,,,
+mp_chat,Chat,Чат,,,Chat,,,Chat,聊天,,,,,
+mp_open_steam_url_warning,Are you sure you want to open the workshop page for this mod in steam?,"Вы уверены, что хотите открыть страницу мастерской Steam для этого мода?",,,"Sind sie sich sicher, dass Sie die Workhshop Liste im Browser öffnen möchten?",,,Czy na pewno chcesz otworzyć stronę tego dodatku w Warsztacie Steam?,您确定要在 Steam 中打开此模组的创意工坊页面吗?,,,,,
+mp_open_download_page_warning,Are you sure you want to open this URL?\n%s,"Вы уверены, что хотите перейти по этой ссылке?\n%s",,,"Sind sie sich sicher, dass Sie die URL öffnen möchten?",,,Czy na pewno chcesz otworzyć ten link?\n%s,你确定要打开这个 链接 吗?\n%s,,,,,
+mp_open_steam_url_tooltip,Press to go to workshop page.,"Нажмите, что бы открыть страницу в мастерской.",,,Drücke um die Workshop Seite zu öffnen ,,,Naciśnij aby przejść do strony Warsztatu.,进入创意工坊页面,,,,,
+mp_open_download_page_tooltip,Press to go to download page.,"Нажмите, что бы перейти на страницу загрузки.",,,Drücke um zur Download Seite zu gehen,,,Naciśnij aby przejść do strony z pobieraniem.,转到下载页面 ,,,,,
+mp_outdated_warning_title,Noita Online Outdated,Мод Noita Online устарел,,,Noita Online veraltet,,,Dodatek Noita Online jest nieaktualny,Noita Online已过时,,,,,
+mp_outdated_warning_description,The Noita Online version you are running is outdated or invalid,Используемая вами версия Noita Online устарела или неисправна,,,Die momentane Noita Online Version ist veraltet oder ungültig,,,Wersja dodatku Noita Online z której korzystasz jest nieaktualna lub niepoprawna,您运行的Noita Online版本已过时或无效,,,,,
+mp_spectator_mode_enabled,Stop spectating,Выйти из режима наблюдателя,,,Zuschauen abbrechen,,,Przestań oglądać,停止旁观,,,,,
+mp_spectator_mode_disabled,Spectator Mode,Режим наблюдателя,,,Zuschauermodus,,,Tryb widza,旁观者模式,,,,,
+mp_kick,[Kick],[Выкинуть],,,[Kick],,,[Wyrzuć],[踢出],,,,,
+mp_kick_notification,You were kicked from the lobby,Вас выкинули из комнаты,,,Du wurdest aus dem Raum gekickt,,,Zostałeś wyrzucony z pokoju,你被踢出房间!(如果是网络问题被踢出,可以重复加入尝试),,,,,
+mp_ban,[Ban],[Забанить],,,[Bann],,,[Zablokuj],[禁入],,,,,
+mp_ban_notification,You were banned from the lobby,Вы были забанены в этой комнате,,,du wurdest aus dem Raum verbannt,,,Zostałeś zbanowany z pokoju,你被禁止加入!,,,,,
+mp_owner,[Owner],[Владелец],,,[Inhaber],,,[Właściciel],[房主],,,,,
+mp_banned_warning,You are banned from this lobby,Вы забанены в этой комнате,,,Du bist von dieser Lobby gebannt,,,Jesteś zbanowany z tego pokoju,您已被禁止进入该房间,,,,,
+mp_client_outdated,You are using an outdated version of Noita Online,Вы используете устаревшую версию Noita Online,,,Du benutzt eine veraltete Version von Noita Online,,,Korzystasz z nieaktualnej wersji dodatku Noita Online,您使用的是旧版 Noita Online,,,,,
+mp_host_outdated,The host is using an outdated version of Noita Online,Хост использует устаревшую версию Noita Online,,,Der Raumbesitzer benutzt eine veraltete Version von Noita Online,,,Właściciel pokoju korzysta z nieaktualnej wersji dodatku Noita Online,主机使用的是旧版 Noita Online,,,,,
+mp_client_gamemode_outdated,You are using an outdated version of the gamemode: %s,Вы используете устаревшую версию игрового режима: %s,,,du benutzt eine veraltete Version von diesem Spielmodus,,,Korzystasz z nieaktualnej wersji dodatku trybu gry: %s,您正在使用旧版本的游戏模式:%s,,,,,
+mp_host_gamemode_outdated,The host is using an outdated version of the gamemode: %s,Хост использует устаревшую версию игрового режима: %s,,,Der Raumbesitzer benutzt eine veraltete Version vom Spielmodus,,,Właściciel pokoju korzysta z nieaktualnej wersji dodatku trybu gry: %s,主机正在使用旧版本的游戏模式:%s,,,,,
+mp_gamemode_missing,Gamemode missing: %s,Игровой режим отсутствует: %s,,,Spielmodus nicht vorhanden,,,Brakuje trybu pokoju: %s,缺少游戏模式:%s,,,,,
+mp_mod_twitch_integration_name,[Vanilla] Twitch Integration,[Ванила] Twitch интеграция,,,[Vanilla] Twitch Integration,,,[Wanilia] Integracja z Twitch, Twitch 整合,,,,,
+mp_mod_twitch_integration_description,Noita's built-in Twitch integration.,Встроенная интеграция Twitch,,,Noita's eingebaute Twitch Integration,,,Wbudowana w grę integracja z Twitch,Noita 的内置 Twitch 整合。,,,,,
+mp_flip_chat_direction_name,Flip Chat Direction,Перевернуть направление чата,,,drehe Chat Richtung um,,,Odwróć kierunek chatu,翻转聊天方向,,,,,
+mp_flip_chat_direction_description,Makes up for the lack of auto scrolling by putting new messages at the top.,Компенсирует отсутствие автопрокрутки отображением новых сообщений сверху.,,,Setze neue Textnachrichten nach oben,,,"Naprawia problem braku automatycznego przesuwania czatu, wyświetlając nowe wiadomości na górze okna.",通过将新消息放在顶部来弥补自动滚动的不足。,,,,,
+mp_no_gamemodes,No gamemodes enabled!,Игровые режимы не установлены!,,,Keine Spielmodies installiert!,,,Nie wykryto żadnych zainstalowanych trybów gry,未安装任何游戏模式!,,,,,
+mp_steam_connection_failed_title,Failed to connect to steam,Не удалось подключиться к steam,,,Kann keine Verbindung zu Steam herstellen!,,,Nie udało połączyć się do steam,连接steam失败,,,,,
+mp_steam_connection_failed_description,"Noita Online failed to connect to steam, are you logged in to the steam friends list?\n*If it is tuesday there may be steam maintenance.","Noita Online не удалось подключиться к steam, убедитесь что список друзей стим активен.\n*По вторникам сервера steam могут быть отключены для технического обслуживания.", ,,"Noita Online kann keine Verbindung zu Steam herstellen, Sind Sie in ihre Steam Freundesliste eingeloggt?",,,Dodatek Noita Online nie mógł połączyć się ze Steam. Czy jesteś podłączony do listy znajomych Steam?\n*We wtorki serwery Steam przechodzą przerwy techniczne.*,Noita Online 连接steam失败,请问您登录steam好友列表了吗?\n*如果是星期二可能有steam维护。,,,,,
+mp_close_popup,Close,Закрыть,,,Schließen,,,Zamknij,关闭,,,,,
+mp_get_updated_version,Get updated version,Скачать новую версию,,,erhalte die aktualisierte Version,,,Pobierz aktualną wersję,获取更新,,,,,
+mp_version_mismatch,[Version Mismatch],[Несоответствие Версий],,,[Version Nichtübereinstimmung],,,[Niezgodnośc wersji],[版本不符],,,,,
+mp_missing,[Missing],[Отсутствует],,,[fehlen],,,[Brakujący],[移交房主],,,,,
+mp_mods,Mods,Моды,,,Mods,,,Dodatki,模组列表,,,,,
+mp_cannot_change_mode_in_lobby,Can not change gamemode while in a lobby,Изменение режима игры невозможно внутри комнаты,,,Kann Spielmodus nicht im Raum ändern,,,Nie można zmienić trybu gry w pokoju,在大厅时无法更改游戏模式,,,,,
+mp_setting_enabled,Enabled,Включено,,,aktiviert,,,Włączony,启用,,,,,
+mp_setting_disabled,Disabled,Выключено,,,deaktiviert,,,Wyłączony,禁用,,,,,
+mp_default_lobby_name,%s's Lobby,Комната %s,,,%s's Raum,,,Pokój %s,%s 的房间 (zh-cn),,,,,
+mp_default_lobby_name_s,%s' Lobby,Комната %s,,,%s' Raum,,,Pokój %s,%s 的房间 (zh-cn),,,,,
+mp_disconnected,Disconnected,Отключено,,,Verbindung getrennt,,,Rozłączono,断开连接,,,,,
+mp_reason,Reason,Причина,,,Begründung,,,Powód,由于,,,,,
+mp_alpha,Alpha,Alpha,,,Alpha,,,Alfa,Alpha,,,,,
+mp_beta,Beta,Beta,,,Beta,,,Beta,Beta,,,,,
+mp_release,Release,Release,,,Freigabe,,,Produkcyjna,公开版,,,,,
+mp_required,[Required],[Необходим],,,[benötigt],,,[Wymagane],[必要],,,,,
+mp_not_required,[Not required],[Опционален],,,[nicht benötigt],,,[Nie wymagane],[非必要],,,,,
+mp_client_missing_mods,You are missing the following required mods: \n%s,У вас отсутствуют необходимые моды: \n%s,,,Dir fehlen die folgenden erforderlichen Mods,,,Nie posiadasz wymaganych dodatków: \n%s,您缺少以下必需的模组:\n%s,,,,,
+mp_lobby_presets,Lobby Presets,Сохраненные настройки лобби,,,Raum Voreinstellungen,,,Zapisane ustawienia,房间预设,,,,,
+mp_save_preset,Save Lobby Preset,Сохранить настройки лобби,,,Speichere Raum Voreinstellung,,,Zapisz ustawienia pokoju,保存房间预设,,,,,
+mp_open_preset_folder,Open Preset Folder,Открыть папку сохраненных лобби,,,Öffne Voreinstellungs Ordner,,,Otwórz folder z zapisanymi ustawieniami,打开预设文件夹,,,,,
+mp_refresh_presets,Refresh Lobby Presets,Обновить сохраненные настройки лобби,,,Aktualisiere Raum Voreinstellungen,,,Odśwież zapisane ustawienia pokojów,刷新房间预设,,,,,
+mp_preset_name,Preset Name:,Название сохраненных настроек:,,,Voreinstellung Name:,,,Nazwa ustawienia:,预设名称:,,,,,
+mp_remove_preset,[Remove],[Удалить],,,[entfernen],,,[Usuń],[删除],,,,,
+mp_default_preset_name,Default,По умолчанию,,,Standart,,,Domyślne,默认,,,,,
+mp_laa_message,Do you want to enable LAA?,Вы хотите включить LAA?,,,,,,Czy chcesz uruchomić LAA?,是否要启用 LAA?,,,,,
+mp_laa_description,Enabling Large Address Aware lets noita use up to 4GB of memory. \nWhich helps prevent crashes.,Включение LAA позволяет игре использовать до 4ГБ ОЗУ\n что помогает избежать крашей,,,,,,"Włączenie LAA pozwoli grze na wykorzystanie 4 GB pamięci, co zmniejsza szansę wystąpienia błędów.",启用 Large Address Aware (LAA)可让 noita 使用高达 4GB 的内存。 \n这有助于防止崩溃。,,,,,
+mp_laa_patch,Patch,Патч,,,,,,Łatka,补丁,,,,,
+mp_laa_warning,This patch is permanent until Noita is updated or reinstalled.,Этот патчи перманентен пока игра не обновится или переустановится,,,,,,Ta łatka jest trwała do momentu aktualizacji lub reinstalacji gry.,在更新或重新安装 Noita 之前,此补丁是永久性的。,,,,,
+mp_in_progress,Game In Progress,Игра в процессе,,,,,,Gra w toku,游戏正在进行中,,,,,
+mp_in_progress_warning,The lobby you attemped to join is in progress,"Лобби, в которое вы пытались зайти, в процессе игры",,,,,,Pokój do którego próbujesz dołączyć jest w trakcie rozgrywki,您试图加入的房间正在游戏中。,,,,,
+mp_in_progress_warning_description,The gamemode does not allow for mid-game joining.,Этот режим игры не позволяет заходить посреди игры,,,,,,Tryb gry nie pozwala na dołączenie w trakcie rozgrywki,游戏模式不允许在游戏中加入。,,,,,
+mp_in_progress_warning_description_2,The lobby host has disabled mid-game joining.,Хост этого лобби отключил заход посреди игры,,,,,,Właściciel pokoju wyłączył możliwość dołączenia w trakcie rozgrywki,房间主机已禁用游戏中加入。,,,,,
+mp_invalid_version,The version of Noita you are running is not compatible with this Noita Online version.,Ваша версия игры несовместима с этой версией Noita Arena,,,,,,Wersja Noity nie jest kompatybilna z tą wersją dodatku Noita Online,您正在运行的 Noita 版本与此 Noita Online 版本不兼容。,,,,,
+mp_invalid_version_description,Try Beta branch?,"Может быть, Бета сработает?",,,,,,Spróbować wersję beta?,使用 Beta 版本吗?,,,,,
+mp_delete_preset_confirm,Delete Preset %s,Удалить шаблон %s,,,,,,Usuń zapisane ustawienia %s,删除预设 %s,,,,,
+mp_delete_preset_confirm_description,Are you sure you want to delete this preset?,Вы действительно хотите удалить этот шаблон?,,,,,,Czy na pewno chcesz usunąc te zapisane ustawienia?,您确定要删除这个预设吗?,,,,,
+mp_delete_preset_confirm_delete,Delete,Удалить,,,,,,Usuń,删除,,,,,
+mp_delete_preset_confirm_cancel,Cancel,Отменить,,,,,,Anuluj,取消,,,,,
+mp_blacklist_player,Ban Player,Заблокировать игрока,,,,,,Zbanuj gracza,禁止玩家,,,,,
+mp_blacklist_player_description,Do you wish to ban or blacklist this player?,Вы хотите заблокировать этого игрока или поместить его в чёрный список?,,,,,,Czy chcesz zbanować czy zablokować gracza?,您想禁止该玩家继续在此房间游玩吗?(墙裂推荐你对卡逼使用此操作,净化游戏环境从你我做起),,,,,
+mp_blacklist_player_description_2,Blacklist will ban the player in any future lobby you make.,Игрок в чёрном списке не сможет заходить во все ваши будущие лобби,,,,,,Zablokowanie gracza zbanuje go z każdego lobby jakie utworzysz.,黑名单将禁止该玩家进入您以后创建的任何房间\n(想删除黑名单要在存档文件删除!!),,,,,
+mp_blacklist_player_option_1,Ban,Заблокировать игрока,,,,,,Zbanuj,禁入,,,,,
+mp_blacklist_player_option_2,Blacklist,В чёрный список,,,,,,Zablokuj,黑名单,,,,,
+mp_blacklist_player_option_3,Cancel,Отменить,,,,,,Anuluj,取消,,,,,
+mp_lobby_info_host_older,The host is running an older version of Noita Online: %s ,У хоста установлена более старая версия Noita Online: %s,,,,,,Host gry korzysta ze starszej wersji Noita Online: %s,主机运行的是旧版本的 Noita在线模式: %s ,,,,,
+mp_lobby_info_host_newer,The host is running a newer version of Noita Online: %s,У хоста установлена более новая версия Noita Online: %s,,,,,,Host gry korzysta z nowszej wersji Noita Online: %s,主机正在运行是新版本的 Noita在线模式: %s ,,,,,
+mp_lobby_info_same_version,You are running the same version of Noita Online,У вас одинаковая версия Noita Online,,,,,,Korzystasz z tej samej wersji Noita Online,您与主机运行的是同一版本的 Noita在线模式,,,,,
+mp_lobby_info_you_using,(You are running version %s),(Ваша версия: %s),,,,,,(Korzystasz z wersji %s),(您正在使用的版本 %s ),,,,,
+mp_lobby_info_gm_host_older,The host is running an older version of %s: %s,У хоста установлена более старая версия %s: %s,,,,,,Host gry korzysta ze starszej wersji %s: %s,主机正在运行旧版本的 %s : %s ,,,,,
+mp_lobby_info_gm_host_newer,The host is running a newer version of %s: %s,У хоста установлена более новая версия %s: %s,,,,,,Host gry korzysta z nowszej wersji %s: %s,主机正在运行新版本的 %s : %s ,,,,,
+mp_lobby_info_gm_same_version,You are running the same version of %s,У вас одинаковая версия %s,,,,,,Korzystasz z tej samej wersji %s,您与主机运行的是相同版本的 %s ,,,,,
+mp_lobby_info_gm_missing,You are missing the gamemode: %s (version %s),У вас отсутствует режим игры %s (версия %s),,,,,,Brakuje trybu gry: %s (wersja %s),您缺少游戏模式: %s(版本 %s ),,,,,
+mp_lobby_info_missing_mods,Missing Mods,Отсутствующие модификации,,,,,,Brakuje dodatków,缺少模组,,,,,
+mp_lobby_info_missing_mods_list,You are missing the following mods: %s,У вас отсутствуют модификации: %s,,,,,,Brakuje następujących dodatków: %s,您缺少以下模组: %s ,,,,,
+mp_streamer_mode_popup,Streaming App Detected!,Обнаружено приложение для стриминга!,,,,,,Wykryto aplikacje do Streaming'u!,检测到串流应用程序!,,,,,
+mp_streamer_mode_popup_detected,"Noita Online has detected that you are running ""%s"".","У вас открыто приложение ""%s"".",,,,,,"Noita Online wykryła, że masz uruchomione ""%s"".",“Noita Online 检测到您正在运行 '%s' ”,,,,,
+mp_streamer_mode_popup_desc,Do you wish to turn on Streamer Mode? This can be disabled from mod settings.,Хотите ли вы включить режим стримера? Может быть выключено в настройках мода,,,,,,Czy chcesz uruchomić tryb Streamer'a? Możesz go wyłączyć w opcjach dodatków.,您需要启用主播模式吗?这可以从模组设置中禁用,,,,,
+mp_streamer_mode_popup_desc2,Streamer mode disables profile pictures and hides usernames.,Режим стримера скрывает картинку профиля и скрывает имена игроков,,,,,,Tryb Streamer'a ukrywa obrazki profilowe i nazwy użytkowników.,主播模式下将会禁用个人资料图片并隐藏其用户名,,,,,
+mp_streamer_mode_popup_enable,Enable Streamer Mode,Включить режим стримера,,,,,,Uruchom tryb Streamer'a,启用主播模式,,,,,
+mp_spectator_hover,"This player is in spectator mode, they will not partake in the game.","Этот игрок в режиме наблюдателя, он не учавствует в игре",,,,,,"Ten gracz jest widzem, nie bierze udziału w grze.",“该玩家处于旁观者模式,不会参与游戏”,,,,,
+mp_game_version_mismatch,You are using a different version of Noita,Вы используете другую версию Noita,,,,,,Korzystasz z innej wersji Noita'y.,您使用的Noita版本不一致,,,,,
+mp_lobby_info_game_host_diff,The host is running a different version of Noita: %s ,Хост использует другую версию Noita: %s,,,,,,Host korzysta z innej wersji Noita'y.,主机正在运行的是 %s 版本的Noita,,,,,
+mp_lobby_info_game_same_version,You are running the same version of Noita,Вы используете одинаковую версию Noita,,,,,,Korzystasz z tej samej wersji Noita'y.,您运行的是相同版本的 Noita,,,,,
+mp_msvcp140_missing,MSVCP140.dll Missing,MSVCP140.dll Не найден,,,,,,Brakuje MSVCP140.dll,MSVCP140.dll 缺失,,,,,
+mp_msvcp140_missing_description,MSVCP140.dll is required for Noita Online to work.,MSVCP140.dll нужен для работы Noita Online,,,,,,MSVCP140.dll jest wymagane do działania Noita Online.,Noita Online 运行需要 MSVCP140.dll,,,,,
+mp_msvcp140_missing_description_2,Please install it and restart the game.,"Пожалуйста, установите MSVCP140.dll и перезапустите игру",,,,,,Proszę zainstaluj go i zrestartuj grę.,请安装并重新启动游戏,,,,,
+mp_msvcp140_install,Download,Загрузить,,,,,,Pobierz,下载,,,,,
+lobby_error_doesnt_exist,Lobby code doesn't exist,Такого кода лобби не существует,,,,,,Kod pokoju nie istnieje,房间密钥不存在,,,,,
+lobby_error_no_permissions,You don't have permission to join the lobby,У вас нет разрешения на присоединение к данному лобби,,,,,,Nie masz uprawnień by dołączyć do tego pokoju,您无权加入房间,,,,,
+lobby_error_full,Lobby is full,Лобби переполнено,,,,,,Pokój jest pełny,房间已满,,,,,
+lobby_error_unexpected,Unexpected error,Неожиданная ошибка,,,,,,Nieoczekiwany błąd,意外错误,,,,,
+lobby_error_banned,You are banned from this lobby,Вы были заблокированы в этом лобби,,,,,,Zostałeś zbanowany z tego pokoju,您已被禁止进入此房间,,,,,
+lobby_error_limited,Joining this lobby is not allowed because you are a limited user,"Присоединение к данному лоби невозможно, потому что вы ограничены.",,,,,,"Dołączenie do pokoju jest niemożliwe, bo jesteś limitowanym użytkownikiem",由于您是受限用户,因此不允许加入此房间,,,,,
+lobby_error_clan_disabled,Attempt to join a clan lobby when the clan is locked or disabled,Попытка зайти в закрытое или отключённое лобби клана,,,,,,Próba dołączenia do pokoju klanu kiedy klan jest zablokowany lub wyłączony,账户被社区封禁时尝试加入大厅,,,,,
+lobby_error_community_ban,Attempt to join a lobby when the user has a community lock on their account,Попытка присоедениться в лобби когда пользователь закрыл свой аккаунт,,,,,,Próba dołączenia do pokoju kiedy użytkownik ma blokadę społecznościową,账户被房间封禁时,尝试加入房间,,,,,
+lobby_error_member_blocked_you,Join failed - a user that is in the lobby has blocked you from joining,Не удалось присоедениться - пользователь в лобби вас заблокировал,,,,,,Połączenie nieudane - użytkownik z tego pokoju cię zablokował,加入失败 - 房间中的用户阻止您加入,,,,,
+lobby_error_you_blocked_member,Join failed - you have blocked a user that is already in the chat. ,Не удалось присоединиться - вы заблокировали пользователя в лобби,,,,,,"Połączenie nieudane - zablokowałeś użytkownika, który jest już w czacie.",加入失败 - 您屏蔽了已在房间中的用户,,,,,
+lobby_error_ratelimit_exceeded,Join failed - too many join attempts in a very short period of time,Не удалось присоединиться - слишком много попыток войти в короткий период времени,,,,,,Połączenie nieudane - zbyt dużo prób w krótkim czasie,加入失败 - 短时间内尝试次数过多,,,,,
+mp_preset_default,This is a default lobby preset.,Стандартный шаблон лобби,,,,,,To są domyślne ustawienia pokoju.,这是默认的房间预设,,,,,
+mp_preset_corrupt,This preset was corrupted.,Этот шаблон испорчен,,,,,,Plik z ustawieniami jest uszkodzony.,此预设已损坏,,,,,
+mp_preset_outdated,This preset file was made on an older version.,Этот шаблон была создан для более старой версии,,,,,,Te ustawienia zostały stworzone w starszej wersji.,此预设文件是在旧版本上制作的,,,,,
+mp_player_left,%s left the game.,Игрок %s покинул игру.,,,Spieler %s hat das Spiel verlassen.,,,Gracz %s opuścił grę.,%s 离开游戏.,,,,,
+mp_player_joined,%s has joined the game,,,,,,,Gracz %s dołączył do gry.,%s 已加入游戏.,,,,,
diff --git a/version.lua b/version.lua
deleted file mode 100644
index 1053feb..0000000
--- a/version.lua
+++ /dev/null
@@ -1,3 +0,0 @@
-VERSION_FLAVOR_TEXT = "$mp_release" -- mp_release
-MP_VERSION = 388
-MP_PRESET_VERSION = 2
\ No newline at end of file
diff --git a/zip.bat b/zip.bat
deleted file mode 100644
index 623c498..0000000
--- a/zip.bat
+++ /dev/null
@@ -1,18 +0,0 @@
-@echo off
-REM Define the gitzip function
-:gitzip
-
-REM -- Extract the folder name of the directory containing this batch script --
-REM (%~dp0 is the full path of the folder where the batch is located;
-REM the trailing dot (.) ensures we don't get a trailing backslash).
-for %%I in ("%~dp0.") do set dirname=%%~nxI
-
-REM -- Create the archive while respecting .gitignore --
-REM Use --prefix so that everything lands inside a top-level folder called %dirname%.
-git archive --format=zip --prefix="%dirname%/" --output="%dirname%.zip" HEAD
-
-goto :eof
-
-REM -- Now actually run the above logic --
-cd mydir
-call :gitzip