added type annotations and descriptions for functions where appropriate
This commit is contained in:
parent
7ddece288b
commit
b89ff14d5c
@ -19,7 +19,7 @@ local function wrapUnits(n)
|
|||||||
return tostring(math.floor(n))..(scale[count] or "")
|
return tostring(math.floor(n))..(scale[count] or "")
|
||||||
end
|
end
|
||||||
|
|
||||||
function shutil.import(lib)
|
function shutil.import(lib) -- string -- boolean -- Imports the functions from library *lib* into the shell environment.
|
||||||
local cE = os.getenv("INCLUDE") or shell.include
|
local cE = os.getenv("INCLUDE") or shell.include
|
||||||
local nE = {}
|
local nE = {}
|
||||||
for k,v in pairs(cE) do
|
for k,v in pairs(cE) do
|
||||||
@ -31,7 +31,7 @@ function shutil.import(lib)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function shutil.unimport(lib)
|
function shutil.unimport(lib) -- string -- boolean -- Removes the functions from *lib* from the shell environment.
|
||||||
local cE = os.getenv("INCLUDE") or shell.include
|
local cE = os.getenv("INCLUDE") or shell.include
|
||||||
local nE = {}
|
local nE = {}
|
||||||
for k,v in pairs(cE) do
|
for k,v in pairs(cE) do
|
||||||
@ -43,7 +43,7 @@ function shutil.unimport(lib)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function shutil.ls(...)
|
function shutil.ls(...) -- string -- -- Prints contents of directories specified as *...*.
|
||||||
local tA = {...}
|
local tA = {...}
|
||||||
if not tA[1] then tA[1] = "." end
|
if not tA[1] then tA[1] = "." end
|
||||||
for _,d in ipairs(tA) do
|
for _,d in ipairs(tA) do
|
||||||
@ -56,7 +56,7 @@ function shutil.ls(...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function shutil.cat(...)
|
function shutil.cat(...) -- string -- -- Outputs the contents of files specified in *...* to the standard output.
|
||||||
for _,fn in ipairs({...}) do
|
for _,fn in ipairs({...}) do
|
||||||
local f = io.open(fn,"rb")
|
local f = io.open(fn,"rb")
|
||||||
io.write(f:read("*a"))
|
io.write(f:read("*a"))
|
||||||
@ -64,7 +64,7 @@ function shutil.cat(...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function shutil.ps()
|
function shutil.ps() -- Prints the processes running on the system.
|
||||||
print("PID# Parent | Name")
|
print("PID# Parent | Name")
|
||||||
for k,v in pairs(os.tasks()) do
|
for k,v in pairs(os.tasks()) do
|
||||||
local t = os.taskInfo(v)
|
local t = os.taskInfo(v)
|
||||||
@ -72,7 +72,7 @@ function shutil.ps()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function shutil.df()
|
function shutil.df() -- Prints free disk space.
|
||||||
local mt = fs.mounts()
|
local mt = fs.mounts()
|
||||||
local ml = 0
|
local ml = 0
|
||||||
for k,v in pairs(mt) do
|
for k,v in pairs(mt) do
|
||||||
@ -88,7 +88,7 @@ function shutil.df()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function shutil.mount(addr,path)
|
function shutil.mount(addr,path) -- string string -- boolean string -- Mounts filesystem component with address *addr* to *path* in the filesystem.
|
||||||
if not addr then
|
if not addr then
|
||||||
local mt = fs.mounts()
|
local mt = fs.mounts()
|
||||||
for k,v in pairs(mt) do
|
for k,v in pairs(mt) do
|
||||||
@ -114,7 +114,7 @@ function shutil.mount(addr,path)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function shutil.free()
|
function shutil.free() -- Displays used and free memory.
|
||||||
print("Total Used Free")
|
print("Total Used Free")
|
||||||
print(string.format("%5s %5s %5s",wrapUnits(computer.totalMemory()),wrapUnits(computer.totalMemory()-computer.freeMemory()),wrapUnits(computer.freeMemory())))
|
print(string.format("%5s %5s %5s",wrapUnits(computer.totalMemory()),wrapUnits(computer.totalMemory()-computer.freeMemory()),wrapUnits(computer.freeMemory())))
|
||||||
end
|
end
|
||||||
|
@ -4,7 +4,7 @@ local function normalise(path)
|
|||||||
return table.concat(fs.segments(path),"/")
|
return table.concat(fs.segments(path),"/")
|
||||||
end
|
end
|
||||||
|
|
||||||
function unionfs.create(...)
|
function unionfs.create(...) -- string -- table -- Returns a unionfs object of the directories specified in *...*.
|
||||||
local paths,fids,fc = {...}, {}, 0
|
local paths,fids,fc = {...}, {}, 0
|
||||||
for k,v in pairs(paths) do
|
for k,v in pairs(paths) do
|
||||||
paths[k] = "/"..normalise(v)
|
paths[k] = "/"..normalise(v)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
local vtansi = {}
|
local vtansi = {}
|
||||||
function vtansi.vtemu(gpu) -- takes GPU component proxy *gpu* and returns a function to write to it in a manner like an ANSI terminal
|
function vtansi.vtemu(gpu) -- table -- function -- takes GPU component proxy *gpu* and returns a function to write to it in a manner like an ANSI terminal
|
||||||
local colours = {0x0,0xFF0000,0x00FF00,0xFFFF00,0x0000FF,0xFF00FF,0x00B6FF,0xFFFFFF}
|
local colours = {0x0,0xFF0000,0x00FF00,0xFFFF00,0x0000FF,0xFF00FF,0x00B6FF,0xFFFFFF}
|
||||||
local mx, my = gpu.maxResolution()
|
local mx, my = gpu.maxResolution()
|
||||||
local cx, cy = 1, 1
|
local cx, cy = 1, 1
|
||||||
@ -142,7 +142,7 @@ function vtansi.vtemu(gpu) -- takes GPU component proxy *gpu* and returns a func
|
|||||||
return termwrite
|
return termwrite
|
||||||
end
|
end
|
||||||
|
|
||||||
function vtansi.vtsession(gpua,scra) -- creates a process to handle the GPU and screen address combination *gpua*/*scra*. Returns read, write and "close" functions.
|
function vtansi.vtsession(gpua,scra) -- string string -- table -- creates a process to handle the GPU and screen address combination *gpua*/*scra*. Returns read, write and "close" functions.
|
||||||
local gpu = component.proxy(gpua)
|
local gpu = component.proxy(gpua)
|
||||||
gpu.bind(scra)
|
gpu.bind(scra)
|
||||||
local write = vtansi.vtemu(gpu)
|
local write = vtansi.vtemu(gpu)
|
||||||
|
@ -181,6 +181,7 @@ env:process(arg[1])
|
|||||||
local tmpfile = os.tmpname()
|
local tmpfile = os.tmpname()
|
||||||
if tmpfile:sub(#tmpfile) == "." then tmpfile = tmpfile:sub(1, #tmpfile - 1) end
|
if tmpfile:sub(#tmpfile) == "." then tmpfile = tmpfile:sub(1, #tmpfile - 1) end
|
||||||
local tmpf = io.open(tmpfile, "wb")
|
local tmpf = io.open(tmpfile, "wb")
|
||||||
|
env.code = env.code:gsub("%-%-.-\n","\n"):gsub("\n\n","\n")
|
||||||
tmpf:write(env.code)
|
tmpf:write(env.code)
|
||||||
tmpf:close()
|
tmpf:close()
|
||||||
--if (os.execute("lua minify.lua "..tmpfile.." > "..arg[2])) then
|
--if (os.execute("lua minify.lua "..tmpfile.." > "..arg[2])) then
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
buffer = {}
|
buffer = {}
|
||||||
|
|
||||||
function buffer.new(mode, stream) -- create a new buffer in mode *mode* backed by stream object *stream*
|
function buffer.new(mode, stream) -- string table -- table -- create a new buffer in mode *mode* backed by stream object *stream*
|
||||||
local result = {
|
local result = {
|
||||||
mode = {},
|
mode = {},
|
||||||
stream = stream,
|
stream = stream,
|
||||||
|
@ -64,7 +64,7 @@ end
|
|||||||
devfs.component.address = "devfs"
|
devfs.component.address = "devfs"
|
||||||
devfs.component.type = "devfs"
|
devfs.component.type = "devfs"
|
||||||
|
|
||||||
function devfs.register(fname,fopen) -- Register a new devfs node with the name *fname* that will run the function *fopen* when opened. This function should return a function for read, a function for write, function for close, and optionally, a function for seek, in that order.
|
function devfs.register(fname,fopen) -- string function -- -- Register a new devfs node with the name *fname* that will run the function *fopen* when opened. This function should return a function for read, a function for write, function for close, and optionally, a function for seek, in that order.
|
||||||
devfs.files[fname] = fopen
|
devfs.files[fname] = fopen
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -3,14 +3,14 @@ fs = {}
|
|||||||
local fsmounts = {}
|
local fsmounts = {}
|
||||||
|
|
||||||
-- basics
|
-- basics
|
||||||
function fs.segments(path) -- splits *path* on each /
|
function fs.segments(path) -- string -- table -- Splits *path* on each /
|
||||||
local segments = {}
|
local segments = {}
|
||||||
for segment in path:gmatch("[^/]+") do
|
for segment in path:gmatch("[^/]+") do
|
||||||
segments[#segments+1] = segment
|
segments[#segments+1] = segment
|
||||||
end
|
end
|
||||||
return segments
|
return segments
|
||||||
end
|
end
|
||||||
function fs.resolve(path) -- resolves *path* to a specific filesystem mount and path
|
function fs.resolve(path) -- string -- string string -- Resolves *path* to a specific filesystem mount and path
|
||||||
if not path or path == "." then path = os.getenv("PWD") end
|
if not path or path == "." then path = os.getenv("PWD") end
|
||||||
if path:sub(1,1) ~= "/" then path=(os.getenv("PWD") or "").."/"..path end
|
if path:sub(1,1) ~= "/" then path=(os.getenv("PWD") or "").."/"..path end
|
||||||
local segments, rpath, rfs= fs.segments(path)
|
local segments, rpath, rfs= fs.segments(path)
|
||||||
@ -44,7 +44,7 @@ local function fclose(self)
|
|||||||
return fsmounts[self.fs].close(self.fid)
|
return fsmounts[self.fs].close(self.fid)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.open(path,mode) -- opens file *path* with mode *mode*
|
function fs.open(path,mode) -- string string -- table -- Opens file *path* with mode *mode*, returning a file object.
|
||||||
mode = mode or "rb"
|
mode = mode or "rb"
|
||||||
local fsi,path = fs.resolve(path)
|
local fsi,path = fs.resolve(path)
|
||||||
if not fsmounts[fsi] then return false end
|
if not fsmounts[fsi] then return false end
|
||||||
@ -62,7 +62,7 @@ function fs.open(path,mode) -- opens file *path* with mode *mode*
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.copy(from,to) -- copies a file from *from* to *to*
|
function fs.copy(from,to) -- string string -- boolean -- copies a file from *from* to *to*
|
||||||
local of = fs.open(from,"rb")
|
local of = fs.open(from,"rb")
|
||||||
local df = fs.open(to,"wb")
|
local df = fs.open(to,"wb")
|
||||||
if not of or not df then
|
if not of or not df then
|
||||||
@ -71,33 +71,34 @@ function fs.copy(from,to) -- copies a file from *from* to *to*
|
|||||||
df:write(of:read("*a"))
|
df:write(of:read("*a"))
|
||||||
df:close()
|
df:close()
|
||||||
of:close()
|
of:close()
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.rename(from,to) -- moves file *from* to *to*
|
function fs.rename(from,to) -- string string -- boolean -- Moves file *from* to *to*
|
||||||
local ofsi, opath = fs.resolve(from)
|
local ofsi, opath = fs.resolve(from)
|
||||||
local dfsi, dpath = fs.resolve(to)
|
local dfsi, dpath = fs.resolve(to)
|
||||||
if ofsi == dfsi then
|
if ofsi == dfsi then
|
||||||
fsmounts[ofsi].rename(opath,dpath)
|
fsmounts[ofsi].rename(opath,dpath)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
fs.copy(from,to)
|
if not fs.copy(from,to) then return false end
|
||||||
fs.remove(from)
|
if not fs.remove(from) then return false end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.mount(path,proxy) -- mounts the filesystem *proxy* to the mount point *path* if it is a directory. BYO proxy.
|
function fs.mount(path,proxy) -- string table -- boolean -- Mounts the filesystem *proxy* to the mount point *path* if it is a directory. BYO proxy.
|
||||||
if fs.isDirectory(path) and not fsmounts[table.concat(fs.segments(path),"/")] then
|
if fs.isDirectory(path) and not fsmounts[table.concat(fs.segments(path),"/")] then
|
||||||
fsmounts[table.concat(fs.segments(path),"/")] = proxy
|
fsmounts[table.concat(fs.segments(path),"/")] = proxy
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
return false, "path is not a directory"
|
return false, "path is not a directory"
|
||||||
end
|
end
|
||||||
function fs.umount(path)
|
function fs.umount(path) -- string -- -- Unmounts filesystem from *path*.
|
||||||
local fsi,_ = fs.resolve(path)
|
local fsi,_ = fs.resolve(path)
|
||||||
fsmounts[fsi] = nil
|
fsmounts[fsi] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.mounts() -- returns a table containing the mount points of all mounted filesystems
|
function fs.mounts() -- -- table -- Returns a table containing the mount points of all mounted filesystems
|
||||||
local rt = {}
|
local rt = {}
|
||||||
for k,v in pairs(fsmounts) do
|
for k,v in pairs(fsmounts) do
|
||||||
rt[#rt+1] = k,v.address or "unknown"
|
rt[#rt+1] = k,v.address or "unknown"
|
||||||
@ -105,11 +106,11 @@ function fs.mounts() -- returns a table containing the mount points of all mount
|
|||||||
return rt
|
return rt
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.address(path) -- returns the address of the filesystem at a given path, if applicable; do not expect a sensical response
|
function fs.address(path) -- string -- string -- Returns the address of the filesystem at a given path, if applicable; do not expect a sensical response
|
||||||
local fsi,_ = fs.resolve(path)
|
local fsi,_ = fs.resolve(path)
|
||||||
return fsmounts[fsi].address
|
return fsmounts[fsi].address
|
||||||
end
|
end
|
||||||
function fs.type(path) -- returns the component type of the filesystem at a given path, if applicable
|
function fs.type(path) -- string -- string -- Returns the component type of the filesystem at a given path, if applicable
|
||||||
local fsi,_ = fs.resolve(path)
|
local fsi,_ = fs.resolve(path)
|
||||||
return fsmounts[fsi].type or "filesystem"
|
return fsmounts[fsi].type or "filesystem"
|
||||||
end
|
end
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
io = {}
|
io = {}
|
||||||
|
|
||||||
function io.open(path,mode) -- Open file *path* in *mode*. Returns a buffer object.
|
function io.open(path,mode) -- string string -- table -- Open file *path* in *mode*. Returns a buffer object.
|
||||||
local f,e = fs.open(path, mode)
|
local f,e = fs.open(path, mode)
|
||||||
if not f then return false, e end
|
if not f then return false, e end
|
||||||
return buffer.new(mode,f)
|
return buffer.new(mode,f)
|
||||||
end
|
end
|
||||||
|
|
||||||
function io.input(fd) -- Sets the default input stream to *fd* if provided, either as a buffer as a path. Returns the default input stream.
|
function io.input(fd) -- table -- table -- Sets the default input stream to *fd* if provided, either as a buffer as a path. Returns the default input stream.
|
||||||
if type(fd) == "string" then
|
if type(fd) == "string" then
|
||||||
fd=io.open(fd,"rb")
|
fd=io.open(fd,"rb")
|
||||||
end
|
end
|
||||||
@ -15,7 +15,7 @@ function io.input(fd) -- Sets the default input stream to *fd* if provided, eith
|
|||||||
end
|
end
|
||||||
return os.getenv("STDIN")
|
return os.getenv("STDIN")
|
||||||
end
|
end
|
||||||
function io.output(fd) -- Sets the default output stream to *fd* if provided, either as a buffer as a path. Returns the default output stream.
|
function io.output(fd) -- table -- table -- Sets the default output stream to *fd* if provided, either as a buffer as a path. Returns the default output stream.
|
||||||
if type(fd) == "string" then
|
if type(fd) == "string" then
|
||||||
fd=io.open(fd,"wb")
|
fd=io.open(fd,"wb")
|
||||||
end
|
end
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
function loadfile(p) -- reads file *p* and returns a function if possible
|
function loadfile(p) -- string -- function -- reads file *p* and returns a function if possible
|
||||||
local f = io.open(p,"rb")
|
local f = io.open(p,"rb")
|
||||||
local c = f:read("*a")
|
local c = f:read("*a")
|
||||||
f:close()
|
f:close()
|
||||||
return load(c,p,"t")
|
return load(c,p,"t")
|
||||||
end
|
end
|
||||||
function runfile(p,...) -- runs file *p* with arbitrary arguments in the current thread
|
function runfile(p,...) -- string -- -- runs file *p* with arbitrary arguments in the current thread
|
||||||
return loadfile(p)(...)
|
return loadfile(p)(...)
|
||||||
end
|
end
|
||||||
function os.spawnfile(p,n,...) -- spawns a new process from file *p* with name *n*, with arguments following *n*.
|
function os.spawnfile(p,n,...) -- string string -- number -- spawns a new process from file *p* with name *n*, with arguments following *n*.
|
||||||
local tA = {...}
|
local tA = {...}
|
||||||
return os.spawn(function() local res={pcall(loadfile(p), table.unpack(tA))} computer.pushSignal("process_finished", os.pid(), table.unpack(res)) dprint(table.concat(res)) end,n or p)
|
return os.spawn(function() local res={pcall(loadfile(p), table.unpack(tA))} computer.pushSignal("process_finished", os.pid(), table.unpack(res)) dprint(table.concat(res)) end,n or p)
|
||||||
end
|
end
|
||||||
_G.package = {}
|
_G.package = {}
|
||||||
package.loaded = {computer=computer,component=component,fs=fs,buffer=buffer}
|
package.loaded = {computer=computer,component=component,fs=fs,buffer=buffer}
|
||||||
function require(f,force) -- searches for a library with name *f* and returns what the library returns, if possible. if *force* is set, loads the library even if it is cached
|
function require(f,force) -- string boolean -- table -- searches for a library with name *f* and returns what the library returns, if possible. if *force* is set, loads the library even if it is cached
|
||||||
if not package.loaded[f] or force then
|
if not package.loaded[f] or force then
|
||||||
local lib = os.getenv("LIB") or "/boot/lib"
|
local lib = os.getenv("LIB") or "/boot/lib"
|
||||||
for d in lib:gmatch("[^\n]+") do
|
for d in lib:gmatch("[^\n]+") do
|
||||||
@ -29,6 +29,6 @@ function require(f,force) -- searches for a library with name *f* and returns wh
|
|||||||
end
|
end
|
||||||
error("library not found: "..f)
|
error("library not found: "..f)
|
||||||
end
|
end
|
||||||
function reload(f)
|
function reload(f) -- string -- table -- Reloads library *f* from disk into memory.
|
||||||
return require(f,true)
|
return require(f,true)
|
||||||
end
|
end
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
function os.chdir(p) -- changes the current working directory of the calling process to the directory specified in *p*, returning true or false, error
|
function os.chdir(p) -- string -- boolean string -- changes the current working directory of the calling process to the directory specified in *p*, returning true or false, error
|
||||||
if not (p:sub(1,1) == "/") then
|
if not (p:sub(1,1) == "/") then
|
||||||
local np = {}
|
local np = {}
|
||||||
for k,v in pairs(fs.segments(os.getenv("PWD").."/"..p)) do
|
for k,v in pairs(fs.segments(os.getenv("PWD").."/"..p)) do
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
do
|
do
|
||||||
local tTasks,nPid,nTimeout,cPid = {},1,0.25,0 -- table of tasks, next process ID, event timeout, current PID
|
local tTasks,nPid,nTimeout,cPid = {},1,0.25,0 -- table of tasks, next process ID, event timeout, current PID
|
||||||
function os.spawn(f,n) -- creates a process from function *f* with name *n*
|
function os.spawn(f,n) -- function string -- number -- creates a process from function *f* with name *n*
|
||||||
tTasks[nPid] = {
|
tTasks[nPid] = {
|
||||||
c=coroutine.create(f), -- actual coroutine
|
c=coroutine.create(f), -- actual coroutine
|
||||||
n=n, -- process name
|
n=n, -- process name
|
||||||
@ -16,20 +16,20 @@ function os.spawn(f,n) -- creates a process from function *f* with name *n*
|
|||||||
nPid = nPid + 1
|
nPid = nPid + 1
|
||||||
return nPid - 1
|
return nPid - 1
|
||||||
end
|
end
|
||||||
function os.kill(pid) -- removes process *pid* from the task list
|
function os.kill(pid) -- number -- -- removes process *pid* from the task list
|
||||||
tTasks[pid] = nil
|
tTasks[pid] = nil
|
||||||
end
|
end
|
||||||
function os.pid() -- returns the current process' PID
|
function os.pid() -- -- number -- returns the current process' PID
|
||||||
return cPid
|
return cPid
|
||||||
end
|
end
|
||||||
function os.tasks() -- returns a table of process IDs
|
function os.tasks() -- -- table -- returns a table of process IDs
|
||||||
local rt = {}
|
local rt = {}
|
||||||
for k,v in pairs(tTasks) do
|
for k,v in pairs(tTasks) do
|
||||||
rt[#rt+1] = k
|
rt[#rt+1] = k
|
||||||
end
|
end
|
||||||
return rt
|
return rt
|
||||||
end
|
end
|
||||||
function os.taskInfo(pid) -- returns info on process *pid* as a table with name and parent values
|
function os.taskInfo(pid) -- number -- table -- returns info on process *pid* as a table with name and parent values
|
||||||
pid = pid or os.pid()
|
pid = pid or os.pid()
|
||||||
if not tTasks[pid] then return false end
|
if not tTasks[pid] then return false end
|
||||||
return {name=tTasks[pid].n,parent=tTasks[pid].P}
|
return {name=tTasks[pid].n,parent=tTasks[pid].P}
|
||||||
|
@ -9,6 +9,7 @@ syslog.notice = 5
|
|||||||
syslog.info = 6
|
syslog.info = 6
|
||||||
syslog.debug = 7
|
syslog.debug = 7
|
||||||
|
|
||||||
|
-- function syslog(msg, level, service) -- string number string -- -- Output *msg* to the system log, with severity *level*, from *service*.
|
||||||
local rdprint=dprint or function() end
|
local rdprint=dprint or function() end
|
||||||
setmetatable(syslog,{__call = function(_,msg, level, service)
|
setmetatable(syslog,{__call = function(_,msg, level, service)
|
||||||
level, service = level or syslog.info, service or (os.taskInfo(os.pid()) or {}).name or "unknown"
|
level, service = level or syslog.info, service or (os.taskInfo(os.pid()) or {}).name or "unknown"
|
||||||
|
Loading…
Reference in New Issue
Block a user