--[[ Copyright (c) 2014-2017 Chukong Technologies Inc. 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. ]] function printLog(tag, fmt, ...) local t = { "[", string.upper(tostring(tag)), "] ", string.format(tostring(fmt), ...) } print(table.concat(t)) end function printError(fmt, ...) printLog("ERR", fmt, ...) print(debug.traceback("", 2)) end function printInfo(fmt, ...) if type(DEBUG) ~= "number" or DEBUG < 2 then return end printLog("INFO", fmt, ...) end local function dump_value_(v) if type(v) == "string" then v = "\"" .. v .. "\"" end return tostring(v) end function dump(value, description, nesting) if type(nesting) ~= "number" then nesting = 3 end local lookupTable = {} local result = {} local traceback = string.split(debug.traceback("", 2), "\n") print("dump from: " .. string.trim(traceback[3])) local function dump_(value, description, indent, nest, keylen) description = description or "" local spc = "" if type(keylen) == "number" then spc = string.rep(" ", keylen - string.len(dump_value_(description))) end if type(value) ~= "table" then result[#result +1 ] = string.format("%s%s%s = %s", indent, dump_value_(description), spc, dump_value_(value)) elseif lookupTable[tostring(value)] then result[#result +1 ] = string.format("%s%s%s = *REF*", indent, dump_value_(description), spc) else lookupTable[tostring(value)] = true if nest > nesting then result[#result +1 ] = string.format("%s%s = *MAX NESTING*", indent, dump_value_(description)) else result[#result +1 ] = string.format("%s%s = {", indent, dump_value_(description)) local indent2 = indent.." " local keys = {} local keylen = 0 local values = {} for k, v in pairs(value) do keys[#keys + 1] = k local vk = dump_value_(k) local vkl = string.len(vk) if vkl > keylen then keylen = vkl end values[k] = v end table.sort(keys, function(a, b) if type(a) == "number" and type(b) == "number" then return a < b else return tostring(a) < tostring(b) end end) for i, k in ipairs(keys) do dump_(values[k], k, indent2, nest + 1, keylen) end result[#result +1] = string.format("%s}", indent) end end end dump_(value, description, "- ", 1) for i, line in ipairs(result) do print(line) end end function printf(fmt, ...) print(string.format(tostring(fmt), ...)) end function checknumber(value, base) return tonumber(value, base) or 0 end function checkint(value) return math.round(checknumber(value)) end function checkbool(value) return (value ~= nil and value ~= false) end function checktable(value) if type(value) ~= "table" then value = {} end return value end function isset(hashtable, key) local t = type(hashtable) return (t == "table" or t == "userdata") and hashtable[key] ~= nil end local setmetatableindex_ setmetatableindex_ = function(t, index) if type(t) == "userdata" then local peer = tolua.getpeer(t) if not peer then peer = {} tolua.setpeer(t, peer) end setmetatableindex_(peer, index) else local mt = getmetatable(t) if not mt then mt = {} end if not mt.__index then mt.__index = index setmetatable(t, mt) elseif mt.__index ~= index then setmetatableindex_(mt, index) end end end setmetatableindex = setmetatableindex_ function clone(object) local lookup_table = {} local function _copy(object) if type(object) ~= "table" then return object elseif lookup_table[object] then return lookup_table[object] end local newObject = {} lookup_table[object] = newObject for key, value in pairs(object) do newObject[_copy(key)] = _copy(value) end return setmetatable(newObject, getmetatable(object)) end return _copy(object) end function class(classname, ...) local cls = {__cname = classname} local supers = {...} for _, super in ipairs(supers) do local superType = type(super) assert(superType == "nil" or superType == "table" or superType == "function", string.format("class() - create class \"%s\" with invalid super class type \"%s\"", classname, superType)) if superType == "function" then assert(cls.__create == nil, string.format("class() - create class \"%s\" with more than one creating function", classname)); -- if super is function, set it to __create cls.__create = super elseif superType == "table" then if super[".isclass"] then -- super is native class assert(cls.__create == nil, string.format("class() - create class \"%s\" with more than one creating function or native class", classname)); cls.__create = function() return super:create() end else -- super is pure lua class cls.__supers = cls.__supers or {} cls.__supers[#cls.__supers + 1] = super if not cls.super then -- set first super pure lua class as class.super cls.super = super end end else error(string.format("class() - create class \"%s\" with invalid super type", classname), 0) end end cls.__index = cls if not cls.__supers or #cls.__supers == 1 then setmetatable(cls, {__index = cls.super}) else setmetatable(cls, {__index = function(_, key) local supers = cls.__supers for i = 1, #supers do local super = supers[i] if super[key] then return super[key] end end end}) end if not cls.ctor then -- add default constructor cls.ctor = function() end end cls.new = function(...) local instance if cls.__create then instance = cls.__create(...) else instance = {} end setmetatableindex(instance, cls) instance.class = cls instance:ctor(...) return instance end cls.create = function(_, ...) return cls.new(...) end return cls end local iskindof_ iskindof_ = function(cls, name) local __index = rawget(cls, "__index") if type(__index) == "table" and rawget(__index, "__cname") == name then return true end if rawget(cls, "__cname") == name then return true end local __supers = rawget(__index, "__supers") if not __supers then return false end for _, super in ipairs(__supers) do if iskindof_(super, name) then return true end end return false end function iskindof(obj, classname) local t = type(obj) if t ~= "table" and t ~= "userdata" then return false end local mt if t == "userdata" then if tolua.iskindof(obj, classname) then return true end mt = getmetatable(tolua.getpeer(obj)) else mt = getmetatable(obj) end if mt then return iskindof_(mt, classname) end return false end function import(moduleName, currentModuleName) local currentModuleNameParts local moduleFullName = moduleName local offset = 1 while true do if string.byte(moduleName, offset) ~= 46 then -- . moduleFullName = string.sub(moduleName, offset) if currentModuleNameParts and #currentModuleNameParts > 0 then moduleFullName = table.concat(currentModuleNameParts, ".") .. "." .. moduleFullName end break end offset = offset + 1 if not currentModuleNameParts then if not currentModuleName then local n,v = debug.getlocal(3, 1) currentModuleName = v end currentModuleNameParts = string.split(currentModuleName, ".") end table.remove(currentModuleNameParts, #currentModuleNameParts) end return require(moduleFullName) end function handler(obj, method) return function(...) return method(obj, ...) end end function math.newrandomseed() local ok, socket = pcall(function() return require("socket") end) if ok then math.randomseed(socket.gettime() * 1000) else math.randomseed(os.time()) end math.random() math.random() math.random() math.random() end function math.round(value) value = checknumber(value) return math.floor(value + 0.5) end local pi_div_180 = math.pi / 180 function math.angle2radian(angle) return angle * pi_div_180 end function math.radian2angle(radian) return radian * 180 / math.pi end function io.exists(path) local file = io.open(path, "r") if file then io.close(file) return true end return false end function io.readfile(path) local file = io.open(path, "r") if file then local content = file:read("*a") io.close(file) return content end return nil end function io.writefile(path, content, mode) mode = mode or "w+b" local file = io.open(path, mode) if file then if file:write(content) == nil then return false end io.close(file) return true else return false end end function io.pathinfo(path) local pos = string.len(path) local extpos = pos + 1 while pos > 0 do local b = string.byte(path, pos) if b == 46 then -- 46 = char "." extpos = pos elseif b == 47 then -- 47 = char "/" break end pos = pos - 1 end local dirname = string.sub(path, 1, pos) local filename = string.sub(path, pos + 1) extpos = extpos - pos local basename = string.sub(filename, 1, extpos - 1) local extname = string.sub(filename, extpos) return { dirname = dirname, filename = filename, basename = basename, extname = extname } end function io.filesize(path) local size = false local file = io.open(path, "r") if file then local current = file:seek() size = file:seek("end") file:seek("set", current) io.close(file) end return size end function table.nums(t) local count = 0 for k, v in pairs(t) do count = count + 1 end return count end function table.keys(hashtable) local keys = {} for k, v in pairs(hashtable) do keys[#keys + 1] = k end return keys end function table.values(hashtable) local values = {} for k, v in pairs(hashtable) do values[#values + 1] = v end return values end function table.merge(dest, src) for k, v in pairs(src) do dest[k] = v end end function table.insertto(dest, src, begin) begin = checkint(begin) if begin <= 0 then begin = #dest + 1 end local len = #src for i = 0, len - 1 do dest[i + begin] = src[i + 1] end end function table.indexof(array, value, begin) for i = begin or 1, #array do if array[i] == value then return i end end return false end function table.keyof(hashtable, value) for k, v in pairs(hashtable) do if v == value then return k end end return nil end function table.removebyvalue(array, value, removeall) local c, i, max = 0, 1, #array while i <= max do if array[i] == value then table.remove(array, i) c = c + 1 i = i - 1 max = max - 1 if not removeall then break end end i = i + 1 end return c end function table.map(t, fn) for k, v in pairs(t) do t[k] = fn(v, k) end end function table.walk(t, fn) for k,v in pairs(t) do fn(v, k) end end function table.filter(t, fn) for k, v in pairs(t) do if not fn(v, k) then t[k] = nil end end end function table.unique(t, bArray) local check = {} local n = {} local idx = 1 for k, v in pairs(t) do if not check[v] then if bArray then n[idx] = v idx = idx + 1 else n[k] = v end check[v] = true end end return n end string._htmlspecialchars_set = {} string._htmlspecialchars_set["&"] = "&" string._htmlspecialchars_set["\""] = """ string._htmlspecialchars_set["'"] = "'" string._htmlspecialchars_set["<"] = "<" string._htmlspecialchars_set[">"] = ">" function string.htmlspecialchars(input) for k, v in pairs(string._htmlspecialchars_set) do input = string.gsub(input, k, v) end return input end function string.restorehtmlspecialchars(input) for k, v in pairs(string._htmlspecialchars_set) do input = string.gsub(input, v, k) end return input end function string.nl2br(input) return string.gsub(input, "\n", "
") end function string.text2html(input) input = string.gsub(input, "\t", " ") input = string.htmlspecialchars(input) input = string.gsub(input, " ", " ") input = string.nl2br(input) return input end function string.split(input, delimiter) input = tostring(input) delimiter = tostring(delimiter) if (delimiter=='') then return false end local pos,arr = 0, {} -- for each divider found for st,sp in function() return string.find(input, delimiter, pos, true) end do table.insert(arr, string.sub(input, pos, st - 1)) pos = sp + 1 end table.insert(arr, string.sub(input, pos)) return arr end function string.ltrim(input) return string.gsub(input, "^[ \t\n\r]+", "") end function string.rtrim(input) return string.gsub(input, "[ \t\n\r]+$", "") end function string.trim(input) input = string.gsub(input, "^[ \t\n\r]+", "") return string.gsub(input, "[ \t\n\r]+$", "") end function string.ucfirst(input) return string.upper(string.sub(input, 1, 1)) .. string.sub(input, 2) end local function urlencodechar(char) return "%" .. string.format("%02X", string.byte(char)) end function string.urlencode(input) -- convert line endings input = string.gsub(tostring(input), "\n", "\r\n") -- escape all characters but alphanumeric, '.' and '-' input = string.gsub(input, "([^%w%.%- ])", urlencodechar) -- convert spaces to "+" symbols return string.gsub(input, " ", "+") end function string.urldecode(input) input = string.gsub (input, "+", " ") input = string.gsub (input, "%%(%x%x)", function(h) return string.char(checknumber(h,16)) end) input = string.gsub (input, "\r\n", "\n") return input end function string.utf8len(input) local len = string.len(input) local left = len local cnt = 0 local arr = {0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc} while left ~= 0 do local tmp = string.byte(input, -left) local i = #arr while arr[i] do if tmp >= arr[i] then left = left - i break end i = i - 1 end cnt = cnt + 1 end return cnt end function string.formatnumberthousands(num) local formatted = tostring(checknumber(num)) local k while true do formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2') if k == 0 then break end end return formatted end