Initial 2024-01-26

This commit is contained in:
root
2024-01-26 07:11:35 +12:00
commit d03c481b33
33 changed files with 4224 additions and 0 deletions

5
.editorconfig Normal file
View File

@@ -0,0 +1,5 @@
[*]
end_of_line = lf
indent_style = tab
tab_width = 4

29
.gitignore vendored Normal file
View File

@@ -0,0 +1,29 @@
**/*_
**/.#*
**/0*
**/1*
**/2*
**/3*
**/4*
**/5*
**/6*
**/7*
**/8*
**/9*
**/*-test.go
**/*.so
**/*.log*
**/*log
**/LOG*
**/main
**/main2
static2/**
cache/**
data/**
old/**
outer/**
secret/**

122
cmpSnipper/cmpSnipper.go Normal file
View File

@@ -0,0 +1,122 @@
package cmpSnipper
import (
"errors"
"plugin"
)
type cmpPluginStruct struct {
Name string
Plug *plugin.Plugin
}
type App struct {
Conf interface{}
ErrIsDir error // = errors.New("Is directory")
CliList []cmpWbsCliStruct
cmpSnipperHttpServ cmpSnipperHttpServ
Rand4d int
PlugList []cmpPluginStruct
SshList []cmpSshCliStruct
}
func (app *App) PlugInit(name string, file string) {
qqq := map[string]interface{}{
"Aaa": "Bbb",
}
var plug cmpPluginStruct
var p *plugin.Plugin
p, err := plugin.Open(file)
if err != nil {
app.Log(err)
return
}
plug.Name = name
plug.Plug = p
plugInitReq, err := plug.Plug.Lookup("CmpPlug1Init")
if err != nil {
app.Log(err)
return
}
plugInitFnc := plugInitReq.(func(int, func(any, ...interface{}), map[string]interface{}) interface{})
plugInitRes := plugInitFnc(33, app.Log, qqq)
app.Log("%+v", plugInitRes)
app.PlugList = append(app.PlugList, plug)
}
func (app *App) PlugCall(pnam string, fnam string) {
for _, plug := range app.PlugList {
if plug.Name != pnam {
continue
}
plugFuncReq, err := plug.Plug.Lookup(fnam)
if err != nil {
app.Log(err)
return
}
plugFuncFnc := plugFuncReq.(func() error)
plugFuncRes := plugFuncFnc()
app.Log("%+v", plugFuncRes)
}
}
func (app *App) Prep() (error) {
app.ErrIsDir = errors.New("Is directory")
app.LogSetup()
var err = app.ConfLoadFile("secret/zest.json");
if err != nil {
return err
}
return nil
}
func (app *App) Proc() error {
var err error // = make(chan error, 1)
var term = make(chan bool, 1)
go app.WaitSignal(term)
err = app.HttpServStart()
if err != nil {
return err
}
<-term
app.HttpServStop()
app.Log("Terminating")
return nil
}
// end

View File

@@ -0,0 +1,103 @@
package cmpSnipper
import (
"fmt"
"errors"
"strconv"
"encoding/json"
)
func (app *App) IfcGet(ifc interface{}, arr ...string) (interface{}, error) {
var cnt = len(arr);
var idx string
for j := 0; j < cnt; j++ {
idx = arr[j]
switch v := ifc.(type) {
case string:
app.Log("Convert string to ifc")
ifc = ifc.(interface{})
case map[string]interface{}:
// app.Log("Valid ifc " + idx)
ifc = v[idx];
default:
app.Log("Invalid type variable %s %T", idx, ifc)
return nil, errors.New("Invalid type variable");
}
}
if ifc == nil {
return nil, errors.New("Undefine variable " + idx);
}
// app.Log("Found ifc %s %T", idx, ifc)
return ifc, nil;
}
func (app *App) ConfGetIfc(arr ...string) (interface{}, error) {
return app.IfcGet(app.Conf, arr...);
}
func (app *App) ConfGetStr(arr ...string) (string, error) {
ifc, err := app.ConfGetIfc(arr...);
if err != nil {
return "", err;
}
switch ifc.(type) {
case string:
return ifc.(string), nil;
case float64:
f := ifc.(float64)
u := uint64(f)
return strconv.FormatUint(u, 10), nil;
default:
return "", errors.New("Invalid type value !s");
}
return "", errors.New("Invalid type value");
}
func (app *App) ConfGetArr(arr ...string) ([]interface{}, error) {
ifc, err := app.ConfGetIfc(arr...);
if err != nil {
return nil, err;
}
switch v := ifc.(type) {
case []interface{}:
return v, nil
default:
fmt.Printf("Invalid type value %+q\n", ifc)
return nil, errors.New("Invalid type value !s");
}
return nil, errors.New("Invalid type value");
}
func (app *App) ConfLoadFile(file string) error {
data, err := app.FileReadLimit(file, 1048576);
if err != nil {
app.Log(err)
return err
}
// fmt.Println(string(data));
err = json.Unmarshal(data, &app.Conf)
if err != nil {
app.Log(err)
return err
}
return nil;
}

View File

@@ -0,0 +1,84 @@
package cmpSnipper
import (
"net"
"net/http"
)
type tcpKeepAliveListener struct {
*net.TCPListener
}
type cmpSnipperHttpServ struct {
HttpListener net.Listener
}
func (app *App) HttpServStart() error {
var err error;
// var subjHttpPortString string = "7070";
// var subjHttpPortUint16 uint16 = subjConf.Http.Port;
host, err := app.ConfGetStr("http", "host")
// fmt.Printf("Success load : %+v\n", host)
if err != nil {
app.Log(err)
return err
}
port, err := app.ConfGetStr("http", "port")
// fmt.Printf("Success load : %+v\n", port)
if err != nil {
app.Log(err)
return err
}
// if subjHttpPortUint16 == 0 || subjHttpPortString != strconv.FormatUint(uint64(subjHttpPortUint16), 10) {
// fmt.Printf("Invalid http.port %s != %d\n", subjHttpPortString, subjHttpPortUint16)
// app.Log(".Fatal");
// }
httpFileServer := http.FileServer(http.Dir("static"))
http.Handle("/go-prefix/static/", http.StripPrefix("/go-prefix/static/", httpFileServer))
http.HandleFunc("/" , app.HttpReq);
http.HandleFunc("/go-prefix/ws" , app.HttpWebSockHand)
var addr = host + ":" + port
server := &http.Server{Addr: addr}
app.Log("Listenning: '%s'", port);
app.cmpSnipperHttpServ.HttpListener, err = net.Listen("tcp", addr)
// defer app.HttpServClose()
if err != nil {
app.Log(err)
return err
}
go func() {
err = server.Serve(tcpKeepAliveListener{app.cmpSnipperHttpServ.HttpListener.(*net.TCPListener)})
if err == nil {
app.Log(err)
return // err
}
}()
return nil
}
func (app *App) HttpServStop() {
app.cmpSnipperHttpServ.HttpListener.Close()
app.Log("Server Closed")
}

View File

@@ -0,0 +1,245 @@
package cmpSnipper
import (
"os"
"strings"
"encoding/json"
"net/http"
)
func (app *App) HttpRespText(w http.ResponseWriter, data []byte) {
w.Write(data)
return
}
func (app *App) HttpRespJson(w http.ResponseWriter, data any) {
w.Header().Set("Content-Type", "application/json")
jsonResp, err := json.MarshalIndent(data, "", "\t")
if err != nil {
app.Log("Error happened in JSON marshal. Err: %s", err)
return
}
app.HttpRespText(w, jsonResp)
}
func HttpRespCodeText(w http.ResponseWriter, req *http.Request, code int, cont string, mesg any) {
w.WriteHeader(code)
w.Header().Set("Content-Type", cont)
}
func (app *App) HttpRespForbidden(w http.ResponseWriter, req *http.Request, mesg string) {
w.WriteHeader(http.StatusForbidden)
resp := make(map[string]any)
resp["code"] = 403
resp["status"] = "Forbidden"
resp["message"] = mesg
app.HttpRespJson(w, resp)
}
func (app *App) HttpReqDir1(w http.ResponseWriter, req *http.Request, targ string, path string) {
resp := map[string]interface{}{
"path" : path,
"directory": targ,
"content" : nil,
}
entries, err := os.ReadDir(targ)
if err != nil {
app.Log(err)
app.HttpRespForbidden(w, req, "Server error")
}
var slice []interface{};
for _, e := range entries {
slice = append(slice, map[string]interface{}{
"name": e.Name(),
})
// fmt.Println(e.Name());
}
resp["content"] = slice
app.HttpRespJson(w, resp)
return
}
func (app *App) HttpReqDir(w http.ResponseWriter, req *http.Request, targ string, path string) {
finx := path + "/index.html"
data, err := app.FileReadLimit(finx, 1048576);
if os.IsNotExist(err) {
app.HttpReqDir1(w, req, targ, path)
return
}
if err == app.ErrIsDir {
app.HttpReqDir1(w, req, targ, path)
return
}
if err != nil {
app.Log("Err: %s", err)
app.HttpRespForbidden(w, req, "Server error")
return
}
w.Header().Set("Content-Type", "text/html")
app.HttpRespText(w, data)
return
}
func (app *App) HttpReq(w http.ResponseWriter, req *http.Request) {
// https://go.dev/src/net/http/request.go
// fmt.Printf("Request: %+v\n", req)
var auri = (strings.Split(req.RequestURI, "/"))
auri[0] = "/"
var aidx = 0
app.Log("Auri: %+v", auri)
var locTarg map[string]interface{}
var locEnd bool
locList, err := app.ConfGetArr("http", "location")
if err != nil {
app.HttpRespForbidden(w, req, "Invalid http.location")
return
}
for uid, uri := range auri {
locEnd = false
for _, locIfc := range locList {
var locMap map[string]interface{};
switch v := locIfc.(type) {
case map[string]interface{}:
locMap = v;
}
if locMap == nil {
app.Log("Not Found")
continue
}
locUri := locMap["uri"]
if 1 == 0 {
// fmt.Printf("Found: %+v\n", locUri)
continue
}
if locUri != uri {
// fmt.Printf(" %s != %s\n", locUri, uri)
continue
}
// fmt.Printf("Found: %s\n", uri)
locTarg = locMap
locEnd = true
aidx = uid
switch v := locMap["list"].(type) {
case []interface{}:
locList = v;
// fmt.Printf("Found list\n");
}
}
if !locEnd {
break
}
}
/*
fmt.Printf("Targ %+v\n", locTarg);
fmt.Printf("Targ %+v\n", locEnd );
fmt.Printf("Targ %s \n", locTarg["uri"] );
fmt.Printf("Targ %+v\n", auri[(aidx+1):]);
*/
switch locTarg["type"] {
case "json":
targ := locTarg["targ"].(string)
app.HttpRespJson(w, locTarg[targ])
return
case "func":
targ := locTarg["targ"].(string)
parm := locTarg["parm"]
resp, err := app.CallFuncByName(targ, parm)
if err != nil {
app.Log("Err: %s", err)
break
}
app.HttpRespJson(w, resp)
return
case "directory":
targ := locTarg["targ"].(string)
path := targ + "/" + strings.Join(auri[(aidx+1):], "/")
app.Log("Location: %s", path)
data, err := app.FileReadLimit(path, 1048576);
if os.IsNotExist(err) {
break
}
if err == app.ErrIsDir {
app.HttpReqDir(w, req, targ, path)
return
}
if err != nil {
app.Log("Err: %s", err)
app.HttpRespForbidden(w, req, "Server error")
return
}
w.Header().Set("Content-Type", "text/html")
app.HttpRespText(w, data)
return
case "redirect":
http.Redirect(w, req, locTarg["targ"].(string), int(locTarg["code"].(float64)))
return
// case "ws":
}
app.HttpRespForbidden(w, req, "Invalid type")
}

View File

@@ -0,0 +1,168 @@
package cmpSnipper
import (
"time"
"net/http"
"github.com/gorilla/websocket"
)
type cmpWbsCliStruct struct {
W http.ResponseWriter
Connect *websocket.Conn
HostPort string
}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
HandshakeTimeout: 60 * time.Second,
}
func (app *App) HttpWebSockHand(w http.ResponseWriter, req *http.Request) {
conn, err := upgrader.Upgrade(w, req, nil)
defer conn.Close()
if err != nil {
app.Log(err)
return
}
app.Log("HttpWebSockHand:for")
HostPort := req.Header.Get("X-Real-Ip")
if HostPort == "" {
HostPort = req.Header.Get("X-Forwarded-For")
}
if HostPort == "" {
HostPort = req.RemoteAddr
}
app.Log("New client: %s", HostPort)
var cmpWbsCli cmpWbsCliStruct = cmpWbsCliStruct{
w,
conn,
HostPort,
}
app.CliList = append(app.CliList, cmpWbsCli)
app.Log(app.CliList)
for i, cli := range app.CliList {
app.Log("Client %s, %s", i, cli.HostPort)
}
for {
var inp = map[string]interface{}{}
var out = map[string]interface{}{
"snip": "",
"result": nil,
}
err := conn.ReadJSON(&inp)
if err != nil {
app.Log("Read JSON: %s", err)
app.Log(err)
var list []cmpWbsCliStruct
for _, ii := range app.CliList {
if ii.HostPort == HostPort {
continue
}
list = append(list, ii)
}
app.CliList = list
return
}
app.Log("Received message: %+v", inp)
out["snip"] = inp["snip"]
// app.Log("Copy snip OK")
var snip string;
snip = inp["snip"].(string)
// app.Log("Look snip")
if app.SnipExists(snip) {
out["result"], err = app.SnipCall(cmpWbsCli, snip, inp)
if err != nil {
out["error"] = "Server error"
}
} else {
out["error"] = "Unknown snip"
app.Log("Unknow snip:", inp["snip"])
}
err = conn.WriteJSON(out)
if err != nil {
app.Log(err)
}
// for
}
return
}
func (app *App) HttpWebSockSendTo(cmpWbsCli cmpWbsCliStruct, snip string, result map[string]interface{}) {
var err error
out := map[string]interface{}{
"snip": snip,
"result": result,
}
err = cmpWbsCli.Connect.WriteJSON(out)
if err != nil {
app.Log(err)
return
}
return
}
func (app *App) HttpWebSockSendAll(snip string, result map[string]interface{}) {
var err error
app.Log("Send to all")
out := map[string]interface{}{
"snip": snip,
"result": result,
}
for _, ii := range app.CliList {
if ii.HostPort == "" {
break
}
err = ii.Connect.WriteJSON(out)
if err != nil {
app.Log(err)
continue
}
}
return
}

View File

@@ -0,0 +1,57 @@
package cmpSnipper
import (
"fmt"
"log"
"time"
"encoding/json"
)
func (app *App) LogMod(arg interface{}) string {
var str string
switch t := arg.(type) {
case nil:
str = /* "N:" + */ "null"
case string:
str = /* "S:" + */ t
case error:
str = /* "E:" + */ t.Error()
case byte:
str = /* "B:" + */ string(t)
case []byte:
str = /* "A:" + */ string(t)
case interface{}:
obyte, _ := json.MarshalIndent(arg, "", "\t")
str = /* "J:" + */ string(obyte)
default:
str = /* "U:" + */ fmt.Sprintf("Unknown type %T", t)
}
return str
}
func (app *App) Log(farg any, iargs ...interface{}) {
var str = app.LogMod(farg)
log.SetPrefix(time.Now().UTC().Format("2006-01-02 15:04:05") + ": ")
oargs := make([]interface{}, len(iargs))
for k, arg := range iargs {
oargs[k] = app.LogMod(arg)
}
log.Output(2, fmt.Sprintf(str + "\n", oargs...))
}
func (app *App) LogSetup() {
log.SetFlags( log.Lshortfile );
}

View File

@@ -0,0 +1,84 @@
package cmpSnipper
import (
"os"
"os/signal"
"syscall"
)
func (app *App) WaitSignal(term chan bool) {
var sigreq = make(chan os.Signal, 1)
for true {
signal.Notify(sigreq)
sigrcv := <-sigreq
// app.Log("Got signal: %s", sigrcv)
if sigrcv == syscall.SIGTERM {
term <- true
// continue
return
}
if sigrcv == syscall.SIGINT {
term <- true
// continue
return
}
if sigrcv == syscall.SIGQUIT {
term <- true
// continue
return
}
if sigrcv == syscall.SIGUSR1 {
app.Log("Got signal: %s", sigrcv)
continue
}
if sigrcv == syscall.SIGUSR2 {
app.Log("Got signal: %s", sigrcv)
app.Log("Rand 4d: %d", app.Rand4d)
continue
}
// 1) SIGHUP
// 2) SIGINT
// 3) SIGQUIT
// 4) SIGILL
// 5) SIGTRAP
// 6) SIGABRT
// 7) SIGBUS
// 8) SIGFPE
// 9) SIGKILL
// 10) SIGUSR1
// 11) SIGSEGV
// 12) SIGUSR2
// 13) SIGPIPE
// 14) SIGALRM
// 15) SIGTERM
// 16) SIGSTKFLT
// 17) SIGCHLD
// 18) SIGCONT
// 19) SIGSTOP
// 20) SIGTSTP
// 21) SIGTTIN
// 22) SIGTTOU
// 23) SIGURG
// 24) SIGXCPU
// 25) SIGXFSZ
// 26) SIGVTALRM
// 27) SIGPROF
// 28) SIGWINCH
// 29) SIGIO
// 30) SIGPWR
// 31) SIGSYS
app.Log("Got signal: %s", sigrcv)
}
}

View File

@@ -0,0 +1,78 @@
package cmpSnipper
import (
"reflect"
"errors"
)
func (app *App) SnipExists(funcName string) bool {
snipName := app.UpperFirst(funcName) + "Snip"
refCls := reflect.ValueOf(app)
refMth := refCls.MethodByName(snipName)
if !refMth.IsValid() {
return false
}
return true
}
func (app *App) SnipCall(cmpWbsCli cmpWbsCliStruct, fnName string, ifcII interface{}) (interface{}, error) {
snName := app.UpperFirst(fnName) + "Snip"
refCls := reflect.ValueOf(app)
refMth := refCls.MethodByName(snName)
if !refMth.IsValid() {
app.Log("Call method \"%s\" not found", snName)
return nil, errors.New("Call method not founnd")
}
app.Log("Call method \"%s\"", snName)
ifcIM := map[string]interface{}{
"InputArgument" : ifcII,
"HostPort" : cmpWbsCli.HostPort,
}
refIL := []reflect.Value{
reflect.ValueOf(ifcIM),
}
refOL := refMth.Call(refIL)
infOI := refOL[0].Interface()
app.Log("Interface output item %+v", infOI)
return infOI, nil
}
func (app *App) SnipGetCli(parm any) (cmpWbsCliStruct, error) {
var err error
var cmpWbsCli cmpWbsCliStruct
HostPortIfc, err := app.IfcGet(parm.(map[string]interface{}), "HostPort")
if err != nil {
app.Log("Invalid iterface")
return cmpWbsCli, err
}
HostPort, ok := HostPortIfc.(string)
if !ok {
app.Log("Invalid string")
return cmpWbsCli, errors.New("Can't covert to string")
}
for _, ii := range app.CliList {
if HostPort != ii.HostPort {
continue
}
return ii, nil
}
return cmpWbsCli, errors.New("Client " + HostPort + " not found")
}

View File

@@ -0,0 +1,12 @@
package cmpSnipper
func (app *App) CliListSnip(parm any) (any, error) {
// app.Log("")
ret := map[string]interface{}{
"list" : app.CliList,
}
return ret, nil
}

View File

@@ -0,0 +1,32 @@
package cmpSnipper
import (
"encoding/json"
)
func (app *App) LeftMenuSnip(parm any) (any, error) {
// app.Log("Read data")
mainMenuFile, err := app.ConfGetStr("mainMenuFile")
if err != nil {
return nil, err
}
data, err := app.FileReadLimit(mainMenuFile, 1048576)
if err != nil {
return nil, err
}
var res = map[string]interface{}{}
err = json.Unmarshal(data, &res)
if err != nil {
return nil, err
}
return res, nil
}

View File

@@ -0,0 +1,70 @@
package cmpSnipper
import (
"os/exec"
"context"
"time"
"strings"
"syscall"
)
func (app *App) PingSnip(parm any) (any, error) {
// log.Println("PingSnip")
path, err := exec.LookPath("ping")
app.Log("Prog:", path)
if err != nil {
return map[string]interface{}{
"retval" : 127,
"error" : "No prog",
}, nil
}
ctx, cancel := context.WithTimeout(context.Background(), 10 * time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "ping", "-c", "4", "8.8.8.8")
cmd.Stdin = strings.NewReader("")
var stdout strings.Builder
cmd.Stdout = &stdout
var stderr strings.Builder
cmd.Stderr = &stderr
var exitCode int;
err = cmd.Run()
if err != nil {
// try to get the exit code
if exitError, ok := err.(*exec.ExitError); ok {
ws := exitError.Sys().(syscall.WaitStatus)
exitCode = ws.ExitStatus()
} else {
// This will happen (in OSX) if `name` is not available in $PATH,
// in this situation, exit code could not be get, and stderr will be
// empty string very likely, so we use the default fail code, and format err
// to string and set to stderr
app.Log("Could not get exit code for failed program")
exitCode = 255
}
} else {
// success, exitCode should be 0 if go is ok
ws := cmd.ProcessState.Sys().(syscall.WaitStatus)
exitCode = ws.ExitStatus()
}
return map[string]interface{}{
"retval" : exitCode,
"error" : err,
"stdout" : stdout.String(),
"stderr" : stderr.String(),
}, nil
}

View File

@@ -0,0 +1,16 @@
package cmpSnipper
import (
"math/rand"
)
func (app *App) Rand4dSnip(parm any) (any, error) {
// app.Log("Rand4dSnip")
app.Rand4d = rand.Intn(10000) + 1000
return map[string]interface{}{
"rand4d" : app.Rand4d,
}, nil
}

View File

@@ -0,0 +1,87 @@
package cmpSnipper
import (
"os"
"errors"
"strings"
"reflect"
)
func (app *App) FileReadLimit(file string, mSize int64) ([]byte, error) {
info, err := os.Stat(file)
if err != nil {
return nil, err
}
if info.IsDir() {
return nil, app.ErrIsDir
}
fSize := info.Size()
if fSize > mSize {
return nil, errors.New("File is big")
}
fd, err := os.Open(file)
if err != nil {
return nil, err
}
defer fd.Close()
var rata = make([]byte, fSize);
rSize, err := fd.Read(rata);
if fSize != int64(rSize) {
return nil, errors.New("Can't read full file size")
}
return rata, nil
}
func (app *App) UpperFirst(si string) string {
bi := []byte(si)
ss := strings.Title(string(bi[0]))
bo := bi
bo[0] = ss[0]
return string(bo)
}
func (app *App) CallFuncByName(funcName string, ifcIL ...interface{}) ([]interface{}, error) {
refCls := reflect.ValueOf(app)
refMth := refCls.MethodByName(funcName)
if !refMth.IsValid() {
app.Log("Call method \"%s\" not found", funcName)
return nil, errors.New("Call method not founnd")
}
app.Log("Call method \"%s\"", funcName)
refIL := make([]reflect.Value, len(ifcIL))
for i, ifcII := range ifcIL {
refIL[i] = reflect.ValueOf(ifcII)
}
// fmt.Println("reflect input list", refIL);
refOL := refMth.Call(refIL)
infOL := make([]interface{}, len(refOL))
for i, refOI := range refOL {
infOL[i] = refOI.Interface()
}
app.Log("Interface output list %+v", infOL)
return infOL, nil
}

View File

@@ -0,0 +1,196 @@
package cmpSnipper
import (
// "crypto/md5"
"net/http"
// "os"
"io"
// "fmt"
"bufio"
// "io/ioutil"
"bytes"
"strings"
// "golang.org/x/net/html"
// "net/url"
"encoding/json"
"compress/gzip"
"compress/flate"
"github.com/andybalholm/brotli"
)
func (app *App) HttpGet(url string) (map[string]interface{}) {
ret := map[string]interface{}{
"Error" : nil ,
"RequestUrl" : url ,
"StatusCode" : 0 ,
"ContentRaw" : nil ,
"ContentJson" : nil ,
"Header" : nil ,
"Content-Encoding" : "" ,
"Content-Type" : "" ,
"Content-Length" : "" ,
}
app.Log(url)
cli := &http.Client{}
ifcRawHead, err := app.ConfGetIfc("httpTest", "head")
if err != nil {
app.Log(err)
ret["Error"] = err
return ret
}
mapIfcHead := ifcRawHead.(map[string]interface{})
mapStrHead := make(map[string][]string)
for key, val := range mapIfcHead {
mapStrHead[key] = []string{ val.(string) }
}
req, err := http.NewRequest("GET", url, nil)
req.Header = mapStrHead
res, err := cli.Do(req)
if err != nil {
app.Log(err)
ret["Error"] = err
return ret
}
defer res.Body.Close()
if err != nil {
app.Log(err)
ret["Error"] = err
return ret
}
ret["StatusCode" ] = res.StatusCode
ret["Content-Length"] = res.ContentLength
ret["Header" ] = res.Header
// app.Log("Response status: %s", res.Status)
// app.Log("Header: %+v", res.Header)
// app.Log("TransferEncoding: %+v", res.TransferEncoding)
// app.Log("ContentLength: %+v", res.ContentLength)
var tmpl []string
tmpl = res.Header["Content-Encoding"]
if len(tmpl) > 0 {
ret["Content-Encoding"] = tmpl[0]
}
tmpl = res.Header["Content-Type"]
if len(tmpl) > 0 {
tmpl = strings.Split(tmpl[0], ";")
if len(tmpl) > 0 {
ret["Content-Type"] = tmpl[0]
}
}
// Content-Disposition: attachment; name="fieldName"; filename="myfile.txt"
out := new(bytes.Buffer)
var encReader io.Reader
switch ret["Content-Encoding"] {
case "":
encReader = bufio.NewReader(res.Body)
case "br":
encReader = brotli.NewReader(res.Body)
case "gzip":
encReader, err = gzip.NewReader(res.Body)
case "deflate":
encReader = flate.NewReader(res.Body)
default:
app.Log("Unknown Content-Encoding %s", ret["Content-Encoding"])
encReader = bufio.NewReader(res.Body)
}
if err != nil {
app.Log(err)
ret["Error"] = err
return ret
}
size, err := out.ReadFrom(encReader)
if err != nil {
app.Log(err)
ret["Error"] = err
return ret
}
app.Log("Read %s", size)
var contRaw []byte = out.Bytes()
ret["ContentRaw"] = contRaw
if ret["Content-Type"] == "application/json" {
var contJson interface{}
err = json.Unmarshal(contRaw, &contJson)
if err != nil {
app.Log(err)
ret["Error"] = err
return ret
}
ret["ContentJson"] = contJson
}
return ret
}
func (app *App) CmpHttpTestSnip(parm any) (any, error) {
var err error
cli, err := app.SnipGetCli(parm)
if err != nil {
return map[string]interface{}{
"status": "error",
"error" : "Not client found",
}, err
}
url, err := app.ConfGetStr("httpTest", "url")
if err != nil {
return map[string]interface{}{
"status": "error",
"error" : "Not test URL",
}, err
}
go func() {
var a map[string]interface{}
a = app.HttpGet(url)
app.Log(a)
app.HttpWebSockSendTo(cli, "cmpHttpTest", map[string]interface{}{
"status" : "response",
"response": a,
})
}()
return map[string]interface{}{
"status" : "request",
"request": url,
}, nil
}

View File

@@ -0,0 +1,288 @@
package cmpSnipper
import (
"io"
"bufio"
"strings"
"net"
"golang.org/x/crypto/ssh"
)
type cmpSshCliStruct struct {
Host string
Connect *ssh.Client
Session *ssh.Session
Output *bufio.Reader
}
func (app *App) SshAddHostKey(host string, remote net.Addr, pubKey ssh.PublicKey) error {
app.Log(pubKey)
return nil
}
func (app *App) SshConnReal(cmpSshCli *cmpSshCliStruct, host string, keyfile string) error {
var err error
cmpSshCli.Host = host
key, err := app.FileReadLimit(keyfile, 1048576)
if err != nil {
app.Log(err)
return err
}
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
app.Log(err)
return err
}
config := &ssh.ClientConfig{
User: "root",
Auth: []ssh.AuthMethod{
// HostKeyCallback: InsecureIgnoreHostKey(),
// ssh.Password("yourpassword"),
ssh.PublicKeys(signer),
},
// HostKeyCallback: ssh.FixedHostKey(hostKey),
HostKeyCallback: ssh.HostKeyCallback(func(host string, remote net.Addr, key ssh.PublicKey) error {
app.SshAddHostKey(host, remote, key)
return nil
}),
}
cmpSshCli.Connect, err = ssh.Dial("tcp", cmpSshCli.Host, config)
if err != nil {
app.Log(err)
return err
}
return nil
}
func (app *App) SshSession(cmpSshCli *cmpSshCliStruct) error {
var err error
cmpSshCli.Session, err = cmpSshCli.Connect.NewSession()
if err != nil {
app.Log(err)
return err
}
// defer cmpSshCli.Session.Close()
modes := ssh.TerminalModes{
ssh.ECHO: 0,
}
err = cmpSshCli.Session.RequestPty("xterm", 50, 80, modes)
if err != nil {
app.Log(err)
return err
}
// sshIn, err := session.StdinPipe()
// if err != nil {
// app.Log(err)
// return err
// }
sshOut, err := cmpSshCli.Session.StdoutPipe()
if err != nil {
app.Log(err)
return err
}
sshErr, err := cmpSshCli.Session.StderrPipe()
if err != nil {
app.Log(err)
return err
}
output := io.MultiReader(sshOut, sshErr)
cmpSshCli.Output = bufio.NewReader(output)
return nil
}
func (app *App) SshConn(host string, keyfile string) (int, error) {
var err error
// app.Log(url)
var cmpSshCli cmpSshCliStruct
err = app.SshConnReal(&cmpSshCli, host, keyfile)
if err != nil {
return -1, err
}
err = app.SshSession(&cmpSshCli)
if err != nil {
return -1, err
}
app.SshList = append(app.SshList, cmpSshCli)
app.Log("Append new")
return len(app.SshList)-1, nil
}
func (app *App) SshExec(cmpWbsCli cmpWbsCliStruct, idx int, cma []string) (error) {
var err error
cmd := strings.Join(cma, " ")
cmpSshCli := app.SshList[idx]
// app.Log("idx: '%s', '%s'", idx, cmpSshCli.Host)
err = cmpSshCli.Session.Start(cmd)
if err != nil {
app.Log(err)
return err
}
res := map[string]interface{}{
"string": nil,
}
var bli []byte
var sli string
for {
bli, _, err = cmpSshCli.Output.ReadLine()
if err != nil {
app.Log("Complete")
break
}
sli = string(bli)
app.Log(sli)
res["string"] = sli
app.HttpWebSockSendTo(cmpWbsCli, "cmpSshTest", res)
}
cmpSshCli.Session.Wait()
app.Log("Free resource SshList[" + string(idx) + "]")
cmpSshCli.Session.Close()
cmpSshCli.Connect.Close()
app.Log("Remove SshList[" + string(idx) + "]")
var list []cmpSshCliStruct
for i, li := range app.SshList {
if i == idx {
continue
}
list = append(list, li)
}
app.SshList = list
app.Log("End")
// done <- true
return nil
}
func (app *App) CmpSshTestSnip(parm any) (any, error) {
var err error
// var ifcIM map[string]interface{} = parm
cli, err := app.SnipGetCli(parm)
// app.Log(cli)
if err != nil {
return map[string]interface{}{
"string": "Not client found",
}, err
}
host, err := app.ConfGetStr("sshTestHost", "HostPort")
if err != nil {
return map[string]interface{}{
"string": "Not set sshTestHost.HostPort",
}, err
}
keyfile, err := app.ConfGetStr("sshTestHost", "PrivateKeyFile")
if err != nil {
return map[string]interface{}{
"string": "Not set sshTestHost.PrivateKeyFile",
}, err
}
cmi, err := app.ConfGetIfc("sshTestHost", "Command")
if err != nil {
return map[string]interface{}{
"string": "Not set sshTestHost.Command",
}, err
}
cml := cmi.([]interface{})
cma := make([]string, len(cml))
for i, v := range cml {
cma[i] = v.(string)
}
/*
if cma[0] == "none" {
return map[string]interface{}{
"string": "Can't get command",
}, err
}
*/
idx, err := app.SshConn(host, keyfile)
if err != nil {
return map[string]interface{}{
"string": "Connection to '" + host + "' failed",
}, err
}
go func() {
app.SshExec(cli, idx, cma)
}()
app.Log("Wait")
return map[string]interface{}{
"string": "Launch: " + strings.Join(cma, " "),
}, nil
}

12
go.mod Normal file
View File

@@ -0,0 +1,12 @@
module t/z
go 1.20
require (
github.com/andybalholm/brotli v1.1.0
github.com/gorilla/websocket v1.5.1
golang.org/x/crypto v0.14.0
golang.org/x/net v0.17.0
)
require golang.org/x/sys v0.13.0 // indirect

10
go.sum Normal file
View File

@@ -0,0 +1,10 @@
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

28
main.go Normal file
View File

@@ -0,0 +1,28 @@
package main
import (
// "fmt"
"os"
"t/z/cmpSnipper"
)
func main() {
var app cmpSnipper.App;
var err error
err = app.Prep()
if err != nil {
os.Exit(1)
}
err = app.Proc()
if err != nil {
os.Exit(1)
}
os.Exit(0)
}

34
plug/CmpPlug1/CmpPlug1.go Normal file
View File

@@ -0,0 +1,34 @@
package main
import (
"fmt"
// "net/html"
)
type CmpPlug struct {
Log func(any, ...interface{})
}
var plg CmpPlug
func CmpPlug1Init(in int, f func(any, ...interface{}), ifc map[string]interface{} ) interface{} {
plg.Log = f
ifc["Ccc"] = "Ddd"
fmt.Printf("This is CmpPlug1: %d\n", in)
return ifc
}
func CmpPlug1Some() error {
plg.Log("This is CmpPlug1Some")
return nil
}
func main() {
fmt.Print(23)
}

558
static/cmpSwoPage.css Normal file
View File

@@ -0,0 +1,558 @@
body {
color:#ccc;
background-color:#222;
font-size: 20px;
}
@media (display-mode: fullscreen) {
body {
color:#ccc;
background-color:#444;
}
}
button {
background-color:transparent;
border:1px solid grey;
border-radius:3px;
color: white;
width:24px;
height:24px;
font-size:18px;
}
button:hover {
background-color:transparent;
border:1px solid white;
color: white;
}
/*
input[type="checkbox"]:checked,
input[type="checkbox"]:not(:checked),
input[type="radio"]:checked,
input[type="radio"]:not(:checked)
{
position: absolute;
left: -9999px;
}
input[type="checkbox"]:checked + label,
input[type="checkbox"]:not(:checked) + label,
input[type="radio"]:checked + label,
input[type="radio"]:not(:checked) + label {
// display: inline-block;
position: relative;
padding-left: 28px;
line-height: 20px;
cursor: pointer;
}
input[type="checkbox"]:checked + label:before,
input[type="checkbox"]:not(:checked) + label:before,
input[type="radio"]:checked + label:before,
input[type="radio"]:not(:checked) + label:before {
content: "";
position: absolute;
left: 0px;
top: 0px;
width: 18px;
height: 18px;
border: 1px solid green;
background-color: #444;
}
input[type="checkbox"]:checked + label:before,
input[type="checkbox"]:not(:checked) + label:before {
border-radius: 4px;
}
input[type="radio"]:checked + label:before,
input[type="radio"]:not(:checked) + label:before {
border-radius: 100%;
}
input[type="checkbox"]:checked + label:after,
input[type="checkbox"]:not(:checked) + label:after,
input[type="radio"]:checked + label:after,
input[type="radio"]:not(:checked) + label:after {
content: "";
position: absolute;
-webkit-transition: all 0.2s ease;
-moz-transition: all 0.2s ease;
-o-transition: all 0.2s ease;
transition: all 0.2s ease;
}
input[type="checkbox"]:checked + label:after,
input[type="checkbox"]:not(:checked) + label:after {
left: 3px;
top: 4px;
width: 10px;
height: 5px;
border-radius: 1px;
border-left: 4px solid #ccc;
border-bottom: 4px solid #ccc;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
transform: rotate(-45deg);
}
input[type="radio"]:checked + label:after,
input[type="radio"]:not(:checked) + label:after {
left: 5px;
top: 5px;
width: 10px;
height: 10px;
border-radius: 100%;
background-color: #e145a3;
}
input[type="checkbox"]:not(:checked) + label:after,
input[type="radio"]:not(:checked) + label:after {
opacity: 0;
}
input[type="checkbox"]:checked + label:after,
input[type="radio"]:checked + label:after {
opacity: 1;
}
*/
table {
width:100%;
padding: 0px;
}
table tr.odd:nth-child(2n) {
background: #2f2f2f;
}
table tr.odd:hover {
background: #282828;
}
table tbody.odd:nth-child(2n) {
background: #2f2f2f;
}
table tbody.odd:hover {
background: #282828;
}
table tr td {
padding:4px;
}
a { color: #37a4a4; text-decoration:none; }
a:visited { color: #37a4a4; text-decoration:none; }
#bodyDiv {
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
border:0px solid black;
}
#topper {
position:absolute;
top:0;
left:0;
right:0;
height:32px;
border:0px solid grey;
overflow:hidden;
}
#topperTab {
vertical-align:top;
color:#222;
background: {SWS_BGCOLOR};
}
#topperTabLeft {
width:33%;
}
#topperTabCenter {
width:33%;
text-align:center;
}
#topperTabRight {
width:33%;
text-align:right;
}
#footer {
background-color: #222;
position:absolute;
left:0;
right:0;
bottom:0;
height:32px;
overflow:hidden;
border:0px solid grey;
}
#footerTab {
margin:0;
padding:0;
vertical-align:top;
border:0px solid grey;
}
#footerTabLeft {
width:33%;
}
#footerTabCenter {
width:33%;
text-align:center;
}
#footerTabRight {
width:33%;
text-align:right;
}
/***********************/
#leftMenu {
position:absolute;
top:32px;
left:0px;
width:142px;
bottom:32px;
border:0px solid grey;
padding:0px;
overflow:auto;
}
#leftMenu input[type=button].leftMenuButton {
white-space: normal;
padding:4px 14px 4px 14px;
border:1px solid grey;
border-radius:4px;
background: #333;
color:#eee;
display:block;
width:138px;
margin:4px;
}
#leftMenu button.leftMenuButton {
white-space: normal;
padding:4px 14px 4px 14px;
border:1px solid grey;
border-radius:4px;
background: #333;
color:#eee;
display:block;
width:138px;
height:100%;
margin:4px;
font-size:12px;
}
#leftMenu a.leftMenuLink {
white-space: normal;
padding:4px 14px 4px 14px;
border:0px solid grey;
border-radius:4px;
display:block;
text-align:center;
}
#leftMenu div {
position:relative;
}
#leftMenu .menuNotifyLab {
border: 1px solid grey;
border-radius: 4px;
width: 6px;
height: 6px;
background-color: red;
position: absolute;
bottom: 8px;
right: 8px;
}
#leftMenu .menuNotifyLabAnim1 {
animation-duration: 0.8s;
animation-name: menuNotifyLabAnim1f;
animation-timing-function: linear;
animation-direction: alternate;
}
@keyframes menuNotifyLabAnim1f {
from {
bottom: 500px;
}
to {
bottom: 8px;
}
}
#leftMenu .menuNotifyLabAnim2 {
animation-duration: 0.6s;
animation-name: menuNotifyLabAnim2f;
animation-timing-function: linear;
}
@keyframes menuNotifyLabAnim2f {
from {
width: 6px;
height: 6px;
bottom: 8px;
right: 8px;
}
50% {
width: 12px;
height: 12px;
bottom: 5px;
right: 5px;
}
to {
width: 6px;
height: 6px;
bottom: 8px;
right: 8px;
}
}
#leftMenu .menuNotifyLabHide {
opacity:0;
animation-duration: 0.6s;
animation-name: menuNotifyLabAnim3f;
animation-timing-function: linear;
}
@keyframes menuNotifyLabAnim3f {
from {
width: 6px;
height: 6px;
bottom: 8px;
right: 8px;
opacity:1;
}
to {
width: 12px;
height: 12px;
bottom: 5px;
right: 5px;
opacity:0;
}
}
.leftMenuBlock {
display: block;
position: relative;
margin-top:4px;
margin-bottom:8px;
padding-bottom:8px;
}
div.leftMenuBlockName {
display: block;
}
button.leftMenuBlockName {
display: block;
border:0;
}
.leftMenuBlockNameButton {
position: absolute;
top: 1px;
right:1px;
border:1px solid green;
border-radius:12px;
padding:0px;
width :24px;
height :24px;
font-size:12px;
}
.leftMenuBlockHide > .leftMenuBlockBody {
display: none;
}
.leftMenuBlockBody {
display: block;
}
/*******************************/
#mainRoot {
position:absolute;
top:32px;
left:150px;
right:0;
bottom:32px;
border:1px solid grey;
overflow:hidden;
}
input[type=text] {
background: #333;
color:#eee;
}
input[type=button] {
padding:4px 14px 4px 14px;
border:1px solid grey;
border-radius:4px;
background: #333;
color:#eee;
}
.headWord {
display:inline-block;
overflow:hidden;
}
.footerWord {
display:inline-block;
overflow:hidden;
padding:0 2px 0 2px;
}
/*********/
#page {
z-index:20;
position:fixed;
top:32px;
left:2px;
right:2px;
bottom:0;
border:1px solid #000;
border-radius:4px;
background:#222;
padding:6px;
}
#pageBody {
border:0px solid red;
overflow:auto;
width:100%;
height:100%;
}
#topRight {
z-index:10;
position:fixed;
background:#000;
top:-4px;
left:76%;
right:80px;
bottom:0px;
overflow:auto;
border:1px solid #000;
border-radius:4px;
padding:8px;
opacity:0.8;
}
#topRight:hover {
z-index:50;
border:1px solid green;
}
#topCent {
z-index:10;
position:fixed;
background:#222;
top:0;
left:20%;
right:20%;
border:1px solid #222;
padding:8px;
}
#topCent:hover {
z-index:50;
}
#topLeft {
z-index:10;
position:fixed;
background:#000;
top:-6px;
left:-2px;
right:80%;
border:1px solid #444;
padding:8px;
}
#topLeft:hover {
z-index:50;
border:1px solid green;
}
#srvDate {
animation-duration: 3s;
animation-name: an1;
letter-spacing: normal;
}
#srvTime {
animation-duration: 3s;
animation-name: an1;
letter-spacing: normal;
}
@keyframes an1 {
from {
letter-spacing: 8px;
font-size: 32px;
}
to {
letter-spacing: normal;
font-size: inhrerit;
}
}
/*******/
.buttonIco {
border:1px solid grey;
border-radius:4px;
padding:2px;
margin:0;
min-width:54px;
background-color:transparent;
color:white;
font-size:16px;
}
/*******/
#diag {
z-index:50;
position:fixed;
border:1px solid red;
border-radius:8px;
background-color:#222;
top:20px;
left:20px;
min-width:640px;
min-height:480px;
overflow:hidden;
}

809
static/cmpSwoPage.js Normal file
View File

@@ -0,0 +1,809 @@
class cmpSwoPage {
constructor() {
this.cmpSwoOnConnect = [];
this.cmpSwoOnDisconnect = [];
this.cmpOnLoad();
}
cmpSwoPageInit() {
this.snip = {};
if(!this.sws_sta_prefix)
this.sws_sta_prefix = "go-prefix/static/";
if(!this.sws_dyn_prefix)
this.sws_dyn_prefix = "go-prefix/ws";
this.connect();
this.git = null;
this.cmpSwoTaskListInit();
this.srvTime = 0;
}
connect() {
var serv = "";
if(window.location.protocol == "https:")
serv = "wss://";
else
serv = "ws://"
serv += window.location.host + "/" + this.sws_dyn_prefix ;
this.wsrv = new WebSocket(serv);
this.wsrv.onopen = this.onopen.bind (this);
this.wsrv.onclose = this.onclose.bind (this);
this.wsrv.onmessage = this.onmessage.bind (this);
this.wsrv.onerror = this.onerror.bind (this);
this.WSState(1);
}
onopen(evt) {
console.log("Connected to WebSocket server");
for(var i = 0; i < this.cmpSwoOnConnect.length; i++) {
(this.cmpSwoOnConnect[i])();
}
if(this.pprm == "only-connect")
return;
// this.gitInfoReq();
// this.leftMenuReq();
// this.contentReq();
}
onclose(evt) {
for(var i = 0; i < this.cmpSwoOnDisconnect.length; i++) {
(this.cmpSwoOnDisconnect[i])();
}
console.log("Disconnected");
console.log("Reason: ", evt);
if(!this.connInterval) {
setTimeout(this.connect.bind(this), 100);
}
}
onmessage(evt) {
// console.log('Retrieved data from server: ' + evt.data);
var obj = null;
if(!evt.data) {
return console.log("Empty answer");
}
try {
obj = JSON.parse(evt.data);
} catch(e) {
console.log(evt);
console.log(e);
}
if(!obj) {
console.log("Invalid JSON");
return;
}
if(!obj.snip) {
console.log("Undefine/empty obj.snip", obj);
return;
}
if(obj.task) {
console.log("Recv snip: " + obj.snip, "Tasked");
if(this.cmpSwoTaskListProc(obj) == 1) {
return;
}
}
if(obj.snip != "swoTick1000") {
console.log("Recv snip: " + obj.snip, obj);
}
if(obj.errors) {
console.log("Error: ", obj.errors);
}
if(!obj.result) {
return console.log("Empty result");
}
if(this.snip[obj.snip]) {
console.log("Call this.snip[" + obj.snip + "].rcv");
return (this.snip[obj.snip].rcv).bind(this, obj.result);
}
do {
var snipFn = obj.snip + "Rcv";
if(typeof(this[snipFn]) != "function")
break;
console.log("Call this[" + snipFn + "]");
// console.log(this[snipFn])
return this[snipFn](obj.result);
} while(0);
return console.log("Unknown snip '" + obj.snip + "'");
}
onerror(evt, e) {
console.log('Error occured: ', evt.data);
console.log(evt);
console.log(e);
}
// Util
setFavicon(i) {
var link = document.querySelector("link[rel~='icon']");
if (!link) {
link = document.createElement('link');
link.rel = 'icon';
document.head.appendChild(link);
}
/*
if(i)
link.href = '/go-prefix/static/img/umbrella-color.png';
else
link.href = '/go-prefix/static/img/umbrella-black.png';
console.log(link.href);
*/
}
WSState(z) {
if(!this.wsrv) {
console.log("WebSocket is NULL");
return 1;
}
var m = "";
switch(this.wsrv.readyState) {
case this.wsrv.CONNECTING : m = "WebSocket state is CONNECTING" ; break;
case this.wsrv.OPEN : m = "WebSocket state is OPEN" ; break;
case this.wsrv.CLOSING : m = "WebSocket state is CLOSING" ; break;
case this.wsrv.CLOSED : m = "WebSocket state is CLOSED" ; break;
default : m = "WebSocket state is UNKNOWN" ; break;
}
if(z)
console.log(m);
if(this.wsrv.readyState == this.wsrv.OPEN) {
this.setFavicon(0);
return 0;
}
this.setFavicon(1);
return 1;
}
readySnip() {
if(!this.wsrv) {
console.log("WebSocket is NULL");
return false;
}
if(this.wsrv.readyState == this.wsrv.OPEN)
return true;
return false;
}
reqSnip(snip, obj) {
if(this.WSState()) {
return this.WSState(1);
}
if(obj) {
obj.snip = snip;
}
else {
obj = {
snip: snip,
};
}
console.log("Send snip: " + obj.snip, obj);
var str = JSON.stringify(obj);
return this.wsrv.send(str);
}
gitInfoReq() {
return this.reqSnip("gitInfo");
}
gitInfoRcv(obj) {
var n;
if(!this.git) {
this.git = obj;
}
if(obj.gitStatus) {
if((n = document.getElementById("gitStatus"))) {
n.innerHTML = obj.gitStatus;
}
if((n = document.getElementById("gitTitl"))) {
n.setAttribute("title", obj.gitStatus);
n.style.color = (obj.gitStatus == "treeClean") ? "#86de74" : "#ff3b6b";
}
}
if(obj.gitTimeStamp) {
if((n = document.getElementById("gitDate"))) {
n.innerHTML = unixtimeToYYYYMMDD(obj.gitTimeStamp);
if(obj.gitTimeStamp != this.git.gitTimeStamp)
n.style.color = "#ffff64";
else
n.style.color = "#86de74";
}
if((n = document.getElementById("gitTime"))) {
n.innerHTML = unixtimeToHHMMSS(obj.gitTimeStamp);
if(obj.gitTimeStamp != this.git.gitTimeStamp)
n.style.color = "#ffff64";
else
n.style.color = "#86de74";
}
}
if(obj.gitCommit && (n = document.getElementById("gitCHID"))) {
n.innerHTML = obj.gitCommit.substr(0, 8);
if(obj.gitTimeStamp != this.git.gitTimeStamp)
n.style.color = "#ffff64";
else
n.style.color = "#86de74";
}
if(obj.gitComment && (n = document.getElementById("gitComm"))) {
n.innerHTML = obj.gitComment;
if(obj.gitTimeStamp != this.git.gitTimeStamp)
n.style.color = "#ffff64";
else
n.style.color = "#86de74";
}
}
swoTick1000Rcv(obj) {
var tzOff = checkTZ(0);
obj.ymd = unixtimeToYYYYMMDD(obj["time"] + tzOff);
obj.hms = unixtimeToHHMMSS (obj["time"] + tzOff);
this.srvTime = obj["time"];
setNodeText("srvDate", obj, "ymd", 0);
setNodeText("srvTime", obj, "hms", 0);
}
timeReStyle(sta) {
var n1 = document.getElementById("srvDate");
var n2 = document.getElementById("srvTime");
if(sta == "connect") {
if(n1) n1.style.color = "#86de74";
if(n2) n2.style.color = "#86de74";
}
else {
if(n1) n1.style.color = "#ff3b6b";
if(n2) n2.style.color = "#ff3b6b";
}
return;
}
// Logic
swoSystemctlRestartSelfServiceReq() {
this.reqSnip("swoSystemctlRestartSelfService");
}
swoSystemctlRestartSelfServiceRcv() {
;
}
rand4dReq() {
this.reqSnip("rand4d");
}
rand4dRcv(obj) {
return setNodeText("srvRand", obj, "rand4d");
}
pingReq() {
return this.reqSnip("ping");
}
pingRcv(obj) {
console.log("pingRcv", obj);
}
/****************/
leftMenuNameClick(obj) {
if(!obj)
return console.log("No obj");
var nodeButton = null;
var nodeBlock = null;
var node = null;
// console.log(button);
if(obj.parentNode) {
node = obj;
}
else if(obj?.target?.parentNode) {
node = obj?.target;
}
var mid = node.getAttribute("mid");
if(!mid)
console.log("Can't get mid");
if(!this.leftMenu.list[mid])
console.log("Invalid mid");
nodeBlock = this.leftMenu.list[mid].nodeBlock;
nodeButton = this.leftMenu.list[mid].nodeButt;
if(!nodeBlock)
return console.log("Invalid nodeBlock");
if(!nodeBlock.classList)
return console.log("Invalid nodeBlock.classList");
if(!nodeBlock.classList.contains("leftMenuBlock"))
return console.log("nodeBlock is not leftMenuBlock");
if(nodeBlock.classList.contains("leftMenuBlockHide")) {
nodeBlock.classList.remove("leftMenuBlockHide");
nodeButton.innerHTML = "-";
}
else {
nodeBlock.classList.add("leftMenuBlockHide");
nodeButton.innerHTML = "+";
}
return;
}
leftMenuItemLinkRend(obj, parn) {
var link = dcrt({
tag : "a" ,
parn : parn ,
id : obj?.id ,
class: "leftMenuLink" ,
href : obj.href ,
html : obj.html
});
}
leftMenuItemRend(obj, parn) {
if(obj.type == "link")
return this.leftMenuItemLinkRend(obj, parn);
var cli = null;
if(this[obj.func]) {
cli = this[obj.func].bind(this, obj.parm);
}
else {
console.log("Invalid func '" + obj.func + "'");
}
var cont = null;
if(obj.parn) {
cont = dcrt({
tag : "div",
parn : parn,
id : obj.parn
});
}
else {
cont = parn;
}
var but = dcrt({
tag : "button" ,
parn : cont ,
id : obj?.id ,
class: "leftMenuButton" ,
click: cli ,
html : obj.html
});
// but.setAttribute("onclick", "window.page." + obj.list[i].func + "();");
}
leftMenuBlockRend(obj) {
if(!this.leftMenuNodeRoot) {
return console.log("No .leftMenuNodeRoot");
}
var id = this.leftMenu.list.length;
var nodeBlock = dcrt({
tag : "div",
parn : this.leftMenuNodeRoot,
class: "leftMenuBlock"
});
if(!obj.view)
nodeBlock.classList.add("leftMenuBlockHide");
var nodeButt = dcrt({
mid : id ,
tag : "button" ,
parn : nodeBlock ,
class: "leftMenuBlockNameButton",
click: this.leftMenuNameClick.bind(this),
html : "+"
});
var nodeName = dcrt({
mid : id ,
tag : "button" ,
parn : nodeBlock ,
class: "leftMenuBlockName" ,
click: this.leftMenuNameClick.bind(this),
html : obj.name
});
var nodeBody = dcrt({
tag : "div",
parn : nodeBlock,
class: "leftMenuBlockBody"
});
this.leftMenu.list[id] = {
nodeBlock : nodeBlock ,
nodeButt : nodeButt ,
nodeName : nodeName ,
nodeBody : nodeBody
}
for(var i = 0; i < obj.list.length; i++) {
this.leftMenuItemRend(obj.list[i], nodeBody);
}
return;
}
leftMenuReq() {
this.reqSnip("leftMenu");
}
leftMenuRcv(obj) {
this.leftMenuNodeRoot = document.getElementById("leftMenu");
if(!this.leftMenuNodeRoot) {
return console.log("No .leftMenuNodeRoot");
}
this.leftMenuNodeRoot.innerHTML = "";
this.leftMenu = {
list: []
}
if(!obj.list) {
return console.log("No obj.list");
}
for(var i = 0; i < obj.list.length; i++) {
this.leftMenuBlockRend(obj.list[i]);
}
if(obj.defaultPage) {
var parm = {};
if(obj.defaultPageParm)
parm = obj.defaultPageParm;
this.pageContent = obj.defaultPage;
this.contentReq(obj.defaultPage, parm);
}
}
/****************/
swoTaskListRcv(obj) {
console.log(obj);
}
swoTaskListReq() {
this.reqSnip("swoTaskList");
}
swoLockListRcv(obj) {
console.log(obj);
}
swoLockListReq() {
this.reqSnip("swoLockList");
}
swoSetLogFileNameReq() {
this.reqSnip("swoSetLogFileName");
}
swoSetLogFileNameRcv(obj) {
console.log(obj);
}
/****************/
cmpSwoTaskListInit() {
this.cmpSwoTaskList = [];
this.cmpSwoTaskListNode = document.getElementById("cmpSwoTaskList");
if(!this.cmpSwoTaskListNode) {
console.log("No cmpSwoTaskList");
}
return;
}
cmpSwoTaskListRendItem(name, obj) {
if(!this.cmpSwoTaskListNode) {
return;
}
this.cmpSwoTaskList[name].node = dcrt({
tag : "span",
parn : this.cmpSwoTaskListNode,
html : "[" + obj.snip + "]"
});
return;
}
cmpSwoTaskListProc(obj) {
// if(!this.cmpSwoTaskListNode) {
// return 1;
// }
var name = obj.task.task;
if(obj.task.stat == "work") {
var tbj = {
snip: obj.snip,
node: null
};
this.cmpSwoTaskList[name] = tbj;
// console.log("Append cmpSwoTaskList node " + name);
this.cmpSwoTaskListRendItem(name, obj);
return 1;
}
if(obj.task.stat == "complete") {
if(this.cmpSwoTaskList[name]?.node) {
// console.log("Remove cmpSwoTaskList node " + name + " by complete");
this.cmpSwoTaskList[name].node.remove();
}
return 0;
}
if(obj.task.stat == "lock") {
if(this.cmpSwoTaskList[name]?.node) {
// console.log("Remove cmpSwoTaskList node " + name + " by lock");
this.cmpSwoTaskList[name].node.remove();
}
// console.log(obj);
var cause = obj?.lock?.cause;
if(cause) {
alert("Заблокировано: " + cause);
}
else {
alert("Заблокировано");
}
return 0;
}
// if(obj.task.stat == "error") {
// ;
//
// return 0;
// }
console.log("Unknown obj.task.stat: " + obj.task.stat);
console.log(obj);
return;
}
cmpOnLoad() {
console.log("OnLoad")
this.nodeDataHeadRoot = document.getElementById("tblheadroot");
this.nodeDataBodyRoot = document.getElementById("tblbodyroot");
dcrt({
tag : "h4",
html : "Default page title",
style: "margin:4px;",
parn : this.nodeDataHeadRoot
});
dcrt({
tag : "span",
html : "Default page data",
parn : this.nodeDataBodyRoot
});
}
cmpSshTestReq() {
this.nodeDataHeadRoot.innerHTML = "";
this.nodeDataBodyRoot.innerHTML = "";
if(!this.nodeSshTestHead) {
this.nodeSshTestHead = dcrt({
tag : "h4",
style: "margin:4px;",
html : "Test SSH",
parn : this.nodeDataHeadRoot
});
this.nodeSshTestBody = dcrt({
tag : "tbody"
});
this.nodeSshTestRoot = dcrt({
tag : "table",
parn : this.nodeDataBodyRoot,
child: [ this.nodeSshTestBody ]
});
}
else {
this.nodeDataHeadRoot.appendChild(this.nodeSshTestHead)
this.nodeDataBodyRoot.appendChild(this.nodeSshTestRoot)
this.nodeSshTestBody.innerHTML = "";
}
this.reqSnip("cmpSshTest");
}
cmpSshTestRcv(obj) {
dcrt({
tag : "tr",
parn : this.nodeSshTestBody,
child: [{
tag : "td",
html : obj.string
}]
});
}
cmpHttpTestReq() {
this.nodeDataHeadRoot.innerHTML = "";
this.nodeDataBodyRoot.innerHTML = "";
if(!this.nodeHttpTestHead) {
this.nodeHttpTestHead = dcrt({
tag : "h4",
style: "margin:4px;",
html : "Test HTTP",
parn : this.nodeDataHeadRoot
});
this.nodeHttpTestBody = dcrt({
tag : "tbody"
});
this.nodeHttpTestRoot = dcrt({
tag : "table",
parn : this.nodeDataBodyRoot,
child: [ this.nodeHttpTestBody ]
});
}
else {
this.nodeDataHeadRoot.appendChild(this.nodeHttpTestHead)
this.nodeDataBodyRoot.appendChild(this.nodeHttpTestRoot)
this.nodeHttpTestBody.innerHTML = "";
}
this.reqSnip("cmpHttpTest");
}
cmpHttpTestRcv(obj) {
if(obj.status == "error") {
dcrt({
tag : "tr",
parn : this.nodeHttpTestBody,
child: [{
tag : "td",
html : obj.error
}]
});
return;
}
if(obj.status == "request") {
dcrt({
tag : "tr",
parn : this.nodeHttpTestBody,
child: [{
tag : "td",
html : obj.request
}]
});
return;
}
if(obj.status == "response") {
dcrt({
tag : "tr",
parn : this.nodeHttpTestBody,
child: [{
tag : "td",
child: [{
tag : "pre",
html : JSON.stringify(obj.response, null, 2)
}]
}]
});
return;
}
dcrt({
tag : "tr",
parn : this.nodeHttpTestBody,
child: [{
tag : "td",
html : "Unknown status: '" + obj.status + "'"
}]
});
console.log(obj.status, obj)
return;
}
// END class
}

343
static/cmpSwoUtil.js Normal file
View File

@@ -0,0 +1,343 @@
function unixtimeToYYYYMMDD(s) {
var n;
if(s)
n = new Date(s * 1000);
else
n = new Date();
var m = n.getMonth()+1;
var d = n.getDate();
return (n.getFullYear()) + "-" + (m < 10 ? ("0" + m) : m) + "-" + (d < 10 ? ("0" + d) : d);
}
function unixtimeToHHMMSS(s) {
var n;
if(s)
n = new Date(s * 1000);
else
n = new Date();
var h = n.getHours();
var m = n.getMinutes();
var s = n.getSeconds();
return (h < 10 ? ("0" + h) : h) + ":" + (m < 10 ? ("0" + m) : m) + ":" + (s < 10 ? ("0" + s) : s);
}
function checkTZ(z) {
if((new Date()).getTimezoneOffset())
return 0;
if(z)
console.log("Auto correct TimeZone");
return 12 * 60 * 60;
}
function setNodeText(nn, obj, idx, q) {
var n = null;
if(typeof q == "undefined")
q = 1;
switch(typeof nn) {
case "string":
n = document.getElementById(nn);
break;
case "object":
if(nn.nodeType != 1)
return console.log("Invalid node object");
n = nn;
break;
default:
return console.log("Invalid node type");
}
if(!n) {
if(q == 1)
return console.log("No node '" + nn + "'");
return;
}
if(!obj[idx])
return;
n.innerHTML = obj[idx];
return;
}
function dpst(no, p) {
var n = null;
do {
if(p.before) {
n = p.before;
break;
}
if(p.after) {
n = p.after;
break;
}
if(p.parn) {
n = p.parn;
break;
}
return;
} while(0);
if(typeof(n) == "string") {
n = document.getElementById(n);
if(!n)
return false;
}
if(n.nodeType !== 1) {
console.log("Invalid node type");
return false;
}
if(p.before) {
n.parentNode.insertBefore(no, n);
return true;
}
if(p.after) {
if(p.after.nextSibling)
n.parentNode.insertBefore(no, n.nextSibling);
else
n.parentNode.appendChild(no);
return true;
}
if(p.parn) {
n.appendChild(no);
return true;
}
return false;
}
function dcrt(p) {
var at = "";
var no = null;
var spc = {
"tag" : 1,
"html" : 1,
"parn" : 1,
"child" : 1,
"class" : 1,
"after" : 1,
"before" : 1,
"click" : 1,
"keyup" : 1,
"keypress" : 1,
"change" : 1,
"load" : 1,
"src" : 1
}
if(!p.tag) {
console.log("Empty .tag");
return null;
}
no = document.createElement(p.tag);
for(at in p) {
if(spc[at])
continue;
no.setAttribute(at, p[at]);
}
if(p.class)
no.className = p.class;
dpst(no, p);
if(p.html) {
no.innerHTML = p.html;
}
if(p.click) {
no.addEventListener("click", p.click, false);
}
if(p.keyup) {
no.addEventListener("keyup", p.keyup, false);
}
if(p.keypress) {
no.addEventListener("keypress", p.keypress, false);
}
if(p.change) {
no.addEventListener("change", p.change, false);
}
if(p.load) {
no.addEventListener("load", p.load, false);
// no.onload = p.load;
}
if(p.src) {
no.setAttribute("src", p.src);
// no.src = p.src;
}
if(!p.child)
return no;
var ch = null;
for(at = 0; at < p.child.length; at++) {
if(!p.child[at])
continue;
if(!p.child[at].nodeType)
ch = dcrt(p.child[at]);
else
ch = p.child[at]
if(!ch)
continue;
no.appendChild(ch);
}
return no;
}
class diag {
constructor(parm) {
this.buildBody(parm);
}
buildBody(parm) {
var top = 0.8 * (window.innerHeight- 480)/2;
var left = 1.0 * (window.innerWidth - 640)/2;
this.diagRoot = dcrt({
tag : "div",
parn : "body",
id : "diag",
style: "display:none; top:"+top+"px; left:"+left+"px;"
});
this.diagHead = dcrt({
tag : "div",
style: "position:absolute; top:0px; left:-2px; right:-2px; height:20px; background:#000; padding:10px; font-weight:bold;",
html : "DIALOG",
parn : this.diagRoot
});
this.diagBody = dcrt({
tag : "div",
style: "position:absolute; left:0; right:0; top:40px; bottom:40px; padding:6px; border:0px solid white;",
parn : this.diagRoot,
// child: parm.child
});
this.diagFloor= dcrt({
tag : "div",
style: "position:absolute; left:-2px; right:-2px; bottom:0px; height:20px; background:#000; padding:10px;",
parn : this.diagRoot
});
do {
if(!parm.head)
break;
if(!parm.head.html)
break;
this.diagHead.innerHTML = parm.head.html;
} while(0);
do {
if(!parm.body)
break;
if(!parm.body.node)
break;
parm.body.node.parn = this.diagBody;
dcrt(parm.body.node);
} while(0);
do {
if(!parm.floor)
break;
if(!parm.floor.node)
break;
parm.floor.node.parn = this.diagFloor;
dcrt(parm.floor.node);
} while(0);
this.diagHead.addEventListener('mousedown', this.diagDraggable.bind(this), false);
}
diagDraggable(e) {
var e = e || window.event;
if(window.diag)
window.diag.diagRoot.style.zIndex = 49;
window.diag = this;
this.diagInnerX = e.clientX + window.pageXOffset - this.diagRoot.offsetLeft;
this.diagInnerY = e.clientY + window.pageYOffset - this.diagRoot.offsetTop;
this.diagHandMove = this.diagMove .bind(this);
this.diagHandMouseUp = this.diagMouseUp.bind(this);
window.addEventListener('mousemove', this.diagHandMove , false);
window.addEventListener('mouseup' , this.diagHandMouseUp, true);
}
diagMouseUp(e) {
window.removeEventListener('mousemove', this.diagHandMove);
window.removeEventListener('mouseup' , this.diagHandMouseUp);
}
diagMove(e) {
this.diagRoot.style.zIndex = 50;
this.diagRoot.style.position = 'fixed';
this.diagRoot.style.left = e.clientX + window.pageXOffset - this.diagInnerX + 'px';
this.diagRoot.style.top = e.clientY + window.pageYOffset - this.diagInnerY + 'px';
}
show() {
this.diagRoot.style.display = "block";
}
hide() {
this.diagRoot.style.display = "none";
}
// CLASS
};

333
static/default.css Normal file
View File

@@ -0,0 +1,333 @@
body {
color:#ccc;
background-color:#222;
font-size: 20px;
font-family: monospace;
}
@media (display-mode: fullscreen) {
body {
color:#ccc;
background-color:#444;
}
}
input[type="checkbox"]:checked,
input[type="checkbox"]:not(:checked),
input[type="radio"]:checked,
input[type="radio"]:not(:checked)
{
position: absolute;
left: -9999px;
}
input[type="checkbox"]:checked + label,
input[type="checkbox"]:not(:checked) + label,
input[type="radio"]:checked + label,
input[type="radio"]:not(:checked) + label {
display: inline-block;
position: relative;
padding-left: 28px;
line-height: 20px;
cursor: pointer;
}
input[type="checkbox"]:checked + label:before,
input[type="checkbox"]:not(:checked) + label:before,
input[type="radio"]:checked + label:before,
input[type="radio"]:not(:checked) + label:before {
content: "";
position: absolute;
left: 0px;
top: 0px;
width: 18px;
height: 18px;
border: 1px solid green;
background-color: #444;
}
input[type="checkbox"]:checked + label:before,
input[type="checkbox"]:not(:checked) + label:before {
border-radius: 4px;
}
input[type="radio"]:checked + label:before,
input[type="radio"]:not(:checked) + label:before {
border-radius: 100%;
}
input[type="checkbox"]:checked + label:after,
input[type="checkbox"]:not(:checked) + label:after,
input[type="radio"]:checked + label:after,
input[type="radio"]:not(:checked) + label:after {
content: "";
position: absolute;
-webkit-transition: all 0.2s ease;
-moz-transition: all 0.2s ease;
-o-transition: all 0.2s ease;
transition: all 0.2s ease;
}
input[type="checkbox"]:checked + label:after,
input[type="checkbox"]:not(:checked) + label:after {
left: 3px;
top: 4px;
width: 10px;
height: 5px;
border-radius: 1px;
border-left: 4px solid #ccc;
border-bottom: 4px solid #ccc;
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
transform: rotate(-45deg);
}
input[type="radio"]:checked + label:after,
input[type="radio"]:not(:checked) + label:after {
left: 5px;
top: 5px;
width: 10px;
height: 10px;
border-radius: 100%;
background-color: #e145a3;
}
input[type="checkbox"]:not(:checked) + label:after,
input[type="radio"]:not(:checked) + label:after {
opacity: 0;
}
input[type="checkbox"]:checked + label:after,
input[type="radio"]:checked + label:after {
opacity: 1;
}
table {
width:100%;
padding: 4px;
}
table tr.odd:nth-child(2n) {
background: #2f2f2f;
}
table tr.odd:hover {
background: #282828;
}
table tr td {
padding:4px;
}
a { color: #37a4a4; text-decoration:none; }
a:visited { color: #37a4a4; text-decoration:none; }
input[type=text] {
background: #333;
color:#eee;
}
input[type=button] {
padding:4px 14px 4px 14px;
border:1px solid grey;
border-radius:4px;
background: #333;
color:#eee;
}
.headWord {
display:inline-block;
overflow:hidden;
}
.lftButn {
padding:4px 14px 4px 14px;
border:1px solid grey;
border-radius:4px;
background: #333;
color:#eee;
display:block;
width:100%;
margin:4px;
}
/*********/
#page {
z-index:20;
position:fixed;
top:32px;
left:2px;
right:2px;
bottom:0;
border:1px solid #000;
border-radius:4px;
background:#222;
padding:6px;
}
#pageBody {
border:0px solid red;
overflow:auto;
width:100%;
height:100%;
}
#topRight {
z-index:10;
position:fixed;
background:#000;
top:-4px;
left:76%;
right:80px;
bottom:0px;
overflow:auto;
border:1px solid #000;
border-radius:4px;
padding:8px;
opacity:0.8;
}
#topRight:hover {
z-index:50;
border:1px solid green;
}
#topCent {
z-index:10;
position:fixed;
background:#222;
top:0;
left:20%;
right:20%;
border:1px solid #222;
padding:8px;
}
#topCent:hover {
z-index:50;
}
#topLeft {
z-index:10;
position:fixed;
background:#000;
top:-6px;
left:-2px;
right:80%;
border:1px solid #444;
padding:8px;
}
#topLeft:hover {
z-index:50;
border:1px solid green;
}
/*******/
#diag {
z-index:50;
position:fixed;
border:1px solid red;
border-radius:8px;
background-color:#222;
top:20px;
left:20px;
min-width:640px;
min-height:480px;
overflow:hidden;
}
/*******/
#cmpKernelVanilaNodeRoot {
border:1px solid grey;
position:absolute;
top:16px;
right:4px;
width:300px;
height:90px;
overflow:hidden;
}
#cmpKernelVanilaTitle {
padding-left:32px;
background-image: url(/go-prefix/static/img/tux-favicon.png);
background-repeat:no-repeat;
background-size:16px;
background-position: 8px 2px;
}
#cmpKernelVanilaHead {
font-size:16px;
border-bottom:1px solid grey;
}
#cmpKernelVanilaHeadButton {
border:0px solid grey;
position:absolute;
top:0;
right:-24px;
padding:0px;
padding-right:0px;
margin:0;
background-color:transparent;
color:white;
font-size:16px;
}
#cmpKernelVanilaNodeRoot:hover #cmpKernelVanilaHeadButton {
right:8px;
transform: rotate(-180deg);
transition: right 1s, transform 1s;
}
#cmpTinkoffCurrencyNodeRoot {
border:1px solid grey;
position:absolute;
top:110px;
right:4px;
width:300px;
height:90px;
overflow:hidden;
}
#cmpTinkoffCurrencyTitle {
padding-left:32px;
background-image: url(/go-prefix/static/img/tkf-favicon-32x32.png);
background-repeat:no-repeat;
background-size:16px;
background-position: 8px 2px;
}
#cmpTinkoffCurrencyHead {
font-size:16px;
border-bottom:1px solid grey;
}
#cmpTinkoffCurrencyHeadButton {
border:0px solid grey;
position:absolute;
top:0;
right:-24px;
padding:0px;
padding-right:0px;
margin:0;
background-color:transparent;
color:white;
font-size:16px;
}
#cmpTinkoffCurrencyNodeRoot:hover #cmpTinkoffCurrencyHeadButton {
right:8px;
transform: rotate(-270deg);
transition: right 1s, transform 1s;
}
#cmpTinkoffCurrencyButton {
width: 100%;
height: 100%;
background-image: url(/go-prefix/static/img/tkf-logo-tinkoff.ru.png);
background-repeat:no-repeat;
background-size:32px;
background-position: 8px 2px;
}

299
static/default.js Normal file
View File

@@ -0,0 +1,299 @@
// import { modTrm } from "/go-prefix/static/modTrm.js";
// import { modYdl } from "/go-prefix/static/modYdl.js";
// import { modNeverc } from "/go-prefix/static/modNeverc.js";
class cmpPage extends cmpSwoPage {
constructor() {
super();
// Object.assign(this, modTrm);
// Object.assign(this, modYdl);
// Object.assign(this, modNeverc);
{
this.tblheadroot = document.getElementById("tblheadroot");
this.tblbodyroot = document.getElementById("tblbodyroot");
this.tblbody = document.getElementById("tblbody");
}
// this.trmInitOnce();
// this.ydlInitOnce();
this.cmpSwoOnConnect.push( this.timeReStyle.bind(this, "connect") );
this.cmpSwoOnConnect.push( this.leftMenuReq.bind(this) );
// this.cmpSwoOnConnect.push( this.trmConnect.bind(this) );
// this.cmpSwoOnConnect.push( this.ydlConnect.bind(this) );
this.cmpSwoOnDisconnect.push( this.timeReStyle.bind(this, "disconnect") );
this.cmpSwoPageInit();
this.offLineInit();
;
}
setHeadHeight(ii) {
this.tblheadroot.style.bottom = ii + "px";
this.tblbodyroot.style.top = (ii+1) + "px";
}
setHead(node) {
if(this.tblheadview)
this.tblheadview.style.display = "none";
this.tblheadview = node;
this.tblheadroot.appendChild(node);
this.tblheadview.style.display = "";
}
setBody(node) {
if(this.tblbodyview)
this.tblbodyview.style.display = "none";
this.tblbodyview = node;
this.tblbodyroot.appendChild(node);
this.tblbodyview.style.display = "";
}
// Util
setNode(nn, obj, idx) {
var n = document.getElementById(nn);
if(!n)
return console.log("No node '" + nn + "'");
n.innerHTML = obj[idx];
return;
}
// Logic
contentReq(page, parm) {
console.log("contentReq", page);
if(page == "trmShow") {
this.trmShow();
}
}
rndTabHead(parn, hdr) {
var hdrTb = document.getElementById("tblhtr");
if(!hdrTb)
return;
hdrTb.innerHTML = "";
for(var n = parn?.firstChild?.firstChild, i = 0; n; n = n.nextSibling, i++) {
var sta = "border-right:1px solid grey; border-bottom:1px solid grey; ";
if(hdr[i].child) {
sta = "";
}
var th = dcrt({
tag : "th",
parn : hdrTb,
style: sta + "width:" + (n.offsetWidth) + "px;",
child: hdr[i].child ? hdr[i].child : null
});
if(hdr[i].html) {
th.innerHTML = hdr[i].html;
}
}
var n = document.getElementById("tblbodyroot");
if(n) {
n.style.top = (hdrTb.offsetHeight + 6) + "px";
}
return;
}
//
//
getSpeeddialElemReq() {
return this.reqSnip("getSpeeddialElem", null);
}
getSpeeddialElemRcv(obj) {
var i = 0;
for(i = 0; i < obj.length; i++) {
this.rndSpeeddialElem(obj[i]);
}
}
//
offLineInit() {
if(1)
return;
this.spdNodeLeftMenu = dcrt({
tag : "div",
parn : "mainRoot",
style: "width:320px; position:relative; height:calc(100% - 10px); top:5px; left:5px; border:1px solid grey;"
});
this.spdNodeLeftMenuScrTop = dcrt({
tag : "div",
parn : this.spdNodeLeftMenu,
style: "width:100%; margin:0px; height:40px; border-bottom:1px solid grey;"
});
this.spdNodeLeftMenuBody = dcrt({
tag : "div",
parn : this.spdNodeLeftMenu,
style: "width:100%; margin:0px; height:calc(100% - 80px); overflow-x:hidden; scroll-x:auto;"
})
this.spdNodeLeftMenuScrBottom = dcrt({
tag : "div",
parn : this.spdNodeLeftMenu,
style: "width:100%; margin:0px; height:40px; border-top:1px solid grey;"
});
return;
}
rndSpeeddialElem(obj) {
if(obj.type != "local")
return;
var lab = dcrt({
tag : "div",
style: "padding:16px;",
html : obj.label ? obj.label : obj.ip4v
});
var com = dcrt({
tag : "div",
style: "color:#888; padding-left:32px; margin-right:32px;",
html : (obj.label ? obj.ip4v : "") + (obj.xport ? (" / " + obj.xport) : "")
});
var zzz = null;
if(obj.xport == "A0") {
zzz = this.rndECtl();
}
dcrt({
tag : "div",
parn : this.spdNodeLeftMenuBody,
style: "position:relative; width:calc(100%-10px); margin:5px; height:100px; border:1px solid grey;",
child: [
lab,
com,
zzz
]
});
}
rndECtl() {
if(!this.listECtl)
this.listECtl = [];
var id = this.listECtl.legth;
this.listECtl[id] = {};
this.listECtl[id].nodePoint = dcrt({
tag : "div",
style: "position:absolute; top:2px; width:0px; height:0px; border-radius:17px; border:16px solid;"
});
this.listECtl[id].nodePoint.style.left = "2px";
this.listECtl[id].nodePoint.style.borderColor = "#a33";
this.listECtl[id].nodeLabel = dcrt({
tag : "div"
});
this.listECtl[id].nodeRoot = dcrt({
tag : "div",
style: "position:absolute; top:32px; right:32px; width:84px; height:36px; border:1px solid grey; border-radius:18px;",
click: this.clickECtl.bind(this, id),
child: [
this.listECtl[id].nodePoint,
this.listECtl[id].nodeLabel
]
});
return this.listECtl[id].nodeRoot;
}
clickECtl(id) {
var style = this.listECtl[id].nodePoint.style;
if(style.left) {
style.left = "";
style.right = "2px";
style.borderColor = "#3a3";
}
else {
style.left = "2px";
style.right = "";
style.borderColor = "#a33";
}
return;
}
//==========================
urlMod(parm) {
if(!parm?.urlMod.url)
return console.log("No .url");
if(!parm?.urlMod.title)
return console.log("No .title");
// const nextState = parm?.urlMod.nextState; // { additionalInformation: 'Updated the URL with JS' };
// This will create a new entry in the browser's history, without reloading
window.history.pushState(parm?.urlMod.nextState, parm?.urlMod.title, parm.urlMod.url);
// This will replace the current entry in the browser's history, without reloading
window.history.replaceState(parm?.urlMod.nextState, parm?.urlMod.title, parm.urlMod.url);
// console.log(window.location)
}
// END class
}
window.diag = null;
function diagMove(e) {
window.diag.diagMove(e);
}
function diagMouseUp(e) {
window.diag.diagRoot.style.zIndex = 50;
window.removeEventListener('mousemove', diagMove, false);
}
var page = null;
document.addEventListener("DOMContentLoaded", function(event) {
page = new cmpPage();
window.page = page;
});
// END

BIN
static/img/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 B

BIN
static/img/tux-favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

61
static/index.html Normal file
View File

@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="ru">
<head>
<meta charset="utf-8"/>
<meta http-equiv="cache-control" content="no-cache"/>
<meta http-equiv="Pragma" content="no-cache"/>
<link href="data:image/svg+xml,%3Csvg%0Axmlns:dc='http://purl.org/dc/elements/1.1/'%0Axmlns:cc='http://creativecommons.org/ns%23'%0Axmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23'%0Axmlns:svg='http://www.w3.org/2000/svg'%0Axmlns='http://www.w3.org/2000/svg'%0Axmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'%0Axmlns:inkscape='http://www.inkscape.org/namespaces/inkscape'%0Aversion='1.1'%0Aid='Layer_3'%0Ax='0px'%0Ay='0px'%0AviewBox='0 0 800 800'%0Axml:space='preserve'%0Asodipodi:docname='Cult Mechanicus %5BImperium, Adeptus Mechanicus%5D.svg'%0Awidth='800'%0Aheight='800'%0Ainkscape:version='0.92.3 (2405546, 2018-03-11)'%3E%3Cmetadata%0Aid='metadata13'%3E%3Crdf:RDF%3E%3Ccc:Work%0Ardf:about=''%3E%3Cdc:format%3Eimage/svg+xml%3C/dc:format%3E%3Cdc:type%0Ardf:resource='http://purl.org/dc/dcmitype/StillImage' /%3E%3Cdc:title%3E%3C/dc:title%3E%3C/cc:Work%3E%3C/rdf:RDF%3E%3C/metadata%3E%3Cdefs%0Aid='defs11' /%3E%3Csodipodi:namedview%0Apagecolor='%23ffffff'%0Abordercolor='%23666666'%0Aborderopacity='1'%0Aobjecttolerance='10'%0Agridtolerance='10'%0Aguidetolerance='10'%0Ainkscape:pageopacity='0'%0Ainkscape:pageshadow='2'%0Ainkscape:window-width='1920'%0Ainkscape:window-height='1017'%0Aid='namedview9'%0Ashowgrid='false'%0Afit-margin-top='0'%0Afit-margin-left='0'%0Afit-margin-right='0'%0Afit-margin-bottom='0'%0Ainkscape:pagecheckerboard='true'%0Ainkscape:zoom='0.3337544'%0Ainkscape:cx='69.895884'%0Ainkscape:cy='339.47885'%0Ainkscape:window-x='-8'%0Ainkscape:window-y='-8'%0Ainkscape:window-maximized='1'%0Ainkscape:current-layer='Layer_3' /%3E%3Cg%0Aid='g6'%0Atransform='matrix(0.81670155,0,0,0.81670155,-8.6162014,-11.801337)'%3E%3Cpath%0Ad='m 552.21,318.59 c 0,-2.16 0,-3.32 0,-3.32 0,-5.42 0.76,-17.36 8.74,-28.55 16.26,-22.78 46.62,-20.57 48.37,-20.39 0,-6.82 0,-13.58 0,-20.39 H 391.33 c 0,6.82 0,13.58 0,20.39 1.75,-0.17 32.11,-2.39 48.37,20.39 7.98,11.19 8.74,23.13 8.74,28.55 0,0 0,1.11 0,3.18 -104.69,18.52 -182.92,92.33 -182.92,180.56 0,88.25 78.25,162.06 182.95,180.57 -0.01,2.48 -0.03,4.61 -0.04,6.33 0.23,3.85 0.87,19.75 -10.49,33.21 -10.96,12.99 -28.9,18.76 -46.62,15.15 v 23.31 h 217.99 v -23.31 c -17.71,3.61 -35.66,-2.16 -46.62,-15.15 -11.36,-13.46 -10.72,-29.37 -10.49,-33.21 -0.02,-1.76 -0.03,-3.93 -0.04,-6.47 C 656.46,660.69 734.31,587.03 734.31,499.01734.33,411 656.5,337.34 552.21,318.59 Z M 358.05,503.95 c 0,-67.54 37.51,-125.24 90.43,-148.35 0.08,72.75 0.21,225.02 0.08,296.74 -52.96,-23.09 -90.51,-80.82 -90.51,-148.39 z m 194.04,148.04 c -0.13,-71.75 0,-223.28 0.08,-296.05 52.5,23.34 89.63,80.81 89.63,148 0,67.24 -37.17,124.73 -89.71,148.05 z'%0Aid='path2'%0Ainkscape:connector-curvature='0' /%3E%3Cpath%0Ad='M 990.1,560.87 V 448.76 h -72.53 c -4.3,-36.57 -13.29,-71.71 -26.37,-104.79 l 61.6,-35.57 -56.06,-97.1 -60.35,34.84 c -22,-29.27 -47.74,-55.58 -76.5,-78.21 l 34.38,-59.54 -97.1,-56.06 -33.85,58.64 C 629.86,96.87 594.19,86.99 556.97,81.97 V 14.45 H 444.86 v 67.37 c -37.23,4.91 -72.93,14.7 -106.43,28.7 l -33.93,-58.78 -97.1,56.06 34.29,59.4 c -28.83,22.55 -54.64,48.79 -76.72,78 l -60.48,-34.92 -56.06,97.1 61.46,35.48C 96.72,375.91 87.62,411.02 83.22,447.58 H 10.55 V 559.7 h 74.09 c 5.25,35.85 15.01,70.23 28.72,102.54 l -65.51,37.82 56.06,97.1 66.65,-38.48 c 21.8,27.57 46.97,52.35 74.91,73.69 l -39.08,67.7 97.1,56.06 39.36,-68.17 c 31.86,12.89 65.66,21.99 100.84,26.73 V 994 h 112.12 v -79.17 c 35.2,-4.64 69.02,-13.64 100.92,-26.44 l 39.44,68.32 97.1,-56.06 -39.01,-67.57 c 28,-21.27 53.25,-45.97 75.12,-73.48 l 66.8,38.57 56.06,-97.1 -65.39,-37.75 c 13.79,-32.27 23.67,-66.62 29.01,-102.45 H 990.1 Z M 500.33,818.15 C 326.95,818.15 186.4,677.6 186.4,504.22 186.4,330.84 326.95,190.3 500.33,190.3 c 173.38,0 313.93,140.55 313.93,313.93 0,173.38 -140.56,313.92 -313.93,313.92 z'%0Aid='path4'%0Ainkscape:connector-curvature='0' /%3E%3C/g%3E%3C/svg%3E%0A"
rel="icon" type="image/svg+xml"/>
<script src="/go-prefix/static/cmpSwoPage.js"></script>
<script src="/go-prefix/static/cmpSwoUtil.js"></script>
<link href="/go-prefix/static/cmpSwoPage.css" rel="stylesheet" type="text/css"/>
<link href="/go-prefix/static/default.css" rel="stylesheet" type="text/css"/>
<script src="/go-prefix/static/default.js" type="module"></script>
<!-- link href="/go-prefix/static/img/tux-favicon.png" rel="preload" as="image"/ -->
<!-- link href="/go-prefix/static/img/tkf-favicon-32x32.png" rel="preload" as="image"/ -->
</head>
<body id="body"><div style="position:absolute; top:0; left:0; right:0; bottom:0; border:0px solid black;">
<div id="topper" style="position:absolute; top:0; left:0; right:0; height:32px; border:0px solid grey; overflow:hidden;">
<table id="topperTab" cellpadding="0" cellspacing="0"><tr>
<td id="topperTabLeft">
&nbsp;
</td><td id="topperTabCenter">
<span>&nbsp;</span>
<span id="cmpSwoTaskList"></span>
</td><td id="topperTabRight">
<div id="user" class="headWord">USER</div>
</td>
</tr></table>
</div>
<div id="leftMenu">
</div>
<div id="mainRoot">
<!-- div id="mid" style="position:absolute; top:32px; left:150px; right:0; bottom:32px; border:1px solid grey;" -->
<div id="tblheadroot" style="position:absolute; top:0px; bottom:31px; left:0; right:12px;"></div>
<div id="tblbodyroot" style="position:absolute; top:32px; left:0; right:0; bottom:0; overflow:auto;"></div>
</div>
<div id="footer" style="position:absolute; left:0; right:0; bottom:0; height:32px; border:0px solid grey;">
<table cellpadding="0" cellspacing="0" style="vertical-align:top;"><tr>
<td style="width:33%; vertical-align:top;">
<div id="gitTitl" class="headWord">GIT</div>
<div id="gitDate" class="headWord">2022-99-99</div>
<div id="gitTime" class="headWord">99:99:99</div>
<div id="gitCHID" class="headWord">00000000</div>
<div id="gitComm" class="headWord">Just string</div>
</td><td style="width:33%; vertical-align:top; text-align:center;">
<div id="srvDate" class="headWord">2022-00-00</div>
<div id="srvTime" class="headWord">00:00:00</div>
<div id="srvRand" class="headWord"></div>
</td><td style="width:33%; vertical-align:top; text-align:right;">
<div id="oraLabs" class="headWord">Qwerty</div>
<div id="oraRole" class="headWord">NONE</div>
<div id="oraAddr" class="headWord">xxx.xxx.xx.xx</div>
<div id="oraUser" class="headWord">USER</div>
</td>
</tr></table>
</div>
</div></body>

61
static/index2.html Normal file
View File

@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="ru">
<head>
<meta charset="utf-8"/>
<meta http-equiv="cache-control" content="no-cache"/>
<meta http-equiv="Pragma" content="no-cache"/>
<link href="data:image/svg+xml,%3Csvg%0Axmlns:dc='http://purl.org/dc/elements/1.1/'%0Axmlns:cc='http://creativecommons.org/ns%23'%0Axmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23'%0Axmlns:svg='http://www.w3.org/2000/svg'%0Axmlns='http://www.w3.org/2000/svg'%0Axmlns:sodipodi='http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'%0Axmlns:inkscape='http://www.inkscape.org/namespaces/inkscape'%0Aversion='1.1'%0Aid='Layer_3'%0Ax='0px'%0Ay='0px'%0AviewBox='0 0 800 800'%0Axml:space='preserve'%0Asodipodi:docname='Cult Mechanicus %5BImperium, Adeptus Mechanicus%5D.svg'%0Awidth='800'%0Aheight='800'%0Ainkscape:version='0.92.3 (2405546, 2018-03-11)'%3E%3Cmetadata%0Aid='metadata13'%3E%3Crdf:RDF%3E%3Ccc:Work%0Ardf:about=''%3E%3Cdc:format%3Eimage/svg+xml%3C/dc:format%3E%3Cdc:type%0Ardf:resource='http://purl.org/dc/dcmitype/StillImage' /%3E%3Cdc:title%3E%3C/dc:title%3E%3C/cc:Work%3E%3C/rdf:RDF%3E%3C/metadata%3E%3Cdefs%0Aid='defs11' /%3E%3Csodipodi:namedview%0Apagecolor='%23ffffff'%0Abordercolor='%23666666'%0Aborderopacity='1'%0Aobjecttolerance='10'%0Agridtolerance='10'%0Aguidetolerance='10'%0Ainkscape:pageopacity='0'%0Ainkscape:pageshadow='2'%0Ainkscape:window-width='1920'%0Ainkscape:window-height='1017'%0Aid='namedview9'%0Ashowgrid='false'%0Afit-margin-top='0'%0Afit-margin-left='0'%0Afit-margin-right='0'%0Afit-margin-bottom='0'%0Ainkscape:pagecheckerboard='true'%0Ainkscape:zoom='0.3337544'%0Ainkscape:cx='69.895884'%0Ainkscape:cy='339.47885'%0Ainkscape:window-x='-8'%0Ainkscape:window-y='-8'%0Ainkscape:window-maximized='1'%0Ainkscape:current-layer='Layer_3' /%3E%3Cg%0Aid='g6'%0Atransform='matrix(0.81670155,0,0,0.81670155,-8.6162014,-11.801337)'%3E%3Cpath%0Ad='m 552.21,318.59 c 0,-2.16 0,-3.32 0,-3.32 0,-5.42 0.76,-17.36 8.74,-28.55 16.26,-22.78 46.62,-20.57 48.37,-20.39 0,-6.82 0,-13.58 0,-20.39 H 391.33 c 0,6.82 0,13.58 0,20.39 1.75,-0.17 32.11,-2.39 48.37,20.39 7.98,11.19 8.74,23.13 8.74,28.55 0,0 0,1.11 0,3.18 -104.69,18.52 -182.92,92.33 -182.92,180.56 0,88.25 78.25,162.06 182.95,180.57 -0.01,2.48 -0.03,4.61 -0.04,6.33 0.23,3.85 0.87,19.75 -10.49,33.21 -10.96,12.99 -28.9,18.76 -46.62,15.15 v 23.31 h 217.99 v -23.31 c -17.71,3.61 -35.66,-2.16 -46.62,-15.15 -11.36,-13.46 -10.72,-29.37 -10.49,-33.21 -0.02,-1.76 -0.03,-3.93 -0.04,-6.47 C 656.46,660.69 734.31,587.03 734.31,499.01734.33,411 656.5,337.34 552.21,318.59 Z M 358.05,503.95 c 0,-67.54 37.51,-125.24 90.43,-148.35 0.08,72.75 0.21,225.02 0.08,296.74 -52.96,-23.09 -90.51,-80.82 -90.51,-148.39 z m 194.04,148.04 c -0.13,-71.75 0,-223.28 0.08,-296.05 52.5,23.34 89.63,80.81 89.63,148 0,67.24 -37.17,124.73 -89.71,148.05 z'%0Aid='path2'%0Ainkscape:connector-curvature='0' /%3E%3Cpath%0Ad='M 990.1,560.87 V 448.76 h -72.53 c -4.3,-36.57 -13.29,-71.71 -26.37,-104.79 l 61.6,-35.57 -56.06,-97.1 -60.35,34.84 c -22,-29.27 -47.74,-55.58 -76.5,-78.21 l 34.38,-59.54 -97.1,-56.06 -33.85,58.64 C 629.86,96.87 594.19,86.99 556.97,81.97 V 14.45 H 444.86 v 67.37 c -37.23,4.91 -72.93,14.7 -106.43,28.7 l -33.93,-58.78 -97.1,56.06 34.29,59.4 c -28.83,22.55 -54.64,48.79 -76.72,78 l -60.48,-34.92 -56.06,97.1 61.46,35.48C 96.72,375.91 87.62,411.02 83.22,447.58 H 10.55 V 559.7 h 74.09 c 5.25,35.85 15.01,70.23 28.72,102.54 l -65.51,37.82 56.06,97.1 66.65,-38.48 c 21.8,27.57 46.97,52.35 74.91,73.69 l -39.08,67.7 97.1,56.06 39.36,-68.17 c 31.86,12.89 65.66,21.99 100.84,26.73 V 994 h 112.12 v -79.17 c 35.2,-4.64 69.02,-13.64 100.92,-26.44 l 39.44,68.32 97.1,-56.06 -39.01,-67.57 c 28,-21.27 53.25,-45.97 75.12,-73.48 l 66.8,38.57 56.06,-97.1 -65.39,-37.75 c 13.79,-32.27 23.67,-66.62 29.01,-102.45 H 990.1 Z M 500.33,818.15 C 326.95,818.15 186.4,677.6 186.4,504.22 186.4,330.84 326.95,190.3 500.33,190.3 c 173.38,0 313.93,140.55 313.93,313.93 0,173.38 -140.56,313.92 -313.93,313.92 z'%0Aid='path4'%0Ainkscape:connector-curvature='0' /%3E%3C/g%3E%3C/svg%3E%0A"
rel="icon" type="image/svg+xml"/>
<script src="/go-prefix/static/cmpSwoPage.js"></script>
<script src="/go-prefix/static/cmpSwoUtil.js"></script>
<link href="/go-prefix/static/cmpSwoPage.css" rel="stylesheet" type="text/css"/>
<link href="/go-prefix/static/default.css" rel="stylesheet" type="text/css"/>
<script src="/go-prefix/static/default.js" type="module"></script>
<!-- link href="/go-prefix/static/img/tux-favicon.png" rel="preload" as="image"/ -->
<!-- link href="/go-prefix/static/img/tkf-favicon-32x32.png" rel="preload" as="image"/ -->
</head>
<body id="body"><div style="position:absolute; top:0; left:0; right:0; bottom:0; border:0px solid black;">
<div id="topper" style="position:absolute; top:0; left:0; right:0; height:32px; border:0px solid grey; overflow:hidden;">
<table id="topperTab" cellpadding="0" cellspacing="0"><tr>
<td id="topperTabLeft">
&nbsp;
</td><td id="topperTabCenter">
<span>&nbsp;</span>
<span id="cmpSwoTaskList"></span>
</td><td id="topperTabRight">
<div id="user" class="headWord">USER</div>
</td>
</tr></table>
</div>
<div id="leftMenu">
</div>
<div id="mainRoot">
<!-- div id="mid" style="position:absolute; top:32px; left:150px; right:0; bottom:32px; border:1px solid grey;" -->
<div id="tblheadroot" style="position:absolute; top:0px; bottom:31px; left:0; right:12px;"></div>
<div id="tblbodyroot" style="position:absolute; top:32px; left:0; right:0; bottom:0; overflow:auto;"></div>
</div>
<div id="footer" style="position:absolute; left:0; right:0; bottom:0; height:32px; border:0px solid grey;">
<table cellpadding="0" cellspacing="0" style="vertical-align:top;"><tr>
<td style="width:33%; vertical-align:top;">
<div id="gitTitl" class="headWord">GIT</div>
<div id="gitDate" class="headWord">2022-99-99</div>
<div id="gitTime" class="headWord">99:99:99</div>
<div id="gitCHID" class="headWord">00000000</div>
<div id="gitComm" class="headWord">Just string</div>
</td><td style="width:33%; vertical-align:top; text-align:center;">
<div id="srvDate" class="headWord">2022-00-00</div>
<div id="srvTime" class="headWord">00:00:00</div>
<div id="srvRand" class="headWord"></div>
</td><td style="width:33%; vertical-align:top; text-align:right;">
<div id="oraLabs" class="headWord">Qwerty</div>
<div id="oraRole" class="headWord">NONE</div>
<div id="oraAddr" class="headWord">xxx.xxx.xx.xx</div>
<div id="oraUser" class="headWord">USER</div>
</td>
</tr></table>
</div>
</div></body>