diff --git a/etc/conf/auto.sh b/etc/conf/auto.sh new file mode 100644 index 00000000..e0f438d6 --- /dev/null +++ b/etc/conf/auto.sh @@ -0,0 +1,65 @@ +#!/bin/sh + +if [ "$ctx_dev" = "" ] || [ "$ctx_dev" = "-" ]; then + ctx_dev="http://localhost:9095" +fi + +ctx_url=$ctx_dev"/code/zsh" +ctx_head=${ctx_head:="Content-Type: application/json"} +ctx_sync=${ctx_sync:=""} +ctx_sid=${ctx_sid:=""} +ctx_welcome=${ctx_welcome:="^_^ Welcome to Context world ^_^"} +ctx_goodbye=${ctx_goodbye:="^_^ Welcome to Context world ^_^"} + +ShyJSON() { + echo -n "{" + [ -n "$1" ] && echo -n \"$1\"\:\"$2\" && shift 2 && while [ -n "$1" ]; do + echo -n \, && echo -n \"$1\"\:\"$2\" && shift 2 + done + echo -n "}" +} +ShyPost() { + ShyJSON "$@" pwd "$(pwd)" sid "${ctx_sid}"| xargs -d'\n' -n1 curl -s "${ctx_url}" -H "${ctx_head}" -d 2>/dev/null +} +ShySync() { + case "$1" in + "history") tail -n0 -f $HISTFILE | while true; do read line + ShyPost arg "$line" cmd history SHELL $SHELL + echo $line + done;; + "input") + curl -s "${ctx_url}?cmd=input&arg=$READLINE_LINE" &>/dev/null + ;; + esac +} +Shy() { + local ctx_res=`ShyPost cmd "$1" arg "$2"` + case "$ctx_res" in + "PS1");; + *) [ -n "${ctx_res}" ] && ShyPost cmd "$1" arg "$2" res `sh -c ${ctx_res}` + esac +} + + +ShyHistory() { + case "$SHELL" in + "/bin/zsh") + ShySync history &>/dev/null & + ctx_sync=$! + ;; + *) bind -x '"\C-gl":ShySync input' + esac +} +ShyLogout() { + echo ${ctx_goodbye} + ShyPost cmd logout +} +ShyLogin() { + ctx_sid=`ShyPost cmd login pid "$$" pane "${TMUX_PANE}" hostname "$(hostname)" username "${USER}"` + echo ${ctx_welcome} + echo "sid: ${ctx_sid}" + echo "pid: $$" +} + +ShyLogin && trap ShyLogout EXIT + diff --git a/etc/conf/auto.vim b/etc/conf/auto.vim index 4fbb15af..efb15ae0 100644 --- a/etc/conf/auto.vim +++ b/etc/conf/auto.vim @@ -1,4 +1,5 @@ -let ctx_dev = (len($ctx_dev) > 1? $ctx_dev: "http://localhost:9095") . "/code/vim" + +let ctx_dev = (len($ctx_dev) > 1? $ctx_dev: "http://127.0.0.1:9095") . "/code/vim" fun! ShyPost(arg) return system("curl -s '" . g:ctx_dev . "' -H 'Content-Type: application/json' -d '" . json_encode(a:arg) . "' 2>/dev/null") diff --git a/etc/conf/zshrc b/etc/conf/zshrc index 3c0b3839..ae25dca4 100644 --- a/etc/conf/zshrc +++ b/etc/conf/zshrc @@ -106,6 +106,8 @@ bindkey "^P" up-line-or-beginning-search bindkey -M vicmd j down-line-or-beginning-search bindkey -M vicmd k up-line-or-beginning-search +source ~/context/etc/conf/auto.sh + # preexec() { # # bench web.code.counter nexec 1 >/dev/null # } diff --git a/etc/exit.shy b/etc/exit.shy index d2612bdb..ee5eb40d 100644 --- a/etc/exit.shy +++ b/etc/exit.shy @@ -1,5 +1,9 @@ +# 应用配置 ~code config save var/tmp/vim.json vim + config save var/tmp/zsh.json zsh + +# 系统配置 ~ssh config save var/data/flow.json flow config save var/data/work.json work diff --git a/etc/init.shy b/etc/init.shy index dc1cc88c..bf6818d5 100644 --- a/etc/init.shy +++ b/etc/init.shy @@ -1,3 +1,4 @@ +# 系统配置 ~cli config load tmp/runtime.json runtime ~aaa @@ -7,6 +8,7 @@ config load data/work.json work config load data/flow.json flow +# 服务配置 ~nfs source etc/common.shy ~ssh @@ -14,9 +16,11 @@ ~nfs source local.shy +# 应用配置 ~code + config load tmp/zsh.json zsh config load tmp/vim.json vim +# 终端配置 ~cli - diff --git a/src/contexts/cli/cli.go b/src/contexts/cli/cli.go index e7ebaf4d..f2ff59ef 100644 --- a/src/contexts/cli/cli.go +++ b/src/contexts/cli/cli.go @@ -471,6 +471,9 @@ var Index = &ctx.Context{Name: "cli", Help: "管理中心", m.Echo(err.String()) return } + if cmd.ProcessState.ExitCode() != 0 { + return + } // 解析结果 if format(m, out); m.Has("cmd_select") { diff --git a/src/contexts/cli/version.go b/src/contexts/cli/version.go index e13405cb..7694e2d6 100644 --- a/src/contexts/cli/version.go +++ b/src/contexts/cli/version.go @@ -7,5 +7,5 @@ var version = struct { self int }{ []string{"2017-11-01 01:02:03", "2019-07-13 18:02:21"}, - `2019-11-04 11:25:56`, `centos`, 655, + `2019-11-07 00:01:51`, `centos`, 657, } diff --git a/src/contexts/ctx/type.go b/src/contexts/ctx/type.go index a8b3d764..8da2a86b 100644 --- a/src/contexts/ctx/type.go +++ b/src/contexts/ctx/type.go @@ -257,7 +257,7 @@ func (m *Message) Push(key interface{}, arg ...interface{}) *Message { m.Add("append", "key", key) key = "value" } - m.Add("append", key, kit.Chain(arg[0], key)) + m.Add("append", key, kit.Format(kit.Chain(arg[0], key))) } } return m diff --git a/src/contexts/nfs/nfs.go b/src/contexts/nfs/nfs.go index bfe33dd7..e3119a23 100644 --- a/src/contexts/nfs/nfs.go +++ b/src/contexts/nfs/nfs.go @@ -318,13 +318,13 @@ func (nfs *NFS) Start(m *ctx.Message, arg ...string) bool { // 终端控制 if nfs.in = m.Optionv("bio.in").(*os.File); m.Has("bio.out") { - if nfs.out = m.Optionv("bio.out").(*os.File); m.Conf("runtime", "host.GOOS") != "windows" && !m.Options("daemon") { + if nfs.out = m.Optionv("bio.out").(*os.File); m.Options("daemon") { + return false + } + if m.Conf("runtime", "host.GOOS") != "windows" { m.Conf("term", "use", nfs.Term(m, "init") != nil) defer nfs.Term(m, "exit") kit.STDIO = nfs - - } else if m.Options("daemon") { - return false } } diff --git a/src/examples/code/code.go b/src/examples/code/code.go index 8a7e2b65..5c47e786 100644 --- a/src/examples/code/code.go +++ b/src/examples/code/code.go @@ -12,19 +12,7 @@ import ( "toolkit" ) -var Index = &ctx.Context{Name: "code", Help: "代码中心", - Caches: map[string]*ctx.Cache{}, - Configs: map[string]*ctx.Config{ - "login": &ctx.Config{Name: "login", Value: map[string]interface{}{"check": false, "local": true, "expire": "720h"}, Help: "用户登录"}, - "package": {Name: "package", Help: "软件包", Value: map[string]interface{}{ - "udpate": []interface{}{"apk", "update"}, - "install": []interface{}{"apk", "add"}, - "build": []interface{}{"build-base"}, - "develop": []interface{}{"zsh", "tmux", "git", "vim", "golang"}, - "product": []interface{}{"nginx", "redis", "mysql"}, - }}, - "docker": {Name: "docker", Help: "容器", Value: map[string]interface{}{ - "shy": ` +var Dockfile = ` FROM {{options . "base"}} WORKDIR /home/{{options . "user"}}/context @@ -34,23 +22,109 @@ RUN wget -q -O - $ctx_dev/publish/boot.sh | sh -s install CMD sh bin/boot.sh -`, +` + +var Index = &ctx.Context{Name: "code", Help: "代码中心", + Caches: map[string]*ctx.Cache{}, + Configs: map[string]*ctx.Config{ + "login": &ctx.Config{Name: "login", Value: map[string]interface{}{"check": false, "local": true, "expire": "720h"}, Help: "用户登录"}, + "prefix": {Name: "prefix", Help: "外部命令", Value: map[string]interface{}{ + "zsh": []interface{}{"cli.system", "zsh"}, + "tmux": []interface{}{"cli.system", "tmux"}, + "docker": []interface{}{"cli.system", "docker"}, + "git": []interface{}{"cli.system", "git"}, + "vim": []interface{}{"cli.system", "vim"}, + }}, + "package": {Name: "package", Help: "软件包", Value: map[string]interface{}{ + "udpate": []interface{}{"apk", "update"}, + "install": []interface{}{"apk", "add"}, + "build": []interface{}{"build-base"}, + "develop": []interface{}{"zsh", "tmux", "git", "vim", "golang"}, + "product": []interface{}{"nginx", "redis", "mysql"}, + }}, + "docker": {Name: "docker", Help: "容器", Value: map[string]interface{}{ + "shy": Dockfile, }}, "git": {Name: "git", Help: "记录", Value: map[string]interface{}{ - "alias": map[string]interface{}{ - "s": "status", - }, + "alias": map[string]interface{}{"s": "status", "b": "branch"}, }}, "vim": {Name: "vim", Help: "记录", Value: map[string]interface{}{ "opens": map[string]interface{}{}, }}, + "zsh": {Name: "vim", Help: "记录", Value: map[string]interface{}{ + "terminal": map[string]interface{}{}, + "history": map[string]interface{}{}, + }}, }, Commands: map[string]*ctx.Command{ + "/zsh": {Name: "/zsh", Help: "终端", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + if !m.Has("res") { + switch m.Option("cmd") { + case "login": + name := kit.Hashs(m.Option("pid"), m.Option("hostname"), m.Option("username")) + m.Conf("zsh", []string{"terminal", name}, map[string]interface{}{ + "sid": name, + "status": "login", + "time": m.Time(), + "pwd": m.Option("pwd"), + "pid": m.Option("pid"), + "pane": m.Option("pane"), + "hostname": m.Option("hostname"), + "username": m.Option("username"), + }) + m.Echo(name) + return + case "logout": + name := m.Option("sid") + m.Conf("zsh", []string{"terminal", name, "status"}, "logout") + m.Conf("zsh", []string{"terminal", name, "time"}, m.Time()) + return + + case "history": + switch path.Base(m.Option("SHELL")) { + case "zsh": + m.Option("arg", strings.SplitN(m.Option("arg"), ";", 2)[1]) + } + + name := m.Option("sid") + m.Conf("zsh", []string{"history", name, "-1"}, map[string]interface{}{ + "sid": name, + "time": m.Time(), + "cmd": m.Option("arg"), + "pwd": m.Option("pwd"), + }) + return + } + } + return + }}, "zsh": {Name: "zsh dir grep key [split reg fields] [filter reg fields] [order key method] [group keys method] [sort keys method]", Form: map[string]int{"split": 2, "filter": 2, "order": 2, "group": 2, "sort": 2, "limit": 2}, Help: "终端", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { p, arg := kit.Select(".", arg[0]), arg[1:] switch arg[0] { + case "terminal": + m.Confm("zsh", "terminal", func(key string, value map[string]interface{}) { + m.Push([]string{"time", "sid", "status", "pwd", "pid", "pane", "hostname", "username"}, value) + }) + m.Sort("time", "time_r").Table() + case "history": + m.Confm("zsh", "history", func(key string, index int, value map[string]interface{}) { + m.Push([]string{"time", "sid", "cmd", "pwd"}, value) + }) + m.Sort("time", "time_r").Table() + case "prune": + ps := []string{} + m.Confm("zsh", []string{"terminal"}, func(key string, value map[string]interface{}) { + if kit.Format(value["status"]) == "logout" { + ps = append(ps, key) + } + }) + for _, v := range ps { + m.Log("info", "prune %v %v", v, kit.Formats(m.Conf("zsh", []string{"terminal", v}))) + m.Confv("zsh", []string{"terminal", v}, "") + } + case "init": m.Cmd("cli.system", m.Confv("package", "upadte")) for _, v := range kit.View(arg[1:], m.Confm("package")) { @@ -58,7 +132,7 @@ CMD sh bin/boot.sh } case "list": - m.Cmdy("nfs.dir", p, "time", "size", "path") + m.Cmdy("nfs.dir", p, "time", "size", "path").Sort("time", "time_r").Table() case "find": m.Cmdy("cli.system", "find", p, "-name", arg[1], "cmd_parse", "cut", "", "1", "path") @@ -116,7 +190,8 @@ CMD sh bin/boot.sh return }}, "tmux": {Name: "tmux [session [window [pane cmd]]]", Help: "窗口", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - prefix := []string{"cli.system", "tmux"} + prefix := kit.Trans(m.Confv("prefix", "tmux")) + // 修改信息 if len(arg) > 1 { switch arg[1] { case "modify": @@ -129,6 +204,7 @@ CMD sh bin/boot.sh return } } + // 查看会话 if m.Cmdy(prefix, "list-session", "-F", "#{session_id},#{session_name},#{session_windows},#{session_height},#{session_width}", "cmd_parse", "cut", ",", "5", "id session windows height width"); len(arg) == 0 { @@ -163,6 +239,7 @@ CMD sh bin/boot.sh // 执行命令 target := arg[0] + ":" + arg[1] + "." + arg[2] if len(arg) > 3 { + // 修改缓存 if len(arg) > 5 { switch arg[5] { case "modify": @@ -173,7 +250,9 @@ CMD sh bin/boot.sh return } } + switch arg[3] { + // 操作缓存 case "buffer": if len(arg) > 5 { m.Cmdy(prefix, "set-buffer", "-b", arg[4], arg[5]) @@ -191,6 +270,7 @@ CMD sh bin/boot.sh } } return + // 面板列表 case "pane": m.Cmdy(prefix, "list-panes", "-a", "cmd_parse", "cut", " ", "8", "pane_name size some lines bytes haha pane_id tag") m.Meta["append"] = []string{"pane_id", "pane_name", "size", "lines", "bytes", "tag"} @@ -203,7 +283,7 @@ CMD sh bin/boot.sh m.Sort("pane_name") m.Table() return - + // 运行命令 case "run": arg = arg[1:] fallthrough @@ -218,7 +298,7 @@ CMD sh bin/boot.sh return }}, "docker": {Name: "docker", Help: "容器", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - prefix := []string{"cli.system", "docker"} + prefix := kit.Trans(m.Confv("prefix", "docker")) switch arg[0] { case "image": prefix = append(prefix, "image") @@ -244,7 +324,7 @@ CMD sh bin/boot.sh // 启动容器 case "运行": m.Set("append").Set("result") - m.Cmdy("cli.system", "docker", "run", "-dt", pos+":"+tag) + m.Cmdy(prefix[:2], "run", "-dt", pos+":"+tag) return // 清理镜像 case "清理": @@ -265,7 +345,7 @@ CMD sh bin/boot.sh if f, _, e := kit.Create(m.Option("file")); m.Assert(e) { defer f.Close() if m.Assert(ctx.ExecuteStr(m, f, m.Conf("docker", arg[0]))) { - m.Cmdy("cli.system", "docker", "image", "build", "-f", m.Option("file"), "-t", m.Option("name"), ".") + m.Cmdy(prefix, "build", "-f", m.Option("file"), "-t", m.Option("name"), ".") } } } @@ -275,7 +355,7 @@ CMD sh bin/boot.sh if len(arg) > 1 { switch arg[2] { case "进入": - m.Cmdy("cli.system", "tmux", "new-window", "-dPF", "#{session_name}:#{window_name}.1", "docker exec -it "+arg[1]+" sh") + m.Cmdy(m.Confv("prefix", "tmux"), "new-window", "-dPF", "#{session_name}:#{window_name}.1", "docker exec -it "+arg[1]+" sh") return case "停止": @@ -311,12 +391,13 @@ CMD sh bin/boot.sh m.Cmdy(prefix, "ls", "-a", "cmd_parse", "cut", "cmd_headers", "CONTAINER ID", "CONTAINER_ID") case "network": + prefix = append(prefix, "network") if len(arg) == 1 { - m.Cmdy("cli.system", "docker", "network", "ls", "cmd_parse", "cut", "cmd_headers", "NETWORK ID", "NETWORK_ID") + m.Cmdy(prefix, "ls", "cmd_parse", "cut", "cmd_headers", "NETWORK ID", "NETWORK_ID") break } - kit.Map(kit.Chain(kit.UnMarshal(m.Cmdx("cli.system", "docker", "network", "inspect", arg[1])), "0.Containers"), "", func(key string, value map[string]interface{}) { + kit.Map(kit.Chain(kit.UnMarshal(m.Cmdx(prefix, "inspect", arg[1])), "0.Containers"), "", func(key string, value map[string]interface{}) { m.Push("CONTAINER_ID", key[:12]) m.Push("name", value["Name"]) m.Push("IPv4", value["IPv4Address"]) @@ -327,32 +408,62 @@ CMD sh bin/boot.sh case "volume": if len(arg) == 1 { - m.Cmdy("cli.system", "docker", "volume", "ls", "cmd_parse", "cut", "cmd_headers", "VOLUME NAME", "VOLUME_NAME") + m.Cmdy(prefix, "volume", "ls", "cmd_parse", "cut", "cmd_headers", "VOLUME NAME", "VOLUME_NAME") break } default: - m.Cmdy("cli.system", "docker", arg) + m.Cmdy(prefix, arg) } return }}, - "git": {Name: "git", Help: "版本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { - prefix, arg := []string{"cli.system", "git", "cmd_dir", kit.Select(".", arg[0])}, arg[1:] + "git": {Name: "git init|diff|status|commit|branch|pull|push|sum", Help: "版本", Hand: func(m *ctx.Message, c *ctx.Context, key string, arg ...string) (e error) { + prefix, arg := append(kit.Trans(m.Confv("prefix", "git")), "cmd_dir", kit.Select(".", arg[0])), arg[1:] switch arg[0] { case "init": + if s, e := os.Stat(path.Join(prefix[len(prefix)-1], ".git")); e == nil && s.IsDir() { + if len(arg) > 1 { + m.Cmdy(prefix, "remote", "add", "-f", kit.Select("origin", arg, 2), arg[1]) + } + } else if len(arg) > 1 { + m.Cmdy(prefix, "clone", arg[1], ".") + } else { + m.Cmdy(prefix, "init") + } + m.Confm("git", "alias", func(key string, value string) { m.Cmdy(prefix, "config", "alias."+key, value) }) + case "diff": m.Cmdy(prefix, "diff") case "status": m.Cmdy(prefix, "status", "-sb", "cmd_parse", "cut", " ", "2", "tags file") case "commit": - if len(arg) > 1 && m.Cmds(prefix, "commit", "-am", arg[1]) { + if len(arg) > 1 && m.Cmdy(prefix, "commit", "-am", arg[1]).Result() == "" { break } m.Cmdy(prefix, "log", "--stat", "-n", "3") + case "branch": + if len(arg) > 1 { + m.Cmd(prefix, "branch", arg[1]) + m.Cmd(prefix, "checkout", arg[1]) + } + for _, v := range strings.Split(m.Cmdx(prefix, "branch", "-v"), "\n") { + if len(v) > 0 { + m.Log("fuck", "waht %v --", v) + m.Push("tags", v[:2]) + vs := strings.SplitN(strings.TrimSpace(v[2:]), " ", 2) + m.Push("branch", vs[0]) + vs = strings.SplitN(strings.TrimSpace(vs[1]), " ", 2) + m.Push("hash", vs[0]) + m.Push("note", strings.TrimSpace(vs[1])) + } + } + m.Table() + case "push": + m.Cmdy(prefix, "push") case "sum": total := false if len(arg) > 1 && arg[1] == "total" { @@ -449,7 +560,6 @@ CMD sh bin/boot.sh m.Table() case "tags": m.Confm("vim", "tag", func(key string, index int, value map[string]interface{}) { - value["file"] = value["in file/text"] m.Push([]string{"tag", "line", "file", "hostname", "username"}, value) }) m.Table() @@ -484,11 +594,11 @@ CMD sh bin/boot.sh m.Split(strings.TrimPrefix(m.Option("tags"), "\n"), " ", "6").Table(func(index int, value map[string]string) { m.Conf("vim", []string{"tag", name, "-1"}, map[string]interface{}{ - "hostname": m.Option("hostname"), - "username": m.Option("username"), - "tag": value["tag"], - "line": value["line"], - "in file/text": value["in file/text"], + "hostname": m.Option("hostname"), + "username": m.Option("username"), + "tag": value["tag"], + "line": value["line"], + "file": value["in file/text"], }) }) m.Set("append").Set("result") diff --git a/src/plugin/docker/index.shy b/src/plugin/docker/index.shy index 7d83f094..ad56e0ec 100644 --- a/src/plugin/docker/index.shy +++ b/src/plugin/docker/index.shy @@ -1,7 +1,7 @@ kit shell "命令行" private "ssh._route" _ "context" "find" "web.code" "zsh" \ text "" name pod imports plugin_pod \ text "" name dir imports plugin_path action auto \ - select "" name cmd values list values find values tail values grep values init \ + select "" name cmd values list values find values tail values grep values init values terminal values history \ exports path path \ text "" name txt \ feature display editor \ @@ -57,7 +57,8 @@ kit volume "存储" private "web.code.docker" "volume" \ kit git "记录" private "ssh._route" _ "web.code.git" \ text "" name pod imports plugin_pod \ text "" name dir imports plugin_path action auto \ - select "" name cmd values diff values status values commit values sum values init \ + select "" name cmd values diff values status values commit values branch values pull values push values sum values init \ + exports branch branch \ button "查看" kit vim "编辑器" private "ssh._route" _ "web.code.vim" \ diff --git a/src/plugin/favor/index.shy b/src/plugin/favor/index.shy index ef9463a4..5944fa39 100644 --- a/src/plugin/favor/index.shy +++ b/src/plugin/favor/index.shy @@ -54,7 +54,7 @@ fun salary "工资单" public \ end kit svg "绘图" public "web.wiki.svg" \ - text "download/usr/script/teacherInfo.svg" name svg \ + text "download/usr/script/teacherInfo.svg" name svg view long \ feature display svg \ button "查看" diff --git a/usr/librarys/chat.js b/usr/librarys/chat.js index 3dfdb13e..8f739f1e 100644 --- a/usr/librarys/chat.js +++ b/usr/librarys/chat.js @@ -98,11 +98,13 @@ var page = Page({ })) }, get: function(event, item, value, page) { - page.toast.Pane.Show( - "export ctx_dev="+location.protocol+"//"+location.host+" && curl $ctx_dev/publish/boot.sh | bash -s installs context" + "
" + - "export ctx_dev="+location.protocol+"//"+location.host+" && bin/boot.sh" + "
" + - "export ctx_box="+location.protocol+"//"+location.host+" && bin/node.sh" + "
", - "Copy to ClipBorad!", 30000) + page.toast.Pane.Show("" + + "export ctx_dev="+location.protocol+"//"+location.host+" && curl -s $ctx_dev/publish/auto.sh | sh -s" + "
" + + "export ctx_dev="+location.protocol+"//"+location.host+" && curl -s $ctx_dev/publish/boot.sh | bash -s installs context" + "
" + + "export ctx_dev="+location.protocol+"//"+location.host+" && bin/boot.sh" + "
" + + "export ctx_dev="+location.protocol+"//"+location.host+" && bin/user.sh" + "
" + + "export ctx_box="+location.protocol+"//"+location.host+" && bin/node.sh" + "
" + , "Copy to ClipBorad!", 30000) }, "工作": function(event, value) { diff --git a/usr/librarys/example.css b/usr/librarys/example.css index 392e5bbb..715a5984 100644 --- a/usr/librarys/example.css +++ b/usr/librarys/example.css @@ -424,7 +424,7 @@ fieldset table td { max-width:1200px; font-family:monospace; padding: 0 6px; - white-space: pre; + /* white-space: pre; */ } fieldset table td.clip { background-color:red;