From 1102c28672a15b3309700a283a48e32add42cdce Mon Sep 17 00:00:00 2001 From: shy Date: Tue, 1 Jul 2025 18:51:04 +0800 Subject: [PATCH] add some --- base/aaa/user.go | 6 +++--- base/cli/runtime.go | 18 +++++++++--------- base/web/dream.go | 4 ++-- base/web/render.go | 5 ++++- base/web/route.go | 2 +- base/web/serve.go | 2 +- base/web/space.go | 8 ++++---- base/web/stats.go | 2 +- core/chat/grant.go | 2 +- core/chat/header.go | 12 +++++++----- core/chat/macos/desktop.css | 2 +- core/chat/macos/desktop.js | 2 +- core/code/autogen.go | 2 +- core/code/version.go | 8 ++++---- core/code/xterm.go | 2 +- info.go | 8 ++++---- misc/wx/agent.go | 3 +-- misc/wx/login.go | 2 +- 18 files changed, 47 insertions(+), 43 deletions(-) diff --git a/base/aaa/user.go b/base/aaa/user.go index 762d7b40..f54d6059 100644 --- a/base/aaa/user.go +++ b/base/aaa/user.go @@ -79,7 +79,7 @@ func UserInfo(m *ice.Message, name ice.Any, key, meta string) (value string) { func UserRole(m *ice.Message, username ice.Any) (role string) { if username == "" { return VOID - } else if role = VOID; username == ice.Info.Username { + } else if role = VOID; username == ice.Info.UserName { return ROOT } else { return UserInfo(m, username, USERROLE, ice.MSG_USERROLE) @@ -99,13 +99,13 @@ func UserEmail(m *ice.Message, username ice.Any) (nick string) { } func UserRoot(m *ice.Message, arg ...string) *ice.Message { userrole := kit.Select(TECH, arg, 0) - username := kit.Select(ice.Info.Username, arg, 1) + username := kit.Select(ice.Info.UserName, arg, 1) usernick := kit.Select(UserNick(m, username), arg, 2) language := kit.Select(UserLang(m, username), arg, 3) userzone := kit.Select(ice.OPS, arg, 4) email := kit.Select(UserEmail(m, username), arg, 5) if len(arg) > 0 { - kit.If(username != ROOT, func() { ice.Info.Username = username }) + kit.If(username != ROOT, func() { ice.Info.UserName = username }) m.Cmd(USER, mdb.CREATE, userrole, username, usernick, language, userzone, email) } return SessAuth(m, kit.Dict(USERROLE, userrole, USERNAME, username, USERNICK, usernick)) diff --git a/base/cli/runtime.go b/base/cli/runtime.go index 3ec53656..e1088a6c 100644 --- a/base/cli/runtime.go +++ b/base/cli/runtime.go @@ -37,15 +37,15 @@ func _runtime_init(m *ice.Message) { if name, e := os.Hostname(); e == nil && name != "" { m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME), name) } - ice.Info.Username = m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME)) - ice.Info.Hostname = m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME)) - ice.Info.Pathname = m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME)) - kit.HashSeed = append(kit.HashSeed, ice.Info.Username) - kit.HashSeed = append(kit.HashSeed, ice.Info.Hostname) - kit.HashSeed = append(kit.HashSeed, ice.Info.Pathname) + ice.Info.UserName = m.Conf(RUNTIME, kit.Keys(BOOT, USERNAME)) + ice.Info.HostName = m.Conf(RUNTIME, kit.Keys(BOOT, HOSTNAME)) + ice.Info.PathName = m.Conf(RUNTIME, kit.Keys(BOOT, PATHNAME)) + kit.HashSeed = append(kit.HashSeed, ice.Info.UserName) + kit.HashSeed = append(kit.HashSeed, ice.Info.HostName) + kit.HashSeed = append(kit.HashSeed, ice.Info.PathName) aaa.UserRoot(ice.Pulse, aaa.TECH, ice.Info.Make.Author, "", "", ice.DEV, ice.Info.Make.Email) aaa.UserRoot(ice.Pulse, aaa.TECH, ice.Info.Make.Username, "", "", ice.DEV, ice.Info.Make.Email) - aaa.UserRoot(ice.Pulse, aaa.ROOT, ice.Info.Username) + aaa.UserRoot(ice.Pulse, aaa.ROOT, ice.Info.UserName) aaa.UserRoot(ice.Pulse, aaa.ROOT, aaa.ROOT) ice.Info.Time = m.Time() m.Conf(RUNTIME, kit.Keys(BOOT, mdb.TIME), ice.Info.Time) @@ -193,9 +193,9 @@ func init() { HOSTINFO: {Hand: func(m *ice.Message, arg ...string) { _runtime_hostinfo(m) }}, HOSTNAME: {Hand: func(m *ice.Message, arg ...string) { if len(arg) > 0 { - ice.Info.Hostname = mdb.Conf(m, RUNTIME, kit.Keys(NODE, mdb.NAME), mdb.Conf(m, RUNTIME, kit.Keys(BOOT, HOSTNAME), arg[0])) + ice.Info.HostName = mdb.Conf(m, RUNTIME, kit.Keys(NODE, mdb.NAME), mdb.Conf(m, RUNTIME, kit.Keys(BOOT, HOSTNAME), arg[0])) } - m.Echo(ice.Info.Hostname) + m.Echo(ice.Info.HostName) }}, MAXPROCS: {Hand: func(m *ice.Message, arg ...string) { kit.If(len(arg) > 0, func() { runtime.GOMAXPROCS(kit.Int(mdb.Conf(m, RUNTIME, kit.Keys(HOST, MAXPROCS), arg[0]))) }) diff --git a/base/web/dream.go b/base/web/dream.go index 1075719b..953edcd1 100644 --- a/base/web/dream.go +++ b/base/web/dream.go @@ -130,7 +130,7 @@ func _dream_start(m *ice.Message, name string) { defer m.Options(cli.CMD_DIR, "", cli.CMD_ENV, "", cli.CMD_OUTPUT, "") m.Options(cli.CMD_DIR, kit.Path(p), cli.CMD_ENV, kit.EnvList(kit.Simple(m.OptionSimple(ice.TCP_DOMAIN), cli.CTX_OPS, HostPort(m, tcp.LOCALHOST, m.Cmdv(SERVE, tcp.PORT)), cli.CTX_LOG, ice.VAR_LOG_BOOT_LOG, - cli.CTX_ROOT, kit.Path(""), cli.PATH, cli.BinPath(p, ""), cli.USER, ice.Info.Username, + cli.CTX_ROOT, kit.Path(""), cli.PATH, cli.BinPath(p, ""), cli.USER, ice.Info.UserName, )...), cli.CMD_OUTPUT, path.Join(p, ice.VAR_LOG_BOOT_LOG), mdb.CACHE_CLEAR_ONEXIT, ice.TRUE) kit.If(m.Option(nfs.BINARY) == "" && !cli.SystemFindGo(m), func(p string) { m.Option(nfs.BINARY, S(name)) }) kit.If(m.Option(nfs.BINARY), func(p string) { _dream_binary(m, p) }) @@ -313,7 +313,7 @@ func init() { if m.Option(mdb.NAME) != "" { return } - defer ToastProcess(m, PUBLISH, ice.Info.Pathname)() + defer ToastProcess(m, PUBLISH, ice.Info.PathName)() m.Cmd(AUTOGEN, BINPACK) kit.For(list, func(goos string) { list := []string{cli.AMD64} diff --git a/base/web/render.go b/base/web/render.go index 4e22327a..dfa7f5d4 100644 --- a/base/web/render.go +++ b/base/web/render.go @@ -175,7 +175,10 @@ func RenderPodCmd(m *ice.Message, pod, cmd string, arg ...ice.Any) { m.OptionDefault(mdb.ICONS, m.Resource(kit.Select(ice.Info.NodeIcon, msg.Option(ice.MSG_NODEICON), msg.Append(mdb.ICONS)))) serve := strings.Split(UserHost(m), "://")[1] pod = kit.Select(pod, msg.Option(ice.MSG_NODENAME), m.Option(ice.MSG_USERPOD) != "") - m.OptionDefault(TITLE, kit.Select(cmd, msg.Append(mdb.HELP), !m.IsEnglish())+" "+kit.Select(serve, pod)) + m.OptionDefault(TITLE, + // kit.Select(cmd, msg.Append(mdb.HELP), !m.IsEnglish())+" "+kit.Select(serve, pod), + kit.Select(serve, pod)+" "+kit.Select(cmd, msg.Append(mdb.HELP), !m.IsEnglish()), + ) RenderCmds(m, kit.Dict(msg.AppendSimple(), ctx.ARGS, kit.Simple(arg), ctx.DISPLAY, m.Option(ice.MSG_DISPLAY))) } } diff --git a/base/web/route.go b/base/web/route.go index 2a680167..34589295 100644 --- a/base/web/route.go +++ b/base/web/route.go @@ -114,7 +114,7 @@ func init() { case nfs.PATH: m.Push(key, kit.Path("")) case tcp.HOSTNAME: - m.Push(key, ice.Info.Hostname) + m.Push(key, ice.Info.HostName) default: m.Push(key, "") } diff --git a/base/web/serve.go b/base/web/serve.go index c41ae1d1..39cf749d 100644 --- a/base/web/serve.go +++ b/base/web/serve.go @@ -33,7 +33,7 @@ func _serve_start(m *ice.Message) { m.Go(func() { m.Cmd(SPIDE, ice.OPS, _serve_address(m)+nfs.PS+ice.EXIT, ice.Maps{CLIENT_TIMEOUT: cli.TIME_30ms, ice.LOG_DISABLE: ice.TRUE}) }).Sleep(cli.TIME_1s) - cli.NodeInfo(m, kit.Select(kit.Split(ice.Info.Hostname, nfs.PT)[0], m.Option(tcp.NODENAME)), SERVER, mdb.Config(m, mdb.ICONS)) + cli.NodeInfo(m, kit.Select(kit.Split(ice.Info.HostName, nfs.PT)[0], m.Option(tcp.NODENAME)), SERVER, mdb.Config(m, mdb.ICONS)) kit.If(ice.HasVar(), func() { m.Cmd(nfs.SAVE, ice.VAR_LOG_ICE_PORT, m.Option(tcp.PORT)) }) kit.For(kit.Split(m.Option(ice.DEV)), func(dev string) { if strings.HasPrefix(dev, HTTP) { diff --git a/base/web/space.go b/base/web/space.go index 4695432c..1a6c5592 100644 --- a/base/web/space.go +++ b/base/web/space.go @@ -94,7 +94,7 @@ func _space_fork(m *ice.Message) { safe := false if m.Option(ice.MSG_USERNAME, ""); kit.IsIn(m.Option(mdb.TYPE), WORKER, PORTAL) { if tcp.IsLocalHost(m, m.Option(ice.MSG_USERIP)) { - aaa.SessAuth(m, kit.Dict(m.Cmd(aaa.USER, m.Option(ice.MSG_USERNAME, ice.Info.Username)).AppendSimple())) + aaa.SessAuth(m, kit.Dict(m.Cmd(aaa.USER, m.Option(ice.MSG_USERNAME, ice.Info.UserName)).AppendSimple())) } } else if m.Option(TOKEN) != "" { if msg := m.Cmd(TOKEN, m.Option(TOKEN)); msg.Append(mdb.TIME) > m.Time() && kit.IsIn(msg.Append(mdb.TYPE), SERVER, SPIDE) { @@ -367,7 +367,7 @@ func init() { "s": {Help: "空间", Actions: ApiWhiteAction(), Hand: func(m *ice.Message, arg ...string) { m.Cmdy(CHAT_POD, arg) }}, SPACE: {Name: "space name cmds auto", Help: "空间站", Actions: ice.MergeActions(ice.Actions{ ice.CTX_INIT: {Hand: func(m *ice.Message, arg ...string) { - cli.NodeInfo(m, ice.Info.Pathname, WORKER) + cli.NodeInfo(m, ice.Info.PathName, WORKER) aaa.White(m, SPACE, ice.MAIN) if kit.IsIn(ice.Info.NodeIcon, "src/main.ico", "") { nfs.Exists(m, "src/main.ico", func(p string) { ice.Info.NodeIcon = p }) @@ -376,7 +376,7 @@ func init() { } }}, mdb.ICONS: {Hand: func(m *ice.Message, arg ...string) { - cli.NodeInfo(m, ice.Info.Pathname, WORKER, arg[0]) + cli.NodeInfo(m, ice.Info.PathName, WORKER, arg[0]) m.Cmd(SERVE, m.ActionKey(), arg) }}, ice.MAIN: {Name: "main index", Role: aaa.VOID, Hand: func(m *ice.Message, arg ...string) { @@ -394,7 +394,7 @@ func init() { m.Push(mdb.ICONS, ice.Info.NodeIcon) m.Push(nfs.MODULE, ice.Info.Make.Module) m.Push(nfs.VERSION, ice.Info.Make.Versions()) - m.Push(nfs.PATHNAME, ice.Info.Pathname) + m.Push(nfs.PATHNAME, ice.Info.PathName) m.Push(tcp.HOSTPORT, HostPort(m, m.Cmd(tcp.HOST).Append(aaa.IP), m.Cmd(SERVER).Append(tcp.PORT))) m.Push(ORIGIN, m.Option(ice.MSG_USERHOST)) }}, diff --git a/base/web/stats.go b/base/web/stats.go index 78a62f9f..1a43813b 100644 --- a/base/web/stats.go +++ b/base/web/stats.go @@ -24,7 +24,7 @@ func init() { PushStats(m, "", "", "", "令牌总数", TOKEN) PushStats(m, "", "", "", "注册总数", aaa.APPLY) PushStats(m, "", "", "", "邀请总数", aaa.OFFER) - if ice.Info.Username == ice.Info.Make.Username { + if ice.Info.UserName == ice.Info.Make.Username { PushStats(m, "", m.Cmd(aaa.USER).Length()-1, "", "用户总数", aaa.USER) } else { PushStats(m, "", m.Cmd(aaa.USER).Length()-2, "", "用户总数", aaa.USER) diff --git a/core/chat/grant.go b/core/chat/grant.go index a7cee945..4a057b98 100644 --- a/core/chat/grant.go +++ b/core/chat/grant.go @@ -60,7 +60,7 @@ func init() { if msg.Length() == 0 { return } - m.Options(tcp.HOSTNAME, ice.Info.Hostname, nfs.PATH, msg.Append(mdb.TEXT)) + m.Options(tcp.HOSTNAME, ice.Info.HostName, nfs.PATH, msg.Append(mdb.TEXT)) if !m.WarnNotValid(m.Option(nfs.PATH) == "", arg[0]) { m.Option(aaa.IP, msg.Append(aaa.IP)) m.Option(ice.MSG_USERUA, msg.Append(aaa.UA)) diff --git a/core/chat/header.go b/core/chat/header.go index 2c20b21f..8573417d 100644 --- a/core/chat/header.go +++ b/core/chat/header.go @@ -127,7 +127,7 @@ func init() { m.Cmd("", mdb.CREATE, mdb.TYPE, mdb.PLUGIN, mdb.NAME, "免登录体验", mdb.ORDER, "12", ctx.INDEX, HEADER, ctx.ARGS, ice.DEMO) mdb.Config(m, ice.DEMO, ice.TRUE) } else if mdb.Config(m, ice.DEMO) == ice.TRUE { - web.RenderCookie(m, aaa.SessCreate(m, ice.Info.Username)) + web.RenderCookie(m, aaa.SessCreate(m, ice.Info.UserName)) m.Echo("login success") } else { m.Echo("login failure") @@ -154,10 +154,12 @@ func init() { m.Option(ice.MSG_NODETYPE, ice.Info.NodeType) m.Option(ice.MSG_NODENAME, ice.Info.NodeName) m.Option("favicon", ice.Info.NodeIcon) - if ice.Info.NodeType == web.WORKER && ice.Info.Titles == "ContextOS" { - return - } - m.Option("titles", ice.Info.Titles) + m.Option("titles", kit.GetValid( + func() string { return kit.Select("", ice.Info.Titles, ice.Info.Titles != "ContextOS") }, + func() string { return kit.Select("", ice.Info.NodeName, ice.Info.NodeName != "ContextOS") }, + func() string { return kit.Select("", ice.Info.PathName, ice.Info.PathName != "ContextOS") }, + func() string { return kit.Select("", ice.Info.HostName, ice.Info.HostName != "ContextOS") }, + )) }) if ice.Info.NodeType == web.WORKER { return diff --git a/core/chat/macos/desktop.css b/core/chat/macos/desktop.css index cc3e8647..97fe7528 100644 --- a/core/chat/macos/desktop.css +++ b/core/chat/macos/desktop.css @@ -115,7 +115,7 @@ fieldset.macos.menu.cmd>div.output>div.menu { padding:0 var(--button-padding); } body.dark fieldset.desktop>div.output>fieldset.macos { background-color:#08234ad1; } body.light fieldset.desktop>div.output>fieldset.macos { background-color:#daefff99; } body.white fieldset.desktop>div.output>div.desktop>div.item>div.name { color:white; } -body.mobile fieldset.desktop>div.output>div.desktop>fieldset>legend { float:none; } +body.mobile fieldset.desktop>div.output>div.desktop>fieldset>legend { float:left; } body.mobile fieldset.desktop>div.output>div.desktop>fieldset>form.option>div.item.text>input { width:60px; } body.mobile fieldset.macos.dock>div.output { overflow-y:hidden; } body.windows fieldset.desktop>div.output>fieldset.macos.notifications>div.action>div.item.refresh>span { font-size:24px; margin-top:0; } diff --git a/core/chat/macos/desktop.js b/core/chat/macos/desktop.js index c3c66180..4db3ff8a 100644 --- a/core/chat/macos/desktop.js +++ b/core/chat/macos/desktop.js @@ -4,7 +4,7 @@ Volcanos(chat.ONIMPORT, { can.onlayout.background(can, can.misc.ResourceIcons(can, can.user.info.background||"usr/icons/background.png"), can._fields) can.onimport._menu(can), can.onimport._notifications(can), can.onimport._searchs(can), can.onimport._dock(can) can.sup.onexport.link = function() { return can.misc.MergeURL(can, {pod: can.ConfSpace()||can.misc.Search(can, ice.POD), cmd: web.DESKTOP}) } - can.onexport.title(can, can.ConfHelp(), can.user.titles) + // can.onexport.title(can, can.ConfHelp(), can.user.titles) }, _menu: function(can) { can.onappend.plugin(can, {index: "web.chat.macos.menu", style: html.OUTPUT, title: can.Conf("title")}, function(sub) { can.ui.menu = sub, sub._desktop = can var tabs = can.misc.sessionStorage(can, [can.ConfIndex(), html.TABS]) diff --git a/core/code/autogen.go b/core/code/autogen.go index 32abe26c..3d35e14b 100644 --- a/core/code/autogen.go +++ b/core/code/autogen.go @@ -106,7 +106,7 @@ func _autogen_git(m *ice.Message, arg ...string) ice.Map { msg.Append("icebergs", value["version"]) } }) - return kit.Dict(arg, aaa.USERNAME, m.Option(ice.MSG_USERNAME), tcp.HOSTNAME, ice.Info.Hostname, nfs.PATH, kit.Path("")+nfs.PS, mdb.TIME, m.Time(), + return kit.Dict(arg, aaa.USERNAME, m.Option(ice.MSG_USERNAME), tcp.HOSTNAME, ice.Info.HostName, nfs.PATH, kit.Path("")+nfs.PS, mdb.TIME, m.Time(), GIT, GitVersion(m), GO, GoVersion(m), nfs.MODULE, _autogen_mod(m, ice.GO_MOD), msg.AppendSimple("remote,branch,version,forword,author,email,hash,when,message,release,icebergs"), web.DOMAIN, m.Spawn(kit.Dict(ice.MSG_USERWEB, web.UserHost(m), ice.MSG_USERPOD, m.Option(ice.MSG_USERPOD))).MergePod(""), diff --git a/core/code/version.go b/core/code/version.go index 9a817d90..3a7baac8 100644 --- a/core/code/version.go +++ b/core/code/version.go @@ -62,13 +62,13 @@ func init() { }), Hand: func(m *ice.Message, arg ...string) { repos := map[string]string{} list := map[string]map[string]string{} - list[ice.Info.Pathname] = map[string]string{} + list[ice.Info.PathName] = map[string]string{} m.Cmds(web.CODE_GIT_REPOS).Table(func(value ice.Maps) { repos[strings.Split(value[web.ORIGIN], "://")[1]] = value[nfs.VERSION] }) m.Cmd(web.CODE_MOD, mdb.RENDER, MOD, ice.GO_MOD, nfs.PWD).Table(func(value ice.Maps) { - list[ice.Info.Pathname][value[REQUIRE]] = value[VERSION] + list[ice.Info.PathName][value[REQUIRE]] = value[VERSION] if value[REPLACE] == nfs.PWD { - list[ice.Info.Pathname][MODULE] = value[REQUIRE] - list[ice.Info.Pathname][VERSION] = value[VERSION] + list[ice.Info.PathName][MODULE] = value[REQUIRE] + list[ice.Info.PathName][VERSION] = value[VERSION] } else { repos[value[REQUIRE]] = value[VERSION] } diff --git a/core/code/xterm.go b/core/code/xterm.go index 147c2881..9d1835bf 100644 --- a/core/code/xterm.go +++ b/core/code/xterm.go @@ -94,7 +94,7 @@ func init() { kit.If(value[mdb.TYPE] == SHELL, func() { m.Push(arg[0], value[mdb.TEXT]) }) }) case mdb.NAME: - m.Push(arg[0], path.Base(m.Option(mdb.TYPE)), ice.Info.Hostname) + m.Push(arg[0], path.Base(m.Option(mdb.TYPE)), ice.Info.HostName) case nfs.PATH: m.Cmdy(nfs.DIR, ice.USR_LOCAL_WORK, nfs.PATH) m.Cmdy(nfs.DIR, ice.USR_LOCAL_REPOS, nfs.PATH) diff --git a/info.go b/info.go index 2d635892..ff21a089 100644 --- a/info.go +++ b/info.go @@ -46,7 +46,7 @@ func (s MakeInfo) Versions() string { } } func (s info) Title() string { - p := path.Base(kit.Select(s.Pathname, s.Make.Remote, s.Titles)) + p := path.Base(kit.Select(s.PathName, s.Make.Remote, s.Titles)) if strings.HasPrefix(p, "20") { p = kit.Join(strings.Split(p, "-")[1:], "-") } @@ -63,9 +63,9 @@ type info struct { Size string Hash string - Username string - Hostname string - Pathname string + UserName string + HostName string + PathName string NodeName string NodeType string NodeIcon string diff --git a/misc/wx/agent.go b/misc/wx/agent.go index 3da56d1a..bf22f0a7 100644 --- a/misc/wx/agent.go +++ b/misc/wx/agent.go @@ -51,8 +51,7 @@ func init() { }, gdb.EventsAction(chat.HEADER_AGENT), ctx.ConfAction( "oauth", "", web.SPACE, "", nfs.SCRIPT, "https://res.wx.qq.com/open/js/jweixin-1.6.0.js", )), Hand: func(m *ice.Message, arg ...string) { - m.Cmdy(ACCESS, AGENT).Options(SIGNATURE, _wx_sign(m, m.Option(NONCESTR, ice.Info.Pathname), m.Option(TIMESTAMP, kit.Format(time.Now().Unix())))).Display("") - m.Info("what %v", m.FormatsMeta(nil)) + m.Cmdy(ACCESS, AGENT).Options(SIGNATURE, _wx_sign(m, m.Option(NONCESTR, ice.Info.PathName), m.Option(TIMESTAMP, kit.Format(time.Now().Unix())))).Display("") ctx.OptionFromConfig(m, "oauth", nfs.SCRIPT) if m.Option(ice.MSG_USERNAME) == "" { msg := m.Spawn() diff --git a/misc/wx/login.go b/misc/wx/login.go index 2f8de751..edfdb30a 100644 --- a/misc/wx/login.go +++ b/misc/wx/login.go @@ -84,7 +84,7 @@ func init() { aaa.SESS: {Name: "sess code", Help: "会话", Hand: func(m *ice.Message, arg ...string) { m.Option(ice.MSG_USERZONE, WX) if mdb.Conf(m, "header", "meta.demo") == ice.TRUE { - m.Echo(aaa.SessCreate(m.Spawn(), ice.Info.Username)) + m.Echo(aaa.SessCreate(m.Spawn(), ice.Info.UserName)) return } appid := kit.Select(m.Option(APPID), kit.Split(kit.ParseURL(m.Option(ice.MSG_REFERER)).Path, nfs.PS), 0)