{"id":22933978,"url":"https://github.com/atypicalim/pure-lua-tools","last_synced_at":"2025-08-12T17:32:11.219Z","repository":{"id":37443001,"uuid":"374191568","full_name":"Atypicalim/pure-lua-tools","owner":"Atypicalim","description":"pure lua tools like class, events, json, table and others ...","archived":false,"fork":false,"pushed_at":"2024-04-10T15:06:00.000Z","size":1401,"stargazers_count":10,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-08-29T11:55:46.938Z","etag":null,"topics":["lua","pure","tools"],"latest_commit_sha":null,"homepage":"","language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Atypicalim.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-05T18:59:10.000Z","updated_at":"2024-05-24T11:36:00.000Z","dependencies_parsed_at":"2024-04-10T16:28:18.225Z","dependency_job_id":"d61c7c1f-c001-4504-8449-24849f90db95","html_url":"https://github.com/Atypicalim/pure-lua-tools","commit_stats":null,"previous_names":["atypicalim/pure-lua-tools"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Atypicalim%2Fpure-lua-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Atypicalim%2Fpure-lua-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Atypicalim%2Fpure-lua-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Atypicalim%2Fpure-lua-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Atypicalim","download_url":"https://codeload.github.com/Atypicalim/pure-lua-tools/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229699948,"owners_count":18109851,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lua","pure","tools"],"created_at":"2024-12-14T11:36:44.492Z","updated_at":"2024-12-14T11:36:45.094Z","avatar_url":"https://github.com/Atypicalim.png","language":"Lua","readme":"### Pure Lua Tools\r\n\r\n0. About\r\n\r\n\u003e there are some useful tools for lua, u can require `tools.lua` file and enjoy the tools ...\r\n\r\n```lua\r\nrequire('./tools')\r\n-- do something with tools\r\n```\r\n\r\n1. class\r\n\r\n```lua\r\nlocal Animal = class(\"Animal\")\r\nfunction Animal:__init__()\r\n    print('animal init ...')\r\nend\r\nfunction Animal:eat(something)\r\n    print(string.format('eating a poor %s ...', something))\r\nend\r\n\r\nlocal Dog, Parent = class(\"Dog\", Animal)\r\nfunction Dog:__init__()\r\n    Parent:__init__(self)\r\n    print('dog init ...')\r\nend\r\nfunction Dog:eat(something)\r\n    Parent.eat(self, something)\r\nend\r\n\r\nlocal dog = Dog()\r\nprint(dog)\r\ndog:eat('cat')\r\n\r\n-- animal init ...\r\n-- dog init ...\r\n-- \u003cobject Dog\u003e: 01085670\r\n-- eating a poor cat ...\r\n```\r\n\r\n2. events\r\n\r\n```lua\r\nevents = Events()\r\nevents:addListener('testEvent', function(argument)\r\n    print('callback1 receive: ' .. argument)\r\nend, 1) -- once\r\nevents:addListener('testEvent', function(argument)\r\n    print('callback2 receive: ' .. argument)\r\nend, 3) -- limeted\r\nevents:addListener('testEvent', function(argument)\r\n    print('callback3 receive: ' .. argument)\r\nend, 0) -- forever\r\nevents:triggerEvent('testEvent', 1)\r\nevents:triggerEvent('testEvent', 2)\r\nevents:triggerEvent('testEvent', 3)\r\nevents:triggerEvent('testEvent', 4)\r\nevents:triggerEvent('testEvent', 5)\r\n\r\n-- callback1 receive: 1\r\n-- callback2 receive: 1\r\n-- callback3 receive: 1\r\n-- callback2 receive: 2\r\n-- callback3 receive: 2\r\n-- callback2 receive: 3\r\n-- callback3 receive: 3\r\n-- callback3 receive: 4\r\n-- callback3 receive: 5\r\n```\r\n\r\n3. files\r\n\r\n```lua\r\n-- write, read\r\nlocal fileName = \"some/file/nam.txt\"\r\nfiles.write(fileName, 'content...')\r\nfiles.is_file(fileName)\r\nlocal content = files.read(fileName)\r\nfiles.delete(fileName)\r\n-- list dir\r\nlocal dirName = 'some/folder/name/'\r\nfiles.is_folder(dirName)\r\nlocal fileNames = files.list(dirName)\r\n-- size\r\nfiles.size(fileName)\r\n-- watch\r\nfiles.watch({'test1.txt', 'test1.txt'}, function(path, newTime)\r\n    print(path, os.date(\"modified at: %Y-%m-%d %H:%M:%S\", newTime))\r\nend)\r\n```\r\n\r\n4. json\r\n\r\n```lua\r\nlocal test = {\r\n    [1] = 'numberKey',\r\n    boolenValue = true,\r\n    nullValue = null,\r\n    objectValue = {\r\n        stringValue = \"json is ready!\",\r\n    },\r\n    arrayValue = {\"enjoy\", \"it\", \"!\"},\r\n}\r\n\r\n-- encode\r\nlocal s = json.encode(test)\r\nprint(s)\r\n-- {\"1\":\"numberKey\",\"objectValue\":{\"stringValue\":\"json is ready!\"},\"nullValue\":null,\"arrayValue\":[\"enjoy\",\"it\",\"!\"],\"boolenValue\":true}\r\n\r\n-- decode\r\nlocal t = json.decode(s)\r\nprint(t)\r\n-- table: 010A3D40\r\n```\r\n\r\n5. table\r\n\r\n```lua\r\n-- test table value with some feature\r\nlocal value = table.new({\r\n    key = \"value\",\r\n})\r\n\r\n-- encode, decode\r\nlocal s = value:encode() -- lua script string of the table value\r\nlocal t = s:decode() -- table value of the script string\r\n\r\n-- write, read\r\nvalue:write_to_file('test.txt')\r\nlocal t = table.read_from_file('test.txt')\r\n\r\n-- keys, values\r\nlocal keys = value:keys()\r\nlocal values = value:values()\r\n\r\n-- merge\r\nlocal t = value:merge({newKey= \"newValue\"})\r\n```\r\n\r\n6. timer\r\n\r\n```lua\r\n-- sync\r\ntimer.async(function()\r\n    timer.sleep(1)\r\n    print('one')\r\n    timer.sleep(1)\r\n    print('two')\r\n    timer.sleep(1)\r\n    print('three')\r\nend)\r\n\r\n-- delay\r\ntimer.delay(2, function()\r\n    print('delay')\r\nend)\r\n\r\n-- start the loop\r\nprint(\"start\")\r\nprint(\"end!\")\r\ntimer.start()\r\n\r\n-- start\r\n-- one\r\n-- delay\r\n-- two\r\n-- three\r\n-- end!\r\n```\r\n\r\n7. string\r\n\r\n```lua\r\n-- test string value with some feature\r\nlocal s = string.new('abcd')\r\n\r\n-- fill\r\nlocal r = s:center(6, ' ') -- ' abcd '\r\nlocal r = s:left(6, ' ') -- 'abcd  '\r\nlocal r = s:right(6, ' ') -- '  abcd'\r\n\r\n-- trim\r\nlocal s = s:trim() -- 'abcd'\r\n\r\n-- execute\r\ns:execute()\r\n```\r\n\r\n8. bit\r\n\r\n```lua\r\nr = bit.rshift(2, 1) -- 1\r\nr = bit.lshift(2, 1) -- 4\r\nr = bit.band(1, 3) -- 1\r\nr = bit.bor(1, 2) -- 3\r\nr = bit.bxor(1, 3) -- 2\r\nr = bit.bnot(1) -- -2\r\n```\r\n\r\n9. encryption\r\n```lua\r\nlocal text = \"hello\"\r\nlocal md5 = encryption.md5(text)\r\nprint(md5)\r\n-- 5d41402abc4b2a76b9719d911017c592\r\nlocal encoded = encryption.base64_encode(text)\r\nprint(encoded)\r\n-- aGVsbG8=\r\nlocal decoded = encryption.base64_decode(encoded)\r\nprint(decoded)\r\n-- hello\r\nlocal key = \"key\"\r\nlocal encoded = encryption.bxor_encode(key, text)\r\nlocal decoded = encryption.bxor_encode(key, encoded)\r\nprint(decoded)\r\n-- hello\r\n```\r\n\r\n10. http\r\n\r\n```lua\r\n-- download\r\nhttp.download('http://example.xyz/some/file.txt', './file.txt')\r\n\r\n-- request\r\nlocal isOk, code, content = http.get('http://example.xyz/some/url', {queryKey = \"value\"}, {headerKey = \"value\"})\r\nlocal isOk, code, content = http.post('http://example.xyz/some/url', {bodyKey = \"value\"}, {headerKey = \"value\"})\r\nassert(isOk and code == 200)\r\nprint(content)\r\n```\r\n\r\n11. Object\r\n\r\n```lua\r\n-- new class\r\nlocal Human = Object:ext()\r\nfunction Human:init()\r\n    print('human...')\r\nend\r\n-- extended class\r\nlocal Man = Human:ext()\r\nfunction Man:init()\r\n    Human.init(self)\r\n    print('man...')\r\nend\r\n-- a object\r\nlocal alex = Man:new()\r\nprint(alex:is(Man))\r\nprint(alex:is(Human))\r\n```\r\n\r\n![log_test](./others/test_object.png)\r\n\r\n12. Log\r\n\r\n```lua\r\nlocal log = Log('log.txt', 'TEST', Log.LEVEL.USER, Log.COLOR.TAG_BG_CONTENT_FG)\r\nlog:user('time:%d', os.time())\r\nlog:error('error ...')\r\nlog:warn('warn ...')\r\nlog:info('info ...')\r\nlog:debug('debug ...')\r\n```\r\n\r\n![log_test](./others/test_log.png)\r\n\r\n13. package\r\n\r\n```lua\r\n-- other.lua\r\na = 10\r\nb = {}\r\nb.c = 'c...'\r\nprint(b)\r\nreturn b\r\n\r\n-- test.lua\r\nlocal path = './other.lua'\r\nlocal m = package.doload(path)\r\nprint(m)\r\nprint(package.isloaded(path))\r\nprint(a)\r\nprint(m.c)\r\n\r\n-- table: 02246FB8\r\n-- table: 02246FB8\r\n-- true\r\n-- 10\r\n-- c...\r\n```\r\n\r\n14. Graphic\r\n\r\n```lua\r\nlocal graphic = Graphic()\r\n-- stage\r\ngraphic:setXY(250, 250):setWH(495, 495):setClip()\r\ngraphic:setXY(250, 250):setWH(500, 500):setColor(\"#222222\"):addRectangle()\r\n-- text\r\ngraphic:setXY(125, 265):setColor(\"#00ff55\"):addText(\"Text...\", 48, nil)\r\n-- iamges\r\ngraphic:setXY(375, 125):setWH(200, 200):addImage(\"./others/yellow.png\", 75, 75, 350, 350)\r\ngraphic:setXY(125, 375):setWH(128, 128):addImage(\"./others/test.png\", 0, 0, 128, 128)\r\n-- lines\r\ngraphic:setColor(\"#2255ff\")\r\ngraphic:addLine({75, 75}, {175, 175})\r\ngraphic:addCurve({50, 100}, {50, 200}, {150, 200})\r\ngraphic:addBezier({10, 10}, {100, 100}, {200, 10}, {200, 200})\r\n-- shapes\r\ngraphic:setColor(\"#55ff55ff\")\r\ngraphic:setXY(425, 325):setWH(50, 50):addEllipse()\r\ngraphic:setXY(375, 375):setWH(100, 100):addPie()\r\ngraphic:setXY(375, 375):setWH(200, 200):addArc()\r\ngraphic:setColor(\"#5577ffaa\")\r\ngraphic:addPolygon({75, 125}, {75, 175}, {125, 175})\r\n-- show or save\r\ngraphic:show()\r\n-- graphic:save(\"./others/graphic.png\")\r\n```\r\n\r\n![log_test](./others/graphic.png)\r\n\r\n15. Dialog\r\n\r\n```lua\r\nlocal r = dialog.show_confirm(\"title...\", \"confirm...\", YesNoCancel)\r\nprint(\"result:\", r)\r\n-- result: true\r\n```\r\n\r\n![log_test](./others/test_dialog.png)\r\n\r\n16. Path\r\n\r\n```lua\r\nlocal path = Path()\r\n-- \r\nprint(path:set(\"~\"):get())\r\n-- C:\\Users\\user\r\nprint(path:push(\"../xyz/abc\"):get())\r\n-- C:\\Users\\xyz\\abc\r\nprint(path:relative(Path(\"~\")):get())\r\n-- ..\\..\\user\r\nprint(Path(\"~\"):relative(path):get())\r\n-- ..\\xyz\\abc\r\n```\r\n\r\n17. Time\r\n\r\n```lua\r\nlocal time = Time(os.time())\r\nprint(time:getYear())\r\n-- 2022\r\nlocal time = Time(60 * 60 * 24 * 10 + 60 * 60 * 5 + 60 * 7 + 9)\r\nprint(time:countDay())\r\n-- 1 3 5 7 9\r\n```\r\n\r\n18. library\r\n\r\n* image\r\n```lua\r\n-- write png\r\nlocal img = library.pngEncode(4, 4, \"rgba\")\r\nwhile not img.done do\r\n    img:write({150, 100, 50, 200})\r\nend\r\nfiles.write(\"./test.png\", table.concat(img.output), \"wb\")\r\n-- read png\r\nlocal data = files.read(\"./test.png\", \"rb\")\r\nlocal img = library.pngDecode(data, printProg)\r\nlocal pixel = img:getPixel(2, 2)\r\nprint(\"size:\", img.width, img.height, \"depth:\", img.depth, \"color:\", img.colorType)\r\nprint(\"pixel:\", pixel.R, pixel.G, pixel.B, pixel.A)\r\n```\r\n\r\n* log30\r\n```lua\r\nlocal Parent = library.log30()\r\nfunction Parent:__init()\r\n    print('parent init ...')\r\nend\r\nfunction Parent:testFunc()\r\n    print('test func ...')\r\nend\r\nlocal Child = Parent:extends()\r\nfunction Child:__init()\r\n\tself.super.__init(self)\r\n    print('child init ...')\r\nend\r\nlocal object = Child()\r\nobject:testFunc()\r\n-- parent init ...\r\n-- child init ...\r\n-- test func ...\r\n```\r\n\r\n* qrcode\r\n```lua\r\nlocal isOk, datas = library.qrcode(\"content...\")\r\nassert(isOk == true, 'qrcode generate failed!')\r\nfor i,column in ipairs(datas) do\r\n    for j,row in ipairs(column) do\r\n        --\r\n    end\r\nend\r\n```\r\n\r\n18. Canvas\r\n\r\n```lua\r\n-- draw canvas\r\nlocal size = 128\r\nlocal canvas = Canvas(size, size)\r\nfor i=1,size do\r\n    for j=1,size do\r\n        local c = (i + j - 1) % 255\r\n        canvas:setPixel(i, j, colors.rgb_to_hex({c, c, c}))\r\n    end\r\nend\r\nlocal c = math.round(size / 2)\r\nlocal d = math.round(c * 0.25)\r\ncanvas:drawLine(c + d * 3, c + d * 3, c - d * 3, c - d * 3, 0xff0000)\r\ncanvas:drawRect(c - d * 2, c + d * 2, c + d * 2, c - d * 2, false, 0x22ffff)\r\ncanvas:drawCircle(c, c, c - d, false, 0xffff44)\r\ncanvas:drawEllipse(c, c, c - d * 2, c - d * 3, 0x22ff88)\r\n-- write to file\r\nlocal img = library.pngEncode(size, size, \"rgba\")\r\nfor y=size,1,-1 do\r\n    for x=1,size do\r\n        local px = canvas:getPixel(x, y)\r\n        local rgba = table.insert(colors.hex_to_rgb(px), 255)\r\n        assert(#rgba == 4)\r\n        img:write(rgba)\r\n    end\r\nend\r\nassert(img.done == true)\r\nfiles.write(\"./others/test_canvas.png\", table.concat(img.output), \"wb\")\r\n```\r\n\r\n![log_test](./others/test_canvas.png)\r\n\r\n19. colors\r\n\r\n```lua\r\nlocal rand = colors.get_random_rgb()\r\nlocal grey = colors.rgb_get_grayscale(rand)\r\nlocal hex = colors.rgb_to_hex(grey)\r\n```\r\n\r\n20. bmp\r\n\r\n```lua\r\nlocal size = 128\r\nlocal pixels = {}\r\nfor y=size,1,-1 do\r\n    pixels[y] = {}\r\n    for x=1,size do\r\n        local r = math.floor((x / size * 255)) % 256\r\n        local g = math.floor((y / size * 255)) % 256\r\n        local b = math.floor(((x + y) / size * 255)) % 256\r\n        pixels[y][x] = {r, g, b}\r\n    end\r\nend\r\nlocal path = \"./others/test_bmp.bmp\"\r\nbmp.write(path, size, size, pixels)\r\nlocal w, h, pxs = bmp.read(path)\r\nassert(w == size and h == size)\r\n```\r\n\r\n![log_test](./others/test_bmp.bmp)\r\n\r\n21. Point\r\n\r\n```lua\r\nlocal p = Point(10, 10):rotate(-90)\r\nprint(p.x, p.y)\r\n-- 10 -10\r\n```\r\n\r\n22. yaml\r\n\r\n```lua\r\nlocal text = [[\r\ntime: 2023-09-12_21:30:00+08\r\none:\u0026anchor1\r\n  a:'aaa'\r\n  b:\"bbb\" # comment2...\r\ntwo:\r\n  c:ccc # comment3...\r\n  \u003c\u003c:*anchor1\r\n  d:0xff\r\nthree:\r\n  - \u0026anchor2 xxx\r\n  - yyy\r\n  # comment1...\r\n  - zzz\r\n  - *anchor2\r\n]]\r\nlocal data = yaml.decode(text)\r\nprint(data)\r\n-- {\r\n--   [time] = 1694496600,\r\n--   [one] = {\r\n--     [a] = \"aaa\",\r\n--     [b] = \"bbb\"\r\n--   },\r\n--   [two] = {\r\n--     [c] = \"ccc\",\r\n--     [a] = \"aaa\",\r\n--     [d] = 255,\r\n--     [b] = \"bbb\"\r\n--   }\r\n--   [three] = {\r\n--     (1) = \"xxx\",\r\n--     (2) = \"yyy\",\r\n--     (3) = \"zzz\",\r\n--     (4) = \"xxx\"\r\n--   },\r\n-- }\r\n```\r\n\r\n22. plist\r\n\r\n```lua\r\nlocal text = [[\r\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\r\n\u003c!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"\u003e\r\n\u003cplist version=\"1.0\"\u003e\r\n\u003cdict\u003e\r\n    \u003ckey\u003ea\u003c/key\u003e\r\n    \u003carray\u003e\r\n        \u003creal\u003e1\u003c/real\u003e\r\n        \u003creal\u003e2\u003c/real\u003e\r\n    \u003c/array\u003e\r\n    \u003ckey\u003es\u003c/key\u003e\r\n    \u003cstring\u003estr...\u003c/string\u003e\r\n    \u003ckey\u003eb\u003c/key\u003e\r\n    \u003ctrue/\u003e\r\n\u003c/dict\u003e\r\n\u003c/plist\u003e \r\n]]\r\nlocal t = plist.decode(text)\r\nprint(t)\r\n-- {\r\n--   [a] = {\r\n--     (1) = 1,\r\n--     (2) = 2\r\n--   },\r\n--   [s] = \"str...\",\r\n--   [b] = true\r\n-- }\r\n```\r\n\r\n23. decorator\r\n\r\n```lua\r\n-- test func\r\nlocal tFunc = function(arg1, arg2)\r\n    return arg1 + arg2\r\nend\r\n-- executed befor test func\r\nlocal bFunc = function(arg1, arg2)\r\n    if arg2 == 40 then\r\n        return arg1, 50 -- change the second argument\r\n    elseif foo then\r\n        return nil, arg2 -- set first argument as nil\r\n    elseif bar then\r\n        return nil -- set all arguments as nil\r\n    else\r\n        -- use given arguments\r\n    end\r\nend\r\n-- executed after test func\r\nlocal aFunc = function(result)\r\n    if result == 70 then\r\n        return 80 -- change the result\r\n    elseif foo then\r\n        return nil -- set result as nil\r\n    else\r\n        -- use returend result\r\n    end\r\nend\r\n-- executed when occurs exception\r\nlocal eFunc = function(err)\r\n    return 0 -- fix the result\r\nend\r\n-- use decorator\r\nlocal addFunc = lua_new_decorator(tFunc):before(bFunc):after(aFunc):error(eFunc)\r\nr = addFunc:call(10, 20)\r\nprint(\"10 + 20 = \" .. r)\r\nr = addFunc:call(10, 40)\r\nprint(\"10 + 40 = \" .. r)\r\nr = addFunc:call(10, 60)\r\nprint(\"10 + 60 = \" .. r)\r\nr = addFunc:call(10, nil)\r\nprint(\"10 + nil = \" .. r)\r\n-- 10 + 20 = 30\r\n-- 10 + 40 = 60\r\n-- 10 + 60 = 80\r\n-- 10 + nil = 0\r\n```\r\n\r\n24. console\r\n\r\n```lua\r\nlocal confirmed = console.print_confirm()\r\nprint(\"confirmed:\", confirmed)\r\n-- ---------------------confirm----------------------\r\n-- |                  Yes or No ?                   |\r\n-- --------------------------------------------------\r\n-- \u003e n\r\n-- * confirmed!\r\n-- confirmed:  false\r\nconsole.print_progress(75)\r\n-- [ ========================================= 100% ]\r\nconsole.print_qrcode(\"hello...\")\r\n-- ----------------------qrcode----------------------\r\n-- | qr code body with white and black blocks \r\n-- --------------------------------------------------\r\nlocal selection = console.print_select({'lua', 'c', 'c++'})\r\nprint('selection:', selection)\r\n-- ----------------------select----------------------\r\n-- |  1 . lua                                       |\r\n-- |  2 . c                                         |\r\n-- --------------------------------------------------\r\n-- \u003e 1\r\n-- * selected!\r\n-- selection:  lua\r\nlocal input = console.print_enter(true)\r\nprint('input:', input)\r\n-- ----------------------enter-----------------------\r\n-- |               Enter a password ?               |\r\n-- --------------------------------------------------\r\n-- \u003e ******\r\n-- * entered!\r\n-- input:  123456\r\nlocal content = console.print_edit('origin content ...')\r\nprint('content:', content)\r\n-- -----------------------edit-----------------------\r\n-- |     e:Edit s:Save p:Print r:Revert q:Quit      |\r\n-- --------------------------------------------------\r\n-- * editing:\r\n-- * edited!\r\n-- |  1  edited content ...\r\n-- * printed!\r\n-- * quitted!\r\n-- content:  edited content ...\r\n```\r\n![log_test](./others/test_qrcode.png)\r\n\r\n25. shell\r\n\r\n```lua\r\nlocal isOk, output = shell.whoami()\r\nprint(isOk, output)\r\n-- true  win\\administrator\r\n```\r\n\r\n---\r\n\r\n\u003e for more feture plz read the source code ...\r\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatypicalim%2Fpure-lua-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fatypicalim%2Fpure-lua-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fatypicalim%2Fpure-lua-tools/lists"}