diff --git a/README.md b/README.md index ccca502d..98607926 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.9. +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..53761f3f 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -18,12 +18,20 @@ - 零第三方依赖 ## 编译 -至少需要Go 1.18版本。 +至少需要Go 1.9版本。 +确保该项目位于 `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..f202d40d 100755 --- a/build/build-all-by-docker.sh +++ b/build/build-all-by-docker.sh @@ -26,6 +26,7 @@ buildByDocker() { sed -i -e "s;://[^/ ]*;://mirrors.aliyun.com;" /etc/apt/sources.list; apt-get update; apt-get install -yq 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 +43,35 @@ buildByDocker() { "$@" } -gover=latest -buildByDocker "$gover" "${builds[@]}" +#gover=1.15 +#builds=() +#builds+=('linux 386' 'linux amd64' 'linux arm' 'linux arm64' 'windows 386' 'windows amd64' 'windows arm' 'darwin amd64' 'darwin arm64') +#builds+=('freebsd 386' 'freebsd amd64' 'freebsd arm' 'freebsd arm64') +#builds+=('openbsd 386' 'openbsd amd64' 'openbsd arm' 'openbsd arm64') +#builds+=('netbsd 386' 'netbsd amd64' 'netbsd arm' 'netbsd arm64') +#buildByDocker "$gover" "${builds[@]}" + +#gover=1.15-alpine +#builds=('linux amd64 -musl' 'linux arm64 -musl') +#buildByDocker "$gover" "${builds[@]}" -#gover=1.24 -#builds=('darwin amd64 -11-big-sur' 'darwin arm64 -11-big-sur') +#gover=1.14 +#builds=('darwin 386 -10.11-el_capitan' 'darwin amd64 -10.11-el_capitan') #buildByDocker "$gover" "${builds[@]}" -#gover=1.22 -#builds=('darwin amd64 -10.15-catalina' 'darwin arm64 -10.15-catalina') +#gover=1.12 +#builds=() +#builds+=('darwin 386 -10.10-yosemite' 'darwin amd64 -10.10-yosemite') +#builds+=('freebsd 386 -10.x' 'freebsd amd64 -10.x' 'freebsd arm -9.x') #buildByDocker "$gover" "${builds[@]}" -gover=1.20 +gover=1.10 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 -xp-vista' 'windows amd64 -xp-vista') +#builds+=('darwin 386 -10.8-mountain_lion' 'darwin amd64 -10.8-mountain_lion') +#builds+=('openbsd 386 -6.0' 'openbsd amd64 -6.0' 'openbsd arm -6.0') buildByDocker "$gover" "${builds[@]}" -#gover=1.16 -#builds=('darwin amd64 -10.12-sierra' 'darwin arm64 -10.12-sierra') +#gover=1.9 +#builds=('freebsd 386 -9.x' 'freebsd amd64 -9.x' 'freebsd arm -9.x') #buildByDocker "$gover" "${builds[@]}" diff --git a/build/pkg/zip_3.0-11+b1_amd64.deb b/build/pkg/zip_3.0-11+b1_amd64.deb new file mode 100644 index 00000000..d15c22f2 Binary files /dev/null and b/build/pkg/zip_3.0-11+b1_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/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/goVirtualHost/vhost.go b/src/goVirtualHost/vhost.go index e5f3a09c..d8f5dd9f 100644 --- a/src/goVirtualHost/vhost.go +++ b/src/goVirtualHost/vhost.go @@ -56,13 +56,6 @@ func (vh *vhost) lookupCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate 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]) 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/util.go b/src/serverHandler/util.go index 38564e39..71b83771 100644 --- a/src/serverHandler/util.go +++ b/src/serverHandler/util.go @@ -68,7 +68,7 @@ func NeedResponseBody(method string) bool { } 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/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 = ` + + + + + + + + + {{.Path}} + + + + +{{$contextQueryString := .Context.QueryString}} +{{$isSimple := .IsSimple}} +{{$SubItemPrefix := .SubItemPrefix}} +{{if not $isSimple}} +
    + {{range .Paths}} +
  1. {{fmtFilename .Name}}
  2. + {{end}} +
+{{if .LoginAvail}} +{{.Trans.LoginLabel}} +{{else if .AuthUserName}} +[{{.AuthUserName}}] +{{end}} +{{if .CanUpload}} +
+ + {{.Trans.UploadingLabel}} + + + {{.Trans.UploadFailLabel}} + + +
+{{end}} + +{{if .CanMkdir}} +
+
+ + + +
+
+{{end}} + +{{if .CanUpload}} + +
+ + {{if .CanMkdir}} + {{end}} +
+
+
+ + + +
+
+{{end}} + +{{if .CanArchive}} +
+ .tar + .tar.gz + .zip +
+{{end}} + +{{if .CanDelete}} + +{{end}} +{{end}} +{{if .SubItemsHtml}} +
+
+ + +
+
+{{end}} + + +{{if ne .Status 200}}
{{.Status}} +{{if eq .Status 401}} + {{.Trans.Error401}} +{{else if eq .Status 403}} + {{.Trans.Error403}} +{{else if eq .Status 404}} + {{.Trans.Error404}} +{{else}} + {{.Trans.ErrorStatus}}
+{{end}} +{{end}} + + + + +` diff --git a/src/tpl/defaultTheme/frontend/index.js.go b/src/tpl/defaultTheme/frontend/index.js.go new file mode 100644 index 00000000..0dc8fc70 --- /dev/null +++ b/src/tpl/defaultTheme/frontend/index.js.go @@ -0,0 +1,1354 @@ +package frontend + +const DefaultJs = ` +(function () { + var strUndef = 'undefined'; + var protoHttps = 'https:'; + + var classNone = 'none'; + var classHeader = 'header'; + + var selectorNone = '.' + classNone; + var selectorNotNone = ':not(' + selectorNone + ')'; + var selectorItem = '.item-list > li:not(.' + classHeader + '):not(.parent)'; + var selectorItemNone = selectorItem + selectorNone; + var selectorItemNotNone = selectorItem + selectorNotNone; + + var leavingEvent = typeof window.onpagehide !== strUndef ? 'pagehide' : 'beforeunload'; + + var Enter = 'Enter'; + var Escape = 'Escape'; + var Esc = 'Esc'; + var Space = ' '; + + var noop = function () { + }; + + var logError; + if (typeof console !== strUndef) { + logError = function (err) { + console.error(err); + } + } else { + logError = noop; + } + + var hasClass, addClass, removeClass; + if (document.body.classList) { + hasClass = function (el, className) { + return el && el.classList.contains(className); + } + addClass = function (el, className) { + el && el.classList.add(className); + } + removeClass = function (el, className) { + el && el.classList.remove(className); + } + } else { + hasClass = function (el, className) { + if (!el) return; + var reClassName = new RegExp('\\b' + className + '\\b'); + return reClassName.test(el.className); + } + addClass = function (el, className) { + if (!el) return; + var originalClassName = el.className; + var reClassName = new RegExp('\\b' + className + '\\b'); + if (!reClassName.test(originalClassName)) { + el.className = originalClassName + ' ' + className; + } + } + removeClass = function (el, className) { + if (!el) return; + var originalClassName = el.className; + var reClassName = new RegExp('^\\s*' + className + '\\s+|\\s+' + className + '\\b', 'g'); + var newClassName = originalClassName.replace(reClassName, ''); + if (originalClassName !== newClassName) { + el.className = newClassName; + } + } + } + + var hasStorage = false; + try { + if (typeof sessionStorage !== strUndef) hasStorage = true; + } catch (err) { + } + + var lastFocused; + + function enableFilter() { + if (!document.querySelector) { + var filter = document.getElementById && document.getElementById('panel-filter'); + if (filter) { + filter.className += ' none'; + } + return; + } + + // pre check + var filter = document.body.querySelector('.filter'); + if (!filter) { + return; + } + if (!filter.addEventListener) { + filter.className += ' none'; + return; + } + + var input = filter.querySelector('input'); + if (!input) { + return; + } + + var trim = String.prototype.trim ? function (input) { + return input.trim(); + } : function () { + var reEdgeSpaces = /^\s+|\s+$/g + return function (input) { + return input.replace(reEdgeSpaces, ''); + } + }(); + + var clear = filter.querySelector('button'); + + // event handler + var timeoutId; + var lastFilterText = ''; + var doFilter = function () { + var filterText = trim(input.value).toLowerCase(); + if (filterText === lastFilterText) { + return; + } + + var selector, items, i; + + if (!filterText) { // filter cleared, show all items + if (clear) { + clear.style.display = ''; + } + selector = selectorItemNone; + items = document.body.querySelectorAll(selector); + for (i = items.length - 1; i >= 0; i--) { + removeClass(items[i], classNone); + } + } else { + if (clear) { + clear.style.display = 'block'; + } + if (filterText.indexOf(lastFilterText) >= 0) { // increment search, find in visible items + selector = selectorItemNotNone; + } else if (lastFilterText.indexOf(filterText) >= 0) { // decrement search, find in hidden items + selector = selectorItemNone; + } else { + selector = selectorItem; + } + + items = document.body.querySelectorAll(selector); + for (i = items.length - 1; i >= 0; i--) { + var item = items[i]; + var name = item.querySelector('.name'); + if (name && name.textContent.toLowerCase().indexOf(filterText) < 0) { + addClass(item, classNone); + } else { + removeClass(item, classNone); + } + } + } + + lastFilterText = filterText; + }; + + var onValueMayChange = function () { + clearTimeout(timeoutId); + timeoutId = setTimeout(doFilter, 350); + }; + input.addEventListener('input', onValueMayChange, false); + input.addEventListener('change', onValueMayChange, false); + + var onEnter = function () { + clearTimeout(timeoutId); + input.blur(); + doFilter(); + }; + var onEscape = function () { + clearTimeout(timeoutId); + input.value = ''; + doFilter(); + }; + + var ENTER_CODE = 13; + var ESCAPE_CODE = 27; + + input.addEventListener('keydown', function (e) { + if (e.key) { + switch (e.key) { + case Enter: + onEnter(); + e.preventDefault(); + break; + case Escape: + case Esc: + onEscape(); + e.preventDefault(); + break; + } + } else if (e.keyCode) { + switch (e.keyCode) { + case ENTER_CODE: + onEnter(); + e.preventDefault(); + break; + case ESCAPE_CODE: + onEscape(); + e.preventDefault(); + break; + } + } + }, false); + + clear && clear.addEventListener('click', function () { + clearTimeout(timeoutId); + input.value = ''; + input.focus(); + doFilter(); + }); + + // init + if (hasStorage) { + var prevSessionFilter = sessionStorage.getItem(location.pathname); + sessionStorage.removeItem(location.pathname); + + window.addEventListener(leavingEvent, function () { + if (input.value) { + sessionStorage.setItem(location.pathname, input.value); + } + }, false); + + if (prevSessionFilter) { + input.value = prevSessionFilter; + } + } + if (input.value) { + doFilter(); + } + } + + function keepFocusOnBackwardForward() { + if (window.onpageshow === undefined || !document.querySelector) return; + + function onFocus(e) { + var link = e.target; + while (link && !(link instanceof HTMLAnchorElement)) { + link = link.parentElement; + } + if (!link || link === lastFocused) return; + lastFocused = link; + } + + var itemList = document.body.querySelector('.item-list'); + itemList.addEventListener('focusin', onFocus); + itemList.addEventListener('click', onFocus); + window.addEventListener('pageshow', function () { + if (lastFocused && lastFocused !== document.activeElement) { + lastFocused.focus(); + lastFocused.scrollIntoView({block: 'center'}); + } + }); + } + + function focusChildOnNavUp() { + if (!document.querySelector) return; + + function extractCleanUrl(url) { + var sepIndex = url.indexOf('?'); + if (sepIndex < 0) sepIndex = url.indexOf('#'); + if (sepIndex >= 0) { + url = url.substring(0, sepIndex); + } + return url; + } + + var prevUrl = document.referrer; + if (!prevUrl) return; + prevUrl = extractCleanUrl(prevUrl); + + var currUrl = extractCleanUrl(location.href); + + if (prevUrl.length <= currUrl.length) return; + if (prevUrl.substring(0, currUrl.length) !== currUrl) return; + var goesUp = prevUrl.substring(currUrl.length); + if (currUrl[currUrl.length - 1] !== '/' && goesUp[0] !== '/') return; + var matchInfo = /[^/]+/.exec(goesUp); + if (!matchInfo) return; + var prevChildName = matchInfo[0]; + if (!prevChildName) return; + prevChildName = decodeURIComponent(prevChildName); + + var items = document.body.querySelectorAll(selectorItem); + items = Array.prototype.slice.call(items); + var selectorName = '.field.name'; + var selectorLink = 'a'; + for (var i = 0, len = items.length; i < len; i++) { + var item = items[i]; + var elName = item.querySelector(selectorName); + if (!elName) continue; + var text = elName.textContent; + if (text[text.length - 1] === '/') { + text = text.substring(0, text.length - 1); + } + if (text !== prevChildName) continue; + var elLink = item.querySelector(selectorLink); + if (elLink) { + lastFocused = elLink; + elLink.focus(); + elLink.scrollIntoView({block: 'center'}); + } + break; + } + } + + function enableKeyboardNavigate() { + if ( + !document.querySelector || + !document.addEventListener || + !document.body.parentElement + ) { + return; + } + + var pathList = document.body.querySelector('.path-list'); + var itemList = document.body.querySelector('.item-list'); + if (!pathList && !itemList) { + return; + } + + function getFocusableSibling(container, isBackward, startA) { + if (!container) { + return + } + if (!startA) { + startA = container.querySelector(':focus'); + } + var startLI = startA; + while (startLI && startLI.tagName !== 'LI') { + startLI = startLI.parentElement; + } + if (!startLI) { + if (isBackward) { + startLI = container.firstElementChild; + } else { + startLI = container.lastElementChild; + } + } + if (!startLI) { + return; + } + + var siblingLI = startLI; + do { + if (isBackward) { + siblingLI = siblingLI.previousElementSibling; + if (!siblingLI) { + siblingLI = container.lastElementChild; + } + } else { + siblingLI = siblingLI.nextElementSibling; + if (!siblingLI) { + siblingLI = container.firstElementChild; + } + } + } while (siblingLI !== startLI && ( + hasClass(siblingLI, classNone) || + hasClass(siblingLI, classHeader) + )); + + if (siblingLI) { + var siblingA = siblingLI.querySelector('a'); + return siblingA; + } + } + + var selectorFirstAvailLi = 'li:not(.' + classNone + '):not(.' + classHeader + ')'; + + function getFirstFocusableSibling(container) { + var li = container.querySelector(selectorFirstAvailLi); + var a = li && li.querySelector('a'); + return a; + } + + function getLastFocusableSibling(container) { + var a = container.querySelector('li a'); + a = getFocusableSibling(container, true, a); + return a; + } + + function getMatchedFocusableSibling(container, isBackward, startA, buf) { + var skipRound = buf.length === 1; // find next prefix + var matchKeyA; + var firstCheckA; + var secondCheckA; + var a = startA; + do { + if (skipRound) { + skipRound = false; + continue; + } + if (!a) { + continue; + } + + // firstCheckA maybe a focused a that not belongs to the list + // secondCheckA must be in the list + if (!firstCheckA) { + firstCheckA = a; + } else if (firstCheckA === a) { + return; + } else if (!secondCheckA) { + secondCheckA = a; + } else if (secondCheckA === a) { + return; + } + + var textContent = (a.querySelector('.name') || a).textContent.toLowerCase(); + if (buf.length <= textContent.length && textContent.substring(0, buf.length) === buf) { + return a; + } + } while (a = getFocusableSibling(container, isBackward, a)); + return matchKeyA; + } + + var UP = 'Up'; + var DOWN = 'Down'; + var LEFT = 'Left'; + var RIGHT = 'Right'; + + var ARROW_UP = 'ArrowUp'; + var ARROW_DOWN = 'ArrowDown'; + var ARROW_LEFT = 'ArrowLeft'; + var ARROW_RIGHT = 'ArrowRight'; + + var ARROW_UP_CODE = 38; + var ARROW_DOWN_CODE = 40; + var ARROW_LEFT_CODE = 37; + var ARROW_RIGHT_CODE = 39; + + var SKIP_TAGS = ['INPUT', 'BUTTON', 'TEXTAREA']; + + var PLATFORM = navigator.platform; + var IS_MAC_PLATFORM = PLATFORM.indexOf('Mac') >= 0 || PLATFORM.indexOf('iPhone') >= 0 || PLATFORM.indexOf('iPad') >= 0 || PLATFORM.indexOf('iPod') >= 0 + + var lookupKey; + var lookupBuffer; + var lookupStartA; + var lookupTimer; + + function clearLookupContext() { + lookupKey = undefined; + lookupBuffer = ''; + lookupStartA = null; + } + + clearLookupContext(); + + function delayClearLookupContext() { + clearTimeout(lookupTimer); + lookupTimer = setTimeout(clearLookupContext, 850); + } + + function lookup(container, key, isBackward) { + key = key.toLowerCase(); + + var currentLookupStartA; + if (key === lookupKey) { + // same as last key, lookup next for the same key as prefix + currentLookupStartA = container.querySelector(':focus'); + } else { + if (!lookupStartA) { + lookupStartA = container.querySelector(':focus'); + } + currentLookupStartA = lookupStartA; + if (lookupKey === undefined) { + lookupKey = key; + } else { + // key changed, no more prefix match + lookupKey = ''; + } + lookupBuffer += key; + } + delayClearLookupContext(); + return getMatchedFocusableSibling(container, isBackward, currentLookupStartA, lookupKey || lookupBuffer); + } + + var canArrowMove; + var isToEnd; + if (IS_MAC_PLATFORM) { + canArrowMove = function (e) { + return !(e.ctrlKey || e.shiftKey || e.metaKey); // only allow Opt + } + isToEnd = function (e) { + return e.altKey; // Opt key + } + } else { + canArrowMove = function (e) { + return !(e.altKey || e.shiftKey || e.metaKey); // only allow Ctrl + } + isToEnd = function (e) { + return e.ctrlKey; + } + } + + function getFocusItemByKeyPress(e) { + if (SKIP_TAGS.indexOf(e.target.tagName) >= 0) { + return; + } + + if (e.key) { + if (canArrowMove(e)) { + switch (e.key) { + case LEFT: + case ARROW_LEFT: + if (isToEnd(e)) { + return getFirstFocusableSibling(pathList); + } else { + return getFocusableSibling(pathList, true); + } + case RIGHT: + case ARROW_RIGHT: + if (isToEnd(e)) { + return getLastFocusableSibling(pathList); + } else { + return getFocusableSibling(pathList, false); + } + case UP: + case ARROW_UP: + if (isToEnd(e)) { + return getFirstFocusableSibling(itemList); + } else { + return getFocusableSibling(itemList, true); + } + case DOWN: + case ARROW_DOWN: + if (isToEnd(e)) { + return getLastFocusableSibling(itemList); + } else { + return getFocusableSibling(itemList, false); + } + } + } + if (!e.ctrlKey && (!e.altKey || IS_MAC_PLATFORM) && !e.metaKey && e.key.length === 1) { + return lookup(itemList, e.key, e.shiftKey); + } + } else if (e.keyCode) { + if (canArrowMove(e)) { + switch (e.keyCode) { + case ARROW_LEFT_CODE: + if (isToEnd(e)) { + return getFirstFocusableSibling(pathList); + } else { + return getFocusableSibling(pathList, true); + } + case ARROW_RIGHT_CODE: + if (isToEnd(e)) { + return getLastFocusableSibling(pathList); + } else { + return getFocusableSibling(pathList, false); + } + case ARROW_UP_CODE: + if (isToEnd(e)) { + return getFirstFocusableSibling(itemList); + } else { + return getFocusableSibling(itemList, true); + } + case ARROW_DOWN_CODE: + if (isToEnd(e)) { + return getLastFocusableSibling(itemList); + } else { + return getFocusableSibling(itemList, false); + } + } + } + if (!e.ctrlKey && (!e.altKey || IS_MAC_PLATFORM) && !e.metaKey && e.keyCode >= 32 && e.keyCode <= 126) { + return lookup(itemList, String.fromCharCode(e.keyCode), e.shiftKey); + } + } + } + + document.addEventListener('keydown', function (e) { + var newFocusEl = getFocusItemByKeyPress(e); + if (newFocusEl) { + e.preventDefault(); + newFocusEl.focus(); + } + }); + } + + function enhanceUpload() { + if (!document.querySelector || !document.addEventListener) { + return; + } + + var upload = document.body.querySelector('.upload'); + if (!upload) { + return; + } + var form = upload.querySelector('form'); + if (!form) { + return; + } + var fileInput = form.querySelector('.file'); + if (!fileInput) { + return; + } + + var uploadType = document.body.querySelector('.upload-type'); + if (!uploadType) { + return; + } + + var file = 'file'; + var dirFile = 'dirfile'; + var innerDirFile = 'innerdirfile'; + + var optFile = uploadType.querySelector('.' + file); + var optDirFile = uploadType.querySelector('.' + dirFile); + var optInnerDirFile = uploadType.querySelector('.' + innerDirFile); + var optActive = optFile; + var canMkdir = Boolean(optDirFile); + + var padStart = String.prototype.padStart ? function (sourceString, targetLength, padTemplate) { + return sourceString.padStart(targetLength, padTemplate); + } : function (sourceString, targetLength, padTemplate) { + var sourceLength = sourceString.length; + if (sourceLength >= targetLength) { + return sourceString; + } + var padLength = targetLength - sourceLength + var repeatCount = Math.ceil(padLength / padTemplate.length); + var padString; + if (String.prototype.repeat) { + padString = padTemplate.repeat(repeatCount); + } else { + padString = ''; + for (var i = 0; i < repeatCount; i++) { + padString += padTemplate; + } + } + if (padString.length > padLength) { + padString = padString.substring(0, padLength); + } + + return padString + sourceString; + } + + function getTimeStamp() { + var now = new Date(); + var date = String(now.getFullYear() * 10000 + (now.getMonth() + 1) * 100 + now.getDate()); + var time = String(now.getHours() * 10000 + now.getMinutes() * 100 + now.getSeconds()); + var ms = String(now.getMilliseconds()); + date = padStart(date, 8, '0'); + time = padStart(time, 6, '0'); + ms = padStart(ms, 3, '0'); + var ts = '-' + date + '-' + time + '-' + ms; + return ts; + } + + var itemsToFiles; + if (location.protocol === protoHttps && typeof FileSystemHandle !== strUndef && !DataTransferItem.prototype.webkitGetAsEntry) { + var handleKindFile = 'file'; + var handleKindDir = 'directory'; + var permDescriptor = {mode: 'read'}; + itemsToFiles = function (dataTransferItems, canMkdir, onDone, onLacksMkdir) { + function resultsToFiles(results, files, dirPath) { + return Promise.all(results.map(function (result) { + var handle = result.value; + if (handle.kind === handleKindFile) { + return handle.queryPermission(permDescriptor).then(function (queryResult) { + if (queryResult === 'prompt') return handle.requestPermission(permDescriptor); + }).then(function () { + return handle.getFile(); + }).then(function (file) { + var relativePath = dirPath + file.name; + files.push({file: file, relativePath: relativePath}); + })['catch'](function (err) { // workaround IE8- syntax error for ".catch"(reserved keyword) + logError(err); + }); + } else if (handle.kind === handleKindDir) { + return new Promise(function (resolve) { + var childResults = []; + var childIter = handle.values(); + + function onLevelDone() { + childResults = null; + childIter = null; + resolve(); + } + + function addChildResult() { + childIter.next().then(function (result) { + if (result.done) { + if (childResults.length) { + resultsToFiles(childResults, files, dirPath + handle.name + '/').then(onLevelDone); + } else onLevelDone(); + } else { + childResults.push(result); + addChildResult(); + } + }); + } + + addChildResult(); + }); + } + })); + } + + var files = []; + var hasDir = false; + if (!dataTransferItems || !dataTransferItems.length) return onDone(files, hasDir); + + var items = Array.prototype.slice.call(dataTransferItems); + Promise.all(items.map(function (item) { + return item.getAsFileSystemHandle(); + })).then(function (handles) { + handles = handles.filter(Boolean); // undefined for pasted content + hasDir = handles.some(function (handle) { + return handle.kind === handleKindDir; + }); + if (hasDir && !canMkdir) { + return onLacksMkdir(); + } + var handleResults = handles.map(function (handle) { + return {value: handle, done: false}; + }); + resultsToFiles(handleResults, files, '').then(function () { + onDone(files, hasDir); + }); + }); + } + } else { + itemsToFiles = function (dataTransferItems, canMkdir, onDone, onLacksMkdir) { + function entriesToFiles(entries, files, onLevelDone) { + var len = entries.length; + var cb = 0; + if (!len) return onLevelDone(); + + function increaseCb() { + cb++; + if (cb === len) { + onLevelDone(); + } + } + + function dirReaderToFiles(dirReader, files, onAllRead) { + dirReader.readEntries(function (subEntries) { + if (!subEntries.length) return onAllRead(); + entriesToFiles(subEntries, files, function () { + dirReaderToFiles(dirReader, files, onAllRead); + }); + }, onAllRead); + } + + entries.forEach(function (entry) { + if (entry.isFile) { + var relativePath = entry.fullPath; + if (relativePath[0] === '/') { + relativePath = relativePath.substring(1); + } + entry.file(function (file) { + files.push({file: file, relativePath: relativePath}); + increaseCb(); + }, function (err) { + increaseCb(); + logError(err); + }); + } else if (entry.isDirectory) { + var dirReader = entry.createReader(); + dirReaderToFiles(dirReader, files, increaseCb); + } + }); + } + + var files = []; + var hasDir = false; + if (!dataTransferItems || !dataTransferItems.length || !dataTransferItems[0].webkitGetAsEntry) return onDone(files, hasDir); + + var entries = []; + for (var i = 0, len = dataTransferItems.length; i < len; i++) { + var item = dataTransferItems[i]; + var entry = item.webkitGetAsEntry(); + if (!entry) { // undefined for pasted text + continue; + } + if (entry.isFile) { + // Safari cannot get file from entry by entry.file(), if it is a pasted image + // so workaround is for all browsers, just get first hierarchy of files by item.getAsFile() + var file = item.getAsFile(); + files.push({file: file, relativePath: file.name}); + } else if (entry.isDirectory) { + hasDir = true; + if (canMkdir) { + entries.push(entry); + } else { + return onLacksMkdir(); + } + } + } + + entriesToFiles(entries, files, function () { + onDone(files, hasDir); + }); + } + } + + function dataTransferToFiles(dataTransfer, canMkdir, onDone, onLacksMkdir) { + itemsToFiles(dataTransfer.items, canMkdir, function (files, hasDir) { + // ancient Browser + if (files.length === 0 && dataTransfer.files && dataTransfer.files.length) { + files = Array.prototype.slice.call(dataTransfer.files); + } + onDone(files, hasDir); + }, onLacksMkdir); + } + + var switchToFileMode = noop; + var switchToDirMode = noop; + + function enableAddDirFile() { + var classHidden = 'hidden'; + var classActive = 'active'; + + function onClickOpt(optTarget, clearInput) { + if (optTarget === optActive) { + return; + } + removeClass(optActive, classActive); + + optActive = optTarget; + addClass(optActive, classActive); + + if (clearInput) { + fileInput.value = ''; + } + return true; + } + + function onClickOptFile(e) { + if (onClickOpt(optFile, Boolean(e))) { + fileInput.name = file; + fileInput.webkitdirectory = false; + } + } + + function onClickOptDirFile() { + if (onClickOpt(optDirFile, optActive === optFile)) { + fileInput.name = dirFile; + fileInput.webkitdirectory = true; + } + } + + function onClickOptInnerDirFile() { + if (onClickOpt(optInnerDirFile, optActive === optFile)) { + fileInput.name = innerDirFile; + fileInput.webkitdirectory = true; + } + } + + function onKeydownOpt(e) { + switch (e.key) { + case Enter: + case Space: + if (e.ctrlKey || e.altKey || e.metaKey || e.shiftKey) { + break; + } + e.preventDefault(); + e.stopPropagation(); + if (e.target === optActive) { + break; + } + e.target.click(); + break; + } + } + + if (typeof fileInput.webkitdirectory === strUndef) { + addClass(uploadType, classNone); + return; + } + optDirFile && removeClass(optDirFile, classHidden); + optInnerDirFile && removeClass(optInnerDirFile, classHidden); + + if (optFile) { + optFile.addEventListener('click', onClickOptFile); + optFile.addEventListener('keydown', onKeydownOpt); + } + if (optDirFile) { + optDirFile.addEventListener('click', onClickOptDirFile); + optDirFile.addEventListener('keydown', onKeydownOpt); + } + if (optInnerDirFile) { + optInnerDirFile.addEventListener('click', onClickOptInnerDirFile); + optInnerDirFile.addEventListener('keydown', onKeydownOpt); + } + + if (hasStorage) { + var uploadTypeField = 'upload-type'; + var prevUploadType = sessionStorage.getItem(uploadTypeField); + sessionStorage.removeItem(uploadTypeField); + + window.addEventListener(leavingEvent, function () { + var activeUploadType = fileInput.name; + if (activeUploadType !== file) { + sessionStorage.setItem(uploadTypeField, activeUploadType) + } + }, false); + + if (prevUploadType === dirFile) { + optDirFile && optDirFile.click(); + } else if (prevUploadType === innerDirFile) { + optInnerDirFile && optInnerDirFile.click(); + } + } + + optFile && fileInput.addEventListener('change', function (e) { + // workaround fix for mobile device, select dir not work but still act like select files + // switch back to file + if (optActive === optFile) { + return; + } + var files = e.target.files; + if (!files || !files.length) { + return; + } + + var nodir = Array.prototype.slice.call(files).every(function (file) { + return !file.webkitRelativePath || file.webkitRelativePath.indexOf('/') < 0; + }); + if (nodir) { + onClickOptFile(); // prevent clear input files + } + }); + + switchToFileMode = function () { + if (optFile && optActive !== optFile) { + optFile.focus(); + onClickOptFile(true); + } + } + + switchToDirMode = function () { + if (optDirFile) { + if (optActive !== optDirFile) { + optDirFile.focus(); + onClickOptDirFile(); + } + } else if (optInnerDirFile) { + if (optActive !== optInnerDirFile) { + optInnerDirFile.focus(); + onClickOptInnerDirFile(); + } + } + } + } + + function enableUploadProgress() { // also fix Safari upload filename has no path info + if (typeof FormData === strUndef) { + return; + } + + var uploading = false; + var batches = []; + var classUploading = 'uploading'; + var classFailed = 'failed'; + var elUploadStatus = document.body.querySelector('.upload-status'); + var elProgress = elUploadStatus && elUploadStatus.querySelector('.progress'); + var elFailedMessage = elUploadStatus && elUploadStatus.querySelector('.warn .message'); + + function onComplete() { + if (elProgress) { + elProgress.style.width = ''; + } + } + + function onSuccess() { + if (batches.length) { + return uploadBatch(batches.shift()); // use "return" for tail call optimize + } else { + uploading = false; + removeClass(elUploadStatus, classUploading); + } + } + + function onFail(e) { + removeClass(elUploadStatus, classUploading); + addClass(elUploadStatus, classFailed); + if (elFailedMessage) { + elFailedMessage.textContent = " - " + e.type; + } + batches.length = 0; + } + + function onLoad() { + var status = this.status; + if (status >= 200 && status <= 299) { + !uploading && location.reload(); + } else { + onFail({type: this.statusText || status}); + } + } + + function onProgress(e) { + if (e.lengthComputable) { + var percent = 100 * e.loaded / e.total; + elProgress.style.width = percent + '%'; + } + } + + function uploadProgressively(files) { + if (!files || !files.length) { + return; + } + + if (uploading) { + batches.push(files); + } else { + uploading = true; + removeClass(elUploadStatus, classFailed); + addClass(elUploadStatus, classUploading); + uploadBatch(files); + } + } + + function uploadBatch(files) { + var formName = fileInput.name; + var parts = new FormData(); + files.forEach(function (file) { + var relativePath + if (file.file) { + // unwrap object {file, relativePath} + relativePath = file.relativePath; + file = file.file; + } else if (file.webkitRelativePath) { + relativePath = file.webkitRelativePath + } + if (!relativePath) { + relativePath = file.name; + } + + parts.append(formName, file, relativePath); + }); + + var xhr = new XMLHttpRequest(); + xhr.addEventListener('error', onComplete); + xhr.addEventListener('error', onFail); + xhr.addEventListener('abort', onComplete); + xhr.addEventListener('abort', onFail); + xhr.addEventListener('load', onComplete); + xhr.addEventListener('load', onSuccess); + xhr.addEventListener('load', onLoad); + if (elProgress) { + xhr.upload.addEventListener('progress', onProgress); + } + + xhr.open(form.method, form.action); + xhr.send(parts); + } + + return uploadProgressively; + } + + function enableFormUploadProgress(uploadProgressively) { + form.addEventListener('submit', function (e) { + e.stopPropagation(); + e.preventDefault(); + + var files = Array.prototype.slice.call(fileInput.files); + uploadProgressively(files); + }); + + fileInput.addEventListener('change', function () { + var files = Array.prototype.slice.call(fileInput.files); + uploadProgressively(files); + }); + } + + function enableAddDragDrop(uploadProgressively) { + var isSelfDragging = false; + var classDragging = 'dragging'; + + function onSelfDragStart() { + isSelfDragging = true; + } + + function onDragEnd() { + isSelfDragging = false; + } + + function onDragEnterOver(e) { + if (!isSelfDragging) { + e.stopPropagation(); + e.preventDefault(); + addClass(e.currentTarget, classDragging); + } + } + + function onDragLeave(e) { + if (e.target === e.currentTarget) { + removeClass(e.currentTarget, classDragging); + } + } + + function onDrop(e) { + e.stopPropagation(); + e.preventDefault(); + removeClass(e.currentTarget, classDragging); + fileInput.value = ''; + + if (!e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files.length) { + return; + } + + dataTransferToFiles(e.dataTransfer, canMkdir && Boolean(uploadProgressively), function (files, hasDir) { + if (hasDir) { + switchToDirMode(); + uploadProgressively(files); + } else { + switchToFileMode(); + if (uploadProgressively) { + uploadProgressively(files); + } else { + fileInput.files = files; + form.submit(); + } + } + }, function () { + typeof showUploadDirFailMessage !== strUndef && showUploadDirFailMessage(); + }); + } + + document.body.addEventListener('dragstart', onSelfDragStart); + document.body.addEventListener('dragend', onDragEnd); + var dragDropEl = document.documentElement; + dragDropEl.addEventListener('dragenter', onDragEnterOver); + dragDropEl.addEventListener('dragover', onDragEnterOver); + dragDropEl.addEventListener('dragleave', onDragLeave); + dragDropEl.addEventListener('drop', onDrop); + } + + function enableAddPasteProgressively(uploadProgressively) { + var typeTextPlain = 'text/plain'; + var createTextFile; + var textFilename = 'text.txt'; + if (Blob && Blob.prototype.msClose) { // legacy Edge + createTextFile = function (content) { + var file = new Blob([content], {type: typeTextPlain}); + file.name = textFilename; + return file; + }; + } else if (File) { + createTextFile = function (content) { + return new File([content], textFilename, {type: typeTextPlain}); + } + } + + var nonTextInputTypes = ['hidden', 'radio', 'checkbox', 'button', 'reset', 'submit', 'image']; + + function uploadPastedFiles(files) { + switchToFileMode(); + var ts = getTimeStamp(); + files = files.map(function (f, i) { + var filename = f.name; + var dotIndex = filename.lastIndexOf('.'); + if (dotIndex < 0) { + dotIndex = filename.length; + } + filename = filename.substring(0, dotIndex) + ts + '-' + i + filename.substring(dotIndex); + return { + file: f, + relativePath: filename + } + }); + uploadProgressively(files); + } + + function generatePastedFiles(data) { + var files; + var items; + if (data.files && data.files.length) { + // pasted content is image + files = Array.prototype.slice.call(data.files); + } else if (data.items && data.items.length) { + // pasted content is text + items = Array.prototype.slice.call(data.items); + files = items.map(function (item) { + return item.getAsFile(); + }).filter(Boolean); + } else { + files = []; + } + + if (files.length) { + uploadPastedFiles(files); + return; + } + + if (!createTextFile) { + return; + } + if (!items) { + return; + } + var plainTextFiles = 0; + for (var i = 0, itemsCount = items.length; i < itemsCount; i++) { + if (data.types[i] !== typeTextPlain) { + continue + } + plainTextFiles++; + items[i].getAsString(function (content) { + var file = createTextFile(content); + files.push(file); + if (files.length === plainTextFiles) { + uploadPastedFiles(files); + } + }); + } + } + + document.documentElement.addEventListener('paste', function (e) { + var tagName = e.target.tagName; + if (tagName === 'INPUT') { + if (nonTextInputTypes.indexOf(e.target.type) < 0) { + return; + } + } + if (tagName === 'TEXTAREA') { + return; + } + var data = e.clipboardData; + if (!data) { + return; + } + + var items = data.items; + if (!items || !items.length) { + generatePastedFiles(data); + return; + } + + itemsToFiles(items, canMkdir, function (files, hasDir) { + // for pasted text + if (!files.length) { + generatePastedFiles(data); + return; + } + + // suppose for pasted image data + if (files.length === 1 && files[0].file.type === 'image/png') { + files = files.map(function (fileInfo) { + return fileInfo && fileInfo.file; + }); + generatePastedFiles({files: files}); + return; + } + + // pasted real files + if (hasDir) { + switchToDirMode(); + } else { + switchToFileMode(); + } + uploadProgressively(files); + }, function () { + typeof showUploadDirFailMessage !== strUndef && showUploadDirFailMessage(); + }); + }); + } + + function enableAddPasteFormSubmit() { + document.documentElement.addEventListener('paste', function (e) { + var data = e.clipboardData; + if (data && data.files && data.files.length) { + switchToFileMode(); + fileInput.files = data.files; + form.submit(); + } + }); + } + + enableAddDirFile(); + var uploadProgressively = enableUploadProgress(); + if (uploadProgressively) { + enableFormUploadProgress(uploadProgressively); + enableAddPasteProgressively(uploadProgressively); + } else { + enableAddPasteFormSubmit(); + } + enableAddDragDrop(uploadProgressively); + } + + function enableNonRefreshDelete() { + if (!document.querySelector) { + return; + } + + var itemList = document.body.querySelector('.item-list'); + if (!itemList || !itemList.addEventListener) { + return; + } + if (!hasClass(itemList, 'has-deletable')) return; + + itemList.addEventListener('submit', function (e) { + if (e.defaultPrevented) { + return; + } + + var form = e.target; + + function onLoad() { + var status = this.status; + if (status >= 200 && status <= 299) { + var elItem = form; + while (elItem && elItem.nodeName !== 'LI') { + elItem = elItem.parentElement; + } + if (!elItem) { + return; + } + var elItemParent = elItem.parentNode; + elItemParent && elItemParent.removeChild(elItem); + } else { + logError('delete failed: ' + status + ' ' + this.statusText); + } + } + + var params = ''; + var els = Array.prototype.slice.call(form.elements); + for (var i = 0, len = els.length; i < len; i++) { + if (!els[i].name) { + continue + } + if (params.length > 0) { + params += '&' + } + params += els[i].name + '=' + encodeURIComponent(els[i].value) + } + var url = form.action; + + var xhr = new XMLHttpRequest(); + xhr.open('POST', url); // will retrieve deleted result into bfcache + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + xhr.addEventListener('load', onLoad); + xhr.send(params); + e.preventDefault(); + return false; + }, false); + } + + enableFilter(); + keepFocusOnBackwardForward(); + focusChildOnNavUp(); + enableKeyboardNavigate(); + enhanceUpload(); + enableNonRefreshDelete(); +})(); +` diff --git a/src/tpl/theme/dirTheme.go b/src/tpl/theme/dirTheme.go index e0cc3564..0451dc55 100644 --- a/src/tpl/theme/dirTheme.go +++ b/src/tpl/theme/dirTheme.go @@ -2,8 +2,8 @@ package theme import ( "io" + "io/ioutil" "net/http" - "os" "path" "strings" ) @@ -12,7 +12,7 @@ type DirTheme string func (dir DirTheme) RenderPage(w io.Writer, data interface{}) error { filename := string(dir) + "/" + templateFilename - tplStr, err := os.ReadFile(filename) + tplStr, err := ioutil.ReadFile(filename) if err != nil { return err } diff --git a/src/tpl/theme/memTheme.go b/src/tpl/theme/memTheme.go index e599f19c..8fed7b3c 100644 --- a/src/tpl/theme/memTheme.go +++ b/src/tpl/theme/memTheme.go @@ -5,6 +5,7 @@ import ( "errors" "html/template" "io" + "io/ioutil" "net/http" "time" ) @@ -37,7 +38,7 @@ func LoadMemTheme(themePath string) (theme MemTheme, err error) { continue } var raw []byte - raw, err = io.ReadAll(rd) + raw, err = ioutil.ReadAll(rd) rd.Close() if err != nil { return diff --git a/src/util/str.go b/src/util/str.go index 719eaa25..0d26c68a 100644 --- a/src/util/str.go +++ b/src/util/str.go @@ -73,7 +73,8 @@ func EscapeControllingRune(str string) []byte { buf = append(buf, '\\', 'x', h, l) } } else { - buf = utf8.AppendRune(buf, r) + nBytes := utf8.EncodeRune(runeBytes, r) + buf = append(buf, runeBytes[:nBytes]...) } }