mirror of
https://shylinux.com/x/ContextOS
synced 2025-04-25 16:58:06 +08:00
add else.yac.go
This commit is contained in:
parent
5461b95f36
commit
65ae0b0a1b
@ -38,6 +38,8 @@ syn match shyCommand "\(^\|\t\| \|$(\)[a-zA-Z0-9_\.]\+\>"
|
||||
call Keys("Operator", ["new"])
|
||||
call Keys("Statment", ["config", "cache"])
|
||||
call Keys("Statment", ["return", "source"])
|
||||
call Keys("Statment", ["if", "for", "else", "else if", "end"])
|
||||
call Keys("Statment", ["let", "var"])
|
||||
" context nfs
|
||||
call Keys("SubCommand", ["import", "export", "load", "save"])
|
||||
|
||||
|
@ -9,8 +9,10 @@
|
||||
~wiki
|
||||
config load tmp/wiki.json wiki_visit
|
||||
|
||||
source etc/common.shy
|
||||
~nfs
|
||||
source etc/common.shy
|
||||
~ssh
|
||||
remote auto
|
||||
source local.shy
|
||||
~nfs
|
||||
source local.shy
|
||||
|
||||
|
@ -407,6 +407,9 @@ func main() {
|
||||
for i := 0; i < len(m.Meta["cmd_env"])-1; i += 2 {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", m.Meta["cmd_env"][i], m.Parse(m.Meta["cmd_env"][i+1])))
|
||||
}
|
||||
for _, k := range []string{"PATH"} {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", k, os.Getenv(k)))
|
||||
}
|
||||
if len(cmd.Env) > 0 {
|
||||
m.Log("info", "env %v", cmd.Env)
|
||||
}
|
||||
@ -770,12 +773,12 @@ func main() {
|
||||
code := kit.Select("0", arg, 0)
|
||||
switch code {
|
||||
case "0":
|
||||
m.Cmd("cli.source", m.Conf("system", "script.exit"))
|
||||
m.Cmd("nfs.source", m.Conf("system", "script.exit"))
|
||||
m.Echo("quit")
|
||||
|
||||
case "1":
|
||||
if m.Option("bio.modal") != "action" {
|
||||
m.Cmd("cli.source", m.Conf("system", "script.exit"))
|
||||
m.Cmd("nfs.source", m.Conf("system", "script.exit"))
|
||||
m.Echo("restart")
|
||||
}
|
||||
|
||||
@ -854,6 +857,7 @@ func main() {
|
||||
return
|
||||
}},
|
||||
"compile": &ctx.Command{Name: "compile all|self|[[[plugin] name] [OS [ARCH]]]", Help: "源码编译", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
wd, _ := os.Getwd()
|
||||
switch arg[0] {
|
||||
case "all":
|
||||
list := [][]string{}
|
||||
@ -864,8 +868,12 @@ func main() {
|
||||
m.Cmdy("nfs.dir", m.Conf("publish", "path"), "dir_reg", "bench")
|
||||
|
||||
case "self":
|
||||
env := []string{
|
||||
"cmd_env", "GOTMPDIR", path.Join(wd, m.Conf("compile", "tmp")),
|
||||
"cmd_env", "GOCACHE", path.Join(wd, m.Conf("compile", "tmp")),
|
||||
}
|
||||
m.Cmd("cli.version", "create")
|
||||
if m.Cmdy("cli.system", "go", "install", m.Cmdx("nfs.path", m.Conf("compile", "bench"))); m.Result(0) == "" {
|
||||
if m.Cmdy("cli.system", env, "go", "install", m.Cmdx("nfs.path", m.Conf("compile", "bench"))); m.Result(0) == "" {
|
||||
m.Cmdy("cli.quit", 1)
|
||||
m.Append("host", version.host)
|
||||
m.Append("self", version.self)
|
||||
@ -890,7 +898,6 @@ func main() {
|
||||
goos := kit.Select(m.Conf("runtime", "host.GOOS"), arg, 0)
|
||||
arch := kit.Select(m.Conf("runtime", "host.GOARCH"), arg, 1)
|
||||
|
||||
wd, _ := os.Getwd()
|
||||
os.MkdirAll(m.Conf("compile", "tmp"), 0777)
|
||||
env := []string{"cmd_env", "GOOS", goos, "cmd_env", "GOARCH", arch,
|
||||
"cmd_env", "GOTMPDIR", path.Join(wd, m.Conf("compile", "tmp")),
|
||||
|
@ -4,5 +4,5 @@ var version = struct {
|
||||
host string
|
||||
self int
|
||||
}{
|
||||
"2019-07-20 17:10:58", "mac", 232,
|
||||
"2019-07-22 22:15:19", "ZYB-20190522USI", 199,
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ var CGI = template.FuncMap{
|
||||
switch m := arg[0].(type) {
|
||||
case *Message:
|
||||
if len(arg) == 1 {
|
||||
return kit.Format(m.Meta["option"])
|
||||
return strings.Join(m.Meta["option"], "")
|
||||
}
|
||||
|
||||
switch value := arg[1].(type) {
|
||||
@ -327,7 +327,12 @@ var CGI = template.FuncMap{
|
||||
}
|
||||
case string:
|
||||
if len(arg) == 2 {
|
||||
return kit.Format(m.Optionv(value))
|
||||
switch v := m.Optionv(value).(type) {
|
||||
case []string:
|
||||
return kit.Format(strings.Join(v, ""))
|
||||
default:
|
||||
return kit.Format(v)
|
||||
}
|
||||
}
|
||||
|
||||
switch val := arg[2].(type) {
|
||||
|
@ -52,6 +52,8 @@ func (ctx *CTX) Start(m *Message, arg ...string) bool {
|
||||
m.Cmd("gdb._init")
|
||||
|
||||
m.Cmd("ctx._init")
|
||||
m.Cmd("aaa.role", "root", "user", m.Option("username", m.Conf("runtime", "boot.username")))
|
||||
m.Option("sessid", m.Cmdx("aaa.user", "session", "select"))
|
||||
m.Cmd("nfs.source", m.Conf("system", "script.init")).Cmd("nfs.source", "stdio").Cmd("nfs.source", m.Conf("system", "script.exit"))
|
||||
} else {
|
||||
m.Option("bio.modal", "action")
|
||||
|
@ -160,6 +160,7 @@ var Index = &ctx.Context{Name: "log", Help: "日志中心",
|
||||
"start": map[string]interface{}{"value": []interface{}{"bench", "red"}},
|
||||
"close": map[string]interface{}{"value": []interface{}{"bench", "red"}},
|
||||
"warn": map[string]interface{}{"value": []interface{}{"bench", "yellow"}},
|
||||
"stack": map[string]interface{}{"value": []interface{}{"bench", "yellow"}},
|
||||
|
||||
"cmd": map[string]interface{}{"value": []interface{}{"bench", "green"},
|
||||
"lex": map[string]interface{}{"value": []interface{}{"debug", "green"}},
|
||||
|
@ -916,16 +916,14 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool {
|
||||
kit.STDIO = nfs
|
||||
|
||||
} else if m.Options("daemon") {
|
||||
return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 终端用户
|
||||
m.Cmd("aaa.role", "root", "user", m.Option("username", m.Conf("runtime", "boot.username")))
|
||||
m.Option("sessid", m.Cmdx("aaa.user", "session", "select"))
|
||||
m.Optionv("bio.ctx", m.Target())
|
||||
// 语句堆栈
|
||||
stack := kit.Stack{}
|
||||
stack.Push(m.Option("stack.key", "source"), m.Options("stack.run", true), m.Optioni("stack.pos", 0))
|
||||
m.Optionv("bio.ctx", m.Target())
|
||||
|
||||
line, bio := "", bufio.NewScanner(nfs)
|
||||
for nfs.prompt(); ; nfs.prompt() {
|
||||
@ -953,7 +951,7 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool {
|
||||
|
||||
// 结束语句
|
||||
if strings.TrimSpace(line) == "end" {
|
||||
m.Log("stack", " pop %v", stack.Peek().String("/"))
|
||||
m.Log("stack", "pop: %v", stack.Peek().String("/"))
|
||||
if stack.Pop(); m.Options("stack.run") && m.Option("stack.key") == "for" {
|
||||
i = m.Optioni("stack.pos") - 1
|
||||
}
|
||||
@ -964,7 +962,7 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool {
|
||||
}
|
||||
|
||||
// 跳过语句
|
||||
if !stack.Peek().Run {
|
||||
if !m.Options("stack.run") && !strings.HasPrefix(strings.TrimSpace(line), "else") {
|
||||
m.Log("stack", "skip %v", line)
|
||||
continue
|
||||
}
|
||||
@ -980,10 +978,18 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool {
|
||||
}
|
||||
|
||||
// 压栈语句
|
||||
if msg.Appends("stack.key") {
|
||||
stack.Push(m.Option("stack.key", msg.Append("stack.key")), m.Options("stack.run", msg.Appends("stack.run")), m.Optioni("stack.pos", i))
|
||||
m.Log("stack", "push %v", stack.Peek().String("\\"))
|
||||
msg.Append("stack.key", "")
|
||||
if msg.Has("stack.key") {
|
||||
m.Log("stack", "push %v", stack.Push(
|
||||
m.Option("stack.key", msg.Append("stack.key")),
|
||||
m.Options("stack.run", msg.Appends("stack.run")),
|
||||
m.Optioni("stack.pos", i),
|
||||
).String("\\"))
|
||||
}
|
||||
if msg.Has("stack.run") {
|
||||
m.Log("stack", "set: run = %v", m.Options("stack.run", msg.Appends("stack.run")))
|
||||
}
|
||||
if msg.Has("stack.else") {
|
||||
m.Options("stack.else", msg.Appends("stack.else"))
|
||||
}
|
||||
|
||||
// 跳转语句
|
||||
|
@ -337,7 +337,7 @@ var Index = &ctx.Context{Name: "ssh", Help: "集群中心",
|
||||
map[string]interface{}{"componet_name": "get", "componet_help": "请求",
|
||||
"componet_tmpl": "componet", "componet_view": "Context", "componet_init": "",
|
||||
"componet_type": "private", "componet_ctx": "ssh", "componet_cmd": "_route",
|
||||
"componet_args": []interface{}{"$$", "context", "web", "get"}, "inputs": []interface{}{
|
||||
"componet_args": []interface{}{"$$", "context", "web", "get", "method", "GET", "parse", "json"}, "inputs": []interface{}{
|
||||
map[string]interface{}{"type": "text", "name": "pod", "imports": "plugin_pod"},
|
||||
map[string]interface{}{"type": "text", "name": "spide", "imports": "plugin_site"},
|
||||
map[string]interface{}{"type": "text", "name": "url", "value": "/", "view": "long"},
|
||||
|
@ -20,6 +20,12 @@ type TCP struct {
|
||||
}
|
||||
|
||||
func (tcp *TCP) parse(m *ctx.Message, arg ...string) ([]string, []string) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
m.Log("warn", "%v", e)
|
||||
}
|
||||
}()
|
||||
|
||||
address := []string{}
|
||||
if arg[1] == "dev" {
|
||||
m.Cmd("web.get", arg[1], arg[2], "temp", "ports", "format", "object").Table(func(line map[string]string) {
|
||||
@ -101,6 +107,9 @@ func (tcp *TCP) Begin(m *ctx.Message, arg ...string) ctx.Server {
|
||||
}
|
||||
func (tcp *TCP) Start(m *ctx.Message, arg ...string) bool {
|
||||
address, arg := tcp.parse(m, arg...)
|
||||
if len(address) == 0 {
|
||||
return true
|
||||
}
|
||||
m.Cap("security", m.Confx("security", arg, 2))
|
||||
m.Cap("protocol", m.Confx("protocol", arg, 3))
|
||||
|
||||
|
@ -185,6 +185,9 @@ func (web *WEB) HandleCmd(m *ctx.Message, key string, cmd *ctx.Command) {
|
||||
for k, v := range r.Form {
|
||||
msg.Add("option", k, v)
|
||||
}
|
||||
if !msg.Has("username") || !m.Options("username") {
|
||||
msg.Option("username", "")
|
||||
}
|
||||
|
||||
// 请求数据
|
||||
switch r.Header.Get("Content-Type") {
|
||||
|
@ -242,14 +242,21 @@ func (yac *YAC) parse(m *ctx.Message, msg *ctx.Message, page int, void int, line
|
||||
if hash == 0 {
|
||||
word = word[:0]
|
||||
|
||||
} else if !m.Confs("exec", []string{yac.hand[hash], "disable"}) { //执行命令
|
||||
} else if !m.Confs("exec", []string{yac.hand[hash], "disable"}) {
|
||||
//执行命令
|
||||
cmd := msg.Spawn(m.Optionv("bio.ctx"))
|
||||
if cmd.Cmd(yac.hand[hash], word); cmd.Hand {
|
||||
word = cmd.Meta["result"]
|
||||
}
|
||||
//切换模块
|
||||
if v := cmd.Optionv("bio.ctx"); v != nil {
|
||||
m.Optionv("bio.ctx", v)
|
||||
}
|
||||
for _, key := range []string{"stack.key", "stack.run", "stack.else"} {
|
||||
if cmd.Has(key) {
|
||||
msg.Appends(key, cmd.Appends(key))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m.Log("debug", "%s %s/%d %s(%d): %v", "parse", strings.Repeat("#", level), level, yac.hand[hash], hash, word)
|
||||
@ -301,11 +308,13 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
|
||||
"seed": &ctx.Config{Name: "seed", Value: []interface{}{
|
||||
map[string]interface{}{"page": "void", "hash": "void", "word": []interface{}{"[\t ]+"}},
|
||||
|
||||
// 数据类型
|
||||
map[string]interface{}{"page": "num", "hash": "num", "word": []interface{}{"mul{", "0", "-?[1-9][0-9]*", "0[0-9]+", "0x[0-9]+", "}"}},
|
||||
map[string]interface{}{"page": "key", "hash": "key", "word": []interface{}{"[A-Za-z_][A-Za-z_0-9]*"}},
|
||||
map[string]interface{}{"page": "str", "hash": "str", "word": []interface{}{"mul{", "\"[^\"]*\"", "'[^']*'", "}"}},
|
||||
map[string]interface{}{"page": "exe", "hash": "exe", "word": []interface{}{"mul{", "$", "@", "}", "opt{", "key", "}"}},
|
||||
|
||||
// 表达式语句
|
||||
map[string]interface{}{"page": "op1", "hash": "op1", "word": []interface{}{"mul{", "-", "+", "}"}},
|
||||
map[string]interface{}{"page": "op2", "hash": "op2", "word": []interface{}{"mul{", "+", "-", "*", "/", "%", "}"}},
|
||||
map[string]interface{}{"page": "op2", "hash": "op2", "word": []interface{}{"mul{", "<", "<=", ">", ">=", "==", "!=", "}"}},
|
||||
@ -315,14 +324,18 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
|
||||
map[string]interface{}{"page": "stm", "hash": "var", "word": []interface{}{"var", "key", "opt{", "=", "exp", "}"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "return", "word": []interface{}{"return", "rep{", "exp", "}"}},
|
||||
|
||||
// 命令语句
|
||||
map[string]interface{}{"page": "word", "hash": "word", "word": []interface{}{"mul{", "~", "!", "\\?", "\\?\\?", "exe", "str", "[\\-a-zA-Z0-9_:/.]+", "=", "<", ">$", ">@", ">", "\\|", "%", "}"}},
|
||||
map[string]interface{}{"page": "cmd", "hash": "cmd", "word": []interface{}{"rep{", "word", "}"}},
|
||||
map[string]interface{}{"page": "com", "hash": "com", "word": []interface{}{"mul{", ";", "#[^\n]*\n?", "\n", "}"}},
|
||||
map[string]interface{}{"page": "line", "hash": "line", "word": []interface{}{"opt{", "mul{", "stm", "cmd", "}", "}", "com"}},
|
||||
|
||||
// 复合语句
|
||||
map[string]interface{}{"page": "exe", "hash": "exe", "word": []interface{}{"$", "(", "cmd", ")"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "if", "word": []interface{}{"if", "exp"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "for", "word": []interface{}{"for", "rep{", "exp", "}"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "else", "word": []interface{}{"else", "opt{", "if", "exp", "}"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "end", "word": []interface{}{"end"}},
|
||||
/*
|
||||
|
||||
map[string]interface{}{"page": "op1", "hash": "op1", "word": []interface{}{"mul{", "-z", "-n", "}"}},
|
||||
@ -337,16 +350,11 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
|
||||
map[string]interface{}{"page": "stm", "hash": "var", "word": []interface{}{"var", "key", "<-", "opt{", "exe", "}"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "let", "word": []interface{}{"let", "key", "<-", "opt{", "exe", "}"}},
|
||||
|
||||
map[string]interface{}{"page": "stm", "hash": "else", "word": []interface{}{"else"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "end", "word": []interface{}{"end"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "for", "word": []interface{}{"for", "opt{", "exp", ";", "}", "exp"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "for", "word": []interface{}{"for", "index", "exp", "opt{", "exp", "}", "exp"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "label", "word": []interface{}{"label", "exp"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "goto", "word": []interface{}{"goto", "exp", "opt{", "exp", "}", "exp"}},
|
||||
|
||||
map[string]interface{}{"page": "stm", "hash": "expr", "word": []interface{}{"expr", "rep{", "exp", "}"}},
|
||||
map[string]interface{}{"page": "stm", "hash": "return", "word": []interface{}{"return", "rep{", "exp", "}"}},
|
||||
|
||||
*/
|
||||
|
||||
}, Help: "语法集合的最大数量"},
|
||||
@ -707,7 +715,7 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
|
||||
switch arg[2] {
|
||||
case "=":
|
||||
m.Cap(arg[1], arg[3])
|
||||
m.Log("stack", " set %v = %v", arg[1], arg[3])
|
||||
m.Log("stack", "let %v = %v", arg[1], arg[3])
|
||||
case "<-":
|
||||
m.Cap(arg[1], m.Cap("last_msg"))
|
||||
}
|
||||
@ -736,8 +744,12 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
|
||||
}},
|
||||
|
||||
"if": &ctx.Command{Name: "if exp", Help: "条件语句, exp: 表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
m.Appends("stack.else", true)
|
||||
m.Push("stack.key", arg[0])
|
||||
m.Push("stack.run", m.Options("stack.run") && kit.Right(arg[1]))
|
||||
if m.Appends("stack.run") {
|
||||
m.Appends("stack.else", false)
|
||||
}
|
||||
return
|
||||
}},
|
||||
"for": &ctx.Command{Name: "for [[express ;] condition]|[index message meta value]",
|
||||
@ -804,11 +816,14 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
|
||||
*/
|
||||
return
|
||||
}},
|
||||
|
||||
"expr": &ctx.Command{Name: "expr arg...", Help: "输出表达式", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
m.Echo("%s", strings.Join(arg[1:], ""))
|
||||
"else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
m.Appends("stack.run", m.Options("stack.else") && !m.Options("stack.run") && (len(arg) == 1 || kit.Right(arg[2])))
|
||||
if m.Appends("stack.run") {
|
||||
m.Appends("stack.else", false)
|
||||
}
|
||||
return
|
||||
}},
|
||||
|
||||
"label": &ctx.Command{Name: "label name", Help: "记录当前脚本的位置, name: 位置名", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
if cli, ok := m.Target().Server.(*YAC); m.Assert(ok) {
|
||||
if cli.label == nil {
|
||||
@ -829,23 +844,6 @@ var Index = &ctx.Context{Name: "yac", Help: "语法中心",
|
||||
}
|
||||
return
|
||||
}},
|
||||
"else": &ctx.Command{Name: "else", Help: "条件语句", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) {
|
||||
/*
|
||||
if cli, ok := m.Target().Server.(*YAC); m.Assert(ok) {
|
||||
if !m.Caps("parse") {
|
||||
m.Caps("parse", true)
|
||||
} else {
|
||||
if len(cli.stack) == 1 {
|
||||
m.Caps("parse", false)
|
||||
} else {
|
||||
frame := cli.stack[len(cli.stack)-2]
|
||||
m.Caps("parse", !frame.run)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,8 @@
|
||||
<meta name="{{index $meta "name"}}" content="{{index $meta "content"}}">
|
||||
{{end}}
|
||||
|
||||
<title>{{options . "componet_name"}}</title>
|
||||
<link rel="shortcut icon" type="image/ico" href="/static/librarys/{{options . "favicon"}}">
|
||||
<title>{{option . "componet_name" 0}}</title>
|
||||
<link rel="shortcut icon" type="image/ico" href="/static/librarys/{{option . "favicon" 0}}">
|
||||
{{range $index, $lib := option . "styles"}}
|
||||
<link rel="stylesheet" type="text/css" href="/static/librarys/{{$lib}}"></link>
|
||||
{{end}}
|
||||
@ -25,18 +25,18 @@
|
||||
</fieldset>
|
||||
{{end}}
|
||||
{{define "banner"}}
|
||||
<fieldset class="{{options . "componet_view"}}" data-init="{{options . "componet_init"}}">
|
||||
<fieldset class="{{option . "componet_view" 0}}" data-init="{{option . "componet_init" 0}}">
|
||||
<ul>{{range $key, $item := conf . "componet"}}<li>{{$key}}</li>{{end}}</ul>
|
||||
</fieldset>
|
||||
{{end}}
|
||||
{{define "fieldset"}}
|
||||
<fieldset class="{{options . "componet_view"}}" data-init="{{options . "componet_init"}}">
|
||||
<form class="option {{options . "componet_name"}}"
|
||||
<fieldset class="{{option . "componet_view" 0}}" data-init="{{option . "componet_init" 0}}">
|
||||
<form class="option {{option . "componet_name" 0}}"
|
||||
data-componet_name="{{options . "componet_name"}}"
|
||||
data-componet_group="{{options . "componet_group"}}">
|
||||
<input style="display:none"></input>
|
||||
</form>
|
||||
<div class="output {{options . "componet_name"}}"></div>
|
||||
<div class="output {{option . "componet_name" 0}}"></div>
|
||||
</fieldset>
|
||||
{{end}}
|
||||
{{define "tail"}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user