diff --git a/base/gdb/gdb.go b/base/gdb/gdb.go index ed708a83..e453639a 100644 --- a/base/gdb/gdb.go +++ b/base/gdb/gdb.go @@ -45,15 +45,17 @@ func (f *Frame) Close(m *ice.Message, arg ...string) bool { } const ( - RESTART = "restart" - BUILD = "build" - SPAWN = "spawn" - START = "start" - STOP = "stop" + BUILD = "build" + SPAWN = "spawn" + START = "start" + STOP = "stop" - BENCH = "bench" - BEGIN = "begin" - END = "end" + RESTART = "restart" + RELOAD = "reload" + BENCH = "bench" + PPROF = "pprof" + BEGIN = "begin" + END = "end" ) const GDB = "gdb" diff --git a/base/nfs/nfs.go b/base/nfs/nfs.go index 9fefeab7..42b42b43 100644 --- a/base/nfs/nfs.go +++ b/base/nfs/nfs.go @@ -88,8 +88,7 @@ func _file_list(m *ice.Message, root string, name string, level int, deep bool, if f.IsDir() { m.Push("link", "") } else { - m.PushRender("link", "a", kit.MergeURL(path.Join("/share/local/", - root, name, f.Name()), "pod", m.Option(ice.MSG_USERPOD)), f.Name()) + m.PushDownload(f.Name(), path.Join(root, name, f.Name())) } case "size": @@ -389,6 +388,9 @@ var Index = &ice.Context{Name: "nfs", Help: "存储模块", _file_show(m, arg[0]) }}, SAVE: {Name: "save file text...", Help: "保存", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + if len(arg) == 1 { + arg = append(arg, m.Option("content")) + } _file_save(m, arg[0], arg[1:]...) }}, COPY: {Name: "copy file from...", Help: "复制", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { diff --git a/core/chat/chat.go b/core/chat/chat.go index 81da7365..aab80c8e 100644 --- a/core/chat/chat.go +++ b/core/chat/chat.go @@ -69,5 +69,6 @@ var Index = &ice.Context{Name: CHAT, Help: "聊天中心", func init() { web.Index.Register(Index, &web.Frame{}, HEADER, RIVER, STORM, ACTION, FOOTER, + LOCATION, PASTE, SCAN, ) } diff --git a/core/chat/location.go b/core/chat/location.go index ea6d3359..9bbda6c8 100644 --- a/core/chat/location.go +++ b/core/chat/location.go @@ -38,20 +38,19 @@ func init() { LOCATION: {Name: "location text auto create@location", Help: "地理位置", Action: map[string]*ice.Action{ mdb.CREATE: {Name: "insert type=text name address latitude longitude", Help: "添加", Hand: func(m *ice.Message, arg ...string) { _trans(arg, map[string]string{"address": "text"}) - m.Conf(LOCATION, kit.Keys(m.Option(ice.MSG_DOMAIN), kit.MDB_META, kit.MDB_SHORT), kit.MDB_TEXT) m.Cmdy(mdb.INSERT, LOCATION, "", mdb.HASH, arg) }}, mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(mdb.MODIFY, LOCATION, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH), arg) }}, mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.DELETE, LOCATION, "", mdb.HASH, kit.MDB_TEXT, m.Option(kit.MDB_TEXT)) + m.Cmdy(mdb.DELETE, LOCATION, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) }}, mdb.EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.EXPORT, m.Prefix(LOCATION), "", mdb.HASH) + m.Cmdy(mdb.EXPORT, LOCATION, "", mdb.HASH) }}, mdb.IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.IMPORT, m.Prefix(LOCATION), "", mdb.HASH) + m.Cmdy(mdb.IMPORT, LOCATION, "", mdb.HASH) }}, mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(mdb.INPUTS, LOCATION, "", mdb.HASH, arg) diff --git a/core/chat/meet.go b/core/chat/meet.go index 9c6522c7..de429679 100644 --- a/core/chat/meet.go +++ b/core/chat/meet.go @@ -26,7 +26,7 @@ func init() { m.Cmdy(mdb.INSERT, m.Prefix(MISS), "", mdb.HASH, arg) }}, mdb.MODIFY: {Name: "modify key value", Help: "编辑", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.MODIFY, m.Prefix(MISS), "", mdb.HASH, kit.MDB_NAME, m.Option(kit.MDB_NAME), arg[0], arg[1]) + m.Cmdy(mdb.MODIFY, m.Prefix(MISS), "", mdb.HASH, kit.MDB_NAME, m.Option(kit.MDB_NAME), arg) }}, mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { m.Cmdy(mdb.DELETE, m.Prefix(MISS), "", mdb.HASH, kit.MDB_NAME, m.Option(kit.MDB_NAME)) @@ -39,8 +39,7 @@ func init() { }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Option(mdb.FIELDS, kit.Select("time,name,照片,性别,年龄,身高,体重,籍贯,户口,学历,学校,职业,公司,年薪,资产,家境", mdb.DETAIL, len(arg) > 0)) - msg := m.Cmd(mdb.SELECT, m.Prefix(MISS), "", mdb.HASH, kit.MDB_NAME, arg) - msg.Table(func(index int, value map[string]string, head []string) { + m.Cmd(mdb.SELECT, m.Prefix(MISS), "", mdb.HASH, kit.MDB_NAME, arg).Table(func(index int, value map[string]string, head []string) { value["照片"] = kit.Format(``, value["照片"], kit.Select("100", "400", m.Option(mdb.FIELDS) == mdb.DETAIL)) m.Push("", value, kit.Split(m.Option(mdb.FIELDS))) }) diff --git a/core/chat/paste.go b/core/chat/paste.go index d16a6de5..6c05063f 100644 --- a/core/chat/paste.go +++ b/core/chat/paste.go @@ -18,31 +18,33 @@ func init() { PASTE: {Name: "paste hash auto create@paste", Help: "粘贴板", Action: map[string]*ice.Action{ mdb.CREATE: {Name: "create type=text name=hi data:textarea=hi", Help: "添加", Hand: func(m *ice.Message, arg ...string) { _trans(arg, map[string]string{"data": "text"}) - m.Conf(m.Prefix(PASTE), kit.Keys(m.Option(ice.MSG_DOMAIN), kit.MDB_META, kit.MDB_SHORT), kit.MDB_TEXT) - m.Cmdy(mdb.INSERT, m.Prefix(PASTE), "", mdb.HASH, arg) + m.Cmdy(mdb.INSERT, PASTE, "", mdb.HASH, arg) + }}, + mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.MODIFY, PASTE, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH), arg) }}, mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.DELETE, m.Prefix(PASTE), "", mdb.HASH, kit.MDB_TEXT, m.Option(kit.MDB_TEXT)) + m.Cmdy(mdb.DELETE, PASTE, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) }}, mdb.EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.EXPORT, m.Prefix(PASTE), "", mdb.HASH) + m.Cmdy(mdb.EXPORT, PASTE, "", mdb.HASH) }}, mdb.IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.IMPORT, m.Prefix(PASTE), "", mdb.HASH) + m.Cmdy(mdb.IMPORT, PASTE, "", mdb.HASH) }}, mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.INPUTS, m.Prefix(PASTE), "", mdb.HASH, arg) + m.Cmdy(mdb.INPUTS, PASTE, "", mdb.HASH, arg) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) > 0 { - text := m.Cmd(mdb.SELECT, m.Prefix(PASTE), "", mdb.HASH, kit.MDB_HASH, arg[0]).Append(kit.MDB_TEXT) - m.Cmdy(wiki.SPARK, "inner", text) + text := m.Cmd(mdb.SELECT, PASTE, "", mdb.HASH, kit.MDB_HASH, arg[0]).Append(kit.MDB_TEXT) m.Cmdy(wiki.IMAGE, "qrcode", text) + m.Cmdy(wiki.SPARK, "inner", text) m.Render("") return } - m.Cmdy(mdb.SELECT, m.Prefix(PASTE), "", mdb.HASH) + m.Cmdy(mdb.SELECT, PASTE, "", mdb.HASH) m.SortTimeR(kit.MDB_TIME) m.PushAction(mdb.REMOVE) }}, diff --git a/core/chat/scan.go b/core/chat/scan.go index a6a586fd..adf664e3 100644 --- a/core/chat/scan.go +++ b/core/chat/scan.go @@ -17,31 +17,30 @@ func init() { Commands: map[string]*ice.Command{ SCAN: {Name: "scan hash auto create@scan", Help: "扫码", Action: map[string]*ice.Action{ mdb.CREATE: {Name: "create type=text name=hi text:textarea=hi", Help: "添加", Hand: func(m *ice.Message, arg ...string) { - m.Conf(m.Prefix(SCAN), kit.Keys(m.Option(ice.MSG_DOMAIN), kit.MDB_META, kit.MDB_SHORT), kit.MDB_TEXT) - m.Cmdy(mdb.INSERT, m.Prefix(SCAN), "", mdb.HASH, arg) + m.Cmdy(mdb.INSERT, SCAN, "", mdb.HASH, arg) }}, mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.DELETE, m.Prefix(SCAN), "", mdb.HASH, kit.MDB_TEXT, m.Option(kit.MDB_TEXT)) + m.Cmdy(mdb.DELETE, SCAN, "", mdb.HASH, kit.MDB_HASH, m.Option(kit.MDB_HASH)) }}, mdb.EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.EXPORT, m.Prefix(SCAN), "", mdb.HASH) + m.Cmdy(mdb.EXPORT, SCAN, "", mdb.HASH) }}, mdb.IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.IMPORT, m.Prefix(SCAN), "", mdb.HASH) + m.Cmdy(mdb.IMPORT, SCAN, "", mdb.HASH) }}, mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.INPUTS, m.Prefix(SCAN), "", mdb.HASH, arg) + m.Cmdy(mdb.INPUTS, SCAN, "", mdb.HASH, arg) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) > 0 { - text := m.Cmd(mdb.SELECT, m.Prefix(SCAN), "", mdb.HASH, kit.MDB_HASH, arg[0]).Append(kit.MDB_TEXT) - m.Cmdy(wiki.SPARK, "inner", text) + text := m.Cmd(mdb.SELECT, SCAN, "", mdb.HASH, kit.MDB_HASH, arg[0]).Append(kit.MDB_TEXT) m.Cmdy(wiki.IMAGE, "qrcode", text) + m.Cmdy(wiki.SPARK, "inner", text) m.Render("") return } - m.Cmdy(mdb.SELECT, m.Prefix(SCAN), "", mdb.HASH) + m.Cmdy(mdb.SELECT, SCAN, "", mdb.HASH) m.SortTimeR(kit.MDB_TIME) m.PushAction(mdb.REMOVE) }}, diff --git a/core/code/autogen.go b/core/code/autogen.go index 745a3d70..5c829783 100644 --- a/core/code/autogen.go +++ b/core/code/autogen.go @@ -1,15 +1,75 @@ package code import ( - "path" - "strings" - ice "github.com/shylinux/icebergs" "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/nfs" kit "github.com/shylinux/toolkits" + + "path" + "strings" ) +func _autogen_script(m *ice.Message, p string) { + // if b, e := kit.Render(m.Conf(AUTOGEN, "meta.shy"), m); m.Assert(e) { + if b, e := kit.Render(` +chapter {{.Option "name"}} +field {{.Option "name"}} web.code.{{.Option "name"}}.{{.Option "name"}} +`, m); m.Assert(e) { + m.Cmd(nfs.SAVE, p, string(b)) + } +} +func _autogen_source(m *ice.Message, name string) { + m.Cmd("nfs.file", "append", "src/main.shy", "\n", `source `+name+"/"+name+".shy", "\n") +} +func _autogen_index(m *ice.Message, p string, from string, ctx string) { + list := []string{} + + up, low := "", "" + key := strings.ToUpper(ctx) + m.Option(nfs.CAT_CB, func(line string, index int) { + if strings.HasPrefix(line, "package") { + line = "package " + ctx + } + if up == "" && strings.HasPrefix(line, "const") { + if ls := kit.Split(line); len(ls) > 3 { + up, low = ls[1], ls[3] + } + } + if up != "" { + line = strings.ReplaceAll(line, up, key) + line = strings.ReplaceAll(line, low, ctx) + } + + list = append(list, line) + }) + + m.Cmd(nfs.CAT, from) + m.Cmdy(nfs.SAVE, p, strings.Join(list, "\n")) +} +func _autogen_main(m *ice.Message, file string, mod string, ctx string) { + list := []string{} + m.Option(nfs.CAT_CB, func(line string, index int) { + list = append(list, line) + if strings.HasPrefix(line, "import (") { + list = append(list, ` _ "`+mod+"/src/"+ctx+`"`, "") + } + }) + m.Cmd(nfs.CAT, file) + + m.Cmd(nfs.SAVE, file, strings.Join(list, "\n")) +} +func _autogen_mod(m *ice.Message, file string) (mod string) { + m.Option(nfs.CAT_CB, func(line string, index int) { + if strings.HasPrefix(line, "module") { + mod = strings.Split(line, " ")[1] + m.Info("module", mod) + } + }) + m.Cmd(nfs.CAT, "go.mod") + return +} + const AUTOGEN = "autogen" func init() { @@ -21,81 +81,36 @@ func init() { }, Commands: map[string]*ice.Command{ AUTOGEN: {Name: "autogen path auto create", Help: "生成", Action: map[string]*ice.Action{ - mdb.CREATE: {Name: "create name=hi@key from=usr/icebergs/misc/zsh/zsh.go@key", Help: "创建", Hand: func(m *ice.Message, arg ...string) { + mdb.CREATE: {Name: "create main=src/main.go@key name=hi@key from=usr/icebergs/misc/zsh/zsh.go@key", Help: "创建", Hand: func(m *ice.Message, arg ...string) { if p := path.Join("src", m.Option("name"), m.Option("name")+".shy"); !kit.FileExists(p) { - m.Cmd(nfs.SAVE, p, `chapter "`+m.Option("name")+`"`, "\n", `field "`+m.Option("name")+`" web.code.`+m.Option("name")+"."+m.Option("name")) - m.Cmd("nfs.file", "append", "src/main.shy", "\n", `source `+m.Option("name")+"/"+m.Option("name")+".shy", "\n") + _autogen_script(m, p) + _autogen_source(m, m.Option("name")) } - p := path.Join("src", m.Option("name"), m.Option("name")+".go") - if kit.FileExists(p) { - m.Echo(p) - return + if p := path.Join("src", m.Option("name"), m.Option("name")+".go"); !kit.FileExists(p) { + _autogen_index(m, p, m.Option("from"), m.Option("name")) + _autogen_main(m, m.Option("main"), _autogen_mod(m, "go.mod"), m.Option("name")) } - - // module file - list := []string{} - up, low := "", "" - name := m.Option("name") - key := strings.ToUpper(m.Option("name")) - m.Option(nfs.CAT_CB, func(line string, index int) { - if strings.HasPrefix(line, "package") { - line = "package " + m.Option("name") - } - if up == "" && strings.HasPrefix(line, "const") { - if ls := kit.Split(line); len(ls) > 3 { - up, low = ls[1], ls[3] - } - } - if up != "" { - line = strings.ReplaceAll(line, up, key) - line = strings.ReplaceAll(line, low, name) - } - - list = append(list, line) - }) - m.Cmd(nfs.CAT, m.Option("from")) - m.Cmdy(nfs.SAVE, p, strings.Join(list, "\n")) - - // go.mod - mod := "" - m.Option(nfs.CAT_CB, func(line string, index int) { - if strings.HasPrefix(line, "module") { - mod = strings.Split(line, " ")[1] - m.Info("module", mod) - } - }) - m.Cmd(nfs.CAT, "go.mod") - - // src/main.go - list = []string{} - m.Option(nfs.CAT_CB, func(line string, index int) { - list = append(list, line) - if strings.HasPrefix(line, "import (") { - list = append(list, ` _ "`+mod+"/src/"+m.Option("name")+`"`, "") - } - }) - m.Cmd(nfs.CAT, "src/main.go") - m.Cmd(nfs.SAVE, "src/main.go", strings.Join(list, "\n")) - - m.Cmd(mdb.INSERT, m.Prefix(AUTOGEN), "", mdb.LIST, arg) }}, mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) { switch arg[0] { + case "main": + m.Cmdy(nfs.DIR, "src") + m.Appendv(ice.MSG_APPEND, "path", "size", "time") + m.Sort(kit.MDB_PATH) case "from": m.Option(nfs.DIR_DEEP, true) m.Cmdy(nfs.DIR, "usr/icebergs") - m.Sort("path") + m.Appendv(ice.MSG_APPEND, "path", "size", "time") + m.Sort(kit.MDB_PATH) } }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if len(arg) > 0 && !strings.HasSuffix(arg[0], "/") { - m.Option(nfs.DIR_ROOT, "src") - m.Cmdy(nfs.CAT, kit.Select("./", arg, 0)) - return + if m.Option(nfs.DIR_ROOT, "src"); len(arg) == 0 || strings.HasSuffix(arg[0], "/") { + m.Cmdy(nfs.DIR, kit.Select("./", arg, 0)) + } else { + m.Cmdy(nfs.CAT, arg[0]) } - m.Option(nfs.DIR_ROOT, "src") - m.Cmdy(nfs.DIR, kit.Select("./", arg, 0)) }}, }, }, nil) diff --git a/core/code/code.go b/core/code/code.go index bb151c2f..450bb254 100644 --- a/core/code/code.go +++ b/core/code/code.go @@ -20,8 +20,8 @@ var Index = &ice.Context{Name: CODE, Help: "编程中心", func init() { web.Index.Register(Index, &web.Frame{}, - INSTALL, COMPILE, PUBLISH, UPGRADE, - INNER, VIMER, BENCH, PPROF, - C, SH, GO, SHY, JS, + INSTALL, AUTOGEN, COMPILE, PUBLISH, UPGRADE, + INNER, VIMER, FAVOR, BENCH, PPROF, + C, SH, SHY, GO, JS, ) } diff --git a/core/code/code.shy b/core/code/code.shy index 42eb574e..caea0695 100644 --- a/core/code/code.shy +++ b/core/code/code.shy @@ -1,6 +1,22 @@ chapter "code" -field "安装" web.code.install -field "编译" web.code.compile -field "发布" web.code.publish -field "升级" web.code.upgrade -field "编程" web.code.autogen + +# field "安装" web.code.install +# field "生成" web.code.autogen +# field "编译" web.code.compile +# field "发布" web.code.publish +# field "升级" web.code.upgrade + +field "查看" web.code.inner +return + +field "编辑" web.code.vimer +field "收藏" web.code.favor +field "测试" web.code.bench +field "优化" web.code.pprof +return + +field "查看" web.code.c +field "编辑" web.code.sh +field "测试" web.code.shy +field "收藏" web.code.go +field "优化" web.code.js diff --git a/core/code/compile.go b/core/code/compile.go index 10a0ef75..e8524219 100644 --- a/core/code/compile.go +++ b/core/code/compile.go @@ -1,16 +1,16 @@ package code import ( - "fmt" - "strings" - ice "github.com/shylinux/icebergs" "github.com/shylinux/icebergs/base/cli" + "github.com/shylinux/icebergs/base/mdb" "github.com/shylinux/icebergs/base/nfs" kit "github.com/shylinux/toolkits" + "fmt" "os" "path" + "strings" ) const COMPILE = "compile" @@ -19,18 +19,21 @@ func init() { Index.Merge(&ice.Context{ Configs: map[string]*ice.Config{ COMPILE: {Name: COMPILE, Help: "编译", Value: kit.Data( - kit.MDB_PATH, "usr/publish", "env", kit.Dict( - "PATH", os.Getenv("PATH"), - "HOME", os.Getenv("HOME"), - "GOCACHE", os.Getenv("GOCACHE"), - "GOPROXY", "https://goproxy.cn,direct", - "GOPRIVATE", "github.com", - "CGO_ENABLED", "0", + kit.MDB_PATH, "usr/publish", kit.SSH_ENV, kit.Dict( + "CGO_ENABLED", "0", "GOCACHE", os.Getenv("GOCACHE"), + "HOME", os.Getenv("HOME"), "PATH", os.Getenv("PATH"), + "GOPROXY", "https://goproxy.cn,direct", "GOPRIVATE", "github.com", ), "go", []interface{}{"go", "build"}, )}, }, Commands: map[string]*ice.Command{ - COMPILE: {Name: "compile os=linux,darwin,windows arch=amd64,386,arm src=src/main.go 执行:button", Help: "编译", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + COMPILE: {Name: "compile os=linux,darwin,windows arch=amd64,386,arm src=src/main.go@key 执行:button", Help: "编译", Action: map[string]*ice.Action{ + mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(nfs.DIR, "src") + m.Appendv(ice.MSG_APPEND, "path", "size", "time") + m.Sort(kit.MDB_PATH) + }}, + }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) == 0 { // 目录列表 m.Cmdy(nfs.DIR, m.Conf(COMPILE, kit.META_PATH), "time size path") @@ -52,7 +55,7 @@ func init() { } // 编译目标 - file := path.Join(m.Conf(cmd, "meta.path"), kit.Keys(kit.Select("ice", path.Base(strings.TrimSuffix(main, ".go")), main != "src/main.go"), goos, arch)) + file := path.Join(m.Conf(cmd, kit.META_PATH), kit.Keys(kit.Select("ice", path.Base(strings.TrimSuffix(main, ".go")), main != "src/main.go"), goos, arch)) args := []string{"-ldflags"} list := []string{ fmt.Sprintf(`-X main.Time="%s"`, m.Time()), diff --git a/core/code/favor.go b/core/code/favor.go index 68d6a071..bf67c356 100644 --- a/core/code/favor.go +++ b/core/code/favor.go @@ -2,75 +2,63 @@ package code import ( ice "github.com/shylinux/icebergs" - "github.com/shylinux/icebergs/base/ctx" "github.com/shylinux/icebergs/base/mdb" kit "github.com/shylinux/toolkits" ) +func _sub_key(m *ice.Message, topic string) string { + return kit.Keys(kit.MDB_HASH, kit.Hashs(topic)) +} + const FAVOR = "favor" func init() { Index.Merge(&ice.Context{ Configs: map[string]*ice.Config{ - FAVOR: {Name: FAVOR, Help: "收藏夹", Value: kit.Data( - kit.MDB_SHORT, kit.MDB_TOPIC, kit.MDB_FIELD, "time,id,type,name,text,path,file,line", - )}, + FAVOR: {Name: FAVOR, Help: "收藏夹", Value: kit.Data(kit.MDB_SHORT, kit.MDB_TOPIC)}, }, Commands: map[string]*ice.Command{ - FAVOR: {Name: "favor topic=auto id=auto auto 创建 导出 导入", Help: "收藏夹", Action: map[string]*ice.Action{ + FAVOR: {Name: "favor topic id auto create export import", Help: "收藏夹", Action: map[string]*ice.Action{ mdb.CREATE: {Name: "create topic", Help: "创建", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.INSERT, m.Prefix(FAVOR), "", mdb.HASH, arg) + m.Cmdy(mdb.INSERT, FAVOR, "", mdb.HASH, arg) }}, - mdb.INSERT: {Name: "insert topic=数据结构 name=hi text=hello", Help: "添加", Hand: func(m *ice.Message, arg ...string) { - m.Richs(m.Prefix(FAVOR), "", m.Option(kit.MDB_TOPIC), func(key string, value map[string]interface{}) { - m.Cmdy(mdb.INSERT, m.Prefix(FAVOR), kit.Keys(kit.MDB_HASH, key), mdb.LIST, arg) - }) + mdb.INSERT: {Name: "insert topic=数据结构 type=go name=hi text=hello path file line", Help: "添加", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.INSERT, FAVOR, _sub_key(m, m.Option(kit.MDB_TOPIC)), mdb.LIST, arg[2:]) }}, mdb.MODIFY: {Name: "modify", Help: "编辑", Hand: func(m *ice.Message, arg ...string) { - m.Richs(m.Prefix(FAVOR), "", m.Option(kit.MDB_TOPIC), func(key string, value map[string]interface{}) { - m.Cmdy(mdb.MODIFY, m.Prefix(FAVOR), kit.Keys(kit.MDB_HASH, key), mdb.LIST, kit.MDB_ID, m.Option(kit.MDB_ID), arg) - }) + m.Cmdy(mdb.MODIFY, FAVOR, _sub_key(m, m.Option(kit.MDB_TOPIC)), mdb.LIST, kit.MDB_ID, m.Option(kit.MDB_ID), arg) }}, mdb.REMOVE: {Name: "remove", Help: "删除", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.DELETE, m.Prefix(FAVOR), "", mdb.HASH, kit.MDB_TOPIC, m.Option(kit.MDB_TOPIC)) + m.Cmdy(mdb.DELETE, FAVOR, "", mdb.HASH, kit.MDB_TOPIC, m.Option(kit.MDB_TOPIC)) }}, mdb.EXPORT: {Name: "export", Help: "导出", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.EXPORT, m.Prefix(FAVOR), "", mdb.HASH) + m.Cmdy(mdb.EXPORT, FAVOR, "", mdb.HASH) }}, mdb.IMPORT: {Name: "import", Help: "导入", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.IMPORT, m.Prefix(FAVOR), "", mdb.HASH) + m.Cmdy(mdb.IMPORT, FAVOR, "", mdb.HASH) }}, mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) { switch arg[0] { case kit.MDB_TOPIC: - m.Option(mdb.FIELDS, "topic,count,time") - m.Cmdy(mdb.SELECT, m.Prefix(FAVOR), "", mdb.HASH) + m.Cmdy(mdb.INPUTS, FAVOR, "", mdb.HASH, arg) + default: + m.Cmdy(mdb.INPUTS, FAVOR, _sub_key(m, m.Option(kit.MDB_TOPIC)), mdb.LIST, arg) } }}, INNER: {Name: "inner", Help: "inner", Hand: func(m *ice.Message, arg ...string) { - m.Option("_process", "_field") - m.Option("_prefix", "_inner") - m.Cmdy(ctx.COMMAND, INNER) - m.Push("args", kit.Format([]string{m.Option(kit.MDB_PATH), m.Option(kit.MDB_FILE), m.Option(kit.MDB_LINE)})) + if len(arg) > 0 && arg[0] == mdb.RENDER { + m.Cmdy(INNER, arg[1:]) + return + } + + m.PushPlugin(INNER, INNER, mdb.RENDER) + m.Push(kit.SSH_ARG, kit.Format([]string{m.Option(kit.MDB_PATH), m.Option(kit.MDB_FILE), m.Option(kit.MDB_LINE)})) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - if len(arg) > 0 && arg[0] == "_inner" { - m.Cmdy(INNER, arg[1:]) - return - } - - if len(arg) > 0 { - m.Option(mdb.FIELDS, kit.Select(m.Conf(m.Prefix(FAVOR), kit.META_FIELD), mdb.DETAIL, len(arg) > 1)) - m.Richs(m.Prefix(FAVOR), "", arg[0], func(key string, value map[string]interface{}) { - m.Cmdy(mdb.SELECT, m.Prefix(FAVOR), kit.Keys(kit.MDB_HASH, key), mdb.LIST, kit.MDB_ID, arg[1:]) - }) - m.PushAction("inner") - return - } - m.Option(mdb.FIELDS, "time,count,topic") - m.Cmdy(mdb.SELECT, m.Prefix(FAVOR), "", mdb.HASH) - m.PushAction("删除") + m.Option(mdb.FIELDS, kit.Select("time,count,topic", kit.Select("time,id,type,name,text,path,file,line", mdb.DETAIL, len(arg) > 1)), len(arg) > 0) + m.Cmdy(mdb.SELECT, FAVOR, "", mdb.ZONE, arg) + m.PushAction(kit.Select(mdb.REMOVE, INNER, len(arg) > 0)) }}, }, }, nil) diff --git a/core/code/inner.go b/core/code/inner.go index 6f49f7ad..c9b01252 100644 --- a/core/code/inner.go +++ b/core/code/inner.go @@ -22,10 +22,10 @@ func _inner_list(m *ice.Message, ext, file, dir string, arg ...string) { } if m.Warn(!m.Right(dir, file), ice.ErrNotAuth, path.Join(dir, file)) { - return + return // 没有权限 } if m.Cmdy(mdb.RENDER, ext, file, dir, arg); m.Result() != "" { - return + return // 解析成功 } if m.Conf(INNER, kit.Keys("meta.source", ext)) == "true" { @@ -37,10 +37,10 @@ func _inner_list(m *ice.Message, ext, file, dir string, arg ...string) { } func _inner_show(m *ice.Message, ext, file, dir string, arg ...string) { if m.Warn(!m.Right(dir, file), ice.ErrNotAuth, path.Join(dir, file)) { - return + return // 没有权限 } if m.Cmdy(mdb.ENGINE, ext, file, dir, arg); m.Result() != "" { - return + return // 执行成功 } if ls := kit.Simple(m.Confv(INNER, kit.Keys("meta.show", ext))); len(ls) > 0 { @@ -53,8 +53,9 @@ const INNER = "inner" func init() { Index.Merge(&ice.Context{ Commands: map[string]*ice.Command{ - INNER: {Name: "inner path=src/ file=main.go line=1 auto 项目", Help: "阅读器", Meta: kit.Dict( + INNER: {Name: "inner path=src/ file=main.go line=1 auto project search", Help: "阅读器", Meta: kit.Dict( "display", "/plugin/local/code/inner.js", "style", "editor", + "trans", kit.Dict("project", "项目"), ), Action: map[string]*ice.Action{ mdb.PLUGIN: {Name: "plugin", Help: "插件", Hand: func(m *ice.Message, arg ...string) { if m.Cmdy(mdb.PLUGIN, arg); m.Result() == "" { @@ -66,18 +67,18 @@ func init() { mdb.RENDER: {Name: "render", Help: "渲染", Hand: func(m *ice.Message, arg ...string) { _inner_list(m, arg[0], arg[1], arg[2], arg[3:]...) }}, - mdb.SEARCH: {Name: "search", Help: "搜索", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(mdb.SEARCH, arg) - }}, mdb.ENGINE: {Name: "engine", Help: "引擎", Hand: func(m *ice.Message, arg ...string) { _inner_show(m, arg[0], arg[1], arg[2], arg[3:]...) }}, + mdb.SEARCH: {Name: "search", Help: "搜索", Hand: func(m *ice.Message, arg ...string) { + m.Cmdy(mdb.SEARCH, arg) + }}, mdb.INPUTS: {Name: "inputs", Help: "补全", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(m.Prefix(FAVOR), mdb.INPUTS, arg) + m.Cmdy(FAVOR, mdb.INPUTS, arg) }}, FAVOR: {Name: "favor", Help: "收藏", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(m.Prefix(FAVOR), mdb.INSERT, arg) + m.Cmdy(FAVOR, mdb.INSERT, arg) }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { if len(arg) < 2 { @@ -90,8 +91,7 @@ func init() { Configs: map[string]*ice.Config{ INNER: {Name: "inner", Help: "阅读器", Value: kit.Data( "source", kit.Dict( - "license", "true", - "makefile", "true", + "license", "true", "makefile", "true", "shy", "true", "py", "true", "csv", "true", "json", "true", "css", "true", "html", "true", diff --git a/core/code/install.go b/core/code/install.go index 009f7d55..de4822d6 100644 --- a/core/code/install.go +++ b/core/code/install.go @@ -29,14 +29,14 @@ func init() { Commands: map[string]*ice.Command{ INSTALL: {Name: "install name port path auto", Help: "安装", Meta: kit.Dict(), Action: map[string]*ice.Action{ web.DOWNLOAD: {Name: "download link", Help: "下载", Hand: func(m *ice.Message, arg ...string) { - name := path.Base(m.Option(kit.MDB_LINK)) + link := m.Option(kit.MDB_LINK) + name := path.Base(link) p := path.Join(m.Conf(INSTALL, kit.META_PATH), name) m.Option(ice.MSG_PROCESS, "_progress") m.Option(mdb.FIELDS, m.Conf(INSTALL, kit.META_FIELD)) if m.Cmd(mdb.SELECT, INSTALL, "", mdb.HASH, kit.MDB_NAME, name).Table(func(index int, value map[string]string, head []string) { if _, e := os.Stat(p); e == nil { - m.Set(kit.MDB_LINK) m.Push("", value, kit.Split(m.Option(mdb.FIELDS))) } }); len(m.Appendv(kit.MDB_NAME)) > 0 { @@ -47,9 +47,9 @@ func init() { m.Cmd(nfs.SAVE, p, "") // 进度 - m.Cmd(mdb.INSERT, INSTALL, "", mdb.HASH, kit.MDB_NAME, name, kit.MDB_LINK, m.Option(kit.MDB_LINK)) + m.Cmd(mdb.INSERT, INSTALL, "", mdb.HASH, kit.MDB_NAME, name, kit.MDB_LINK, link) m.Richs(INSTALL, "", name, func(key string, value map[string]interface{}) { - value = value[kit.MDB_META].(map[string]interface{}) + value = kit.GetMeta(value) m.Optionv(web.DOWNLOAD_CB, func(size int, total int) { s := size * 100 / total if s != kit.Int(value[kit.SSH_STEP]) && s%10 == 0 { @@ -62,26 +62,22 @@ func init() { // 下载 m.Go(func() { m.Option(cli.CMD_DIR, m.Conf(INSTALL, kit.META_PATH)) - msg := m.Cmd(web.SPIDE, web.SPIDE_DEV, web.SPIDE_CACHE, web.SPIDE_GET, m.Option(kit.MDB_LINK)) + msg := m.Cmd(web.SPIDE, web.SPIDE_DEV, web.SPIDE_CACHE, web.SPIDE_GET, link) m.Cmdy(nfs.LINK, p, msg.Append(kit.MDB_FILE)) m.Cmd(cli.SYSTEM, "tar", "xvf", name) }) }}, gdb.BUILD: {Name: "build link", Help: "构建", Hand: func(m *ice.Message, arg ...string) { - m.Option("cache.action", "build") m.Option(ice.MSG_PROCESS, "_follow") - if m.Option("cache.hash") != "" { + if m.Option("cache.action", "build"); m.Option("cache.hash") != "" { m.Cmdy(cli.OUTPUT, m.Option("cache.hash")) m.Sort(kit.MDB_ID).Table(func(index int, value map[string]string, head []string) { m.Option("cache.begin", value[kit.MDB_ID]) m.Echo(value[kit.SSH_RES]) }) - if len(m.Resultv()) > 0 { - return - } - if m.Conf(cli.OUTPUT, kit.Keys(kit.MDB_HASH, m.Option("cache.hash"), kit.MDB_META, kit.MDB_STATUS)) == gdb.STOP { + if len(m.Resultv()) == 0 && m.Conf(cli.OUTPUT, kit.Keys(kit.MDB_HASH, m.Option("cache.hash"), kit.MDB_META, kit.MDB_STATUS)) == gdb.STOP { m.Echo(gdb.STOP) } return @@ -144,7 +140,7 @@ func init() { if len(arg) == 1 { // 服务列表 - arg = kit.Split(arg[0], "-.") + arg = kit.Split(path.Base(arg[0]), "-.") m.Option(mdb.FIELDS, "time,port,status,pid,cmd,dir") m.Cmd(mdb.SELECT, cli.DAEMON, "", mdb.HASH).Table(func(index int, value map[string]string, head []string) { if strings.Contains(value["cmd"], "bin/"+arg[0]) { diff --git a/core/code/publish.go b/core/code/publish.go index c2783868..3d1018eb 100644 --- a/core/code/publish.go +++ b/core/code/publish.go @@ -9,7 +9,6 @@ import ( "fmt" "os" "path" - "runtime" "strings" ) @@ -42,7 +41,7 @@ func init() { )}, }, Commands: map[string]*ice.Command{ - PUBLISH: {Name: "publish path auto can ice ish", Help: "发布", Action: map[string]*ice.Action{ + PUBLISH: {Name: "publish path auto ish ice can", Help: "发布", Action: map[string]*ice.Action{ "contexts": {Name: "contexts", Help: "环境", Hand: func(m *ice.Message, arg ...string) { u := kit.ParseURL(m.Option(ice.MSG_USERWEB)) m.Option("httphost", fmt.Sprintf("%s://%s:%s", u.Scheme, strings.Split(u.Host, ":")[0], kit.Select(kit.Select("80", "443", u.Scheme == "https"), strings.Split(u.Host, ":"), 1))) @@ -52,28 +51,48 @@ func init() { m.Option("userhost", fmt.Sprintf("%s@%s", m.Option(ice.MSG_USERNAME), strings.Split(u.Host, ":")[0])) m.Option("hostpath", kit.Path("./.ish/pluged")) - if buf, err := kit.Render(m.Conf(PUBLISH, kit.Keys("meta.contexts", kit.Select("base", arg, 0))), m); m.Assert(err) { - m.Cmdy("web.wiki.spark", "shell", string(buf)) + if len(arg) == 0 { + arg = append(arg, "base") + } + for _, k := range arg { + if buf, err := kit.Render(m.Conf(PUBLISH, kit.Keys("meta.contexts", k)), m); m.Assert(err) { + m.Cmdy("web.wiki.spark", "shell", string(buf)) + } } }}, "ish": {Name: "ish", Help: "神农架", Hand: func(m *ice.Message, arg ...string) { + m.Option(nfs.DIR_DEEP, true) m.Option(nfs.DIR_REG, ".*\\.(sh|vim|conf)") - m.Cmdy(nfs.DIR, m.Conf(PUBLISH, kit.META_PATH), "time size line path link") + m.Option(nfs.DIR_ROOT, m.Conf(PUBLISH, kit.META_PATH)) + m.Cmdy(nfs.DIR, "./", "time size line path link") + m.Cmdy(PUBLISH, "contexts", "tmux") }}, "ice": {Name: "ice", Help: "冰山架", Hand: func(m *ice.Message, arg ...string) { - _publish_file(m, "bin/ice.bin", fmt.Sprintf("ice.%s.%s", runtime.GOOS, runtime.GOARCH)) - _publish_file(m, "bin/ice.sh") - m.Option(nfs.DIR_REG, "ice.*") - m.Cmdy(nfs.DIR, m.Conf(PUBLISH, kit.META_PATH), "time size path link") + p := m.Option(cli.CMD_DIR, m.Conf(PUBLISH, kit.META_PATH)) + ls := strings.Split(m.Cmdx(cli.SYSTEM, "bash", "-c", "ls |xargs file |grep executable"), "\n") + for _, ls := range ls { + if file := strings.TrimSpace(strings.Split(ls, ":")[0]); file != "" { + if s, e := os.Stat(path.Join(p, file)); m.Assert(e) { + m.Push(kit.MDB_TIME, s.ModTime()) + m.Push(kit.MDB_SIZE, kit.FmtSize(s.Size())) + m.Push(kit.MDB_FILE, file) + m.PushDownload(file, path.Join(p, file)) + } + } + } + m.SortTimeR(kit.MDB_TIME) + m.Cmdy(PUBLISH, "contexts", "base") }}, "can": {Name: "can", Help: "火山架", Hand: func(m *ice.Message, arg ...string) { m.Option(nfs.DIR_DEEP, true) m.Option(nfs.DIR_REG, ".*\\.(js|css|html)") - m.Cmdy(nfs.DIR, m.Conf(PUBLISH, kit.META_PATH), "time size line path link") + m.Option(nfs.DIR_ROOT, m.Conf(PUBLISH, kit.META_PATH)) + m.Cmdy(nfs.DIR, "./", "time size line path link") + m.Cmdy(PUBLISH, "contexts", "miss") }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { - m.Option(nfs.DIR_ROOT, m.Conf(cmd, kit.META_PATH)) - m.Cmdy(nfs.DIR, kit.Select("", arg, 0), "time size path") + m.Option(nfs.DIR_ROOT, m.Conf(PUBLISH, kit.META_PATH)) + m.Cmdy(nfs.DIR, kit.Select("", arg, 0), "time size path link") }}, }, }, nil) diff --git a/core/code/upgrade.go b/core/code/upgrade.go index 2b6daaf3..605be0b8 100644 --- a/core/code/upgrade.go +++ b/core/code/upgrade.go @@ -22,7 +22,7 @@ func init() { ))}, }, Commands: map[string]*ice.Command{ - UPGRADE: {Name: "upgrade item", Help: "升级", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { + UPGRADE: {Name: "upgrade item:select=system 执行:button", Help: "升级", Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { exit := false m.Grows(cmd, kit.Keys(kit.MDB_HASH, kit.Select("system", arg, 0)), "", "", func(index int, value map[string]interface{}) { if value[kit.MDB_FILE] == "ice.bin" { diff --git a/core/code/vimer.go b/core/code/vimer.go index 6af6d3ec..5c4f74e5 100644 --- a/core/code/vimer.go +++ b/core/code/vimer.go @@ -2,6 +2,7 @@ package code import ( ice "github.com/shylinux/icebergs" + "github.com/shylinux/icebergs/base/ctx" "github.com/shylinux/icebergs/base/nfs" "github.com/shylinux/icebergs/base/web" kit "github.com/shylinux/toolkits" @@ -9,13 +10,15 @@ import ( "path" ) -func _vimer_save(m *ice.Message, ext, file, dir string, text string) { - if f, p, e := kit.Create(path.Join(dir, file)); e == nil { - defer f.Close() - if n, e := f.WriteString(text); m.Assert(e) { - m.Log_EXPORT("file", path.Join(dir, file), "size", n) - } - m.Echo(p) +func _vimer_path(m *ice.Message, arg ...string) string { + return path.Join(m.Option(ice.MSG_LOCAL), path.Join(arg...)) +} +func _vimer_upload(m *ice.Message, dir string) { + up := kit.Simple(m.Optionv(ice.MSG_UPLOAD)) + if p := _vimer_path(m, dir, up[1]); m.Option(ice.MSG_USERPOD) == "" { + m.Cmdy(web.CACHE, web.WATCH, up[0], p) + } else { + m.Cmdy(web.SPIDE, web.SPIDE_DEV, web.SPIDE_SAVE, p, web.SPIDE_GET, kit.MergeURL2(m.Option(ice.MSG_USERWEB), "/share/cache/"+up[0])) } } @@ -25,19 +28,20 @@ func init() { Index.Merge(&ice.Context{ Configs: map[string]*ice.Config{}, Commands: map[string]*ice.Command{ - VIMER: {Name: "vimer path=usr/demo file=hi.sh line=1 刷新:button=auto 保存:button 运行:button 项目:button", Help: "编辑器", Meta: kit.Dict( + VIMER: {Name: "vimer path=usr/demo file=hi.sh line=1 刷新:button=auto save project", Help: "编辑器", Meta: kit.Dict( "display", "/plugin/local/code/vimer.js", "style", "editor", + "trans", kit.Dict("project", "项目"), ), Action: map[string]*ice.Action{ - web.UPLOAD: {Name: "upload path name", Help: "上传", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(web.CACHE, web.UPLOAD) - m.Cmdy(web.CACHE, web.WATCH, m.Option(web.DATA), path.Join(m.Option("path"), m.Option("name"))) + web.UPLOAD: {Name: "upload", Help: "上传", Hand: func(m *ice.Message, arg ...string) { + _vimer_upload(m, m.Option(kit.MDB_PATH)) }}, nfs.SAVE: {Name: "save type file path", Help: "保存", Hand: func(m *ice.Message, arg ...string) { - _vimer_save(m, arg[0], arg[1], arg[2], m.Option("content")) + m.Cmdy(nfs.SAVE, path.Join(m.Option(kit.MDB_PATH), m.Option(kit.MDB_FILE))) }}, - - "cmd": {Name: "cmd type file path", Help: "命令", Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(arg) + ctx.COMMAND: {Name: "command", Help: "命令", Hand: func(m *ice.Message, arg ...string) { + if !m.Warn(!m.Right(arg)) { + m.Cmdy(arg) + } }}, }, Hand: func(m *ice.Message, c *ice.Context, cmd string, arg ...string) { m.Cmdy(INNER, arg) diff --git a/misc.go b/misc.go index 9da6a344..467ff819 100644 --- a/misc.go +++ b/misc.go @@ -95,6 +95,17 @@ func (m *Message) PushRender(key, view, name string, arg ...string) *Message { func (m *Message) PushButton(arg ...string) { m.PushRender("action", "button", strings.Join(arg, ",")) } +func (m *Message) PushAnchor(name string, arg ...string) { + m.PushRender("link", "a", name, arg...) +} +func (m *Message) PushDownload(name string, arg ...string) { + if len(arg) == 0 { + name = kit.MergeURL2(m.Option(MSG_USERWEB), path.Join("/share/local", name), "pod", m.Option(MSG_USERPOD)) + } else { + arg[0] = kit.MergeURL2(m.Option(MSG_USERWEB), path.Join("/share/local", arg[0]), "pod", m.Option(MSG_USERPOD)) + } + m.PushRender("link", "download", name, arg...) +} func (m *Message) PushAction(list ...interface{}) { m.Table(func(index int, value map[string]string, head []string) { m.PushRender(kit.MDB_ACTION, kit.MDB_BUTTON, strings.Join(kit.Simple(list...), ","))