diff --git a/README.md b/README.md index ccca502d..7a922786 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,20 @@ Simple command line based HTTP file server to share local file system. - Zero third party dependency ## Compile -Minimal required Go version is 1.18. +Minimal required Go version is 1.2. +Ensure this project is located at `GOPATH/src/mjpclab.dev/ghfs`. ```sh go build main.go ``` Will generate executable file "main" in current directory. +If default html template files under `src/tpl` changed, need to re-embed templates into go files: +```bash +cd src +make tpls +``` +Then compile the project like above. + ## Examples Start server on port 8080, root directory is current working directory: ```sh diff --git a/README.zh-CN.md b/README.zh-CN.md index a0f52762..66cf7593 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -18,12 +18,20 @@ - 零第三方依赖 ## 编译 -至少需要Go 1.18版本。 +至少需要Go 1.2版本。 +确保该项目位于 `GOPATH/src/mjpclab.dev/ghfs`。 ```sh go build main.go ``` 会在当前目录生成"main"可执行文件。 +如果修改过`src/tpl`下的默认html模板,需要将其重新嵌入go文件: +```bash +cd src +make tpls +``` +然后再像上面那样编译。 + ## 举例 在8080端口启动服务器,根目录为当前工作目录: ```sh diff --git a/build/build-all-by-docker.sh b/build/build-all-by-docker.sh index 30168d2b..3c9bb617 100755 --- a/build/build-all-by-docker.sh +++ b/build/build-all-by-docker.sh @@ -17,6 +17,7 @@ buildByDocker() { docker run \ --rm \ + --privileged \ -v "$prefix":"$ghfs" \ -e EX_UID="$(id -u)" \ -e EX_GID="$(id -g)" \ @@ -25,7 +26,8 @@ buildByDocker() { if [ -e /etc/apt/sources.list ]; then sed -i -e "s;://[^/ ]*;://mirrors.aliyun.com;" /etc/apt/sources.list; apt-get update; - apt-get install -yq git zip; + apt-get install -yq --force-yes git zip; + dpkg -i '"$ghfs"'/build/pkg/*.deb elif [ -e /etc/apt/sources.list.d/debian.sources ]; then sed -i -e "s;://[^/ ]*;://mirrors.aliyun.com;" /etc/apt/sources.list.d/debian.sources; apt-get update; @@ -42,24 +44,8 @@ buildByDocker() { "$@" } -gover=latest -buildByDocker "$gover" "${builds[@]}" - -#gover=1.24 -#builds=('darwin amd64 -11-big-sur' 'darwin arm64 -11-big-sur') -#buildByDocker "$gover" "${builds[@]}" - -#gover=1.22 -#builds=('darwin amd64 -10.15-catalina' 'darwin arm64 -10.15-catalina') -#buildByDocker "$gover" "${builds[@]}" - -gover=1.20 +gover=1.2 builds=() -builds+=('windows 386 -7-8' 'windows amd64 -7-8') -#builds+=('windows amd64,v2 -7-8' 'windows amd64,v3 -7-8') -#builds+=('darwin amd64 -10.13-high-sierra-10.14-mojave' 'darwin arm64 -10.13-high-sierra-10.14-mojave') +builds+=('windows 386 -2000') +#builds+=("${builds[@]}" 'freebsd 386 -8.x' 'freebsd amd64 -8.x') buildByDocker "$gover" "${builds[@]}" - -#gover=1.16 -#builds=('darwin amd64 -10.12-sierra' 'darwin arm64 -10.12-sierra') -#buildByDocker "$gover" "${builds[@]}" diff --git a/build/build.inc.sh b/build/build.inc.sh index 164869c2..5a325dc6 100755 --- a/build/build.inc.sh +++ b/build/build.inc.sh @@ -4,5 +4,5 @@ MAINNAME='ghfs' MOD=$(go list ../src/) source ./build.inc.version.sh getLdFlags() { - echo "-s -w -X $MOD/version.appVer=$VERSION -X $MOD/version.appArch=${ARCH:-$(go env GOARCH)}" + echo "-s -w" } diff --git a/build/build.sh b/build/build.sh index 05df53bf..a089e6a5 100755 --- a/build/build.sh +++ b/build/build.sh @@ -21,11 +21,23 @@ for build in "$@"; do fi OS_SUFFIX="${arg[2]}" + if [ -n "$GOLANG_VERSION" ]; then # in docker container + cd /usr/src/go/src/ + bash make.bash + cd - + fi; + + cp -r ../src/ /tmp/ + sed -i -e '/var appVer/s/"dev"/"'$VERSION'"/' /tmp/src/version/main.go + sed -i -e '/var appArch/s/runtime.GOARCH/"'$ARCH'"/' /tmp/src/version/main.go + mount --bind /tmp/src ../src + TMP=$(mktemp -d) echo "Building: $GOOS$OS_SUFFIX $ARCH" go build -ldflags "$(getLdFlags)" -o "$TMP/$MAINNAME$(go env GOEXE)" ../main.go cp ../LICENSE "$TMP" + cp ../src/shimgo/LICENSE_GO "$TMP" OUTFILE="$OUTDIR/$MAINNAME-$VERSION-$GOOS$OS_SUFFIX-$GOARCH$ARCH_OPT" if [ "$GOOS" == "windows" ]; then diff --git a/build/pkg/zip_3.0-8_amd64.deb b/build/pkg/zip_3.0-8_amd64.deb new file mode 100644 index 00000000..e20bddc1 Binary files /dev/null and b/build/pkg/zip_3.0-8_amd64.deb differ diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 00000000..6a43f361 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,16 @@ +define embedStr + sed -i -e '/= `/,/`/ { /`/!d }' $(1).go + sed -i -e '/= `/r$(1)' $(1).go + #sed -i -e '/= `/,/`/ { /`/! { /^\s*$$/d; s/^\s\s*// } }' $(1).go +endef + +define embedHex + sed -i -e '/= \[\]byte/,/\}/ { /[{}]/!d }' $(1).go + od -An -tx1 -w16 -v $(1) | sed -e 's/^\s*/\t/g' | sed -E -e 's/[0-9a-fA-F]+/0x&,/g' | sed -i -e '/= \[\]byte/r/dev/stdin' $(1).go +endef + +tpls: + $(call embedStr, tpl/defaultTheme/frontend/index.html) + $(call embedStr, tpl/defaultTheme/frontend/index.css) + $(call embedStr, tpl/defaultTheme/frontend/index.js) + $(call embedHex, tpl/defaultTheme/frontend/favicon.ico) diff --git a/src/app/main.go b/src/app/main.go index 6bfa5d46..2db7cc20 100644 --- a/src/app/main.go +++ b/src/app/main.go @@ -1,14 +1,11 @@ package app import ( - "context" "mjpclab.dev/ghfs/src/goVirtualHost" "mjpclab.dev/ghfs/src/param" "mjpclab.dev/ghfs/src/serverHandler" "mjpclab.dev/ghfs/src/serverLog" "mjpclab.dev/ghfs/src/tpl/theme" - "net/http" - "time" ) type App struct { @@ -18,14 +15,7 @@ type App struct { } func (app *App) Open() []error { - errs := app.vhostSvc.Open() - es := make([]error, 0, len(errs)) - for i := range errs { - if errs[i] != http.ErrServerClosed { - es = append(es, errs[i]) - } - } - return es + return app.vhostSvc.Open() } func (app *App) Close() { @@ -33,14 +23,6 @@ func (app *App) Close() { app.logMan.CloseFiles() } -func (app *App) Shutdown() { - ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100) - app.vhostSvc.Shutdown(ctx) - cancel() - - app.logMan.CloseFiles() -} - func (app *App) ReOpenLog() []error { return app.logMan.ReOpenFiles() } diff --git a/src/goNixArgParser/helper.go b/src/goNixArgParser/helper.go index 79d0f954..d32b38a5 100644 --- a/src/goNixArgParser/helper.go +++ b/src/goNixArgParser/helper.go @@ -1,7 +1,7 @@ package goNixArgParser import ( - "io" + "io/ioutil" "os" "regexp" ) @@ -79,7 +79,7 @@ func LoadConfigArgs(filename string) (args []string, err error) { defer file.Close() } - bytesConfig, err := io.ReadAll(file) + bytesConfig, err := ioutil.ReadAll(file) if err != nil { return nil, err } diff --git a/src/goNixArgParser/optionSet.go b/src/goNixArgParser/optionSet.go index 311b053c..1949e6ba 100644 --- a/src/goNixArgParser/optionSet.go +++ b/src/goNixArgParser/optionSet.go @@ -3,7 +3,7 @@ package goNixArgParser import ( "errors" "io" - "os" + "mjpclab.dev/ghfs/src/shimgo" "strings" ) @@ -155,11 +155,12 @@ func (s *OptionSet) Add(opt Option) error { } // redundant - env maps + for _, envVar := range option.EnvVars { if len(envVar) == 0 { continue } - envValue, hasEnv := os.LookupEnv(envVar) + envValue, hasEnv := shimgo.Os_LookupEnv(envVar) if !hasEnv { continue } diff --git a/src/goVirtualHost/serveable.go b/src/goVirtualHost/serveable.go index e222a453..806f14d0 100644 --- a/src/goVirtualHost/serveable.go +++ b/src/goVirtualHost/serveable.go @@ -1,8 +1,8 @@ package goVirtualHost import ( - "context" "crypto/tls" + "mjpclab.dev/ghfs/src/shimgo" "net/http" ) @@ -72,6 +72,9 @@ func (serveable *serveable) loadCertificates() (errs []error) { errs = append(errs, es...) } + es := serveable.updateHttpServerTLSConfig() + errs = append(errs, es...) + return } @@ -80,12 +83,17 @@ func (serveable *serveable) updateHttpServerTLSConfig() (errs []error) { return } + certs := make([]tls.Certificate, 0, len(serveable.vhosts)) + for _, vh := range serveable.vhosts { + for _, cert := range vh.loadedCerts { + certs = append(certs, *cert) + } + } + serveable.server.TLSConfig = &tls.Config{ - GetCertificate: func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { - vh := serveable.lookupVhost(hello.ServerName) - return vh.lookupCertificate(hello) - }, + Certificates: certs, } + serveable.server.TLSConfig.BuildNameToCertificate() return } @@ -94,22 +102,17 @@ func (serveable *serveable) init() (errs []error) { serveable.updateDefaultVhost() serveable.updateHttpServerHandler() errs = serveable.loadCertificates() - serveable.updateHttpServerTLSConfig() return } func (serveable *serveable) open(l *listenable) error { if serveable.useTLS { - return serveable.server.ServeTLS(l.listener, "", "") + return shimgo.Net_Http_Server_ServeTLS(serveable.server, l.listener, "", "") } else { return serveable.server.Serve(l.listener) } } -func (serveable *serveable) shutdown(ctx context.Context) error { - return serveable.server.Shutdown(ctx) -} - func (serveable *serveable) close() error { - return serveable.server.Close() + return nil } diff --git a/src/goVirtualHost/service.go b/src/goVirtualHost/service.go index ca435cd1..f87b6fe4 100644 --- a/src/goVirtualHost/service.go +++ b/src/goVirtualHost/service.go @@ -1,7 +1,6 @@ package goVirtualHost import ( - "context" "errors" "sync" ) @@ -143,31 +142,6 @@ func (svc *Service) ReloadCertificates() (errs []error) { return } -func (svc *Service) Shutdown(ctx context.Context) { - svc.mu.Lock() - if svc.state >= stateClosed { - svc.mu.Unlock() - return - } - svc.state = stateClosed - svc.mu.Unlock() - - wg := &sync.WaitGroup{} - for _, lis := range svc.listenables { - l := lis - - wg.Add(1) - go func() { - if l.serveable != nil { - l.serveable.shutdown(ctx) - } - l.close() - wg.Done() - }() - } - wg.Wait() -} - func (svc *Service) Close() { svc.mu.Lock() if svc.state >= stateClosed { diff --git a/src/goVirtualHost/util.go b/src/goVirtualHost/util.go index b1b0db72..5ecd69ed 100644 --- a/src/goVirtualHost/util.go +++ b/src/goVirtualHost/util.go @@ -1,6 +1,7 @@ package goVirtualHost import ( + "mjpclab.dev/ghfs/src/shimgo" "net" "sort" "strings" @@ -29,7 +30,7 @@ func extractHostName(host string) string { } } - colonIndex := strings.LastIndexByte(host, ':') + colonIndex := shimgo.Strings_LastIndexByte(host, ':') if colonIndex >= 0 { return host[:colonIndex] } @@ -104,7 +105,7 @@ func splitListen(listen string, useTLS bool) (l43proto, ip, port string) { } colonIndex := strings.IndexByte(listen, ':') - lastColonIndex := strings.LastIndexByte(listen, ':') + lastColonIndex := shimgo.Strings_LastIndexByte(listen, ':') // ipv6 squareEnd := strings.IndexByte(listen, ']') @@ -129,7 +130,7 @@ func splitListen(listen string, useTLS bool) (l43proto, ip, port string) { dotIndex2 := dotIndex1 + 1 + strings.IndexByte(listen[dotIndex1+1:], '.') dotIndex3 := dotIndex2 + 1 + strings.IndexByte(listen[dotIndex2+1:], '.') dotIndex4 := dotIndex3 + 1 + strings.IndexByte(listen[dotIndex3+1:], '.') - lastDotIndex := strings.LastIndexByte(listen, '.') + lastDotIndex := shimgo.Strings_LastIndexByte(listen, '.') isIPv4 := dotIndex1 > 0 && dotIndex2 > dotIndex1 && dotIndex3 > dotIndex2 && dotIndex4 == dotIndex3 && colonIndex == lastColonIndex && (lastColonIndex == -1 || lastColonIndex > lastDotIndex+1) diff --git a/src/goVirtualHost/vhost.go b/src/goVirtualHost/vhost.go index e5f3a09c..7cccf052 100644 --- a/src/goVirtualHost/vhost.go +++ b/src/goVirtualHost/vhost.go @@ -1,9 +1,6 @@ package goVirtualHost import ( - "crypto/tls" - "crypto/x509" - "errors" "net/http" "strings" ) @@ -49,36 +46,3 @@ func (vh *vhost) loadCertificates() []error { return errs } - -func (vh *vhost) lookupCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { - certLen := len(vh.loadedCerts) - if certLen == 1 { - return vh.loadedCerts[0], nil - } - - for _, cert := range vh.loadedCerts { - err := hello.SupportsCertificate(cert) - if err == nil { - return cert, err - } - } - - for _, cert := range vh.loadedCerts { - if cert.Leaf == nil { - cert.Leaf, _ = x509.ParseCertificate(cert.Certificate[0]) - if cert.Leaf == nil { - continue - } - } - err := cert.Leaf.VerifyHostname(hello.ServerName) - if err == nil { - return cert, err - } - } - - if certLen > 0 { - return vh.loadedCerts[0], nil - } - - return nil, errors.New("cannot find proper certificate for " + hello.ServerName) -} diff --git a/src/serverHandler/archive.go b/src/serverHandler/archive.go index 4136705b..e181a1ca 100644 --- a/src/serverHandler/archive.go +++ b/src/serverHandler/archive.go @@ -1,9 +1,9 @@ package serverHandler import ( + "mjpclab.dev/ghfs/src/shimgo" "mjpclab.dev/ghfs/src/util" "net/http" - "net/url" "os" "path" "strings" @@ -52,13 +52,6 @@ func (h *aliasHandler) visitTreeNode( childSelections []string, archiveCallback archiveCallback, ) { - select { - case <-r.Context().Done(): - return - default: - break - } - needAuth, _ := h.needAuth("", urlPath, fsPath) userId, _, err := h.verifyAuth(r, urlPath, fsPath) if needAuth && err != nil { @@ -179,7 +172,7 @@ func (h *aliasHandler) archiveFiles( } func writeArchiveHeader(w http.ResponseWriter, contentType, filename string) { - filename = url.PathEscape(filename) + filename = shimgo.Net_Url_PathEscape(filename) header := w.Header() header.Set("Content-Type", contentType) diff --git a/src/serverHandler/auth.go b/src/serverHandler/auth.go index 0f1a393b..8a58bfd5 100644 --- a/src/serverHandler/auth.go +++ b/src/serverHandler/auth.go @@ -2,6 +2,7 @@ package serverHandler import ( "errors" + "mjpclab.dev/ghfs/src/shimgo" "net/http" "net/url" "strings" @@ -34,7 +35,7 @@ func (h *aliasHandler) notifyAuth(w http.ResponseWriter) { } func (h *aliasHandler) verifyAuth(r *http.Request, vhostReqPath, reqFsPath string) (authUserId int, authUserName string, err error) { - inputUser, inputPass, hasAuthReq := r.BasicAuth() + inputUser, inputPass, hasAuthReq := shimgo.Net_Http_BasicAuth(r) if hasAuthReq { userid, username, success := h.users.Auth(inputUser, inputPass) @@ -60,7 +61,7 @@ func (h *aliasHandler) redirectWithoutRequestAuth(w http.ResponseWriter, r *http index := strings.Index(r.URL.RawQuery, authQueryParam+"=") if index >= 0 { returnUrl = r.URL.RawQuery[index+len(authQueryParam)+1:] - index = strings.LastIndexByte(returnUrl, '&') + index = shimgo.Strings_LastIndexByte(returnUrl, '&') if index >= 0 { returnUrl = returnUrl[:index] } diff --git a/src/serverHandler/content.go b/src/serverHandler/content.go index 5d9dcf55..7e1f0681 100644 --- a/src/serverHandler/content.go +++ b/src/serverHandler/content.go @@ -1,8 +1,8 @@ package serverHandler import ( + "mjpclab.dev/ghfs/src/shimgo" "net/http" - "net/url" ) func (h *aliasHandler) content(w http.ResponseWriter, r *http.Request, session *sessionContext, data *responseData) { @@ -10,7 +10,7 @@ func (h *aliasHandler) content(w http.ResponseWriter, r *http.Request, session * header.Set("Vary", session.vary) header.Set("X-Content-Type-Options", "nosniff") if data.IsDownload { - filename := url.PathEscape(data.ItemName) + filename := shimgo.Net_Url_PathEscape(data.ItemName) header.Set("Content-Disposition", "attachment; filename="+filename+"; filename*=UTF-8''"+filename) } diff --git a/src/serverHandler/log.go b/src/serverHandler/log.go index 0ec83de0..eb11a22e 100644 --- a/src/serverHandler/log.go +++ b/src/serverHandler/log.go @@ -2,9 +2,9 @@ package serverHandler import ( "mjpclab.dev/ghfs/src/serverLog" + "mjpclab.dev/ghfs/src/shimgo" "mjpclab.dev/ghfs/src/util" "net/http" - "net/url" "strconv" ) @@ -24,7 +24,7 @@ func logRequest(logger *serverLog.Logger, r *http.Request, statusCode int) { var unescapedUri []byte unescapedLen := 0 - unescapedStr, err := url.PathUnescape(r.RequestURI) + unescapedStr, err := shimgo.Net_Url_PathUnescape(r.RequestURI) if err == nil && unescapedStr != r.RequestURI { unescapedUri = util.EscapeControllingRune(unescapedStr) if len(unescapedUri) > 0 { diff --git a/src/serverHandler/mutate.go b/src/serverHandler/mutate.go index 6cdb385c..d56acc4e 100644 --- a/src/serverHandler/mutate.go +++ b/src/serverHandler/mutate.go @@ -1,11 +1,12 @@ package serverHandler import ( + "mjpclab.dev/ghfs/src/shimgo" "net/http" ) func (h *aliasHandler) mutate(w http.ResponseWriter, r *http.Request, session *sessionContext, data *responseData) (ok bool) { - if r.Method != http.MethodPost { + if r.Method != shimgo.Net_Http_MethodPost { data.Status = http.StatusMethodNotAllowed return } diff --git a/src/serverHandler/pathTransformHandler.go b/src/serverHandler/pathTransformHandler.go index 240a8b3b..af535594 100644 --- a/src/serverHandler/pathTransformHandler.go +++ b/src/serverHandler/pathTransformHandler.go @@ -28,7 +28,10 @@ func (transformer pathTransformHandler) ServeHTTP(w http.ResponseWriter, r *http } else { urlPathDir = urlPath } - r.URL.RawPath = urlPathDir + r.RequestURI = urlPathDir + if len(r.URL.RawQuery) > 0 { + r.RequestURI += "?" + r.URL.RawQuery + } if len(transformer.prefixes) == 0 { r.URL.Path = urlPathDir diff --git a/src/serverHandler/pathValues.go b/src/serverHandler/pathValues.go index 221196ad..8822e9b6 100644 --- a/src/serverHandler/pathValues.go +++ b/src/serverHandler/pathValues.go @@ -4,26 +4,26 @@ package serverHandler type prefixFilter func(whole, prefix string) bool -// pathValues +// pathInts -type pathValues[T any] struct { +type pathInts struct { path string - values []T + values []int } -type pathValuesList[T any] []pathValues[T] +type pathIntsList []pathInts -func (list pathValuesList[T]) mergePrefixMatched(mergeWith []T, matchPrefix prefixFilter, refPath string) []T { - var result []T +func (list pathIntsList) mergePrefixMatched(mergeWith []int, matchPrefix prefixFilter, refPath string) []int { + var result []int if mergeWith != nil { - result = make([]T, len(mergeWith)) + result = make([]int, len(mergeWith)) copy(result, mergeWith) } for i := range list { if matchPrefix(refPath, list[i].path) { if result == nil { - result = []T{} + result = []int{} } result = append(result, list[i].values...) } @@ -36,8 +36,8 @@ func (list pathValuesList[T]) mergePrefixMatched(mergeWith []T, matchPrefix pref } } -func (list pathValuesList[T]) filterSuccessor(includeSelfPredecessor bool, matchPrefix prefixFilter, refPath string) pathValuesList[T] { - var result pathValuesList[T] +func (list pathIntsList) filterSuccessor(includeSelfPredecessor bool, matchPrefix prefixFilter, refPath string) pathIntsList { + var result pathIntsList for i := range list { if len(list[i].path) <= len(refPath) { @@ -56,20 +56,109 @@ func (list pathValuesList[T]) filterSuccessor(includeSelfPredecessor bool, match } } -// pathInts +// pathStrings -type pathInts = pathValues[int] -type pathIntsList = pathValuesList[int] +type pathStrings struct { + path string + values []string +} -// pathStrings +type pathStringsList []pathStrings + +func (list pathStringsList) mergePrefixMatched(mergeWith []string, matchPrefix prefixFilter, refPath string) []string { + var result []string + if mergeWith != nil { + result = make([]string, len(mergeWith)) + copy(result, mergeWith) + } + + for i := range list { + if matchPrefix(refPath, list[i].path) { + if result == nil { + result = []string{} + } + result = append(result, list[i].values...) + } + } + + if mergeWith != nil && len(mergeWith) == len(result) { + return mergeWith + } else { + return result + } +} -type pathStrings = pathValues[string] -type pathStringsList = pathValuesList[string] +func (list pathStringsList) filterSuccessor(includeSelfPredecessor bool, matchPrefix prefixFilter, refPath string) pathStringsList { + var result pathStringsList + + for i := range list { + if len(list[i].path) <= len(refPath) { + if includeSelfPredecessor && matchPrefix(refPath, list[i].path) { + result = append(result, list[i]) + } + } else if matchPrefix(list[i].path, refPath) { + result = append(result, list[i]) + } + } + + if len(list) == len(result) { + return list + } else { + return result + } +} // pathHeaders -type pathHeaders = pathValues[[2]string] -type pathHeadersList = pathValuesList[[2]string] +type pathHeaders struct { + path string + values [][2]string +} + +type pathHeadersList []pathHeaders + +func (list pathHeadersList) mergePrefixMatched(mergeWith [][2]string, matchPrefix prefixFilter, refPath string) [][2]string { + var result [][2]string + if mergeWith != nil { + result = make([][2]string, len(mergeWith)) + copy(result, mergeWith) + } + + for i := range list { + if matchPrefix(refPath, list[i].path) { + if result == nil { + result = [][2]string{} + } + result = append(result, list[i].values...) + } + } + + if mergeWith != nil && len(mergeWith) == len(result) { + return mergeWith + } else { + return result + } +} + +func (list pathHeadersList) filterSuccessor(includeSelfPredecessor bool, matchPrefix prefixFilter, refPath string) pathHeadersList { + var result pathHeadersList + + for i := range list { + if len(list[i].path) <= len(refPath) { + if includeSelfPredecessor && matchPrefix(refPath, list[i].path) { + result = append(result, list[i]) + } + } else if matchPrefix(list[i].path, refPath) { + result = append(result, list[i]) + } + } + + if len(list) == len(result) { + return list + } else { + return result + } +} // []string diff --git a/src/serverHandler/preprocessHandler.go b/src/serverHandler/preprocessHandler.go index 43364468..2019447b 100644 --- a/src/serverHandler/preprocessHandler.go +++ b/src/serverHandler/preprocessHandler.go @@ -5,6 +5,7 @@ import ( "mjpclab.dev/ghfs/src/serverCompress" "mjpclab.dev/ghfs/src/serverLog" "net/http" + "strings" ) type preprocessHandler struct { @@ -20,9 +21,13 @@ func (pph preprocessHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { rw := serverCompress.NewResponseWriter(w, r) if len(pph.preMiddlewares) > 0 { + prefixReqPath := r.RequestURI // init by pathTransformHandler + if qsIndex := strings.IndexByte(prefixReqPath, '?'); qsIndex >= 0 { + prefixReqPath = prefixReqPath[:qsIndex] + } status := 0 middlewareContext := &middleware.Context{ - PrefixReqPath: r.URL.RawPath, // init by pathTransformHandler + PrefixReqPath: prefixReqPath, VhostReqPath: r.URL.Path, Logger: pph.logger, Status: &status, diff --git a/src/serverHandler/sessionData.go b/src/serverHandler/sessionData.go index 6cf61d6b..3cf6d818 100644 --- a/src/serverHandler/sessionData.go +++ b/src/serverHandler/sessionData.go @@ -4,6 +4,7 @@ import ( "html/template" "mjpclab.dev/ghfs/src/acceptHeaders" "mjpclab.dev/ghfs/src/i18n" + "mjpclab.dev/ghfs/src/shimgo" "mjpclab.dev/ghfs/src/util" "net/http" "os" @@ -348,7 +349,11 @@ func dereferenceSymbolLinks(reqFsPath string, subItems []os.FileInfo) (errs []er func (h *aliasHandler) getSessionData(r *http.Request) (session *sessionContext, data *responseData) { var errs []error - prefixReqPath := r.URL.RawPath // init by pathTransformHandler + prefixReqPath := r.RequestURI // init by pathTransformHandler + if qsIndex := strings.IndexByte(prefixReqPath, '?'); qsIndex >= 0 { + prefixReqPath = prefixReqPath[:qsIndex] + } + vhostReqPath := r.URL.Path tailSlash := vhostReqPath[len(vhostReqPath)-1] == '/' @@ -383,7 +388,7 @@ func (h *aliasHandler) getSessionData(r *http.Request) (session *sessionContext, isSimple = true case strings.HasPrefix(rawQuery, "download"): isDownload = true - case strings.HasPrefix(rawQuery, "upload") && r.Method == http.MethodPost: + case strings.HasPrefix(rawQuery, "upload") && r.Method == shimgo.Net_Http_MethodPost: isUpload = true isMutate = true case strings.HasPrefix(rawQuery, "mkdir"): diff --git a/src/serverHandler/sort.go b/src/serverHandler/sort.go index bc5f51b5..1b9869f3 100644 --- a/src/serverHandler/sort.go +++ b/src/serverHandler/sort.go @@ -1,7 +1,7 @@ package serverHandler import ( - "bytes" + "mjpclab.dev/ghfs/src/shimgo" "mjpclab.dev/ghfs/src/util" "os" "sort" @@ -81,8 +81,8 @@ func (xInfos infosNames) LessFileType(i, j int) (less, ok bool) { bufferI := xInfos.names[i] bufferJ := xInfos.names[j] for { - dotIndexI := bytes.LastIndexByte(bufferI, '.') - dotIndexJ := bytes.LastIndexByte(bufferJ, '.') + dotIndexI := shimgo.Bytes_LastIndexByte(bufferI, '.') + dotIndexJ := shimgo.Bytes_LastIndexByte(bufferJ, '.') if dotIndexI < 0 && dotIndexJ < 0 { break } diff --git a/src/serverHandler/upload.go b/src/serverHandler/upload.go index 87bc3f08..a04a533e 100644 --- a/src/serverHandler/upload.go +++ b/src/serverHandler/upload.go @@ -5,6 +5,7 @@ import ( "io" "mime" "mime/multipart" + "mjpclab.dev/ghfs/src/shimgo" "mjpclab.dev/ghfs/src/util" "net/http" "os" @@ -81,7 +82,7 @@ func (h *aliasHandler) saveUploadFiles(authUserName, fsPrefix string, createDir, continue } - filenameIndex := strings.LastIndexByte(partFilePath, '/') + filenameIndex := shimgo.Strings_LastIndexByte(partFilePath, '/') fsInfix := "" formname := part.FormName() diff --git a/src/serverHandler/util.go b/src/serverHandler/util.go index 38564e39..a9365fb0 100644 --- a/src/serverHandler/util.go +++ b/src/serverHandler/util.go @@ -1,6 +1,7 @@ package serverHandler import ( + "mjpclab.dev/ghfs/src/shimgo" "mjpclab.dev/ghfs/src/user" "mjpclab.dev/ghfs/src/util" "net/http" @@ -53,7 +54,7 @@ func wildcardToRegexp(wildcards []string) (*regexp.Regexp, error) { } func getRedirectCode(r *http.Request) int { - if r.Method == http.MethodPost { + if r.Method == shimgo.Net_Http_MethodPost { return http.StatusTemporaryRedirect } else { return http.StatusMovedPermanently @@ -61,14 +62,14 @@ func getRedirectCode(r *http.Request) int { } func NeedResponseBody(method string) bool { - return method != http.MethodHead && - method != http.MethodOptions && - method != http.MethodConnect && - method != http.MethodTrace + return method != shimgo.Net_Http_MethodHead && + method != shimgo.Net_Http_MethodOptions && + method != shimgo.Net_Http_MethodConnect && + method != shimgo.Net_Http_MethodTrace } func lacksHeader(header http.Header, key string) bool { - return len(header.Values(key)) == 0 + return len(header.Get(key)) == 0 } func getCleanFilePath(requestPath string) (filePath string, ok bool) { diff --git a/src/shimgo/LICENSE_GO b/src/shimgo/LICENSE_GO new file mode 100644 index 00000000..6a66aea5 --- /dev/null +++ b/src/shimgo/LICENSE_GO @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/shimgo/net_http.go b/src/shimgo/net_http.go new file mode 100644 index 00000000..6fe648ae --- /dev/null +++ b/src/shimgo/net_http.go @@ -0,0 +1,75 @@ +package shimgo + +import ( + "crypto/tls" + "encoding/base64" + "net" + "net/http" + "strings" +) + +const ( + Net_Http_MethodGet = "GET" + Net_Http_MethodHead = "HEAD" + Net_Http_MethodPost = "POST" + Net_Http_MethodPut = "PUT" + Net_Http_MethodPatch = "PATCH" // RFC 5789 + Net_Http_MethodDelete = "DELETE" + Net_Http_MethodConnect = "CONNECT" + Net_Http_MethodOptions = "OPTIONS" + Net_Http_MethodTrace = "TRACE" +) + +func Net_Http_Server_ServeTLS(srv *http.Server, l net.Listener, certFile, keyFile string) error { + addr := srv.Addr + if addr == "" { + addr = ":https" + } + config := &tls.Config{} + if srv.TLSConfig != nil { + *config = *srv.TLSConfig + } + if config.NextProtos == nil { + config.NextProtos = []string{"http/1.1"} + } + + if len(config.Certificates) == 0 { + var err error + config.Certificates = make([]tls.Certificate, 1) + config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return err + } + } + + tlsListener := tls.NewListener(l, config) + return srv.Serve(tlsListener) +} + +func Net_Http_BasicAuth(r *http.Request) (username, password string, ok bool) { + auth := r.Header.Get("Authorization") + if auth == "" { + return + } + return net_http_parseBasicAuth(auth) +} + +// parseBasicAuth parses an HTTP Basic Authentication string. +// "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true). +func net_http_parseBasicAuth(auth string) (username, password string, ok bool) { + const prefix = "Basic " + // Case insensitive prefix match. See Issue 22736. + if len(auth) < len(prefix) || !strings.EqualFold(auth[:len(prefix)], prefix) { + return + } + c, err := base64.StdEncoding.DecodeString(auth[len(prefix):]) + if err != nil { + return + } + cs := string(c) + s := strings.IndexByte(cs, ':') + if s < 0 { + return + } + return cs[:s], cs[s+1:], true +} diff --git a/src/shimgo/net_url.go b/src/shimgo/net_url.go new file mode 100644 index 00000000..87eb5b2a --- /dev/null +++ b/src/shimgo/net_url.go @@ -0,0 +1,283 @@ +package shimgo + +import ( + "bytes" + "strconv" +) + +type Net_Url_EscapeError string + +func (e Net_Url_EscapeError) Error() string { + return "invalid URL escape " + strconv.Quote(string(e)) +} + +type Net_Url_InvalidHostError string + +func (e Net_Url_InvalidHostError) Error() string { + return "invalid character " + strconv.Quote(string(e)) + " in host name" +} + +type net_url_encoding int + +const ( + net_url_encodePath net_url_encoding = 1 + iota + net_url_encodePathSegment + net_url_encodeHost + net_url_encodeZone + net_url_encodeUserPassword + net_url_encodeQueryComponent + net_url_encodeFragment +) +const net_url_upperhex = "0123456789ABCDEF" + +func net_url_ishex(c byte) bool { + switch { + case '0' <= c && c <= '9': + return true + case 'a' <= c && c <= 'f': + return true + case 'A' <= c && c <= 'F': + return true + } + return false +} + +func net_url_unhex(c byte) byte { + switch { + case '0' <= c && c <= '9': + return c - '0' + case 'a' <= c && c <= 'f': + return c - 'a' + 10 + case 'A' <= c && c <= 'F': + return c - 'A' + 10 + } + return 0 +} + +func Net_Url_PathEscape(s string) string { + return net_url_escape(s, net_url_encodePathSegment) +} + +func net_url_escape(s string, mode net_url_encoding) string { + spaceCount, hexCount := 0, 0 + for i := 0; i < len(s); i++ { + c := s[i] + if net_url_shouldEscape(c, mode) { + if c == ' ' && mode == net_url_encodeQueryComponent { + spaceCount++ + } else { + hexCount++ + } + } + } + + if spaceCount == 0 && hexCount == 0 { + return s + } + + var buf [64]byte + var t []byte + + required := len(s) + 2*hexCount + if required <= len(buf) { + t = buf[:required] + } else { + t = make([]byte, required) + } + + if hexCount == 0 { + copy(t, s) + for i := 0; i < len(s); i++ { + if s[i] == ' ' { + t[i] = '+' + } + } + return string(t) + } + + j := 0 + for i := 0; i < len(s); i++ { + switch c := s[i]; { + case c == ' ' && mode == net_url_encodeQueryComponent: + t[j] = '+' + j++ + case net_url_shouldEscape(c, mode): + t[j] = '%' + t[j+1] = net_url_upperhex[c>>4] + t[j+2] = net_url_upperhex[c&15] + j += 3 + default: + t[j] = s[i] + j++ + } + } + return string(t) +} + +// Return true if the specified character should be escaped when +// appearing in a URL string, according to RFC 3986. +// +// Please be informed that for now shouldEscape does not check all +// reserved characters correctly. See golang.org/issue/5684. +func net_url_shouldEscape(c byte, mode net_url_encoding) bool { + // §2.3 Unreserved characters (alphanum) + if 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9' { + return false + } + + if mode == net_url_encodeHost || mode == net_url_encodeZone { + // §3.2.2 Host allows + // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" + // as part of reg-name. + // We add : because we include :port as part of host. + // We add [ ] because we include [ipv6]:port as part of host. + // We add < > because they're the only characters left that + // we could possibly allow, and Parse will reject them if we + // escape them (because hosts can't use %-encoding for + // ASCII bytes). + switch c { + case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']', '<', '>', '"': + return false + } + } + + switch c { + case '-', '_', '.', '~': // §2.3 Unreserved characters (mark) + return false + + case '$', '&', '+', ',', '/', ':', ';', '=', '?', '@': // §2.2 Reserved characters (reserved) + // Different sections of the URL allow a few of + // the reserved characters to appear unescaped. + switch mode { + case net_url_encodePath: // §3.3 + // The RFC allows : @ & = + $ but saves / ; , for assigning + // meaning to individual path segments. This package + // only manipulates the path as a whole, so we allow those + // last three as well. That leaves only ? to escape. + return c == '?' + + case net_url_encodePathSegment: // §3.3 + // The RFC allows : @ & = + $ but saves / ; , for assigning + // meaning to individual path segments. + return c == '/' || c == ';' || c == ',' || c == '?' + + case net_url_encodeUserPassword: // §3.2.1 + // The RFC allows ';', ':', '&', '=', '+', '$', and ',' in + // userinfo, so we must escape only '@', '/', and '?'. + // The parsing of userinfo treats ':' as special so we must escape + // that too. + return c == '@' || c == '/' || c == '?' || c == ':' + + case net_url_encodeQueryComponent: // §3.4 + // The RFC reserves (so we must escape) everything. + return true + + case net_url_encodeFragment: // §4.1 + // The RFC text is silent but the grammar allows + // everything, so escape nothing. + return false + } + } + + if mode == net_url_encodeFragment { + // RFC 3986 §2.2 allows not escaping sub-delims. A subset of sub-delims are + // included in reserved from RFC 2396 §2.2. The remaining sub-delims do not + // need to be escaped. To minimize potential breakage, we apply two restrictions: + // (1) we always escape sub-delims outside of the fragment, and (2) we always + // escape single quote to avoid breaking callers that had previously assumed that + // single quotes would be escaped. See issue #19917. + switch c { + case '!', '(', ')', '*': + return false + } + } + + // Everything else must be escaped. + return true +} + +// PathUnescape does the inverse transformation of PathEscape, +// converting each 3-byte encoded substring of the form "%AB" into the +// hex-decoded byte 0xAB. It returns an error if any % is not followed +// by two hexadecimal digits. +// +// PathUnescape is identical to QueryUnescape except that it does not +// unescape '+' to ' ' (space). +func Net_Url_PathUnescape(s string) (string, error) { + return unescape(s, net_url_encodePathSegment) +} + +// unescape unescapes a string; the mode specifies +// which section of the URL string is being unescaped. +func unescape(s string, mode net_url_encoding) (string, error) { + // Count %, check that they're well-formed. + n := 0 + hasPlus := false + for i := 0; i < len(s); { + switch s[i] { + case '%': + n++ + if i+2 >= len(s) || !net_url_ishex(s[i+1]) || !net_url_ishex(s[i+2]) { + s = s[i:] + if len(s) > 3 { + s = s[:3] + } + return "", Net_Url_EscapeError(s) + } + // Per https://tools.ietf.org/html/rfc3986#page-21 + // in the host component %-encoding can only be used + // for non-ASCII bytes. + // But https://tools.ietf.org/html/rfc6874#section-2 + // introduces %25 being allowed to escape a percent sign + // in IPv6 scoped-address literals. Yay. + if mode == net_url_encodeHost && net_url_unhex(s[i+1]) < 8 && s[i:i+3] != "%25" { + return "", Net_Url_EscapeError(s[i : i+3]) + } + if mode == net_url_encodeZone { + // RFC 6874 says basically "anything goes" for zone identifiers + // and that even non-ASCII can be redundantly escaped, + // but it seems prudent to restrict %-escaped bytes here to those + // that are valid host name bytes in their unescaped form. + // That is, you can use escaping in the zone identifier but not + // to introduce bytes you couldn't just write directly. + // But Windows puts spaces here! Yay. + v := net_url_unhex(s[i+1])<<4 | net_url_unhex(s[i+2]) + if s[i:i+3] != "%25" && v != ' ' && net_url_shouldEscape(v, net_url_encodeHost) { + return "", Net_Url_EscapeError(s[i : i+3]) + } + } + i += 3 + case '+': + hasPlus = mode == net_url_encodeQueryComponent + i++ + default: + if (mode == net_url_encodeHost || mode == net_url_encodeZone) && s[i] < 0x80 && net_url_shouldEscape(s[i], mode) { + return "", Net_Url_InvalidHostError(s[i : i+1]) + } + i++ + } + } + + if n == 0 && !hasPlus { + return s, nil + } + + var t bytes.Buffer + t.Grow(len(s) - 2*n) + for i := 0; i < len(s); i++ { + switch s[i] { + case '%': + t.WriteByte(net_url_unhex(s[i+1])<<4 | net_url_unhex(s[i+2])) + i += 2 + case '+': + if mode == net_url_encodeQueryComponent { + t.WriteByte(' ') + } else { + t.WriteByte('+') + } + default: + t.WriteByte(s[i]) + } + } + return t.String(), nil +} diff --git a/src/shimgo/shim.go b/src/shimgo/shim.go new file mode 100644 index 00000000..7e492b95 --- /dev/null +++ b/src/shimgo/shim.go @@ -0,0 +1,18 @@ +package shimgo + +import ( + "syscall" +) + +func Bytes_LastIndexByte(s []byte, c byte) int { + for i := len(s) - 1; i >= 0; i-- { + if s[i] == c { + return i + } + } + return -1 +} + +func Os_LookupEnv(key string) (string, bool) { + return syscall.Getenv(key) +} diff --git a/src/shimgo/strings.go b/src/shimgo/strings.go new file mode 100644 index 00000000..ac05e2e2 --- /dev/null +++ b/src/shimgo/strings.go @@ -0,0 +1,10 @@ +package shimgo + +func Strings_LastIndexByte(s string, c byte) int { + for i := len(s) - 1; i >= 0; i-- { + if s[i] == c { + return i + } + } + return -1 +} diff --git a/src/shimgo/time.go b/src/shimgo/time.go new file mode 100644 index 00000000..02ef6257 --- /dev/null +++ b/src/shimgo/time.go @@ -0,0 +1,8 @@ +package shimgo + +import "time" + +func Time_AppendFormat(t time.Time, b []byte, layout string) []byte { + formatted := t.Format(layout) + return append(b, []byte(formatted)...) +} diff --git a/src/signal.go b/src/signal.go index 6aa80155..a120962e 100644 --- a/src/signal.go +++ b/src/signal.go @@ -14,7 +14,7 @@ func cleanupOnEnd(appInst *app.App) { go func() { <-chSignal - appInst.Shutdown() + appInst.Close() }() } @@ -23,15 +23,15 @@ func reInitOnHup(appInst *app.App) { signal.Notify(chSignal, syscall.SIGHUP) go func() { - for range chSignal { + for _ = range chSignal { errs := appInst.ReOpenLog() if serverError.CheckError(errs...) { - appInst.Shutdown() + appInst.Close() break } errs = appInst.ReLoadCertificates() if serverError.CheckError(errs...) { - appInst.Shutdown() + appInst.Close() break } } diff --git a/src/tpl/defaultTheme/defaultTheme.go b/src/tpl/defaultTheme/defaultTheme.go index 7e3f206b..f897a5d4 100644 --- a/src/tpl/defaultTheme/defaultTheme.go +++ b/src/tpl/defaultTheme/defaultTheme.go @@ -2,35 +2,24 @@ package defaultTheme import ( "bytes" - _ "embed" + "mjpclab.dev/ghfs/src/tpl/defaultTheme/frontend" "mjpclab.dev/ghfs/src/tpl/theme" + "strings" ) -//go:embed frontend/index.html -var defaultTplStr string - -//go:embed frontend/index.css -var defaultCss []byte - -//go:embed frontend/index.js -var defaultJs []byte - -//go:embed frontend/favicon.ico -var defaultFavicon []byte - var DefaultTheme theme.MemTheme func init() { var err error - DefaultTheme.Template, err = theme.ParsePageTpl(defaultTplStr) + DefaultTheme.Template, err = theme.ParsePageTpl(frontend.DefaultTplStr) if err != nil { DefaultTheme.Template, _ = theme.ParsePageTpl("Builtin Template Error") } DefaultTheme.Assets = theme.Assets{ - {"index.css", "text/css; charset=utf-8", bytes.NewReader(defaultCss)}, - {"index.js", "application/javascript; charset=utf-8", bytes.NewReader(defaultJs)}, - {"favicon.ico", "image/x-icon", bytes.NewReader(defaultFavicon)}, + {"index.css", "text/css; charset=utf-8", strings.NewReader(frontend.DefaultCss)}, + {"index.js", "application/javascript; charset=utf-8", strings.NewReader(frontend.DefaultJs)}, + {"favicon.ico", "image/x-icon", bytes.NewReader(frontend.DefaultFavicon)}, } } diff --git a/src/tpl/defaultTheme/frontend/favicon.ico.go b/src/tpl/defaultTheme/frontend/favicon.ico.go new file mode 100644 index 00000000..47f62b07 --- /dev/null +++ b/src/tpl/defaultTheme/frontend/favicon.ico.go @@ -0,0 +1,341 @@ +package frontend + +var DefaultFavicon = []byte{ + 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x20, 0x20, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0xa8, 0x08, + 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0xc8, 0x06, + 0x00, 0x00, 0xde, 0x08, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x68, 0x05, + 0x00, 0x00, 0xa6, 0x0f, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0x00, 0x80, 0x80, + 0x80, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, + 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x08, 0x08, + 0x08, 0x00, 0x17, 0x17, 0x17, 0x00, 0x27, 0x27, 0x27, 0x00, 0x37, 0x37, 0x37, 0x00, 0x47, 0x47, + 0x47, 0x00, 0x57, 0x57, 0x57, 0x00, 0x67, 0x67, 0x67, 0x00, 0x77, 0x77, 0x77, 0x00, 0x87, 0x87, + 0x87, 0x00, 0x97, 0x97, 0x97, 0x00, 0xa7, 0xa7, 0xa7, 0x00, 0xb7, 0xb7, 0xb7, 0x00, 0xc7, 0xc7, + 0xc7, 0x00, 0xd7, 0xd7, 0xd7, 0x00, 0xe7, 0xe7, 0xe7, 0x00, 0xf7, 0xf7, 0xf7, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x19, 0x19, + 0xff, 0x00, 0x4c, 0x4c, 0xfe, 0x00, 0x7f, 0x7f, 0xff, 0x00, 0xb2, 0xb2, 0xff, 0x00, 0x00, 0x10, + 0x4c, 0x00, 0x00, 0x1b, 0x7f, 0x00, 0x00, 0x26, 0xb2, 0x00, 0x00, 0x31, 0xe5, 0x00, 0x19, 0x4a, + 0xff, 0x00, 0x4c, 0x72, 0xfe, 0x00, 0x7f, 0x9a, 0xff, 0x00, 0xb2, 0xc2, 0xff, 0x00, 0x00, 0x20, + 0x4c, 0x00, 0x00, 0x36, 0x7f, 0x00, 0x00, 0x4c, 0xb2, 0x00, 0x00, 0x62, 0xe5, 0x00, 0x19, 0x7b, + 0xff, 0x00, 0x4c, 0x99, 0xfe, 0x00, 0x7f, 0xb6, 0xff, 0x00, 0xb2, 0xd3, 0xff, 0x00, 0x00, 0x31, + 0x4c, 0x00, 0x00, 0x51, 0x7f, 0x00, 0x00, 0x72, 0xb2, 0x00, 0x00, 0x93, 0xe5, 0x00, 0x19, 0xad, + 0xff, 0x00, 0x4c, 0xbf, 0xfe, 0x00, 0x7f, 0xd1, 0xff, 0x00, 0xb2, 0xe3, 0xff, 0x00, 0x00, 0x41, + 0x4c, 0x00, 0x00, 0x6d, 0x7f, 0x00, 0x00, 0x99, 0xb2, 0x00, 0x00, 0xc4, 0xe5, 0x00, 0x19, 0xde, + 0xff, 0x00, 0x4c, 0xe5, 0xfe, 0x00, 0x7f, 0xec, 0xff, 0x00, 0xb2, 0xf4, 0xff, 0x00, 0x00, 0x4c, + 0x47, 0x00, 0x00, 0x7f, 0x76, 0x00, 0x00, 0xb2, 0xa5, 0x00, 0x00, 0xe5, 0xd5, 0x00, 0x19, 0xff, + 0xee, 0x00, 0x4c, 0xfe, 0xf2, 0x00, 0x7f, 0xff, 0xf5, 0x00, 0xb2, 0xff, 0xf9, 0x00, 0x00, 0x4c, + 0x36, 0x00, 0x00, 0x7f, 0x5b, 0x00, 0x00, 0xb2, 0x7f, 0x00, 0x00, 0xe5, 0xa3, 0x00, 0x19, 0xff, + 0xbd, 0x00, 0x4c, 0xfe, 0xcc, 0x00, 0x7f, 0xff, 0xda, 0x00, 0xb2, 0xff, 0xe9, 0x00, 0x00, 0x4c, + 0x26, 0x00, 0x00, 0x7f, 0x3f, 0x00, 0x00, 0xb2, 0x59, 0x00, 0x00, 0xe5, 0x72, 0x00, 0x19, 0xff, + 0x8c, 0x00, 0x4c, 0xfe, 0xa5, 0x00, 0x7f, 0xff, 0xbf, 0x00, 0xb2, 0xff, 0xd8, 0x00, 0x00, 0x4c, + 0x15, 0x00, 0x00, 0x7f, 0x24, 0x00, 0x00, 0xb2, 0x33, 0x00, 0x00, 0xe5, 0x41, 0x00, 0x19, 0xff, + 0x5b, 0x00, 0x4c, 0xfe, 0x7f, 0x00, 0x7f, 0xff, 0xa3, 0x00, 0xb2, 0xff, 0xc8, 0x00, 0x00, 0x4c, + 0x05, 0x00, 0x00, 0x7f, 0x09, 0x00, 0x00, 0xb2, 0x0c, 0x00, 0x00, 0xe5, 0x10, 0x00, 0x19, 0xff, + 0x29, 0x00, 0x4c, 0xfe, 0x59, 0x00, 0x7f, 0xff, 0x88, 0x00, 0xb2, 0xff, 0xb7, 0x00, 0x0a, 0x4c, + 0x00, 0x00, 0x12, 0x7f, 0x00, 0x00, 0x19, 0xb2, 0x00, 0x00, 0x20, 0xe5, 0x00, 0x00, 0x3a, 0xff, + 0x19, 0x00, 0x66, 0xfe, 0x4c, 0x00, 0x91, 0xff, 0x7f, 0x00, 0xbd, 0xff, 0xb2, 0x00, 0x1b, 0x4c, + 0x00, 0x00, 0x2d, 0x7f, 0x00, 0x00, 0x3f, 0xb2, 0x00, 0x00, 0x51, 0xe5, 0x00, 0x00, 0x6b, 0xff, + 0x19, 0x00, 0x8c, 0xfe, 0x4c, 0x00, 0xad, 0xff, 0x7f, 0x00, 0xcd, 0xff, 0xb2, 0x00, 0x2b, 0x4c, + 0x00, 0x00, 0x48, 0x7f, 0x00, 0x00, 0x65, 0xb2, 0x00, 0x00, 0x83, 0xe5, 0x00, 0x00, 0x9c, 0xff, + 0x19, 0x00, 0xb2, 0xfe, 0x4c, 0x00, 0xc8, 0xff, 0x7f, 0x00, 0xde, 0xff, 0xb2, 0x00, 0x3c, 0x4c, + 0x00, 0x00, 0x64, 0x7f, 0x00, 0x00, 0x8c, 0xb2, 0x00, 0x00, 0xb4, 0xe5, 0x00, 0x00, 0xcd, 0xff, + 0x19, 0x00, 0xd8, 0xfe, 0x4c, 0x00, 0xe3, 0xff, 0x7f, 0x00, 0xee, 0xff, 0xb2, 0x00, 0x4c, 0x4c, + 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xb2, 0xb2, 0x00, 0x00, 0xe5, 0xe5, 0x00, 0x00, 0xff, 0xff, + 0x19, 0x00, 0xfe, 0xfe, 0x4c, 0x00, 0xff, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xb2, 0x00, 0x4c, 0x3c, + 0x00, 0x00, 0x7f, 0x64, 0x00, 0x00, 0xb2, 0x8c, 0x00, 0x00, 0xe5, 0xb4, 0x00, 0x00, 0xff, 0xcd, + 0x19, 0x00, 0xfe, 0xd8, 0x4c, 0x00, 0xff, 0xe3, 0x7f, 0x00, 0xff, 0xee, 0xb2, 0x00, 0x4c, 0x2b, + 0x00, 0x00, 0x7f, 0x48, 0x00, 0x00, 0xb2, 0x66, 0x00, 0x00, 0xe5, 0x83, 0x00, 0x00, 0xff, 0x9c, + 0x19, 0x00, 0xfe, 0xb2, 0x4c, 0x00, 0xff, 0xc8, 0x7f, 0x00, 0xff, 0xde, 0xb2, 0x00, 0x4c, 0x1b, + 0x00, 0x00, 0x7f, 0x2d, 0x00, 0x00, 0xb2, 0x3f, 0x00, 0x00, 0xe5, 0x51, 0x00, 0x00, 0xff, 0x6b, + 0x19, 0x00, 0xfe, 0x8c, 0x4c, 0x00, 0xff, 0xad, 0x7f, 0x00, 0xff, 0xcd, 0xb2, 0x00, 0x4c, 0x0a, + 0x00, 0x00, 0x7f, 0x12, 0x00, 0x00, 0xb2, 0x19, 0x00, 0x00, 0xe5, 0x20, 0x00, 0x00, 0xff, 0x3a, + 0x19, 0x00, 0xfe, 0x65, 0x4c, 0x00, 0xff, 0x91, 0x7f, 0x00, 0xff, 0xbd, 0xb2, 0x00, 0x4c, 0x00, + 0x05, 0x00, 0x7f, 0x00, 0x09, 0x00, 0xb2, 0x00, 0x0c, 0x00, 0xe5, 0x00, 0x10, 0x00, 0xff, 0x19, + 0x29, 0x00, 0xfe, 0x4c, 0x59, 0x00, 0xff, 0x7f, 0x88, 0x00, 0xff, 0xb2, 0xb7, 0x00, 0x4c, 0x00, + 0x15, 0x00, 0x7f, 0x00, 0x24, 0x00, 0xb2, 0x00, 0x32, 0x00, 0xe5, 0x00, 0x41, 0x00, 0xff, 0x19, + 0x5b, 0x00, 0xfe, 0x4c, 0x7f, 0x00, 0xff, 0x7f, 0xa3, 0x00, 0xff, 0xb2, 0xc8, 0x00, 0x4c, 0x00, + 0x26, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0xb2, 0x00, 0x59, 0x00, 0xe5, 0x00, 0x72, 0x00, 0xff, 0x19, + 0x8c, 0x00, 0xfe, 0x4c, 0xa5, 0x00, 0xff, 0x7f, 0xbf, 0x00, 0xff, 0xb2, 0xd8, 0x00, 0x4c, 0x00, + 0x36, 0x00, 0x7f, 0x00, 0x5b, 0x00, 0xb2, 0x00, 0x7f, 0x00, 0xe5, 0x00, 0xa3, 0x00, 0xff, 0x19, + 0xbd, 0x00, 0xfe, 0x4c, 0xcc, 0x00, 0xff, 0x7f, 0xda, 0x00, 0xff, 0xb2, 0xe9, 0x00, 0x4c, 0x00, + 0x47, 0x00, 0x7f, 0x00, 0x76, 0x00, 0xb2, 0x00, 0xa5, 0x00, 0xe5, 0x00, 0xd5, 0x00, 0xff, 0x19, + 0xee, 0x00, 0xfe, 0x4c, 0xf2, 0x00, 0xff, 0x7f, 0xf5, 0x00, 0xff, 0xb2, 0xf9, 0x00, 0x41, 0x00, + 0x4c, 0x00, 0x6d, 0x00, 0x7f, 0x00, 0x99, 0x00, 0xb2, 0x00, 0xc4, 0x00, 0xe5, 0x00, 0xde, 0x19, + 0xff, 0x00, 0xe5, 0x4c, 0xfe, 0x00, 0xec, 0x7f, 0xff, 0x00, 0xf4, 0xb2, 0xff, 0x00, 0x31, 0x00, + 0x4c, 0x00, 0x51, 0x00, 0x7f, 0x00, 0x72, 0x00, 0xb2, 0x00, 0x93, 0x00, 0xe5, 0x00, 0xad, 0x19, + 0xff, 0x00, 0xbf, 0x4c, 0xfe, 0x00, 0xd1, 0x7f, 0xff, 0x00, 0xe3, 0xb2, 0xff, 0x00, 0x20, 0x00, + 0x4c, 0x00, 0x36, 0x00, 0x7f, 0x00, 0x4c, 0x00, 0xb2, 0x00, 0x62, 0x00, 0xe5, 0x00, 0x7b, 0x19, + 0xff, 0x00, 0x99, 0x4c, 0xfe, 0x00, 0xb6, 0x7f, 0xff, 0x00, 0xd3, 0xb2, 0xff, 0x00, 0x10, 0x00, + 0x4c, 0x00, 0x1b, 0x00, 0x7f, 0x00, 0x26, 0x00, 0xb2, 0x00, 0x31, 0x00, 0xe5, 0x00, 0x4a, 0x19, + 0xff, 0x00, 0x72, 0x4c, 0xfe, 0x00, 0x9a, 0x7f, 0xff, 0x00, 0xc2, 0xb2, 0xff, 0x00, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x08, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x08, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x08, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x08, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x08, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x08, + 0x08, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x1d, 0x08, + 0x08, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, + 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x08, 0x08, 0x08, 0x00, 0x17, 0x17, 0x17, 0x00, 0x27, 0x27, + 0x27, 0x00, 0x37, 0x37, 0x37, 0x00, 0x47, 0x47, 0x47, 0x00, 0x57, 0x57, 0x57, 0x00, 0x67, 0x67, + 0x67, 0x00, 0x77, 0x77, 0x77, 0x00, 0x87, 0x87, 0x87, 0x00, 0x97, 0x97, 0x97, 0x00, 0xa7, 0xa7, + 0xa7, 0x00, 0xb7, 0xb7, 0xb7, 0x00, 0xc7, 0xc7, 0xc7, 0x00, 0xd7, 0xd7, 0xd7, 0x00, 0xe7, 0xe7, + 0xe7, 0x00, 0xf7, 0xf7, 0xf7, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, + 0xb2, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x19, 0x19, 0xff, 0x00, 0x4c, 0x4c, 0xfe, 0x00, 0x7f, 0x7f, + 0xff, 0x00, 0xb2, 0xb2, 0xff, 0x00, 0x00, 0x10, 0x4c, 0x00, 0x00, 0x1b, 0x7f, 0x00, 0x00, 0x26, + 0xb2, 0x00, 0x00, 0x31, 0xe5, 0x00, 0x19, 0x4a, 0xff, 0x00, 0x4c, 0x72, 0xfe, 0x00, 0x7f, 0x9a, + 0xff, 0x00, 0xb2, 0xc2, 0xff, 0x00, 0x00, 0x20, 0x4c, 0x00, 0x00, 0x36, 0x7f, 0x00, 0x00, 0x4c, + 0xb2, 0x00, 0x00, 0x62, 0xe5, 0x00, 0x19, 0x7b, 0xff, 0x00, 0x4c, 0x99, 0xfe, 0x00, 0x7f, 0xb6, + 0xff, 0x00, 0xb2, 0xd3, 0xff, 0x00, 0x00, 0x31, 0x4c, 0x00, 0x00, 0x51, 0x7f, 0x00, 0x00, 0x72, + 0xb2, 0x00, 0x00, 0x93, 0xe5, 0x00, 0x19, 0xad, 0xff, 0x00, 0x4c, 0xbf, 0xfe, 0x00, 0x7f, 0xd1, + 0xff, 0x00, 0xb2, 0xe3, 0xff, 0x00, 0x00, 0x41, 0x4c, 0x00, 0x00, 0x6d, 0x7f, 0x00, 0x00, 0x99, + 0xb2, 0x00, 0x00, 0xc4, 0xe5, 0x00, 0x19, 0xde, 0xff, 0x00, 0x4c, 0xe5, 0xfe, 0x00, 0x7f, 0xec, + 0xff, 0x00, 0xb2, 0xf4, 0xff, 0x00, 0x00, 0x4c, 0x47, 0x00, 0x00, 0x7f, 0x76, 0x00, 0x00, 0xb2, + 0xa5, 0x00, 0x00, 0xe5, 0xd5, 0x00, 0x19, 0xff, 0xee, 0x00, 0x4c, 0xfe, 0xf2, 0x00, 0x7f, 0xff, + 0xf5, 0x00, 0xb2, 0xff, 0xf9, 0x00, 0x00, 0x4c, 0x36, 0x00, 0x00, 0x7f, 0x5b, 0x00, 0x00, 0xb2, + 0x7f, 0x00, 0x00, 0xe5, 0xa3, 0x00, 0x19, 0xff, 0xbd, 0x00, 0x4c, 0xfe, 0xcc, 0x00, 0x7f, 0xff, + 0xda, 0x00, 0xb2, 0xff, 0xe9, 0x00, 0x00, 0x4c, 0x26, 0x00, 0x00, 0x7f, 0x3f, 0x00, 0x00, 0xb2, + 0x59, 0x00, 0x00, 0xe5, 0x72, 0x00, 0x19, 0xff, 0x8c, 0x00, 0x4c, 0xfe, 0xa5, 0x00, 0x7f, 0xff, + 0xbf, 0x00, 0xb2, 0xff, 0xd8, 0x00, 0x00, 0x4c, 0x15, 0x00, 0x00, 0x7f, 0x24, 0x00, 0x00, 0xb2, + 0x33, 0x00, 0x00, 0xe5, 0x41, 0x00, 0x19, 0xff, 0x5b, 0x00, 0x4c, 0xfe, 0x7f, 0x00, 0x7f, 0xff, + 0xa3, 0x00, 0xb2, 0xff, 0xc8, 0x00, 0x00, 0x4c, 0x05, 0x00, 0x00, 0x7f, 0x09, 0x00, 0x00, 0xb2, + 0x0c, 0x00, 0x00, 0xe5, 0x10, 0x00, 0x19, 0xff, 0x29, 0x00, 0x4c, 0xfe, 0x59, 0x00, 0x7f, 0xff, + 0x88, 0x00, 0xb2, 0xff, 0xb7, 0x00, 0x0a, 0x4c, 0x00, 0x00, 0x12, 0x7f, 0x00, 0x00, 0x19, 0xb2, + 0x00, 0x00, 0x20, 0xe5, 0x00, 0x00, 0x3a, 0xff, 0x19, 0x00, 0x66, 0xfe, 0x4c, 0x00, 0x91, 0xff, + 0x7f, 0x00, 0xbd, 0xff, 0xb2, 0x00, 0x1b, 0x4c, 0x00, 0x00, 0x2d, 0x7f, 0x00, 0x00, 0x3f, 0xb2, + 0x00, 0x00, 0x51, 0xe5, 0x00, 0x00, 0x6b, 0xff, 0x19, 0x00, 0x8c, 0xfe, 0x4c, 0x00, 0xad, 0xff, + 0x7f, 0x00, 0xcd, 0xff, 0xb2, 0x00, 0x2b, 0x4c, 0x00, 0x00, 0x48, 0x7f, 0x00, 0x00, 0x65, 0xb2, + 0x00, 0x00, 0x83, 0xe5, 0x00, 0x00, 0x9c, 0xff, 0x19, 0x00, 0xb2, 0xfe, 0x4c, 0x00, 0xc8, 0xff, + 0x7f, 0x00, 0xde, 0xff, 0xb2, 0x00, 0x3c, 0x4c, 0x00, 0x00, 0x64, 0x7f, 0x00, 0x00, 0x8c, 0xb2, + 0x00, 0x00, 0xb4, 0xe5, 0x00, 0x00, 0xcd, 0xff, 0x19, 0x00, 0xd8, 0xfe, 0x4c, 0x00, 0xe3, 0xff, + 0x7f, 0x00, 0xee, 0xff, 0xb2, 0x00, 0x4c, 0x4c, 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xb2, 0xb2, + 0x00, 0x00, 0xe5, 0xe5, 0x00, 0x00, 0xff, 0xff, 0x19, 0x00, 0xfe, 0xfe, 0x4c, 0x00, 0xff, 0xff, + 0x7f, 0x00, 0xff, 0xff, 0xb2, 0x00, 0x4c, 0x3c, 0x00, 0x00, 0x7f, 0x64, 0x00, 0x00, 0xb2, 0x8c, + 0x00, 0x00, 0xe5, 0xb4, 0x00, 0x00, 0xff, 0xcd, 0x19, 0x00, 0xfe, 0xd8, 0x4c, 0x00, 0xff, 0xe3, + 0x7f, 0x00, 0xff, 0xee, 0xb2, 0x00, 0x4c, 0x2b, 0x00, 0x00, 0x7f, 0x48, 0x00, 0x00, 0xb2, 0x66, + 0x00, 0x00, 0xe5, 0x83, 0x00, 0x00, 0xff, 0x9c, 0x19, 0x00, 0xfe, 0xb2, 0x4c, 0x00, 0xff, 0xc8, + 0x7f, 0x00, 0xff, 0xde, 0xb2, 0x00, 0x4c, 0x1b, 0x00, 0x00, 0x7f, 0x2d, 0x00, 0x00, 0xb2, 0x3f, + 0x00, 0x00, 0xe5, 0x51, 0x00, 0x00, 0xff, 0x6b, 0x19, 0x00, 0xfe, 0x8c, 0x4c, 0x00, 0xff, 0xad, + 0x7f, 0x00, 0xff, 0xcd, 0xb2, 0x00, 0x4c, 0x0a, 0x00, 0x00, 0x7f, 0x12, 0x00, 0x00, 0xb2, 0x19, + 0x00, 0x00, 0xe5, 0x20, 0x00, 0x00, 0xff, 0x3a, 0x19, 0x00, 0xfe, 0x65, 0x4c, 0x00, 0xff, 0x91, + 0x7f, 0x00, 0xff, 0xbd, 0xb2, 0x00, 0x4c, 0x00, 0x05, 0x00, 0x7f, 0x00, 0x09, 0x00, 0xb2, 0x00, + 0x0c, 0x00, 0xe5, 0x00, 0x10, 0x00, 0xff, 0x19, 0x29, 0x00, 0xfe, 0x4c, 0x59, 0x00, 0xff, 0x7f, + 0x88, 0x00, 0xff, 0xb2, 0xb7, 0x00, 0x4c, 0x00, 0x15, 0x00, 0x7f, 0x00, 0x24, 0x00, 0xb2, 0x00, + 0x32, 0x00, 0xe5, 0x00, 0x41, 0x00, 0xff, 0x19, 0x5b, 0x00, 0xfe, 0x4c, 0x7f, 0x00, 0xff, 0x7f, + 0xa3, 0x00, 0xff, 0xb2, 0xc8, 0x00, 0x4c, 0x00, 0x26, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0xb2, 0x00, + 0x59, 0x00, 0xe5, 0x00, 0x72, 0x00, 0xff, 0x19, 0x8c, 0x00, 0xfe, 0x4c, 0xa5, 0x00, 0xff, 0x7f, + 0xbf, 0x00, 0xff, 0xb2, 0xd8, 0x00, 0x4c, 0x00, 0x36, 0x00, 0x7f, 0x00, 0x5b, 0x00, 0xb2, 0x00, + 0x7f, 0x00, 0xe5, 0x00, 0xa3, 0x00, 0xff, 0x19, 0xbd, 0x00, 0xfe, 0x4c, 0xcc, 0x00, 0xff, 0x7f, + 0xda, 0x00, 0xff, 0xb2, 0xe9, 0x00, 0x4c, 0x00, 0x47, 0x00, 0x7f, 0x00, 0x76, 0x00, 0xb2, 0x00, + 0xa5, 0x00, 0xe5, 0x00, 0xd5, 0x00, 0xff, 0x19, 0xee, 0x00, 0xfe, 0x4c, 0xf2, 0x00, 0xff, 0x7f, + 0xf5, 0x00, 0xff, 0xb2, 0xf9, 0x00, 0x41, 0x00, 0x4c, 0x00, 0x6d, 0x00, 0x7f, 0x00, 0x99, 0x00, + 0xb2, 0x00, 0xc4, 0x00, 0xe5, 0x00, 0xde, 0x19, 0xff, 0x00, 0xe5, 0x4c, 0xfe, 0x00, 0xec, 0x7f, + 0xff, 0x00, 0xf4, 0xb2, 0xff, 0x00, 0x31, 0x00, 0x4c, 0x00, 0x51, 0x00, 0x7f, 0x00, 0x72, 0x00, + 0xb2, 0x00, 0x93, 0x00, 0xe5, 0x00, 0xad, 0x19, 0xff, 0x00, 0xbf, 0x4c, 0xfe, 0x00, 0xd1, 0x7f, + 0xff, 0x00, 0xe3, 0xb2, 0xff, 0x00, 0x20, 0x00, 0x4c, 0x00, 0x36, 0x00, 0x7f, 0x00, 0x4c, 0x00, + 0xb2, 0x00, 0x62, 0x00, 0xe5, 0x00, 0x7b, 0x19, 0xff, 0x00, 0x99, 0x4c, 0xfe, 0x00, 0xb6, 0x7f, + 0xff, 0x00, 0xd3, 0xb2, 0xff, 0x00, 0x10, 0x00, 0x4c, 0x00, 0x1b, 0x00, 0x7f, 0x00, 0x26, 0x00, + 0xb2, 0x00, 0x31, 0x00, 0xe5, 0x00, 0x4a, 0x19, 0xff, 0x00, 0x72, 0x4c, 0xfe, 0x00, 0x9a, 0x7f, + 0xff, 0x00, 0xc2, 0xb2, 0xff, 0x00, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x08, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x08, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x08, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x08, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x08, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x08, + 0x08, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x08, 0x08, + 0x1d, 0x1d, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x08, 0x08, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x80, 0x00, + 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0x00, 0x80, 0x80, + 0x80, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, + 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x08, 0x08, + 0x08, 0x00, 0x17, 0x17, 0x17, 0x00, 0x27, 0x27, 0x27, 0x00, 0x37, 0x37, 0x37, 0x00, 0x47, 0x47, + 0x47, 0x00, 0x57, 0x57, 0x57, 0x00, 0x67, 0x67, 0x67, 0x00, 0x77, 0x77, 0x77, 0x00, 0x87, 0x87, + 0x87, 0x00, 0x97, 0x97, 0x97, 0x00, 0xa7, 0xa7, 0xa7, 0x00, 0xb7, 0xb7, 0xb7, 0x00, 0xc7, 0xc7, + 0xc7, 0x00, 0xd7, 0xd7, 0xd7, 0x00, 0xe7, 0xe7, 0xe7, 0x00, 0xf7, 0xf7, 0xf7, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x19, 0x19, + 0xff, 0x00, 0x4c, 0x4c, 0xfe, 0x00, 0x7f, 0x7f, 0xff, 0x00, 0xb2, 0xb2, 0xff, 0x00, 0x00, 0x10, + 0x4c, 0x00, 0x00, 0x1b, 0x7f, 0x00, 0x00, 0x26, 0xb2, 0x00, 0x00, 0x31, 0xe5, 0x00, 0x19, 0x4a, + 0xff, 0x00, 0x4c, 0x72, 0xfe, 0x00, 0x7f, 0x9a, 0xff, 0x00, 0xb2, 0xc2, 0xff, 0x00, 0x00, 0x20, + 0x4c, 0x00, 0x00, 0x36, 0x7f, 0x00, 0x00, 0x4c, 0xb2, 0x00, 0x00, 0x62, 0xe5, 0x00, 0x19, 0x7b, + 0xff, 0x00, 0x4c, 0x99, 0xfe, 0x00, 0x7f, 0xb6, 0xff, 0x00, 0xb2, 0xd3, 0xff, 0x00, 0x00, 0x31, + 0x4c, 0x00, 0x00, 0x51, 0x7f, 0x00, 0x00, 0x72, 0xb2, 0x00, 0x00, 0x93, 0xe5, 0x00, 0x19, 0xad, + 0xff, 0x00, 0x4c, 0xbf, 0xfe, 0x00, 0x7f, 0xd1, 0xff, 0x00, 0xb2, 0xe3, 0xff, 0x00, 0x00, 0x41, + 0x4c, 0x00, 0x00, 0x6d, 0x7f, 0x00, 0x00, 0x99, 0xb2, 0x00, 0x00, 0xc4, 0xe5, 0x00, 0x19, 0xde, + 0xff, 0x00, 0x4c, 0xe5, 0xfe, 0x00, 0x7f, 0xec, 0xff, 0x00, 0xb2, 0xf4, 0xff, 0x00, 0x00, 0x4c, + 0x47, 0x00, 0x00, 0x7f, 0x76, 0x00, 0x00, 0xb2, 0xa5, 0x00, 0x00, 0xe5, 0xd5, 0x00, 0x19, 0xff, + 0xee, 0x00, 0x4c, 0xfe, 0xf2, 0x00, 0x7f, 0xff, 0xf5, 0x00, 0xb2, 0xff, 0xf9, 0x00, 0x00, 0x4c, + 0x36, 0x00, 0x00, 0x7f, 0x5b, 0x00, 0x00, 0xb2, 0x7f, 0x00, 0x00, 0xe5, 0xa3, 0x00, 0x19, 0xff, + 0xbd, 0x00, 0x4c, 0xfe, 0xcc, 0x00, 0x7f, 0xff, 0xda, 0x00, 0xb2, 0xff, 0xe9, 0x00, 0x00, 0x4c, + 0x26, 0x00, 0x00, 0x7f, 0x3f, 0x00, 0x00, 0xb2, 0x59, 0x00, 0x00, 0xe5, 0x72, 0x00, 0x19, 0xff, + 0x8c, 0x00, 0x4c, 0xfe, 0xa5, 0x00, 0x7f, 0xff, 0xbf, 0x00, 0xb2, 0xff, 0xd8, 0x00, 0x00, 0x4c, + 0x15, 0x00, 0x00, 0x7f, 0x24, 0x00, 0x00, 0xb2, 0x33, 0x00, 0x00, 0xe5, 0x41, 0x00, 0x19, 0xff, + 0x5b, 0x00, 0x4c, 0xfe, 0x7f, 0x00, 0x7f, 0xff, 0xa3, 0x00, 0xb2, 0xff, 0xc8, 0x00, 0x00, 0x4c, + 0x05, 0x00, 0x00, 0x7f, 0x09, 0x00, 0x00, 0xb2, 0x0c, 0x00, 0x00, 0xe5, 0x10, 0x00, 0x19, 0xff, + 0x29, 0x00, 0x4c, 0xfe, 0x59, 0x00, 0x7f, 0xff, 0x88, 0x00, 0xb2, 0xff, 0xb7, 0x00, 0x0a, 0x4c, + 0x00, 0x00, 0x12, 0x7f, 0x00, 0x00, 0x19, 0xb2, 0x00, 0x00, 0x20, 0xe5, 0x00, 0x00, 0x3a, 0xff, + 0x19, 0x00, 0x66, 0xfe, 0x4c, 0x00, 0x91, 0xff, 0x7f, 0x00, 0xbd, 0xff, 0xb2, 0x00, 0x1b, 0x4c, + 0x00, 0x00, 0x2d, 0x7f, 0x00, 0x00, 0x3f, 0xb2, 0x00, 0x00, 0x51, 0xe5, 0x00, 0x00, 0x6b, 0xff, + 0x19, 0x00, 0x8c, 0xfe, 0x4c, 0x00, 0xad, 0xff, 0x7f, 0x00, 0xcd, 0xff, 0xb2, 0x00, 0x2b, 0x4c, + 0x00, 0x00, 0x48, 0x7f, 0x00, 0x00, 0x65, 0xb2, 0x00, 0x00, 0x83, 0xe5, 0x00, 0x00, 0x9c, 0xff, + 0x19, 0x00, 0xb2, 0xfe, 0x4c, 0x00, 0xc8, 0xff, 0x7f, 0x00, 0xde, 0xff, 0xb2, 0x00, 0x3c, 0x4c, + 0x00, 0x00, 0x64, 0x7f, 0x00, 0x00, 0x8c, 0xb2, 0x00, 0x00, 0xb4, 0xe5, 0x00, 0x00, 0xcd, 0xff, + 0x19, 0x00, 0xd8, 0xfe, 0x4c, 0x00, 0xe3, 0xff, 0x7f, 0x00, 0xee, 0xff, 0xb2, 0x00, 0x4c, 0x4c, + 0x00, 0x00, 0x7f, 0x7f, 0x00, 0x00, 0xb2, 0xb2, 0x00, 0x00, 0xe5, 0xe5, 0x00, 0x00, 0xff, 0xff, + 0x19, 0x00, 0xfe, 0xfe, 0x4c, 0x00, 0xff, 0xff, 0x7f, 0x00, 0xff, 0xff, 0xb2, 0x00, 0x4c, 0x3c, + 0x00, 0x00, 0x7f, 0x64, 0x00, 0x00, 0xb2, 0x8c, 0x00, 0x00, 0xe5, 0xb4, 0x00, 0x00, 0xff, 0xcd, + 0x19, 0x00, 0xfe, 0xd8, 0x4c, 0x00, 0xff, 0xe3, 0x7f, 0x00, 0xff, 0xee, 0xb2, 0x00, 0x4c, 0x2b, + 0x00, 0x00, 0x7f, 0x48, 0x00, 0x00, 0xb2, 0x66, 0x00, 0x00, 0xe5, 0x83, 0x00, 0x00, 0xff, 0x9c, + 0x19, 0x00, 0xfe, 0xb2, 0x4c, 0x00, 0xff, 0xc8, 0x7f, 0x00, 0xff, 0xde, 0xb2, 0x00, 0x4c, 0x1b, + 0x00, 0x00, 0x7f, 0x2d, 0x00, 0x00, 0xb2, 0x3f, 0x00, 0x00, 0xe5, 0x51, 0x00, 0x00, 0xff, 0x6b, + 0x19, 0x00, 0xfe, 0x8c, 0x4c, 0x00, 0xff, 0xad, 0x7f, 0x00, 0xff, 0xcd, 0xb2, 0x00, 0x4c, 0x0a, + 0x00, 0x00, 0x7f, 0x12, 0x00, 0x00, 0xb2, 0x19, 0x00, 0x00, 0xe5, 0x20, 0x00, 0x00, 0xff, 0x3a, + 0x19, 0x00, 0xfe, 0x65, 0x4c, 0x00, 0xff, 0x91, 0x7f, 0x00, 0xff, 0xbd, 0xb2, 0x00, 0x4c, 0x00, + 0x05, 0x00, 0x7f, 0x00, 0x09, 0x00, 0xb2, 0x00, 0x0c, 0x00, 0xe5, 0x00, 0x10, 0x00, 0xff, 0x19, + 0x29, 0x00, 0xfe, 0x4c, 0x59, 0x00, 0xff, 0x7f, 0x88, 0x00, 0xff, 0xb2, 0xb7, 0x00, 0x4c, 0x00, + 0x15, 0x00, 0x7f, 0x00, 0x24, 0x00, 0xb2, 0x00, 0x32, 0x00, 0xe5, 0x00, 0x41, 0x00, 0xff, 0x19, + 0x5b, 0x00, 0xfe, 0x4c, 0x7f, 0x00, 0xff, 0x7f, 0xa3, 0x00, 0xff, 0xb2, 0xc8, 0x00, 0x4c, 0x00, + 0x26, 0x00, 0x7f, 0x00, 0x3f, 0x00, 0xb2, 0x00, 0x59, 0x00, 0xe5, 0x00, 0x72, 0x00, 0xff, 0x19, + 0x8c, 0x00, 0xfe, 0x4c, 0xa5, 0x00, 0xff, 0x7f, 0xbf, 0x00, 0xff, 0xb2, 0xd8, 0x00, 0x4c, 0x00, + 0x36, 0x00, 0x7f, 0x00, 0x5b, 0x00, 0xb2, 0x00, 0x7f, 0x00, 0xe5, 0x00, 0xa3, 0x00, 0xff, 0x19, + 0xbd, 0x00, 0xfe, 0x4c, 0xcc, 0x00, 0xff, 0x7f, 0xda, 0x00, 0xff, 0xb2, 0xe9, 0x00, 0x4c, 0x00, + 0x47, 0x00, 0x7f, 0x00, 0x76, 0x00, 0xb2, 0x00, 0xa5, 0x00, 0xe5, 0x00, 0xd5, 0x00, 0xff, 0x19, + 0xee, 0x00, 0xfe, 0x4c, 0xf2, 0x00, 0xff, 0x7f, 0xf5, 0x00, 0xff, 0xb2, 0xf9, 0x00, 0x41, 0x00, + 0x4c, 0x00, 0x6d, 0x00, 0x7f, 0x00, 0x99, 0x00, 0xb2, 0x00, 0xc4, 0x00, 0xe5, 0x00, 0xde, 0x19, + 0xff, 0x00, 0xe5, 0x4c, 0xfe, 0x00, 0xec, 0x7f, 0xff, 0x00, 0xf4, 0xb2, 0xff, 0x00, 0x31, 0x00, + 0x4c, 0x00, 0x51, 0x00, 0x7f, 0x00, 0x72, 0x00, 0xb2, 0x00, 0x93, 0x00, 0xe5, 0x00, 0xad, 0x19, + 0xff, 0x00, 0xbf, 0x4c, 0xfe, 0x00, 0xd1, 0x7f, 0xff, 0x00, 0xe3, 0xb2, 0xff, 0x00, 0x20, 0x00, + 0x4c, 0x00, 0x36, 0x00, 0x7f, 0x00, 0x4c, 0x00, 0xb2, 0x00, 0x62, 0x00, 0xe5, 0x00, 0x7b, 0x19, + 0xff, 0x00, 0x99, 0x4c, 0xfe, 0x00, 0xb6, 0x7f, 0xff, 0x00, 0xd3, 0xb2, 0xff, 0x00, 0x10, 0x00, + 0x4c, 0x00, 0x1b, 0x00, 0x7f, 0x00, 0x26, 0x00, 0xb2, 0x00, 0x31, 0x00, 0xe5, 0x00, 0x4a, 0x19, + 0xff, 0x00, 0x72, 0x4c, 0xfe, 0x00, 0x9a, 0x7f, 0xff, 0x00, 0xc2, 0xb2, 0xff, 0x00, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x08, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x0f, 0x0f, + 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, + 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x08, + 0x08, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x1d, 0x08, 0x08, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x08, + 0x08, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x1d, 0x08, 0x08, 0x1d, 0x08, 0x08, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +} diff --git a/src/tpl/defaultTheme/frontend/index.css.go b/src/tpl/defaultTheme/frontend/index.css.go new file mode 100644 index 00000000..75268ef6 --- /dev/null +++ b/src/tpl/defaultTheme/frontend/index.css.go @@ -0,0 +1,665 @@ +package frontend + +const DefaultCss = ` +html, body { + margin: 0; + padding: 0; + background: #fff; +} + +html { + font-family: "roboto_condensedbold", "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +body { + color: #333; + font-size: 0.625em; + font-variant-ligatures: none; + font-variant-numeric: tabular-nums; + font-kerning: none; + -webkit-text-size-adjust: none; + text-size-adjust: none; + hyphens: none; + padding-bottom: 2em; +} + +body, input, textarea, button { + font-family: "Cascadia Mono", Consolas, "Lucida Console", "San Francisco Mono", Menlo, Monaco, "Andale Mono", "DejaVu Sans Mono", "Jetbrains Mono NL", monospace; +} + +input::-ms-clear { + display: none; +} + +form { + margin: 0; + padding: 0; +} + +ul, ol, li { + display: block; + margin: 0; + padding: 0; +} + +a { + display: block; + padding: 0.5em; + color: #000; + text-decoration: none; + outline: 0; +} + +a:hover { + background: #f5f5f5; +} + +a:focus { + background: #fffae0; +} + +a:hover:focus { + background: #faf7ea; +} + +input, button { + min-width: 0; + margin: 0; + padding: 0.25em 0; +} + +input[type=button], +input[type=submit], +input[type=reset], +button { + cursor: pointer; +} + +input:disabled[type=button], +input:disabled[type=submit], +input:disabled[type=reset], +button:disabled { + cursor: default; +} + +input[type=text] { + padding: 0.25em; +} + +em { + font-style: normal; + font-weight: normal; + padding: 0 0.2em; + border: 1px #ddd solid; + border-radius: 3px; +} + +.none, :root body .none { + display: none; +} + +.hidden { + visibility: hidden; +} + + +html::before { + display: none; + content: ''; + position: absolute; + position: fixed; + z-index: 2; + left: 0; + top: 0; + right: 0; + bottom: 0; + opacity: 0.7; + background: #c9c; +} + +html.dragging::before { + display: block; +} + + +.path-list { + font-size: 1.5em; + line-height: 1.2; + overflow: hidden; + border-bottom: 1px #999 solid; + zoom: 1; +} + +.path-list li { + position: relative; + float: left; + text-align: center; + white-space: nowrap; +} + +.path-list a { + display: block; + padding-right: 1.2em; + min-width: 1em; + white-space: pre-wrap; +} + +.path-list a:after { + content: ''; + position: absolute; + top: 50%; + right: 0.5em; + width: 0.4em; + height: 0.4em; + border: 1px solid; + border-color: #ccc #ccc transparent transparent; + -webkit-transform: rotate(45deg) translateY(-50%); + transform: rotate(45deg) translateY(-50%); +} + +.path-list li:last-child a { + padding-right: 0.5em; +} + +.path-list li:last-child a:after { + display: none; +} + +.login { + position: absolute; + z-index: 1; + right: 0; + padding: 0.5em 1em; +} + +.tab { + display: flex; + white-space: nowrap; + margin: 1em 1em -1em 1em; +} + +.tab label { + flex: 0 0 auto; + margin-right: 0.5em; + padding: 1em; + cursor: pointer; +} + +.tab label:focus { + outline: 0; + text-decoration: underline; + text-decoration-style: dotted; +} + +.tab label:hover { + background: #fbfbfb; +} + +.tab label.active { + color: #000; + background: #f7f7f7; +} + +.tab label:last-child { + margin-right: 0; +} + +.panel { + margin: 1em; + padding: 1em; + background: #f7f7f7; +} + +.upload-status { + visibility: hidden; + position: absolute; + position: sticky; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 4px; + margin-bottom: -4px; + background: #faf5fa; + background-color: rgba(204, 153, 204, 0.1); + pointer-events: none; +} + +.upload-status.uploading, +.upload-status.failed { + visibility: visible; +} + +.upload-status .label { + position: absolute; + left: 0; + top: 0; + width: 100%; + color: #fff; + text-align: center; + opacity: 0; + transition: transform .2s, opacity .2s; +} + +.upload-status .label .content { + position: relative; + display: inline-block; + vertical-align: top; + text-align: left; + text-align: start; + padding: 0.5em 1em; + box-sizing: border-box; + overflow-wrap: break-word; + word-break: break-word; +} + +.upload-status .info .content { + padding-left: 2.5em; + background: #c9c; + background-color: rgba(204, 153, 204, 0.8); +} + +@keyframes wheel { + from { + transform: rotate(0); + } + to { + transform: rotate(360deg); + } +} + +.upload-status .info .content:before, +.upload-status .info .content:after { + content: ''; + position: absolute; + left: 1em; + top: 0.70em; + width: 1em; + height: 1em; + box-sizing: border-box; + border: 2px solid rgba(255, 255, 255, 0.3); + border-radius: 50%; + animation: wheel 1s linear infinite; +} + +.upload-status .info .content:after { + border-color: currentColor transparent transparent transparent; +} + +.upload-status .warn .content { + background: #800000; + background-color: rgba(128, 0, 0, 0.8); +} + +.upload-status.uploading .info, +.upload-status.failed .warn { + opacity: 1; + -webkit-transform: translateY(25%); + transform: translateY(25%); +} + +.upload-status .progress { + position: absolute; + left: 0; + top: 0; + width: 0; + height: 100%; + background: #c9c; +} + +.upload { + position: relative; +} + +.upload input, +.upload button { + display: block; + width: 100%; + box-sizing: border-box; +} + +.upload button { + position: relative; + margin-top: 0.5em; + overflow: hidden; +} + +.upload button span { + position: relative; +} + +.archive { + margin: 1em; + overflow: hidden; + zoom: 1; +} + +.archive a { + position: relative; + float: left; + margin: 0 0.5em; + padding: 1em 1em 1em 3em; + border: 2px #f5f5f5 solid; +} + +.archive a:hover { + border-color: #ddd; +} + +.archive a:before { + content: ''; + position: absolute; + left: 1.1em; + top: 1em; + height: 1em; + width: 3px; + background: #aaa; +} + +.archive a:after { + content: ''; + position: absolute; + left: 0.6em; + top: 1em; + width: 0.5em; + height: 0.5em; + margin-left: 1px; + border: 3px #aaa solid; + border-top-color: transparent; + border-left-color: transparent; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); +} + +.mkdir form { + display: flex; + align-items: center; +} + +.mkdir .name { + flex: 1 1 auto; +} + +.mkdir .submit { + padding-left: 0.5em; + padding-right: 0.5em; +} + +.filter { + display: none; +} + +:root .filter { + display: block; +} + +.filter .form { + position: relative; + display: flex; +} + +.filter input { + flex: 1 1 auto; + width: 97%; + padding-right: 1.5em; + box-sizing: border-box; +} + +.filter button { + display: none; + position: absolute; + right: 0; + top: 0; + bottom: 0; + border: 0; + background: none; + padding: 0 0.5em; +} + +.item-list { + margin: 1em; + line-height: 1.2; +} + +.item-list li { + position: relative; + zoom: 1; +} + +.item-list a { + padding: 0.6em; +} + +.item-list .detail, +.item-list .delete { + display: flex; + flex-flow: row nowrap; + align-items: center; + border-bottom: 1px #f5f5f5 solid; + overflow: hidden; + zoom: 1; +} + +.has-deletable .detail { + padding-right: 2.2em; +} + +.item-list .field { + margin: 0 0 0 1em; + flex-shrink: 0; +} + +.item-list .name { + flex-grow: 1; + flex-shrink: 1; + flex-basis: 0; + margin-left: 0; + font-size: 1.5em; + white-space: pre-wrap; + word-break: break-all; +} + +.item-list .size { + white-space: nowrap; + text-align: right; + color: #666; +} + +.item-list .time { + color: #999; + text-align: right; + white-space: nowrap; + overflow: hidden; +} + +.item-list .delete { + position: absolute; + top: 0; + right: 0; + bottom: 0; + display: flex; + align-items: stretch; +} + +.item-list .delete button { + border: 0; + color: #800000; + background: none; + font-weight: bold; + font-size: 1.6em; + line-height: 1em; + padding: 0.1875em 0.3125em 0.3125em; +} + +.item-list .delete button:hover { + background: #fee; +} + +.item-list .header .detail { + background: #fcfcfc; +} + +.item-list .header .field { + display: inline-block; + margin: 0; + font-size: 1.5em; + color: #808080; + overflow: hidden; +} + +.item-list .header .time { + width: 6.5em; + text-align: center; +} + +.error { + margin: 1em; + padding: 1em; + background: #ffc; +} + +@media only screen and (prefers-color-scheme: light) { + html { + color-scheme: light; + } +} + +@media only screen and (prefers-color-scheme: dark) { + html { + color-scheme: dark; + } + + html, body { + background: #111; + } + + body { + color: #ccc; + } + + a { + color: #ddd; + } + + a:hover { + background-color: #333; + } + + a:focus { + background-color: #330; + } + + a:hover:focus { + background-color: #33331a; + } + + em { + border-color: #555; + } + + .path-list { + border-bottom-color: #999; + } + + .path-list a:after { + border-color: #555 #555 transparent transparent; + } + + .tab label:hover { + background-color: #181818; + } + + .tab label.active { + color: #fff; + background-color: #222; + } + + .panel { + background-color: #222; + } + + .archive a { + border-color: #222; + } + + .archive a:hover { + border-color: #555; + } + + .item-list .detail, + .item-list .delete { + border-bottom-color: #222; + } + + .item-list .size { + color: #999; + } + + .item-list .time { + color: #666; + } + + .item-list .delete button { + color: #f99; + } + + .item-list .delete button:hover { + background-color: #433; + } + + .item-list .header .detail { + background-color: #181818; + } + + .error { + background: #663; + } +} + +@media only screen and (max-width: 375px) { + .item-list .header .time { + width: 4.05em; + } + + .item-list .detail .time span { + display: none; + } +} + +@media only screen and (max-width: 350px) { + .item-list .detail .time { + display: none; + } +} + +@media print { + .panel, .archive { + display: none; + } + + :root .panel { + display: none; + } + + .tab { + display: none; + } + + .item-list li { + page-break-inside: avoid; + break-inside: avoid; + } + + .item-list li.parent { + display: none; + } + + .has-deletable .detail { + padding-right: 0; + } + + .has-deletable .delete { + display: none; + } +} +` diff --git a/src/tpl/defaultTheme/frontend/index.html.go b/src/tpl/defaultTheme/frontend/index.html.go new file mode 100644 index 00000000..36514e22 --- /dev/null +++ b/src/tpl/defaultTheme/frontend/index.html.go @@ -0,0 +1,149 @@ +package frontend + +const DefaultTplStr = ` + + +
+ + + + + +