From b7fb414eb720df5173aef32ffebef41262c5de93 Mon Sep 17 00:00:00 2001 From: marjune Date: Fri, 8 Jan 2021 00:33:40 +0800 Subject: [PATCH 01/57] feat: apply shim based on Go 1.2 This makes it possible to build executable for Windows 2000 platform. --- build/build-all-docker.sh | 30 +----- build/build.sh | 16 ++- src/goNixArgParser/optionSet.go | 4 +- src/goVirtualHost/server.go | 5 +- src/goVirtualHost/util.go | 7 +- src/main.go | 3 +- src/serverHandler/archive.go | 4 +- src/serverHandler/auth.go | 7 +- src/serverHandler/cors.go | 17 ++-- src/serverHandler/mutate.go | 3 +- src/serverHandler/responseData.go | 3 +- src/serverHandler/sort.go | 14 +-- src/serverHandler/upload.go | 3 +- src/serverHandler/util.go | 10 +- src/shimgo/LICENSE_GO | 27 ++++++ src/shimgo/net_http.go | 75 ++++++++++++++ src/shimgo/net_url.go | 156 ++++++++++++++++++++++++++++++ src/shimgo/shim.go | 18 ++++ src/shimgo/strings.go | 33 +++++++ src/util/hostname.go | 9 +- 20 files changed, 377 insertions(+), 67 deletions(-) create mode 100644 src/shimgo/LICENSE_GO create mode 100644 src/shimgo/net_http.go create mode 100644 src/shimgo/net_url.go create mode 100644 src/shimgo/shim.go create mode 100644 src/shimgo/strings.go diff --git a/build/build-all-docker.sh b/build/build-all-docker.sh index 408a3595..11ff1f84 100644 --- a/build/build-all-docker.sh +++ b/build/build-all-docker.sh @@ -19,7 +19,7 @@ buildByDocker() { /bin/bash -c ' 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; /bin/bash /mnt/build/build.sh "$@"; chown -R $EX_UID:$EX_GID /mnt/output ' \ @@ -27,29 +27,7 @@ buildByDocker() { "$@" } -gover=latest -builds=('linux 386' 'linux amd64' 'linux arm' 'linux arm64' 'windows 386' 'windows amd64' 'windows arm' 'darwin amd64') -builds=("${builds[@]}" 'freebsd 386' 'freebsd amd64' 'freebsd arm' 'freebsd arm64') -builds=("${builds[@]}" 'openbsd 386' 'openbsd amd64' 'openbsd arm' 'openbsd arm64') -builds=("${builds[@]}" 'netbsd 386' 'netbsd amd64' 'netbsd arm' 'netbsd arm64') -builds=("${builds[@]}" 'plan9 386' 'plan9 amd64' 'plan9 arm') +gover=1.2 +builds=('windows 386 -2000') +#builds=("${builds[@]}" 'freebsd 386 -8' 'freebsd amd64 -8') buildByDocker "$gover" "${builds[@]}" - -#gover=1.9 -#builds=('freebsd 386 -9.x' 'freebsd amd64 -9.x' 'freebsd arm -9.x') -#buildByDocker "$gover" "${builds[@]}" - -gover=1.10 -builds=('windows 386 -xp-vista' 'windows amd64 -xp-vista') -#builds=("${builds[@]}" 'darwin 386 -10.8-mountain_lion' 'darwin amd64 -10.8-mountain_lion') -#builds=("${builds[@]}" 'openbsd 386 -6.0' 'openbsd amd64 -6.0' 'openbsd arm -6.0') -buildByDocker "$gover" "${builds[@]}" - -#gover=1.12 -#builds=('darwin 386 -10.10-yosemite' 'darwin amd64 -10.10-yosemite') -#builds=("${builds[@]}" 'freebsd 386 -10.x' 'freebsd amd64 -10.x' 'freebsd arm -9.x') -#buildByDocker "$gover" "${builds[@]}" - -#gover=1.14 -#builds=('darwin 386 -10.11-el_capitan' 'darwin amd64 -10.11-el_capitan') -#buildByDocker "$gover" "${builds[@]}" diff --git a/build/build.sh b/build/build.sh index bbc3dab1..b7edff00 100644 --- a/build/build.sh +++ b/build/build.sh @@ -7,8 +7,9 @@ OUTDIR='../output' MAINNAME='ghfs' MOD=$(go list ../src/) VERSION=$(git describe --abbrev=0 --tags 2> /dev/null || git rev-parse --abbrev-ref HEAD 2> /dev/null) -LDFLAGS="-s -w -X $MOD/version.appVer=$VERSION" +LDFLAGS="-s -w" LICENSE='../LICENSE' +LICENSE_GO='../src/shimgo/LICENSE_GO' mkdir -p "$OUTDIR" @@ -18,14 +19,23 @@ for build in "$@"; do export GOARCH="${arg[1]}" 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 + BIN="$TMP"/"$MAINNAME" if [ "$GOOS" == 'windows' ]; then BIN="${BIN}.exe" fi; rm -f "$BIN" echo "Building: $GOOS$OS_SUFFIX $GOARCH" - go build -ldflags "$LDFLAGS" -o "$BIN" ../src/main.go + go build -ldflags "$LDFLAGS" -o "$BIN" /tmp/src/main.go OUT="$OUTDIR"/"$MAINNAME"-"$VERSION"-"$GOOS""$OS_SUFFIX"-"$GOARCH".zip - zip -j "$OUT" "$BIN" "$LICENSE" + zip -j "$OUT" "$BIN" "$LICENSE" "$LICENSE_GO" done diff --git a/src/goNixArgParser/optionSet.go b/src/goNixArgParser/optionSet.go index d9cbc730..2576bb6a 100644 --- a/src/goNixArgParser/optionSet.go +++ b/src/goNixArgParser/optionSet.go @@ -1,9 +1,9 @@ package goNixArgParser import ( + "../shimgo" "bytes" "errors" - "os" "strings" ) @@ -165,7 +165,7 @@ func (s *OptionSet) Add(opt Option) error { if len(envVar) == 0 { continue } - envValue, hasEnv := os.LookupEnv(envVar) + envValue, hasEnv := shimgo.Os_LookupEnv(envVar) if !hasEnv || len(envValue) == 0 { continue } diff --git a/src/goVirtualHost/server.go b/src/goVirtualHost/server.go index 7c7b3277..1429c1ae 100644 --- a/src/goVirtualHost/server.go +++ b/src/goVirtualHost/server.go @@ -1,6 +1,7 @@ package goVirtualHost import ( + "../shimgo" "crypto/tls" "net/http" ) @@ -79,12 +80,12 @@ func (server *server) updateHttpServerHandler() { func (server *server) open(listener *listener) error { if server.useTLS { - return server.httpServer.ServeTLS(listener.netListener, "", "") + return shimgo.Net_Http_Server_ServeTLS(server.httpServer, listener.netListener, "", "") } else { return server.httpServer.Serve(listener.netListener) } } func (server *server) close() error { - return server.httpServer.Close() + return nil } diff --git a/src/goVirtualHost/util.go b/src/goVirtualHost/util.go index 32b6ebd0..644fe937 100644 --- a/src/goVirtualHost/util.go +++ b/src/goVirtualHost/util.go @@ -1,6 +1,7 @@ package goVirtualHost import ( + "../shimgo" "strings" ) @@ -21,7 +22,7 @@ func extractHostName(host string) string { } } - colonIndex := strings.LastIndexByte(host, ':') + colonIndex := shimgo.Strings_LastIndexByte(host, ':') if colonIndex >= 0 { return host[:colonIndex] } @@ -82,7 +83,7 @@ func splitListen(listen string, useTLS bool) (proto, addr string) { } colonIndex := strings.IndexByte(listen, ':') - lastColonIndex := strings.LastIndexByte(listen, ':') + lastColonIndex := shimgo.Strings_LastIndexByte(listen, ':') // ipv6 squareEnd := strings.IndexByte(listen, ']') @@ -99,7 +100,7 @@ func splitListen(listen string, useTLS bool) (proto, addr 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/main.go b/src/main.go index 0a59f0b1..f3f31463 100644 --- a/src/main.go +++ b/src/main.go @@ -26,7 +26,8 @@ func reOpenLogOnHup() { signal.Notify(chSignal, syscall.SIGHUP) go func() { - for range chSignal { + for sig := range chSignal { + sig = sig // ignore iterate value appInst.ReOpenLog() } }() diff --git a/src/serverHandler/archive.go b/src/serverHandler/archive.go index 547337fb..1a062500 100644 --- a/src/serverHandler/archive.go +++ b/src/serverHandler/archive.go @@ -1,9 +1,9 @@ package serverHandler import ( + "../shimgo" "../util" "net/http" - "net/url" "os" "path" "strings" @@ -150,7 +150,7 @@ func (h *handler) archive( } 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 1368708d..3534c8b0 100644 --- a/src/serverHandler/auth.go +++ b/src/serverHandler/auth.go @@ -1,12 +1,15 @@ package serverHandler -import "net/http" +import ( + "../shimgo" + "net/http" +) func (h *handler) auth(w http.ResponseWriter, r *http.Request) (success bool) { header := w.Header() header.Set("WWW-Authenticate", "Basic realm=\""+r.URL.Path+"\"") - username, password, hasAuthReq := r.BasicAuth() + username, password, hasAuthReq := shimgo.Net_Http_BasicAuth(r) if hasAuthReq { success = h.users.Auth(username, password) } diff --git a/src/serverHandler/cors.go b/src/serverHandler/cors.go index 12a7d467..7d1d5179 100644 --- a/src/serverHandler/cors.go +++ b/src/serverHandler/cors.go @@ -1,6 +1,7 @@ package serverHandler import ( + "../shimgo" "../util" "net/http" "strings" @@ -11,19 +12,19 @@ func (h *handler) cors(w http.ResponseWriter, r *http.Request) { header.Set("Access-Control-Allow-Origin", "*") - if r.Method != http.MethodOptions { + if r.Method != shimgo.Net_Http_MethodOptions { return } // Access-Control-Allow-Methods acAllowMethods := []string{ - http.MethodGet, - http.MethodHead, - http.MethodPost, - http.MethodPut, - http.MethodDelete, - http.MethodOptions, - http.MethodTrace, + shimgo.Net_Http_MethodGet, + shimgo.Net_Http_MethodHead, + shimgo.Net_Http_MethodPost, + shimgo.Net_Http_MethodPut, + shimgo.Net_Http_MethodDelete, + shimgo.Net_Http_MethodOptions, + shimgo.Net_Http_MethodTrace, } acReqMethods := r.Header["Access-Control-Request-Method"] if len(acReqMethods) > 0 { diff --git a/src/serverHandler/mutate.go b/src/serverHandler/mutate.go index 08ff7736..8ae6735d 100644 --- a/src/serverHandler/mutate.go +++ b/src/serverHandler/mutate.go @@ -1,6 +1,7 @@ package serverHandler import ( + "../shimgo" "net/http" "strings" ) @@ -10,7 +11,7 @@ func (h *handler) mutate(w http.ResponseWriter, r *http.Request, data *responseD switch { case data.IsUpload: - if data.CanUpload && r.Method == http.MethodPost { + if data.CanUpload && r.Method == shimgo.Net_Http_MethodPost { success = h.saveUploadFiles(h.root+data.handlerReqPath, data.CanMkdir, data.CanDelete, data.AliasSubItems, r) } case data.IsMkdir: diff --git a/src/serverHandler/responseData.go b/src/serverHandler/responseData.go index 7493ec56..214ae0b2 100644 --- a/src/serverHandler/responseData.go +++ b/src/serverHandler/responseData.go @@ -1,6 +1,7 @@ package serverHandler import ( + "../shimgo" "../util" "html/template" "net/http" @@ -362,7 +363,7 @@ func (h *handler) getResponseData(r *http.Request) *responseData { switch { 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 278b10bd..42b946d7 100644 --- a/src/serverHandler/sort.go +++ b/src/serverHandler/sort.go @@ -1,8 +1,8 @@ package serverHandler import ( + "../shimgo" "../util" - "bytes" "os" "sort" "strings" @@ -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 } @@ -232,7 +232,7 @@ func (infos infosSizeAsc) Less(i, j int) bool { return items[i].Size() < items[j].Size() } - cmpResult := strings.Compare(items[i].Name(), items[j].Name()) + cmpResult := shimgo.Strings_Compare(items[i].Name(), items[j].Name()) if cmpResult != 0 { return cmpResult < 0 } @@ -262,7 +262,7 @@ func (infos infosSizeDesc) Less(i, j int) bool { return items[j].Size() < items[i].Size() } - cmpResult := strings.Compare(items[j].Name(), items[i].Name()) + cmpResult := shimgo.Strings_Compare(items[j].Name(), items[i].Name()) if cmpResult != 0 { return cmpResult < 0 } @@ -292,7 +292,7 @@ func (infos infosTimeAsc) Less(i, j int) bool { return items[i].ModTime().Before(items[j].ModTime()) } - cmpResult := strings.Compare(items[i].Name(), items[j].Name()) + cmpResult := shimgo.Strings_Compare(items[i].Name(), items[j].Name()) if cmpResult != 0 { return cmpResult < 0 } @@ -322,7 +322,7 @@ func (infos infosTimeDesc) Less(i, j int) bool { return items[j].ModTime().Before(items[i].ModTime()) } - cmpResult := strings.Compare(items[j].Name(), items[i].Name()) + cmpResult := shimgo.Strings_Compare(items[j].Name(), items[i].Name()) if cmpResult != 0 { return cmpResult < 0 } diff --git a/src/serverHandler/upload.go b/src/serverHandler/upload.go index b2e9c7ad..edd02695 100644 --- a/src/serverHandler/upload.go +++ b/src/serverHandler/upload.go @@ -1,6 +1,7 @@ package serverHandler import ( + "../shimgo" "../util" "errors" "io" @@ -68,7 +69,7 @@ func (h *handler) saveUploadFiles(fsPrefix string, createDir, overwriteExists bo continue } - slashIndex := strings.LastIndexByte(partFilename, '/') + slashIndex := shimgo.Strings_LastIndexByte(partFilename, '/') fsInfix := "" formname := part.FormName() diff --git a/src/serverHandler/util.go b/src/serverHandler/util.go index 55128861..4853bf52 100644 --- a/src/serverHandler/util.go +++ b/src/serverHandler/util.go @@ -1,17 +1,17 @@ package serverHandler import ( - "net/http" + "../shimgo" "os" "path" "strings" ) 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 containsItem(infos []os.FileInfo, name string) 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..f2a794ab --- /dev/null +++ b/src/shimgo/net_url.go @@ -0,0 +1,156 @@ +package shimgo + +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_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 +} 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..3117486d --- /dev/null +++ b/src/shimgo/strings.go @@ -0,0 +1,33 @@ +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 +} + +// Compare returns an integer comparing two strings lexicographically. +// The result will be 0 if a==b, -1 if a < b, and +1 if a > b. +// +// Compare is included only for symmetry with package bytes. +// It is usually clearer and always faster to use the built-in +// string comparison operators ==, <, >, and so on. +func Strings_Compare(a, b string) int { + // NOTE(rsc): This function does NOT call the runtime cmpstring function, + // because we do not want to provide any performance justification for + // using strings.Compare. Basically no one should use strings.Compare. + // As the comment above says, it is here only for symmetry with package bytes. + // If performance is important, the compiler should be changed to recognize + // the pattern so that all code doing three-way comparisons, not just code + // using strings.Compare, can benefit. + if a == b { + return 0 + } + if a < b { + return -1 + } + return +1 +} diff --git a/src/util/hostname.go b/src/util/hostname.go index 7061c428..d9dcdf21 100644 --- a/src/util/hostname.go +++ b/src/util/hostname.go @@ -1,6 +1,9 @@ package util -import "strings" +import ( + "../shimgo" + "strings" +) func ExtractHostnamePort(host string) (hostname, port string) { if len(host) == 0 { @@ -11,7 +14,7 @@ func ExtractHostnamePort(host string) (hostname, port string) { if hostname[len(hostname)-1] != ']' { // not [IPv6] if colonIndex := strings.LastIndex(hostname, "]:"); colonIndex > 0 { // [IPv6]:port hostname = hostname[:colonIndex+1] - } else if colonIndex = strings.LastIndexByte(hostname, ':'); colonIndex >= 0 { + } else if colonIndex = shimgo.Strings_LastIndexByte(hostname, ':'); colonIndex >= 0 { hostname = hostname[:colonIndex] } } @@ -30,7 +33,7 @@ func ExtractListenPort(listen string) string { return listen[colonIndex+2:] } else if listen[len(listen)-1] == ']' { // [IPv6] return "" - } else if colonIndex = strings.LastIndexByte(listen, ':'); colonIndex >= 0 { + } else if colonIndex = shimgo.Strings_LastIndexByte(listen, ':'); colonIndex >= 0 { return listen[colonIndex+1:] } else { lenListen := len(listen) From ef5814d3ec43bb09667c50744cea3997cea8c6de Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 20 Feb 2021 23:44:40 +0800 Subject: [PATCH 02/57] Revert "refactor(tpl): refine file structure" This reverts commit eddc0f2501ad417a991169065ab22c1d54a24cec. --- src/serverHandler/asset.go | 4 ++-- src/tpl/{frontend => asset}/main.css | 0 src/tpl/asset/main.css.go | 6 ++++++ src/tpl/{asset.go => asset/main.go} | 11 ++--------- src/tpl/{frontend => asset}/main.js | 0 src/tpl/asset/main.js.go | 6 ++++++ src/tpl/{frontend => }/page.html | 0 src/tpl/{template.go => page.html.go} | 2 +- 8 files changed, 17 insertions(+), 12 deletions(-) rename src/tpl/{frontend => asset}/main.css (100%) create mode 100644 src/tpl/asset/main.css.go rename src/tpl/{asset.go => asset/main.go} (64%) rename src/tpl/{frontend => asset}/main.js (100%) create mode 100644 src/tpl/asset/main.js.go rename src/tpl/{frontend => }/page.html (100%) rename src/tpl/{template.go => page.html.go} (96%) diff --git a/src/serverHandler/asset.go b/src/serverHandler/asset.go index f480d049..1c39023d 100644 --- a/src/serverHandler/asset.go +++ b/src/serverHandler/asset.go @@ -1,7 +1,7 @@ package serverHandler import ( - "../tpl" + "../tpl/asset" "net/http" "time" ) @@ -9,7 +9,7 @@ import ( var initTime = time.Now() func (h *handler) asset(w http.ResponseWriter, r *http.Request, assetPath string) { - content, ok := tpl.GetAsset(assetPath) + content, ok := asset.Get(assetPath) if !ok { return } diff --git a/src/tpl/frontend/main.css b/src/tpl/asset/main.css similarity index 100% rename from src/tpl/frontend/main.css rename to src/tpl/asset/main.css diff --git a/src/tpl/asset/main.css.go b/src/tpl/asset/main.css.go new file mode 100644 index 00000000..00626bb9 --- /dev/null +++ b/src/tpl/asset/main.css.go @@ -0,0 +1,6 @@ +package asset + +import _ "embed" + +//go:embed main.css +var mainCss []byte diff --git a/src/tpl/asset.go b/src/tpl/asset/main.go similarity index 64% rename from src/tpl/asset.go rename to src/tpl/asset/main.go index 84d6e301..8eb33d70 100644 --- a/src/tpl/asset.go +++ b/src/tpl/asset/main.go @@ -1,17 +1,10 @@ -package tpl +package asset import ( "bytes" - _ "embed" "io" ) -//go:embed frontend/main.css -var mainCss []byte - -//go:embed frontend/main.js -var mainJs []byte - type content struct { ContentType string ReadSeeker io.ReadSeeker @@ -22,7 +15,7 @@ var assets = map[string]content{ "main.js": {"application/javascript", bytes.NewReader(mainJs)}, } -func GetAsset(path string) (content, bool) { +func Get(path string) (content, bool) { c, ok := assets[path] return c, ok } diff --git a/src/tpl/frontend/main.js b/src/tpl/asset/main.js similarity index 100% rename from src/tpl/frontend/main.js rename to src/tpl/asset/main.js diff --git a/src/tpl/asset/main.js.go b/src/tpl/asset/main.js.go new file mode 100644 index 00000000..0a68eeeb --- /dev/null +++ b/src/tpl/asset/main.js.go @@ -0,0 +1,6 @@ +package asset + +import _ "embed" + +//go:embed main.js +var mainJs []byte diff --git a/src/tpl/frontend/page.html b/src/tpl/page.html similarity index 100% rename from src/tpl/frontend/page.html rename to src/tpl/page.html diff --git a/src/tpl/template.go b/src/tpl/page.html.go similarity index 96% rename from src/tpl/template.go rename to src/tpl/page.html.go index d7e80623..74a42ac2 100644 --- a/src/tpl/template.go +++ b/src/tpl/page.html.go @@ -8,7 +8,7 @@ import ( "path" ) -//go:embed frontend/page.html +//go:embed page.html var pageTplStr string var defaultPageTpl *template.Template From e968c09c01aa6ce11c69800c201e8dbd699175ae Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 20 Feb 2021 23:44:42 +0800 Subject: [PATCH 03/57] Revert "refactor(param): use `os.ReadFile` instead of `ioutil.ReadFile`" This reverts commit 0fdcd81f8e20cac33fe24505c96f27a7d6229da3. --- src/param/cli.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/param/cli.go b/src/param/cli.go index 743f91df..c6161166 100644 --- a/src/param/cli.go +++ b/src/param/cli.go @@ -7,6 +7,7 @@ import ( "../version" "errors" "fmt" + "io/ioutil" "os" "strings" ) @@ -213,7 +214,7 @@ func doParseCli() []*Param { continue } - configStr, err := os.ReadFile(config) + configStr, err := ioutil.ReadFile(config) if serverErrHandler.CheckError(err) || len(configStr) == 0 { continue } From e331e8b4d478a669a2abb1fa40317ae6bd2b9208 Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 20 Feb 2021 23:44:43 +0800 Subject: [PATCH 04/57] Revert "feat(tpl): use `go:embed` to embed asserts" This reverts commit c55bb44f55d1c6d6e00d41e15e148a779c95d81d. --- README.md | 9 +- README.zh-CN.md | 9 +- build/build-all-docker.sh | 19 + src/Makefile | 13 + src/tpl/asset/main.css.go | 436 ++++++++++++++++++- src/tpl/asset/main.go | 6 +- src/tpl/asset/main.js.go | 873 +++++++++++++++++++++++++++++++++++++- src/tpl/page.html | 4 +- src/tpl/page.html.go | 114 ++++- 9 files changed, 1465 insertions(+), 18 deletions(-) create mode 100644 src/Makefile diff --git a/README.md b/README.md index ca3da6a1..52aad395 100644 --- a/README.md +++ b/README.md @@ -13,12 +13,19 @@ Simple command line based HTTP file server to share local file system. - Support location alias(mount another directory to url location) ## Compile -Minimal required Go version is 1.16. +Minimal required Go version is 1.9. ```bash GO111MODULE=auto go build src/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 deda8007..4d471793 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -13,12 +13,19 @@ - 支持目录别名(将另一个目录挂载到某个URL路径) ## 编译 -至少需要Go 1.16版本。 +至少需要Go 1.9版本。 ```bash GO111MODULE=auto go build src/main.go ``` 会在当前目录生成"main"可执行文件。 +如果修改过`src/tpl`下的默认html模板,需要将其重新嵌入go文件: +```bash +cd src +make tpls +``` +然后再像上面那样编译。 + ## 举例 在8080端口启动服务器,根目录为当前工作目录: ```sh diff --git a/build/build-all-docker.sh b/build/build-all-docker.sh index 2fd8e4b9..fe448b4c 100644 --- a/build/build-all-docker.sh +++ b/build/build-all-docker.sh @@ -35,6 +35,25 @@ builds=("${builds[@]}" 'netbsd 386' 'netbsd amd64' 'netbsd arm' 'netbsd arm64') builds=("${builds[@]}" 'plan9 386' 'plan9 amd64' 'plan9 arm') buildByDocker "$gover" "${builds[@]}" +#gover=1.9 +#builds=('freebsd 386 -9.x' 'freebsd amd64 -9.x' 'freebsd arm -9.x') +#buildByDocker "$gover" "${builds[@]}" + +gover=1.10 +builds=('windows 386 -xp-vista' 'windows amd64 -xp-vista') +#builds=("${builds[@]}" 'darwin 386 -10.8-mountain_lion' 'darwin amd64 -10.8-mountain_lion') +#builds=("${builds[@]}" 'openbsd 386 -6.0' 'openbsd amd64 -6.0' 'openbsd arm -6.0') +buildByDocker "$gover" "${builds[@]}" + +#gover=1.12 +#builds=('darwin 386 -10.10-yosemite' 'darwin amd64 -10.10-yosemite') +#builds=("${builds[@]}" 'freebsd 386 -10.x' 'freebsd amd64 -10.x' 'freebsd arm -9.x') +#buildByDocker "$gover" "${builds[@]}" + +#gover=1.14 +#builds=('darwin 386 -10.11-el_capitan' 'darwin amd64 -10.11-el_capitan') +#buildByDocker "$gover" "${builds[@]}" + #gover=1.16 #builds=('darwin amd64 -10.12-sierra') #buildByDocker "$gover" "${builds[@]}" diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 00000000..d3b117d4 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,13 @@ +define embed + sed -i -e '/= `/,/`/ { /`/!d }' $(1).go + sed -i -e '/= `/r$(1)' $(1).go + sed -i -e '/= `/,/`/ { /`/! { /^\s*$$/d; s/^\s\s*// } }' $(1).go +endef + +tpls: + $(call embed, tpl/page.html) + sed -i -e 's;/../asset/;?asset=;g' tpl/page.html.go + + $(call embed, tpl/asset/main.css) + + $(call embed, tpl/asset/main.js) diff --git a/src/tpl/asset/main.css.go b/src/tpl/asset/main.css.go index 00626bb9..495e1ba9 100644 --- a/src/tpl/asset/main.css.go +++ b/src/tpl/asset/main.css.go @@ -1,6 +1,434 @@ package asset -import _ "embed" - -//go:embed main.css -var mainCss []byte +const mainCss = ` +html, body { +margin: 0; +padding: 0; +background: #fff; +} +html { +font-family: "roboto_condensedbold", "Helvetica Neue", Helvetica, Arial, sans-serif; +} +body, input, textarea { +font-family: Consolas, "Lucida Console", "San Francisco Mono", Menlo, Monaco, "Andale Mono", "DejaVu Sans Mono", monospace; +} +body { +color: #333; +font-size: 0.625em; +font-variant-ligatures: none; +font-kerning: none; +hyphens: none; +padding-bottom: 1em; +} +form { +margin: 0; +padding: 0; +} +ul, ol, li { +display: block; +margin: 0; +padding: 0; +} +a { +display: block; +padding: 0.45em 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; +} +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; +} +.if-disabled { +display: none; +} +:disabled .if-disabled { +display: inherit; +} +:disabled .if-enabled { +display: none; +} +.path-list { +font-size: 1.5em; +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; +} +.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 { +position: relative; +} +.upload::before { +display: none; +content: ''; +position: absolute; +z-index: 1; +left: 0; +top: 0; +right: 0; +bottom: 0; +opacity: 0.7; +background: #c9c; +} +.upload.dragging::before { +display: block; +} +.upload.uploading.dragging::before { +background: transparent; +} +.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; +} +.upload button .progress { +position: absolute; +left: 0; +top: 0; +bottom: 0; +width: 0; +opacity: 0.5; +background: #c9c; +} +.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: 1.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; +} +.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 { +display: flex; +} +.filter .filter-text { +flex: 1 1 auto; +width: 100%; +box-sizing: border-box; +} +.item-list { +margin: 1em; +} +.item-list li { +position: relative; +zoom: 1; +} +.item-list li:hover { +background: #f5f5f5; +} +.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; +color: #800000; +font-weight: bold; +font-size: 1.6em; +line-height: 1em; +padding: 0.1875em 0.3125em 0.3125em; +} +.item-list .delete:hover { +background: #fee; +} +.item-list .header:hover { +background: none; +} +.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 (prefers-color-scheme: dark) { +html, body { +background: #111; +} +body { +color: #ccc; +} +a { +color: #ddd; +} +a:hover { +background-color: #222; +} +a:focus { +background-color: #220; +} +a:hover:focus { +background-color: #2f2f0f; +} +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 li:hover { +background: #222; +} +.item-list .detail, +.item-list .delete { +border-bottom-color: #222; +} +.item-list .size { +color: #999; +} +.item-list .time { +color: #666; +} +.item-list .delete { +color: #f99; +} +.item-list .delete:hover { +background-color: #433; +} +.item-list .header .detail { +background-color: #181818; +} +} +@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/asset/main.go b/src/tpl/asset/main.go index 8eb33d70..6409428e 100644 --- a/src/tpl/asset/main.go +++ b/src/tpl/asset/main.go @@ -1,8 +1,8 @@ package asset import ( - "bytes" "io" + "strings" ) type content struct { @@ -11,8 +11,8 @@ type content struct { } var assets = map[string]content{ - "main.css": {"text/css", bytes.NewReader(mainCss)}, - "main.js": {"application/javascript", bytes.NewReader(mainJs)}, + "main.css": {"text/css", strings.NewReader(mainCss)}, + "main.js": {"application/javascript", strings.NewReader(mainJs)}, } func Get(path string) (content, bool) { diff --git a/src/tpl/asset/main.js.go b/src/tpl/asset/main.js.go index 0a68eeeb..43596d89 100644 --- a/src/tpl/asset/main.js.go +++ b/src/tpl/asset/main.js.go @@ -1,6 +1,871 @@ package asset -import _ "embed" - -//go:embed main.js -var mainJs []byte +const mainJs = ` +(function () { +var strUndef = 'undefined'; +var classNone = 'none'; +var classHeader = 'header'; +var leavingEvent = typeof window.onpagehide !== strUndef ? 'pagehide' : 'beforeunload'; +var Enter = 'Enter'; +var Escape = 'Escape'; +var Esc = 'Esc'; +var Space = ' '; +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.classList || !filter.addEventListener) { +filter.className += ' none'; +return; +} +var input = filter.querySelector('input.filter-text'); +if (!input) { +return; +} +var selectorNone = '.' + classNone; +var selectorNotNone = ':not(' + selectorNone + ')'; +var selectorItem = '.item-list > li:not(.' + classHeader + '):not(.parent)'; +var selectorItemNone = selectorItem + selectorNone; +var selectorItemNotNone = selectorItem + selectorNotNone; +// event handler +var timeoutId; +var lastFilterText = ''; +var doFilter = function () { +var filterText = input.value.trim().toLowerCase(); +if (filterText === lastFilterText) { +return; +} +var selector, items, i; +if (!filterText) { // filter cleared, show all items +selector = selectorItemNone; +items = document.body.querySelectorAll(selector); +for (i = items.length - 1; i >= 0; i--) { +items[i].classList.remove(classNone); +} +} else { +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) { +item.classList.add(classNone); +} else { +item.classList.remove(classNone); +} +} +} +lastFilterText = filterText; +}; +var onValueMayChange = function () { +clearTimeout(timeoutId); +timeoutId = setTimeout(doFilter, 350); +}; +input.addEventListener('input', onValueMayChange, false); +input.addEventListener('change', onValueMayChange, false); +input.addEventListener('keydown', function (e) { +switch (e.key) { +case Enter: +clearTimeout(timeoutId); +input.blur(); +doFilter(); +e.preventDefault(); +break; +case Escape: +case Esc: +clearTimeout(timeoutId); +input.value = ''; +doFilter(); +e.preventDefault(); +break; +} +}, false); +// init +if (sessionStorage) { +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 enableKeyboardNavigate() { +if ( +!document.querySelector || +!document.addEventListener || +!document.body.classList || +!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, isPrev, startA) { +if (!container) { +return +} +if (!startA) { +startA = container.querySelector(':focus'); +} +var startLI = startA; +while (startLI && startLI.tagName !== 'LI') { +startLI = startLI.parentElement; +} +if (!startLI) { +if (isPrev) { +startLI = container.firstElementChild; +} else { +startLI = container.lastElementChild; +} +} +if (!startLI) { +return; +} +var siblingLI = startLI; +do { +if (isPrev) { +siblingLI = siblingLI.previousElementSibling; +if (!siblingLI) { +siblingLI = container.lastElementChild; +} +} else { +siblingLI = siblingLI.nextElementSibling; +if (!siblingLI) { +siblingLI = container.firstElementChild; +} +} +} while (siblingLI !== startLI && ( +siblingLI.classList.contains(classNone) || +siblingLI.classList.contains(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, isPrev, 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, isPrev, 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(key) { +key = key.toLowerCase(); +var currentLookupStartA; +if (key === lookupKey) { +// same as last key, lookup next for the same key as prefix +currentLookupStartA = itemList.querySelector(':focus'); +} else { +if (!lookupStartA) { +lookupStartA = itemList.querySelector(':focus'); +} +currentLookupStartA = lookupStartA; +if (lookupKey === undefined) { +lookupKey = key; +} else { +// key changed, no more prefix match +lookupKey = ''; +} +} +lookupBuffer += key; +delayClearLookupContext(); +return getMatchedFocusableSibling(itemList, false, 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(e.key); +} +} 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(String.fromCharCode(e.keyCode)); +} +} +} +document.addEventListener('keydown', function (e) { +var newFocusEl = getFocusItemByKeyPress(e); +if (newFocusEl) { +e.preventDefault(); +newFocusEl.focus(); +} +}); +} +function enhanceUpload() { +if (!document.querySelector || !document.addEventListener || !document.body.classList) { +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 btnSubmit = form.querySelector('.submit') || form.querySelector('input[type=submit]'); +if (!btnSubmit) { +return; +} +var uploadType = document.body.querySelector('.upload-type'); +if (!uploadType) { +return; +} +var classUploading = 'uploading'; +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; +function addClass(ele, className) { +ele && ele.classList.add(className); +} +function removeClass(ele, className) { +ele && ele.classList.remove(className); +} +function hasClass(ele, className) { +return ele && ele.classList.contains(className); +} +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'); +var ms = padStart(ms, 3, '0'); +var ts = '-' + date + '-' + time + '-' + ms; +return ts; +} +function enableAddDir() { +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 (sessionStorage) { +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; +}); +if (nodir) { +onClickOptFile(); // prevent clear input files +} +}); +} +function enableUploadProgress() { // also fix Safari upload filename has no path info +if (!FormData) { +return; +} +var elProgress = btnSubmit.querySelector('.progress'); +function onComplete() { +if (elProgress) { +elProgress.style.width = ''; +} +fileInput.disabled = false; +btnSubmit.disabled = false; +removeClass(upload, classUploading); +} +function onLoad() { +location.reload(); +} +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; +} +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.upload.addEventListener('error', onComplete); +xhr.upload.addEventListener('abort', onComplete); +xhr.upload.addEventListener('load', onComplete); +xhr.upload.addEventListener('load', onLoad); +if (elProgress) { +xhr.upload.addEventListener('progress', onProgress); +} +xhr.open(form.method, form.action); +xhr.send(parts); +addClass(upload, classUploading); +fileInput.disabled = true; +btnSubmit.disabled = true; +} +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); +}); +return uploadProgressively; +} +function enableAddDragDrop(uploadProgressively) { +var classDragging = 'dragging'; +function onDragEnterOver(e) { +e.stopPropagation(); +e.preventDefault(); +addClass(e.currentTarget, classDragging); +} +function onDragLeave(e) { +if (e.target === e.currentTarget) { +removeClass(e.currentTarget, classDragging); +} +} +function getFilesFromEntries(entries, onDone) { +var files = []; +var len = entries.length; +var cb = 0; +function increaseCb() { +cb++; +if (cb === len) { +onDone(files); +} +} +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(); +typeof console !== strUndef && console.error(err); +}); +} else { +var reader = entry.createReader(); +reader.readEntries(function (subEntries) { +if (subEntries.length) { +getFilesFromEntries(subEntries, function (subFiles) { +Array.prototype.push.apply(files, subFiles); +increaseCb(); +}); +} else { +increaseCb(); +} +}); +} +}); +} +function getFilesFromItems(items, onDone) { +var files = []; +var entries = []; +for (var i = 0, len = items.length; i < len; i++) { +var entry = items[i].webkitGetAsEntry(); +entries.push(entry); +} +getFilesFromEntries(entries, onDone); +} +function onDrop(e) { +e.stopPropagation(); +e.preventDefault(); +removeClass(e.currentTarget, classDragging); +if (hasClass(e.currentTarget, classUploading)) { +return; +} +fileInput.value = ''; +if (!e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files.length) { +return; +} +var hasDir = false; +if (e.dataTransfer.items) { +var items = Array.prototype.slice.call(e.dataTransfer.items); +if (items.length && items[0].webkitGetAsEntry) { +for (var i = 0, len = items.length; i < len; i++) { +var entry = items[i].webkitGetAsEntry(); +if (entry.isDirectory) { +hasDir = true; +break; +} +} +} +} +if (hasDir) { +if (!uploadProgressively) { +return; +} +if (!optDirFile && !optInnerDirFile) { +return; +} +if (optActive === optFile) { +if (optDirFile) { +optDirFile.focus(); +optDirFile.click(); +} else if (optInnerDirFile) { +optInnerDirFile.focus(); +optInnerDirFile.click(); +} +} +btnSubmit.disabled = true; // disable earlier +getFilesFromItems(e.dataTransfer.items, function (files) { +uploadProgressively(files); +}); +} else { +if (optFile && optActive !== optFile) { +optFile.focus(); +optFile.click(); +} +if (uploadProgressively) { +var files = Array.prototype.slice.call(e.dataTransfer.files); +uploadProgressively(files); +} else { +fileInput.files = e.dataTransfer.files; +form.submit(); +} +} +} +upload.addEventListener('dragenter', onDragEnterOver); +upload.addEventListener('dragover', onDragEnterOver); +upload.addEventListener('dragleave', onDragLeave); +upload.addEventListener('drop', onDrop); +} +function enableAddPaste(uploadProgressively) { +if (!uploadProgressively) { +document.documentElement.addEventListener('paste', function (e) { +var data = e.clipboardData; +if (data && data.files && data.files.length) { +if (optFile && optActive !== optFile) { +optFile.focus(); +optFile.click(); +} +fileInput.files = data.files; +form.submit(); +} +}); +return; +} +var typeTextPlain = 'text/plain'; +function uploadPastedFiles(files) { +if (optFile && optActive !== optFile) { +optFile.focus(); +optFile.click(); +} +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); +} +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}); +} +} +document.documentElement.addEventListener('paste', function (e) { +var data = e.clipboardData; +if (!data) { +return; +} +var files; +var items; +if (data.files && data.files.length) { +files = Array.prototype.slice.call(data.files); +} else if (data.items && data.items.length) { +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); +} +}); +} +}); +} +enableAddDir(); +var uploadProgressively = enableUploadProgress(); +enableAddDragDrop(uploadProgressively); +enableAddPaste(uploadProgressively); +} +function enableNonRefreshDelete() { +if (!document.querySelector) { +return; +} +var itemList = document.body.querySelector('.item-list'); +if (!itemList || !itemList.addEventListener) { +return; +} +if (itemList.classList) { +if (!itemList.classList.contains('has-deletable')) { +return; +} +} else if (itemList.className.indexOf('has-deletable') < 0) { +return; +} +itemList.addEventListener('click', function (e) { +if (e.defaultPrevented || !e.target || !e.target.href || e.target.className.indexOf('delete') < 0) { +return; +} +function onLoad() { +var elItem = e.target; +while (elItem && elItem.nodeName !== 'LI') { +elItem = elItem.parentNode; +} +if (!elItem) { +return; +} +var elItemParent = elItem.parentNode; +elItemParent && elItemParent.removeChild(elItem); +} +var xhr = new XMLHttpRequest(); +xhr.open('POST', e.target.href); // will retrieve deleted result into bfcache +xhr.addEventListener('load', onLoad); +xhr.send(); +e.preventDefault(); +return false; +}, false); +} +enableFilter(); +enableKeyboardNavigate(); +enhanceUpload(); +enableNonRefreshDelete(); +})(); +` diff --git a/src/tpl/page.html b/src/tpl/page.html index eceb9ffa..d0d4ac9a 100644 --- a/src/tpl/page.html +++ b/src/tpl/page.html @@ -8,7 +8,7 @@ {{.Path}} - + {{$contextQueryString := .Context.QueryString}} @@ -111,6 +111,6 @@
500 potential issue occurred
{{end}} - + diff --git a/src/tpl/page.html.go b/src/tpl/page.html.go index 74a42ac2..0f4b6248 100644 --- a/src/tpl/page.html.go +++ b/src/tpl/page.html.go @@ -3,13 +3,121 @@ package tpl import ( "../serverErrHandler" "./util" - _ "embed" "html/template" "path" ) -//go:embed page.html -var pageTplStr string +const pageTplStr = ` + + + + + + + + + +{{.Path}} + + + +{{$contextQueryString := .Context.QueryString}} +{{$isDownload := .IsDownload}} +{{if not $isDownload}} +
    +{{range .Paths}} +
  1. {{fmtFilename .Name}}
  2. +{{end}} +
+{{if .CanMkdir}} +
+
+ + +
+
+{{end}} +{{if .CanUpload}} +
+ +{{if .CanMkdir}}{{end}} + +
+
+
+ + +
+
+{{end}} +{{if .CanArchive}} + +{{end}} +{{if .SubItemsHtml}} +
+
+ +
+
+{{end}} +{{if .CanDelete}} + +{{end}} +{{end}} + +{{if eq .Status 403}} +
403 resource is forbidden
+{{else if eq .Status 404}} +
404 resource not found
+{{else if eq .Status 500}} +
500 potential issue occurred
+{{end}} + + + +` var defaultPageTpl *template.Template From 78c87b56d51e2c126d118287a66e82c339424832 Mon Sep 17 00:00:00 2001 From: marjune Date: Sun, 21 Feb 2021 00:25:40 +0800 Subject: [PATCH 05/57] refactor(tpl): refine file structure --- src/Makefile | 11 +- src/serverHandler/asset.go | 4 +- src/tpl/asset.go | 22 + src/tpl/asset/main.css.go | 434 ------------ src/tpl/asset/main.go | 21 - src/tpl/asset/main.js.go | 871 ------------------------ src/tpl/{asset => frontend}/main.css | 0 src/tpl/frontend/main.css.go | 531 +++++++++++++++ src/tpl/{asset => frontend}/main.js | 0 src/tpl/frontend/main.js.go | 983 +++++++++++++++++++++++++++ src/tpl/{ => frontend}/page.html | 4 +- src/tpl/frontend/page.html.go | 120 ++++ src/tpl/page.html.go | 157 ----- src/tpl/template.go | 46 ++ 14 files changed, 1710 insertions(+), 1494 deletions(-) create mode 100644 src/tpl/asset.go delete mode 100644 src/tpl/asset/main.css.go delete mode 100644 src/tpl/asset/main.go delete mode 100644 src/tpl/asset/main.js.go rename src/tpl/{asset => frontend}/main.css (100%) create mode 100644 src/tpl/frontend/main.css.go rename src/tpl/{asset => frontend}/main.js (100%) create mode 100644 src/tpl/frontend/main.js.go rename src/tpl/{ => frontend}/page.html (95%) create mode 100644 src/tpl/frontend/page.html.go delete mode 100644 src/tpl/page.html.go create mode 100644 src/tpl/template.go diff --git a/src/Makefile b/src/Makefile index d3b117d4..60f273ab 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,13 +1,10 @@ define embed sed -i -e '/= `/,/`/ { /`/!d }' $(1).go sed -i -e '/= `/r$(1)' $(1).go - sed -i -e '/= `/,/`/ { /`/! { /^\s*$$/d; s/^\s\s*// } }' $(1).go + #sed -i -e '/= `/,/`/ { /`/! { /^\s*$$/d; s/^\s\s*// } }' $(1).go endef tpls: - $(call embed, tpl/page.html) - sed -i -e 's;/../asset/;?asset=;g' tpl/page.html.go - - $(call embed, tpl/asset/main.css) - - $(call embed, tpl/asset/main.js) + $(call embed, tpl/frontend/page.html) + $(call embed, tpl/frontend/main.css) + $(call embed, tpl/frontend/main.js) diff --git a/src/serverHandler/asset.go b/src/serverHandler/asset.go index 1c39023d..f480d049 100644 --- a/src/serverHandler/asset.go +++ b/src/serverHandler/asset.go @@ -1,7 +1,7 @@ package serverHandler import ( - "../tpl/asset" + "../tpl" "net/http" "time" ) @@ -9,7 +9,7 @@ import ( var initTime = time.Now() func (h *handler) asset(w http.ResponseWriter, r *http.Request, assetPath string) { - content, ok := asset.Get(assetPath) + content, ok := tpl.GetAsset(assetPath) if !ok { return } diff --git a/src/tpl/asset.go b/src/tpl/asset.go new file mode 100644 index 00000000..b5182179 --- /dev/null +++ b/src/tpl/asset.go @@ -0,0 +1,22 @@ +package tpl + +import ( + "./frontend" + "io" + "strings" +) + +type content struct { + ContentType string + ReadSeeker io.ReadSeeker +} + +var assets = map[string]content{ + "main.css": {"text/css", strings.NewReader(frontend.MainCss)}, + "main.js": {"application/javascript", strings.NewReader(frontend.MainJs)}, +} + +func GetAsset(path string) (content, bool) { + c, ok := assets[path] + return c, ok +} diff --git a/src/tpl/asset/main.css.go b/src/tpl/asset/main.css.go deleted file mode 100644 index 495e1ba9..00000000 --- a/src/tpl/asset/main.css.go +++ /dev/null @@ -1,434 +0,0 @@ -package asset - -const mainCss = ` -html, body { -margin: 0; -padding: 0; -background: #fff; -} -html { -font-family: "roboto_condensedbold", "Helvetica Neue", Helvetica, Arial, sans-serif; -} -body, input, textarea { -font-family: Consolas, "Lucida Console", "San Francisco Mono", Menlo, Monaco, "Andale Mono", "DejaVu Sans Mono", monospace; -} -body { -color: #333; -font-size: 0.625em; -font-variant-ligatures: none; -font-kerning: none; -hyphens: none; -padding-bottom: 1em; -} -form { -margin: 0; -padding: 0; -} -ul, ol, li { -display: block; -margin: 0; -padding: 0; -} -a { -display: block; -padding: 0.45em 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; -} -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; -} -.if-disabled { -display: none; -} -:disabled .if-disabled { -display: inherit; -} -:disabled .if-enabled { -display: none; -} -.path-list { -font-size: 1.5em; -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; -} -.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 { -position: relative; -} -.upload::before { -display: none; -content: ''; -position: absolute; -z-index: 1; -left: 0; -top: 0; -right: 0; -bottom: 0; -opacity: 0.7; -background: #c9c; -} -.upload.dragging::before { -display: block; -} -.upload.uploading.dragging::before { -background: transparent; -} -.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; -} -.upload button .progress { -position: absolute; -left: 0; -top: 0; -bottom: 0; -width: 0; -opacity: 0.5; -background: #c9c; -} -.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: 1.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; -} -.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 { -display: flex; -} -.filter .filter-text { -flex: 1 1 auto; -width: 100%; -box-sizing: border-box; -} -.item-list { -margin: 1em; -} -.item-list li { -position: relative; -zoom: 1; -} -.item-list li:hover { -background: #f5f5f5; -} -.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; -color: #800000; -font-weight: bold; -font-size: 1.6em; -line-height: 1em; -padding: 0.1875em 0.3125em 0.3125em; -} -.item-list .delete:hover { -background: #fee; -} -.item-list .header:hover { -background: none; -} -.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 (prefers-color-scheme: dark) { -html, body { -background: #111; -} -body { -color: #ccc; -} -a { -color: #ddd; -} -a:hover { -background-color: #222; -} -a:focus { -background-color: #220; -} -a:hover:focus { -background-color: #2f2f0f; -} -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 li:hover { -background: #222; -} -.item-list .detail, -.item-list .delete { -border-bottom-color: #222; -} -.item-list .size { -color: #999; -} -.item-list .time { -color: #666; -} -.item-list .delete { -color: #f99; -} -.item-list .delete:hover { -background-color: #433; -} -.item-list .header .detail { -background-color: #181818; -} -} -@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/asset/main.go b/src/tpl/asset/main.go deleted file mode 100644 index 6409428e..00000000 --- a/src/tpl/asset/main.go +++ /dev/null @@ -1,21 +0,0 @@ -package asset - -import ( - "io" - "strings" -) - -type content struct { - ContentType string - ReadSeeker io.ReadSeeker -} - -var assets = map[string]content{ - "main.css": {"text/css", strings.NewReader(mainCss)}, - "main.js": {"application/javascript", strings.NewReader(mainJs)}, -} - -func Get(path string) (content, bool) { - c, ok := assets[path] - return c, ok -} diff --git a/src/tpl/asset/main.js.go b/src/tpl/asset/main.js.go deleted file mode 100644 index 43596d89..00000000 --- a/src/tpl/asset/main.js.go +++ /dev/null @@ -1,871 +0,0 @@ -package asset - -const mainJs = ` -(function () { -var strUndef = 'undefined'; -var classNone = 'none'; -var classHeader = 'header'; -var leavingEvent = typeof window.onpagehide !== strUndef ? 'pagehide' : 'beforeunload'; -var Enter = 'Enter'; -var Escape = 'Escape'; -var Esc = 'Esc'; -var Space = ' '; -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.classList || !filter.addEventListener) { -filter.className += ' none'; -return; -} -var input = filter.querySelector('input.filter-text'); -if (!input) { -return; -} -var selectorNone = '.' + classNone; -var selectorNotNone = ':not(' + selectorNone + ')'; -var selectorItem = '.item-list > li:not(.' + classHeader + '):not(.parent)'; -var selectorItemNone = selectorItem + selectorNone; -var selectorItemNotNone = selectorItem + selectorNotNone; -// event handler -var timeoutId; -var lastFilterText = ''; -var doFilter = function () { -var filterText = input.value.trim().toLowerCase(); -if (filterText === lastFilterText) { -return; -} -var selector, items, i; -if (!filterText) { // filter cleared, show all items -selector = selectorItemNone; -items = document.body.querySelectorAll(selector); -for (i = items.length - 1; i >= 0; i--) { -items[i].classList.remove(classNone); -} -} else { -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) { -item.classList.add(classNone); -} else { -item.classList.remove(classNone); -} -} -} -lastFilterText = filterText; -}; -var onValueMayChange = function () { -clearTimeout(timeoutId); -timeoutId = setTimeout(doFilter, 350); -}; -input.addEventListener('input', onValueMayChange, false); -input.addEventListener('change', onValueMayChange, false); -input.addEventListener('keydown', function (e) { -switch (e.key) { -case Enter: -clearTimeout(timeoutId); -input.blur(); -doFilter(); -e.preventDefault(); -break; -case Escape: -case Esc: -clearTimeout(timeoutId); -input.value = ''; -doFilter(); -e.preventDefault(); -break; -} -}, false); -// init -if (sessionStorage) { -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 enableKeyboardNavigate() { -if ( -!document.querySelector || -!document.addEventListener || -!document.body.classList || -!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, isPrev, startA) { -if (!container) { -return -} -if (!startA) { -startA = container.querySelector(':focus'); -} -var startLI = startA; -while (startLI && startLI.tagName !== 'LI') { -startLI = startLI.parentElement; -} -if (!startLI) { -if (isPrev) { -startLI = container.firstElementChild; -} else { -startLI = container.lastElementChild; -} -} -if (!startLI) { -return; -} -var siblingLI = startLI; -do { -if (isPrev) { -siblingLI = siblingLI.previousElementSibling; -if (!siblingLI) { -siblingLI = container.lastElementChild; -} -} else { -siblingLI = siblingLI.nextElementSibling; -if (!siblingLI) { -siblingLI = container.firstElementChild; -} -} -} while (siblingLI !== startLI && ( -siblingLI.classList.contains(classNone) || -siblingLI.classList.contains(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, isPrev, 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, isPrev, 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(key) { -key = key.toLowerCase(); -var currentLookupStartA; -if (key === lookupKey) { -// same as last key, lookup next for the same key as prefix -currentLookupStartA = itemList.querySelector(':focus'); -} else { -if (!lookupStartA) { -lookupStartA = itemList.querySelector(':focus'); -} -currentLookupStartA = lookupStartA; -if (lookupKey === undefined) { -lookupKey = key; -} else { -// key changed, no more prefix match -lookupKey = ''; -} -} -lookupBuffer += key; -delayClearLookupContext(); -return getMatchedFocusableSibling(itemList, false, 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(e.key); -} -} 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(String.fromCharCode(e.keyCode)); -} -} -} -document.addEventListener('keydown', function (e) { -var newFocusEl = getFocusItemByKeyPress(e); -if (newFocusEl) { -e.preventDefault(); -newFocusEl.focus(); -} -}); -} -function enhanceUpload() { -if (!document.querySelector || !document.addEventListener || !document.body.classList) { -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 btnSubmit = form.querySelector('.submit') || form.querySelector('input[type=submit]'); -if (!btnSubmit) { -return; -} -var uploadType = document.body.querySelector('.upload-type'); -if (!uploadType) { -return; -} -var classUploading = 'uploading'; -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; -function addClass(ele, className) { -ele && ele.classList.add(className); -} -function removeClass(ele, className) { -ele && ele.classList.remove(className); -} -function hasClass(ele, className) { -return ele && ele.classList.contains(className); -} -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'); -var ms = padStart(ms, 3, '0'); -var ts = '-' + date + '-' + time + '-' + ms; -return ts; -} -function enableAddDir() { -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 (sessionStorage) { -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; -}); -if (nodir) { -onClickOptFile(); // prevent clear input files -} -}); -} -function enableUploadProgress() { // also fix Safari upload filename has no path info -if (!FormData) { -return; -} -var elProgress = btnSubmit.querySelector('.progress'); -function onComplete() { -if (elProgress) { -elProgress.style.width = ''; -} -fileInput.disabled = false; -btnSubmit.disabled = false; -removeClass(upload, classUploading); -} -function onLoad() { -location.reload(); -} -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; -} -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.upload.addEventListener('error', onComplete); -xhr.upload.addEventListener('abort', onComplete); -xhr.upload.addEventListener('load', onComplete); -xhr.upload.addEventListener('load', onLoad); -if (elProgress) { -xhr.upload.addEventListener('progress', onProgress); -} -xhr.open(form.method, form.action); -xhr.send(parts); -addClass(upload, classUploading); -fileInput.disabled = true; -btnSubmit.disabled = true; -} -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); -}); -return uploadProgressively; -} -function enableAddDragDrop(uploadProgressively) { -var classDragging = 'dragging'; -function onDragEnterOver(e) { -e.stopPropagation(); -e.preventDefault(); -addClass(e.currentTarget, classDragging); -} -function onDragLeave(e) { -if (e.target === e.currentTarget) { -removeClass(e.currentTarget, classDragging); -} -} -function getFilesFromEntries(entries, onDone) { -var files = []; -var len = entries.length; -var cb = 0; -function increaseCb() { -cb++; -if (cb === len) { -onDone(files); -} -} -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(); -typeof console !== strUndef && console.error(err); -}); -} else { -var reader = entry.createReader(); -reader.readEntries(function (subEntries) { -if (subEntries.length) { -getFilesFromEntries(subEntries, function (subFiles) { -Array.prototype.push.apply(files, subFiles); -increaseCb(); -}); -} else { -increaseCb(); -} -}); -} -}); -} -function getFilesFromItems(items, onDone) { -var files = []; -var entries = []; -for (var i = 0, len = items.length; i < len; i++) { -var entry = items[i].webkitGetAsEntry(); -entries.push(entry); -} -getFilesFromEntries(entries, onDone); -} -function onDrop(e) { -e.stopPropagation(); -e.preventDefault(); -removeClass(e.currentTarget, classDragging); -if (hasClass(e.currentTarget, classUploading)) { -return; -} -fileInput.value = ''; -if (!e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files.length) { -return; -} -var hasDir = false; -if (e.dataTransfer.items) { -var items = Array.prototype.slice.call(e.dataTransfer.items); -if (items.length && items[0].webkitGetAsEntry) { -for (var i = 0, len = items.length; i < len; i++) { -var entry = items[i].webkitGetAsEntry(); -if (entry.isDirectory) { -hasDir = true; -break; -} -} -} -} -if (hasDir) { -if (!uploadProgressively) { -return; -} -if (!optDirFile && !optInnerDirFile) { -return; -} -if (optActive === optFile) { -if (optDirFile) { -optDirFile.focus(); -optDirFile.click(); -} else if (optInnerDirFile) { -optInnerDirFile.focus(); -optInnerDirFile.click(); -} -} -btnSubmit.disabled = true; // disable earlier -getFilesFromItems(e.dataTransfer.items, function (files) { -uploadProgressively(files); -}); -} else { -if (optFile && optActive !== optFile) { -optFile.focus(); -optFile.click(); -} -if (uploadProgressively) { -var files = Array.prototype.slice.call(e.dataTransfer.files); -uploadProgressively(files); -} else { -fileInput.files = e.dataTransfer.files; -form.submit(); -} -} -} -upload.addEventListener('dragenter', onDragEnterOver); -upload.addEventListener('dragover', onDragEnterOver); -upload.addEventListener('dragleave', onDragLeave); -upload.addEventListener('drop', onDrop); -} -function enableAddPaste(uploadProgressively) { -if (!uploadProgressively) { -document.documentElement.addEventListener('paste', function (e) { -var data = e.clipboardData; -if (data && data.files && data.files.length) { -if (optFile && optActive !== optFile) { -optFile.focus(); -optFile.click(); -} -fileInput.files = data.files; -form.submit(); -} -}); -return; -} -var typeTextPlain = 'text/plain'; -function uploadPastedFiles(files) { -if (optFile && optActive !== optFile) { -optFile.focus(); -optFile.click(); -} -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); -} -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}); -} -} -document.documentElement.addEventListener('paste', function (e) { -var data = e.clipboardData; -if (!data) { -return; -} -var files; -var items; -if (data.files && data.files.length) { -files = Array.prototype.slice.call(data.files); -} else if (data.items && data.items.length) { -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); -} -}); -} -}); -} -enableAddDir(); -var uploadProgressively = enableUploadProgress(); -enableAddDragDrop(uploadProgressively); -enableAddPaste(uploadProgressively); -} -function enableNonRefreshDelete() { -if (!document.querySelector) { -return; -} -var itemList = document.body.querySelector('.item-list'); -if (!itemList || !itemList.addEventListener) { -return; -} -if (itemList.classList) { -if (!itemList.classList.contains('has-deletable')) { -return; -} -} else if (itemList.className.indexOf('has-deletable') < 0) { -return; -} -itemList.addEventListener('click', function (e) { -if (e.defaultPrevented || !e.target || !e.target.href || e.target.className.indexOf('delete') < 0) { -return; -} -function onLoad() { -var elItem = e.target; -while (elItem && elItem.nodeName !== 'LI') { -elItem = elItem.parentNode; -} -if (!elItem) { -return; -} -var elItemParent = elItem.parentNode; -elItemParent && elItemParent.removeChild(elItem); -} -var xhr = new XMLHttpRequest(); -xhr.open('POST', e.target.href); // will retrieve deleted result into bfcache -xhr.addEventListener('load', onLoad); -xhr.send(); -e.preventDefault(); -return false; -}, false); -} -enableFilter(); -enableKeyboardNavigate(); -enhanceUpload(); -enableNonRefreshDelete(); -})(); -` diff --git a/src/tpl/asset/main.css b/src/tpl/frontend/main.css similarity index 100% rename from src/tpl/asset/main.css rename to src/tpl/frontend/main.css diff --git a/src/tpl/frontend/main.css.go b/src/tpl/frontend/main.css.go new file mode 100644 index 00000000..691536ec --- /dev/null +++ b/src/tpl/frontend/main.css.go @@ -0,0 +1,531 @@ +package frontend + +const MainCss = ` +html, body { + margin: 0; + padding: 0; + background: #fff; +} + +html { + font-family: "roboto_condensedbold", "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +body, input, textarea { + font-family: Consolas, "Lucida Console", "San Francisco Mono", Menlo, Monaco, "Andale Mono", "DejaVu Sans Mono", monospace; +} + +body { + color: #333; + font-size: 0.625em; + font-variant-ligatures: none; + font-kerning: none; + hyphens: none; + padding-bottom: 1em; +} + +form { + margin: 0; + padding: 0; +} + +ul, ol, li { + display: block; + margin: 0; + padding: 0; +} + +a { + display: block; + padding: 0.45em 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; +} + +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; +} + +.if-disabled { + display: none; +} + +:disabled .if-disabled { + display: inherit; +} + +:disabled .if-enabled { + display: none; +} + + +.path-list { + font-size: 1.5em; + 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; +} + +.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 { + position: relative; +} + +.upload::before { + display: none; + content: ''; + position: absolute; + z-index: 1; + left: 0; + top: 0; + right: 0; + bottom: 0; + opacity: 0.7; + background: #c9c; +} + +.upload.dragging::before { + display: block; +} + +.upload.uploading.dragging::before { + background: transparent; +} + +.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; +} + +.upload button .progress { + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 0; + opacity: 0.5; + background: #c9c; +} + +.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: 1.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; +} + +.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 { + display: flex; +} + +.filter .filter-text { + flex: 1 1 auto; + width: 100%; + box-sizing: border-box; +} + +.item-list { + margin: 1em; +} + +.item-list li { + position: relative; + zoom: 1; +} + +.item-list li:hover { + background: #f5f5f5; +} + +.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; + color: #800000; + font-weight: bold; + font-size: 1.6em; + line-height: 1em; + padding: 0.1875em 0.3125em 0.3125em; +} + +.item-list .delete:hover { + background: #fee; +} + +.item-list .header:hover { + background: none; +} + +.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 (prefers-color-scheme: dark) { + html, body { + background: #111; + } + + body { + color: #ccc; + } + + a { + color: #ddd; + } + + a:hover { + background-color: #222; + } + + a:focus { + background-color: #220; + } + + a:hover:focus { + background-color: #2f2f0f; + } + + 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 li:hover { + background: #222; + } + + .item-list .detail, + .item-list .delete { + border-bottom-color: #222; + } + + .item-list .size { + color: #999; + } + + .item-list .time { + color: #666; + } + + .item-list .delete { + color: #f99; + } + + .item-list .delete:hover { + background-color: #433; + } + + .item-list .header .detail { + background-color: #181818; + } +} + +@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/asset/main.js b/src/tpl/frontend/main.js similarity index 100% rename from src/tpl/asset/main.js rename to src/tpl/frontend/main.js diff --git a/src/tpl/frontend/main.js.go b/src/tpl/frontend/main.js.go new file mode 100644 index 00000000..5903f5cb --- /dev/null +++ b/src/tpl/frontend/main.js.go @@ -0,0 +1,983 @@ +package frontend + +const MainJs = ` +(function () { + var strUndef = 'undefined'; + + var classNone = 'none'; + var classHeader = 'header'; + var leavingEvent = typeof window.onpagehide !== strUndef ? 'pagehide' : 'beforeunload'; + + var Enter = 'Enter'; + var Escape = 'Escape'; + var Esc = 'Esc'; + var Space = ' '; + + 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.classList || !filter.addEventListener) { + filter.className += ' none'; + return; + } + + var input = filter.querySelector('input.filter-text'); + if (!input) { + return; + } + + var selectorNone = '.' + classNone; + var selectorNotNone = ':not(' + selectorNone + ')'; + var selectorItem = '.item-list > li:not(.' + classHeader + '):not(.parent)'; + var selectorItemNone = selectorItem + selectorNone; + var selectorItemNotNone = selectorItem + selectorNotNone; + + // event handler + var timeoutId; + var lastFilterText = ''; + var doFilter = function () { + var filterText = input.value.trim().toLowerCase(); + if (filterText === lastFilterText) { + return; + } + + var selector, items, i; + + if (!filterText) { // filter cleared, show all items + selector = selectorItemNone; + items = document.body.querySelectorAll(selector); + for (i = items.length - 1; i >= 0; i--) { + items[i].classList.remove(classNone); + } + } else { + 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) { + item.classList.add(classNone); + } else { + item.classList.remove(classNone); + } + } + } + + lastFilterText = filterText; + }; + + var onValueMayChange = function () { + clearTimeout(timeoutId); + timeoutId = setTimeout(doFilter, 350); + }; + input.addEventListener('input', onValueMayChange, false); + input.addEventListener('change', onValueMayChange, false); + input.addEventListener('keydown', function (e) { + switch (e.key) { + case Enter: + clearTimeout(timeoutId); + input.blur(); + doFilter(); + e.preventDefault(); + break; + case Escape: + case Esc: + clearTimeout(timeoutId); + input.value = ''; + doFilter(); + e.preventDefault(); + break; + } + }, false); + + // init + if (sessionStorage) { + 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 enableKeyboardNavigate() { + if ( + !document.querySelector || + !document.addEventListener || + !document.body.classList || + !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, isPrev, startA) { + if (!container) { + return + } + if (!startA) { + startA = container.querySelector(':focus'); + } + var startLI = startA; + while (startLI && startLI.tagName !== 'LI') { + startLI = startLI.parentElement; + } + if (!startLI) { + if (isPrev) { + startLI = container.firstElementChild; + } else { + startLI = container.lastElementChild; + } + } + if (!startLI) { + return; + } + + var siblingLI = startLI; + do { + if (isPrev) { + siblingLI = siblingLI.previousElementSibling; + if (!siblingLI) { + siblingLI = container.lastElementChild; + } + } else { + siblingLI = siblingLI.nextElementSibling; + if (!siblingLI) { + siblingLI = container.firstElementChild; + } + } + } while (siblingLI !== startLI && ( + siblingLI.classList.contains(classNone) || + siblingLI.classList.contains(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, isPrev, 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, isPrev, 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(key) { + key = key.toLowerCase(); + + var currentLookupStartA; + if (key === lookupKey) { + // same as last key, lookup next for the same key as prefix + currentLookupStartA = itemList.querySelector(':focus'); + } else { + if (!lookupStartA) { + lookupStartA = itemList.querySelector(':focus'); + } + currentLookupStartA = lookupStartA; + if (lookupKey === undefined) { + lookupKey = key; + } else { + // key changed, no more prefix match + lookupKey = ''; + } + } + lookupBuffer += key; + delayClearLookupContext(); + return getMatchedFocusableSibling(itemList, false, 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(e.key); + } + } 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(String.fromCharCode(e.keyCode)); + } + } + } + + document.addEventListener('keydown', function (e) { + var newFocusEl = getFocusItemByKeyPress(e); + if (newFocusEl) { + e.preventDefault(); + newFocusEl.focus(); + } + }); + } + + function enhanceUpload() { + if (!document.querySelector || !document.addEventListener || !document.body.classList) { + 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 btnSubmit = form.querySelector('.submit') || form.querySelector('input[type=submit]'); + if (!btnSubmit) { + return; + } + + var uploadType = document.body.querySelector('.upload-type'); + if (!uploadType) { + return; + } + + var classUploading = 'uploading'; + + 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; + + function addClass(ele, className) { + ele && ele.classList.add(className); + } + + function removeClass(ele, className) { + ele && ele.classList.remove(className); + } + + function hasClass(ele, className) { + return ele && ele.classList.contains(className); + } + + 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'); + var ms = padStart(ms, 3, '0'); + var ts = '-' + date + '-' + time + '-' + ms; + return ts; + } + + function enableAddDir() { + 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 (sessionStorage) { + 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; + }); + if (nodir) { + onClickOptFile(); // prevent clear input files + } + }); + } + + function enableUploadProgress() { // also fix Safari upload filename has no path info + if (!FormData) { + return; + } + + var elProgress = btnSubmit.querySelector('.progress'); + + function onComplete() { + if (elProgress) { + elProgress.style.width = ''; + } + fileInput.disabled = false; + btnSubmit.disabled = false; + removeClass(upload, classUploading); + } + + function onLoad() { + location.reload(); + } + + 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; + } + + 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.upload.addEventListener('error', onComplete); + xhr.upload.addEventListener('abort', onComplete); + xhr.upload.addEventListener('load', onComplete); + xhr.upload.addEventListener('load', onLoad); + if (elProgress) { + xhr.upload.addEventListener('progress', onProgress); + } + + xhr.open(form.method, form.action); + xhr.send(parts); + addClass(upload, classUploading); + fileInput.disabled = true; + btnSubmit.disabled = true; + } + + 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); + }); + return uploadProgressively; + } + + function enableAddDragDrop(uploadProgressively) { + var classDragging = 'dragging'; + + function onDragEnterOver(e) { + e.stopPropagation(); + e.preventDefault(); + addClass(e.currentTarget, classDragging); + } + + function onDragLeave(e) { + if (e.target === e.currentTarget) { + removeClass(e.currentTarget, classDragging); + } + } + + function getFilesFromEntries(entries, onDone) { + var files = []; + var len = entries.length; + var cb = 0; + + function increaseCb() { + cb++; + if (cb === len) { + onDone(files); + } + } + + 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(); + typeof console !== strUndef && console.error(err); + }); + } else { + var reader = entry.createReader(); + reader.readEntries(function (subEntries) { + if (subEntries.length) { + getFilesFromEntries(subEntries, function (subFiles) { + Array.prototype.push.apply(files, subFiles); + increaseCb(); + }); + } else { + increaseCb(); + } + }); + } + }); + } + + function getFilesFromItems(items, onDone) { + var files = []; + + var entries = []; + for (var i = 0, len = items.length; i < len; i++) { + var entry = items[i].webkitGetAsEntry(); + entries.push(entry); + } + getFilesFromEntries(entries, onDone); + } + + function onDrop(e) { + e.stopPropagation(); + e.preventDefault(); + removeClass(e.currentTarget, classDragging); + if (hasClass(e.currentTarget, classUploading)) { + return; + } + fileInput.value = ''; + + if (!e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files.length) { + return; + } + + var hasDir = false; + if (e.dataTransfer.items) { + var items = Array.prototype.slice.call(e.dataTransfer.items); + if (items.length && items[0].webkitGetAsEntry) { + for (var i = 0, len = items.length; i < len; i++) { + var entry = items[i].webkitGetAsEntry(); + if (entry.isDirectory) { + hasDir = true; + break; + } + } + } + } + + if (hasDir) { + if (!uploadProgressively) { + return; + } + if (!optDirFile && !optInnerDirFile) { + return; + } + if (optActive === optFile) { + if (optDirFile) { + optDirFile.focus(); + optDirFile.click(); + } else if (optInnerDirFile) { + optInnerDirFile.focus(); + optInnerDirFile.click(); + } + } + btnSubmit.disabled = true; // disable earlier + getFilesFromItems(e.dataTransfer.items, function (files) { + uploadProgressively(files); + }); + } else { + if (optFile && optActive !== optFile) { + optFile.focus(); + optFile.click(); + } + + if (uploadProgressively) { + var files = Array.prototype.slice.call(e.dataTransfer.files); + uploadProgressively(files); + } else { + fileInput.files = e.dataTransfer.files; + form.submit(); + } + } + } + + upload.addEventListener('dragenter', onDragEnterOver); + upload.addEventListener('dragover', onDragEnterOver); + upload.addEventListener('dragleave', onDragLeave); + upload.addEventListener('drop', onDrop); + } + + function enableAddPaste(uploadProgressively) { + if (!uploadProgressively) { + document.documentElement.addEventListener('paste', function (e) { + var data = e.clipboardData; + if (data && data.files && data.files.length) { + if (optFile && optActive !== optFile) { + optFile.focus(); + optFile.click(); + } + fileInput.files = data.files; + form.submit(); + } + }); + return; + } + + var typeTextPlain = 'text/plain'; + + function uploadPastedFiles(files) { + if (optFile && optActive !== optFile) { + optFile.focus(); + optFile.click(); + } + + 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); + } + + 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}); + } + } + + document.documentElement.addEventListener('paste', function (e) { + var data = e.clipboardData; + if (!data) { + return; + } + + var files; + var items; + if (data.files && data.files.length) { + files = Array.prototype.slice.call(data.files); + } else if (data.items && data.items.length) { + 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); + } + }); + } + }); + } + + enableAddDir(); + var uploadProgressively = enableUploadProgress(); + enableAddDragDrop(uploadProgressively); + enableAddPaste(uploadProgressively); + } + + function enableNonRefreshDelete() { + if (!document.querySelector) { + return; + } + + var itemList = document.body.querySelector('.item-list'); + if (!itemList || !itemList.addEventListener) { + return; + } + if (itemList.classList) { + if (!itemList.classList.contains('has-deletable')) { + return; + } + } else if (itemList.className.indexOf('has-deletable') < 0) { + return; + } + + itemList.addEventListener('click', function (e) { + if (e.defaultPrevented || !e.target || !e.target.href || e.target.className.indexOf('delete') < 0) { + return; + } + + function onLoad() { + var elItem = e.target; + while (elItem && elItem.nodeName !== 'LI') { + elItem = elItem.parentNode; + } + if (!elItem) { + return; + } + var elItemParent = elItem.parentNode; + elItemParent && elItemParent.removeChild(elItem); + } + + var xhr = new XMLHttpRequest(); + xhr.open('POST', e.target.href); // will retrieve deleted result into bfcache + xhr.addEventListener('load', onLoad); + xhr.send(); + e.preventDefault(); + return false; + }, false); + } + + enableFilter(); + enableKeyboardNavigate(); + enhanceUpload(); + enableNonRefreshDelete(); +})(); +` diff --git a/src/tpl/page.html b/src/tpl/frontend/page.html similarity index 95% rename from src/tpl/page.html rename to src/tpl/frontend/page.html index d0d4ac9a..eceb9ffa 100644 --- a/src/tpl/page.html +++ b/src/tpl/frontend/page.html @@ -8,7 +8,7 @@ {{.Path}} - + {{$contextQueryString := .Context.QueryString}} @@ -111,6 +111,6 @@
500 potential issue occurred
{{end}} - + diff --git a/src/tpl/frontend/page.html.go b/src/tpl/frontend/page.html.go new file mode 100644 index 00000000..81057679 --- /dev/null +++ b/src/tpl/frontend/page.html.go @@ -0,0 +1,120 @@ +package frontend + +const PageTplStr = ` + + + + + + + + + + {{.Path}} + + + +{{$contextQueryString := .Context.QueryString}} +{{$isDownload := .IsDownload}} +{{if not $isDownload}} +
    + {{range .Paths}} +
  1. {{fmtFilename .Name}}
  2. + {{end}} +
+ +{{if .CanMkdir}} +
+
+ + +
+
+{{end}} + +{{if .CanUpload}} +
+ + {{if .CanMkdir}}{{end}} + +
+
+
+ + +
+
+{{end}} + +{{if .CanArchive}} +
+ .tar + .tar.gz + .zip +
+{{end}} + +{{if .SubItemsHtml}} +
+
+ +
+
+{{end}} + +{{if .CanDelete}} + +{{end}} +{{end}} + + +{{if eq .Status 403}} +
403 resource is forbidden
+{{else if eq .Status 404}} +
404 resource not found
+{{else if eq .Status 500}} +
500 potential issue occurred
+{{end}} + + + + +` diff --git a/src/tpl/page.html.go b/src/tpl/page.html.go deleted file mode 100644 index 0f4b6248..00000000 --- a/src/tpl/page.html.go +++ /dev/null @@ -1,157 +0,0 @@ -package tpl - -import ( - "../serverErrHandler" - "./util" - "html/template" - "path" -) - -const pageTplStr = ` - - - - - - - - - -{{.Path}} - - - -{{$contextQueryString := .Context.QueryString}} -{{$isDownload := .IsDownload}} -{{if not $isDownload}} -
    -{{range .Paths}} -
  1. {{fmtFilename .Name}}
  2. -{{end}} -
-{{if .CanMkdir}} -
-
- - -
-
-{{end}} -{{if .CanUpload}} -
- -{{if .CanMkdir}}{{end}} - -
-
-
- - -
-
-{{end}} -{{if .CanArchive}} - -{{end}} -{{if .SubItemsHtml}} -
-
- -
-
-{{end}} -{{if .CanDelete}} - -{{end}} -{{end}} - -{{if eq .Status 403}} -
403 resource is forbidden
-{{else if eq .Status 404}} -
404 resource not found
-{{else if eq .Status 500}} -
500 potential issue occurred
-{{end}} - - - -` - -var defaultPageTpl *template.Template - -func init() { - pageTpl := template.New("page") - pageTpl = addFuncMap(pageTpl) - - var err error - defaultPageTpl, err = pageTpl.Parse(pageTplStr) - if serverErrHandler.CheckError(err) { - defaultPageTpl = template.Must(pageTpl.Parse("Builtin Template Error")) - } -} - -func LoadPageTpl(tplPath string) (*template.Template, error) { - if len(tplPath) == 0 { - return defaultPageTpl, nil - } - - var err error - pageTpl := template.New(path.Base(tplPath)) - pageTpl = addFuncMap(pageTpl) - pageTpl, err = pageTpl.ParseFiles(tplPath) - if err != nil { - pageTpl = defaultPageTpl - } - - return pageTpl, err -} - -func addFuncMap(tpl *template.Template) *template.Template { - return tpl.Funcs(template.FuncMap{ - "fmtFilename": util.FormatFilename, - "fmtSize": util.FormatSize, - "fmtTime": util.FormatTime, - }) -} diff --git a/src/tpl/template.go b/src/tpl/template.go new file mode 100644 index 00000000..7ee2e472 --- /dev/null +++ b/src/tpl/template.go @@ -0,0 +1,46 @@ +package tpl + +import ( + "../serverErrHandler" + "./frontend" + "./util" + "html/template" + "path" +) + +var defaultPageTpl *template.Template + +func init() { + pageTpl := template.New("page") + pageTpl = addFuncMap(pageTpl) + + var err error + defaultPageTpl, err = pageTpl.Parse(frontend.PageTplStr) + if serverErrHandler.CheckError(err) { + defaultPageTpl = template.Must(pageTpl.Parse("Builtin Template Error")) + } +} + +func LoadPageTpl(tplPath string) (*template.Template, error) { + if len(tplPath) == 0 { + return defaultPageTpl, nil + } + + var err error + pageTpl := template.New(path.Base(tplPath)) + pageTpl = addFuncMap(pageTpl) + pageTpl, err = pageTpl.ParseFiles(tplPath) + if err != nil { + pageTpl = defaultPageTpl + } + + return pageTpl, err +} + +func addFuncMap(tpl *template.Template) *template.Template { + return tpl.Funcs(template.FuncMap{ + "fmtFilename": util.FormatFilename, + "fmtSize": util.FormatSize, + "fmtTime": util.FormatTime, + }) +} From 09e6c524050b090826c889757407ca64b7db9ca7 Mon Sep 17 00:00:00 2001 From: marjune Date: Sun, 21 Feb 2021 10:50:27 +0800 Subject: [PATCH 06/57] chore: disable build on latest Go version It is the main branch's duty to maintain build on latest Go version. --- build/build-all-docker.sh | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/build/build-all-docker.sh b/build/build-all-docker.sh index fe448b4c..494222cc 100644 --- a/build/build-all-docker.sh +++ b/build/build-all-docker.sh @@ -27,33 +27,29 @@ buildByDocker() { "$@" } -gover=latest -builds=('linux 386' 'linux amd64' 'linux arm' 'linux arm64' 'windows 386' 'windows amd64' 'windows arm' 'darwin amd64' 'darwin arm64') -builds=("${builds[@]}" 'freebsd 386' 'freebsd amd64' 'freebsd arm' 'freebsd arm64') -builds=("${builds[@]}" 'openbsd 386' 'openbsd amd64' 'openbsd arm' 'openbsd arm64') -builds=("${builds[@]}" 'netbsd 386' 'netbsd amd64' 'netbsd arm' 'netbsd arm64') -builds=("${builds[@]}" 'plan9 386' 'plan9 amd64' 'plan9 arm') -buildByDocker "$gover" "${builds[@]}" - -#gover=1.9 -#builds=('freebsd 386 -9.x' 'freebsd amd64 -9.x' 'freebsd arm -9.x') +#gover=1.15 +#builds=('linux 386' 'linux amd64' 'linux arm' 'linux arm64' 'windows 386' 'windows amd64' 'windows arm' 'darwin amd64' 'darwin arm64') +#builds=("${builds[@]}" 'freebsd 386' 'freebsd amd64' 'freebsd arm' 'freebsd arm64') +#builds=("${builds[@]}" 'openbsd 386' 'openbsd amd64' 'openbsd arm' 'openbsd arm64') +#builds=("${builds[@]}" 'netbsd 386' 'netbsd amd64' 'netbsd arm' 'netbsd arm64') +#builds=("${builds[@]}" 'plan9 386' 'plan9 amd64' 'plan9 arm') #buildByDocker "$gover" "${builds[@]}" -gover=1.10 -builds=('windows 386 -xp-vista' 'windows amd64 -xp-vista') -#builds=("${builds[@]}" 'darwin 386 -10.8-mountain_lion' 'darwin amd64 -10.8-mountain_lion') -#builds=("${builds[@]}" 'openbsd 386 -6.0' 'openbsd amd64 -6.0' 'openbsd arm -6.0') -buildByDocker "$gover" "${builds[@]}" +#gover=1.14 +#builds=('darwin 386 -10.11-el_capitan' 'darwin amd64 -10.11-el_capitan') +#buildByDocker "$gover" "${builds[@]}" #gover=1.12 #builds=('darwin 386 -10.10-yosemite' 'darwin amd64 -10.10-yosemite') #builds=("${builds[@]}" 'freebsd 386 -10.x' 'freebsd amd64 -10.x' 'freebsd arm -9.x') #buildByDocker "$gover" "${builds[@]}" -#gover=1.14 -#builds=('darwin 386 -10.11-el_capitan' 'darwin amd64 -10.11-el_capitan') -#buildByDocker "$gover" "${builds[@]}" +gover=1.10 +builds=('windows 386 -xp-vista' 'windows amd64 -xp-vista') +#builds=("${builds[@]}" 'darwin 386 -10.8-mountain_lion' 'darwin amd64 -10.8-mountain_lion') +#builds=("${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') +#gover=1.9 +#builds=('freebsd 386 -9.x' 'freebsd amd64 -9.x' 'freebsd arm -9.x') #buildByDocker "$gover" "${builds[@]}" From 2aa992935351fa306b8ea1a8a12c6a09e1fc6f62 Mon Sep 17 00:00:00 2001 From: marjune Date: Mon, 22 Feb 2021 21:54:16 +0800 Subject: [PATCH 07/57] docs: update minimal required Go version --- README.md | 2 +- README.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 52aad395..e6c1f7dd 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Simple command line based HTTP file server to share local file system. - Support location alias(mount another directory to url location) ## Compile -Minimal required Go version is 1.9. +Minimal required Go version is 1.2. ```bash GO111MODULE=auto go build src/main.go ``` diff --git a/README.zh-CN.md b/README.zh-CN.md index 4d471793..e9a7790e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -13,7 +13,7 @@ - 支持目录别名(将另一个目录挂载到某个URL路径) ## 编译 -至少需要Go 1.9版本。 +至少需要Go 1.2版本。 ```bash GO111MODULE=auto go build src/main.go ``` From 72153827310616d5499ab3e188c8d462f3cf79f6 Mon Sep 17 00:00:00 2001 From: marjune Date: Sun, 21 Mar 2021 11:32:33 +0800 Subject: [PATCH 08/57] feat: fix issue after merge down - re-embed default theme file into go files - use manually embeded resource instead of those embeded by instruction - use `ioutil.ReadAll` instead of `io.ReadAll` - use `ioutil.ReadFile` instead of `os.ReadFile` --- src/Makefile | 6 +-- src/tpl/defaultTheme.go | 19 ++------ src/tpl/dirTheme.go | 4 +- .../frontend/{main.css.go => index.css.go} | 14 ++++-- .../frontend/{page.html.go => index.html.go} | 46 +++++++++---------- src/tpl/frontend/{main.js.go => index.js.go} | 32 +++++++++++-- src/tpl/memTheme.go | 3 +- 7 files changed, 74 insertions(+), 50 deletions(-) rename src/tpl/frontend/{main.css.go => index.css.go} (97%) rename src/tpl/frontend/{page.html.go => index.html.go} (60%) rename src/tpl/frontend/{main.js.go => index.js.go} (96%) diff --git a/src/Makefile b/src/Makefile index 60f273ab..62c75f60 100644 --- a/src/Makefile +++ b/src/Makefile @@ -5,6 +5,6 @@ define embed endef tpls: - $(call embed, tpl/frontend/page.html) - $(call embed, tpl/frontend/main.css) - $(call embed, tpl/frontend/main.js) + $(call embed, tpl/frontend/index.html) + $(call embed, tpl/frontend/index.css) + $(call embed, tpl/frontend/index.js) diff --git a/src/tpl/defaultTheme.go b/src/tpl/defaultTheme.go index 9ea30662..32fb3b83 100644 --- a/src/tpl/defaultTheme.go +++ b/src/tpl/defaultTheme.go @@ -1,31 +1,22 @@ package tpl import ( - "bytes" - _ "embed" + "./frontend" + "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 - var DefaultTheme MemTheme func init() { - defaultTpl, err := ParsePageTpl(defaultTplStr) + defaultTpl, err := ParsePageTpl(frontend.DefaultTplStr) if err != nil { defaultTpl, _ = ParsePageTpl("Builtin Template Error") } DefaultTheme.template = defaultTpl defaultAssets := map[string]asset{ - "index.css": {"text/css", bytes.NewReader(defaultCss)}, - "index.js": {"application/javascript", bytes.NewReader(defaultJs)}, + "index.css": {"text/css", strings.NewReader(frontend.DefaultCss)}, + "index.js": {"application/javascript", strings.NewReader(frontend.DefaultJs)}, } DefaultTheme.assets = defaultAssets } diff --git a/src/tpl/dirTheme.go b/src/tpl/dirTheme.go index 9597dea7..e53dadba 100644 --- a/src/tpl/dirTheme.go +++ b/src/tpl/dirTheme.go @@ -2,8 +2,8 @@ package tpl 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/frontend/main.css.go b/src/tpl/frontend/index.css.go similarity index 97% rename from src/tpl/frontend/main.css.go rename to src/tpl/frontend/index.css.go index 691536ec..b230d059 100644 --- a/src/tpl/frontend/main.css.go +++ b/src/tpl/frontend/index.css.go @@ -1,6 +1,6 @@ package frontend -const MainCss = ` +const DefaultCss = ` html, body { margin: 0; padding: 0; @@ -11,7 +11,7 @@ html { font-family: "roboto_condensedbold", "Helvetica Neue", Helvetica, Arial, sans-serif; } -body, input, textarea { +body, input, textarea, button { font-family: Consolas, "Lucida Console", "San Francisco Mono", Menlo, Monaco, "Andale Mono", "DejaVu Sans Mono", monospace; } @@ -356,14 +356,22 @@ em { 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; + cursor: pointer; } -.item-list .delete:hover { +.item-list .delete button:hover { background: #fee; } diff --git a/src/tpl/frontend/page.html.go b/src/tpl/frontend/index.html.go similarity index 60% rename from src/tpl/frontend/page.html.go rename to src/tpl/frontend/index.html.go index 81057679..6ef01395 100644 --- a/src/tpl/frontend/page.html.go +++ b/src/tpl/frontend/index.html.go @@ -1,8 +1,8 @@ package frontend -const PageTplStr = ` +const DefaultTplStr = ` - + @@ -11,11 +11,12 @@ const PageTplStr = ` {{.Path}} - + {{$contextQueryString := .Context.QueryString}} {{$isDownload := .IsDownload}} +{{$SubItemPrefix := .SubItemPrefix}} {{if not $isDownload}}
    {{range .Paths}} @@ -27,23 +28,23 @@ const PageTplStr = `
    - +
    {{end}} {{if .CanUpload}}
    - - {{if .CanMkdir}}{{end}} - + + {{if .CanMkdir}}{{end}} +
    @@ -60,17 +61,16 @@ const PageTplStr = ` {{if .SubItemsHtml}}
    - +
    {{end}} {{if .CanDelete}} {{end}} @@ -79,11 +79,11 @@ const PageTplStr = ` {{if not .IsDownload}}
  1. {{$dirSort := .SortState.DirSort}}{{$sortKey := .SortState.Key}} - Dir{{if eq $dirSort -1}}↑{{else if eq $dirSort 1}}↓{{end}} - Name{{if eq $sortKey "n"}}↑{{else if eq $sortKey "N"}}↓{{end}} - Type{{if eq $sortKey "e"}}↑{{else if eq $sortKey "E"}}↓{{end}} - Size{{if eq $sortKey "s"}}↑{{else if eq $sortKey "S"}}↓{{end}} - Time{{if eq $sortKey "t"}}↑{{else if eq $sortKey "T"}}↓{{end}} + {{.Trans.ListDirLabel}}{{if eq $dirSort -1}}↑{{else if eq $dirSort 1}}↓{{end}} + {{.Trans.ListNameLabel}}{{if eq $sortKey "n"}}↑{{else if eq $sortKey "N"}}↓{{end}} + {{.Trans.ListTypeLabel}}{{if eq $sortKey "e"}}↑{{else if eq $sortKey "E"}}↓{{end}} + {{.Trans.ListSizeLabel}}{{if eq $sortKey "s"}}↑{{else if eq $sortKey "S"}}↓{{end}} + {{.Trans.ListTimeLabel}}{{if eq $sortKey "t"}}↑{{else if eq $sortKey "T"}}↓{{end}}
  2. @@ -101,20 +101,20 @@ const PageTplStr = ` {{.DisplaySize}} {{.DisplayTime}} - {{if and (not $isDownload) .DeleteUrl}}x{{end}} + {{if and (not $isDownload) .DeleteUrl}}
    {{end}}
  3. {{end}} {{if eq .Status 403}} -
    403 resource is forbidden
    +
    {{.Trans.Error403}}
    {{else if eq .Status 404}} -
    404 resource not found
    +
    {{.Trans.Error404}}
    {{else if eq .Status 500}} -
    500 potential issue occurred
    +
    {{.Trans.Error500}}
    {{end}} - + ` diff --git a/src/tpl/frontend/main.js.go b/src/tpl/frontend/index.js.go similarity index 96% rename from src/tpl/frontend/main.js.go rename to src/tpl/frontend/index.js.go index 5903f5cb..bf489970 100644 --- a/src/tpl/frontend/main.js.go +++ b/src/tpl/frontend/index.js.go @@ -1,6 +1,6 @@ package frontend -const MainJs = ` +const DefaultJs = ` (function () { var strUndef = 'undefined'; @@ -879,7 +879,17 @@ const MainJs = ` } } + var nonTextInputTypes = ['hidden', 'radio', 'checkbox', 'button', 'reset', 'submit', 'image']; 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; @@ -949,8 +959,8 @@ const MainJs = ` return; } - itemList.addEventListener('click', function (e) { - if (e.defaultPrevented || !e.target || !e.target.href || e.target.className.indexOf('delete') < 0) { + itemList.addEventListener('submit', function (e) { + if (e.defaultPrevented) { return; } @@ -966,8 +976,22 @@ const MainJs = ` elItemParent && elItemParent.removeChild(elItem); } + var params = ''; + var els = []; + Array.prototype.push.apply(els, e.target.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 = e.target.action + '?' + params + var xhr = new XMLHttpRequest(); - xhr.open('POST', e.target.href); // will retrieve deleted result into bfcache + xhr.open('POST', url); // will retrieve deleted result into bfcache xhr.addEventListener('load', onLoad); xhr.send(); e.preventDefault(); diff --git a/src/tpl/memTheme.go b/src/tpl/memTheme.go index 9c6df73f..4868ff92 100644 --- a/src/tpl/memTheme.go +++ b/src/tpl/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 From f0890d69b9441970f269d143af4122b78522efcf Mon Sep 17 00:00:00 2001 From: marjune Date: Mon, 12 Apr 2021 18:34:38 +0800 Subject: [PATCH 09/57] chore: re-embed frontend assets --- src/tpl/frontend/index.js.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tpl/frontend/index.js.go b/src/tpl/frontend/index.js.go index bf489970..d7246144 100644 --- a/src/tpl/frontend/index.js.go +++ b/src/tpl/frontend/index.js.go @@ -992,6 +992,7 @@ const DefaultJs = ` 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(); e.preventDefault(); From fa04424bafbdb173e58ef51ca3362e16f80a066a Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 12 Jun 2021 16:52:40 +0800 Subject: [PATCH 10/57] chore: re-embed frontend assets --- src/tpl/frontend/index.css.go | 43 ++++- src/tpl/frontend/index.html.go | 13 +- src/tpl/frontend/index.js.go | 337 +++++++++++++++++++++------------ 3 files changed, 253 insertions(+), 140 deletions(-) diff --git a/src/tpl/frontend/index.css.go b/src/tpl/frontend/index.css.go index b230d059..4fb7215f 100644 --- a/src/tpl/frontend/index.css.go +++ b/src/tpl/frontend/index.css.go @@ -11,10 +11,6 @@ html { font-family: "roboto_condensedbold", "Helvetica Neue", Helvetica, Arial, sans-serif; } -body, input, textarea, button { - font-family: Consolas, "Lucida Console", "San Francisco Mono", Menlo, Monaco, "Andale Mono", "DejaVu Sans Mono", monospace; -} - body { color: #333; font-size: 0.625em; @@ -24,6 +20,14 @@ body { padding-bottom: 1em; } +body, input, textarea, button { + font-family: Consolas, "Lucida Console", "San Francisco Mono", Menlo, Monaco, "Andale Mono", "DejaVu Sans Mono", monospace; +} + +input::-ms-clear { + display: none; +} + form { margin: 0; padding: 0; @@ -37,7 +41,7 @@ ul, ol, li { a { display: block; - padding: 0.45em 0.5em; + padding: 0.5em; color: #000; text-decoration: none; outline: 0; @@ -61,6 +65,13 @@ input, button { padding: 0.25em 0; } +input[type=button], +input[type=submit], +input[type=reset], +button { + cursor: pointer; +} + em { font-style: normal; font-weight: normal; @@ -287,15 +298,28 @@ em { } .filter .form { + position: relative; display: flex; } -.filter .filter-text { +.filter input { flex: 1 1 auto; width: 100%; + 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; } @@ -368,7 +392,6 @@ em { font-size: 1.6em; line-height: 1em; padding: 0.1875em 0.3125em 0.3125em; - cursor: pointer; } .item-list .delete button:hover { @@ -416,15 +439,15 @@ em { } a:hover { - background-color: #222; + background-color: #333; } a:focus { - background-color: #220; + background-color: #330; } a:hover:focus { - background-color: #2f2f0f; + background-color: #33331a; } em { diff --git a/src/tpl/frontend/index.html.go b/src/tpl/frontend/index.html.go index 6ef01395..ccf7bfd5 100644 --- a/src/tpl/frontend/index.html.go +++ b/src/tpl/frontend/index.html.go @@ -6,7 +6,7 @@ const DefaultTplStr = ` - + @@ -18,7 +18,7 @@ const DefaultTplStr = ` {{$isDownload := .IsDownload}} {{$SubItemPrefix := .SubItemPrefix}} {{if not $isDownload}} -
      +
        {{range .Paths}}
      1. {{fmtFilename .Name}}
      2. {{end}} @@ -61,7 +61,8 @@ const DefaultTplStr = ` {{if .SubItemsHtml}}
        - + +
        {{end}} @@ -86,9 +87,9 @@ const DefaultTplStr = ` {{.Trans.ListTimeLabel}}{{if eq $sortKey "t"}}↑{{else if eq $sortKey "T"}}↓{{end}} -
      3. +
      4. - ../ + ../ @@ -97,7 +98,7 @@ const DefaultTplStr = ` {{range .SubItemsHtml}}
      5. - {{.DisplayName}} + {{.DisplayName}} {{.DisplaySize}} {{.DisplayTime}} diff --git a/src/tpl/frontend/index.js.go b/src/tpl/frontend/index.js.go index d7246144..8c4cf130 100644 --- a/src/tpl/frontend/index.js.go +++ b/src/tpl/frontend/index.js.go @@ -32,10 +32,11 @@ const DefaultJs = ` return; } - var input = filter.querySelector('input.filter-text'); + var input = filter.querySelector('input'); if (!input) { return; } + var clear = filter.querySelector('button'); var selectorNone = '.' + classNone; var selectorNotNone = ':not(' + selectorNone + ')'; @@ -55,12 +56,18 @@ const DefaultJs = ` 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--) { items[i].classList.remove(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 @@ -108,6 +115,13 @@ const DefaultJs = ` } }, false); + clear && clear.addEventListener('click', function () { + clearTimeout(timeoutId); + input.value = ''; + input.focus(); + doFilter(); + }); + // init if (sessionStorage) { var prevSessionFilter = sessionStorage.getItem(location.pathname); @@ -492,6 +506,131 @@ const DefaultJs = ` return ts; } + function entriesToFiles(entries, onDone) { + var files = []; + var len = entries.length; + var cb = 0; + if (!len) { + onDone(files); + } + + function increaseCb() { + cb++; + if (cb === len) { + onDone(files); + } + } + + 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(); + typeof console !== strUndef && console.error(err); + }); + } else { + var reader = entry.createReader(); + reader.readEntries(function (subEntries) { + if (subEntries.length) { + entriesToFiles(subEntries, function (subFiles) { + Array.prototype.push.apply(files, subFiles); + increaseCb(); + }); + } else { + increaseCb(); + } + }); + } + }); + } + + function itemsToFiles(dataTransferItems, onDone) { + var files = []; + var len = dataTransferItems.length; + if (!len) { + onDone(files); + } + + var entries = []; + for (var i = 0; i < len; i++) { + var item = dataTransferItems[i]; + var entry = item.webkitGetAsEntry(); + if (!entry) { + 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 { + entries.push(entry); + } + } + + entriesToFiles(entries, function (entryFiles) { + files.push.apply(files, entryFiles); + onDone(files); + }); + } + + function itemsHasDir(dataTransferItems) { + if (!dataTransferItems) { + return false; + } + var hasDir = false; + var items = Array.prototype.slice.call(dataTransferItems); + if (items.length && items[0].webkitGetAsEntry) { + for (var i = 0, len = items.length; i < len; i++) { + var entry = items[i].webkitGetAsEntry(); + if (entry && entry.isDirectory) { + hasDir = true; + break; + } + } + } + return hasDir; + } + + function switchToFileMode() { + if (optFile && optActive !== optFile) { + optFile.focus(); + optFile.click(); + } + } + + function switchToDirMode() { + if (optDirFile) { + if (optActive !== optDirFile) { + optDirFile.focus(); + optDirFile.click(); + } + } else if (optInnerDirFile) { + if (optActive !== optInnerDirFile) { + optInnerDirFile.focus(); + optInnerDirFile.click(); + } + } + } + + function switchToAnyDirMode() { + if (optActive === optFile) { + if (optDirFile) { + optDirFile.focus(); + optDirFile.click(); + } else if (optInnerDirFile) { + optInnerDirFile.focus(); + optInnerDirFile.click(); + } + } + } + function enableAddDir() { var classHidden = 'hidden'; var classActive = 'active'; @@ -704,58 +843,6 @@ const DefaultJs = ` } } - function getFilesFromEntries(entries, onDone) { - var files = []; - var len = entries.length; - var cb = 0; - - function increaseCb() { - cb++; - if (cb === len) { - onDone(files); - } - } - - 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(); - typeof console !== strUndef && console.error(err); - }); - } else { - var reader = entry.createReader(); - reader.readEntries(function (subEntries) { - if (subEntries.length) { - getFilesFromEntries(subEntries, function (subFiles) { - Array.prototype.push.apply(files, subFiles); - increaseCb(); - }); - } else { - increaseCb(); - } - }); - } - }); - } - - function getFilesFromItems(items, onDone) { - var files = []; - - var entries = []; - for (var i = 0, len = items.length; i < len; i++) { - var entry = items[i].webkitGetAsEntry(); - entries.push(entry); - } - getFilesFromEntries(entries, onDone); - } - function onDrop(e) { e.stopPropagation(); e.preventDefault(); @@ -769,45 +856,20 @@ const DefaultJs = ` return; } - var hasDir = false; - if (e.dataTransfer.items) { - var items = Array.prototype.slice.call(e.dataTransfer.items); - if (items.length && items[0].webkitGetAsEntry) { - for (var i = 0, len = items.length; i < len; i++) { - var entry = items[i].webkitGetAsEntry(); - if (entry.isDirectory) { - hasDir = true; - break; - } - } - } - } - - if (hasDir) { + var items = e.dataTransfer.items; + if (itemsHasDir(items)) { if (!uploadProgressively) { + // must use progressive upload by JS if has directory return; } - if (!optDirFile && !optInnerDirFile) { - return; - } - if (optActive === optFile) { - if (optDirFile) { - optDirFile.focus(); - optDirFile.click(); - } else if (optInnerDirFile) { - optInnerDirFile.focus(); - optInnerDirFile.click(); - } - } btnSubmit.disabled = true; // disable earlier - getFilesFromItems(e.dataTransfer.items, function (files) { + var itemsCount = items.length; // save items count earlier, items will be lost after calling FileSystemFileEntry.file() + itemsToFiles(items, function (files) { + itemsCount > 1 ? switchToDirMode() : switchToAnyDirMode(); uploadProgressively(files); }); } else { - if (optFile && optActive !== optFile) { - optFile.focus(); - optFile.click(); - } + switchToFileMode(); if (uploadProgressively) { var files = Array.prototype.slice.call(e.dataTransfer.files); @@ -830,10 +892,7 @@ const DefaultJs = ` document.documentElement.addEventListener('paste', function (e) { var data = e.clipboardData; if (data && data.files && data.files.length) { - if (optFile && optActive !== optFile) { - optFile.focus(); - optFile.click(); - } + switchToFileMode(); fileInput.files = data.files; form.submit(); } @@ -842,13 +901,24 @@ const DefaultJs = ` } var typeTextPlain = 'text/plain'; - - function uploadPastedFiles(files) { - if (optFile && optActive !== optFile) { - optFile.focus(); - optFile.click(); + 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; @@ -865,41 +935,14 @@ const DefaultJs = ` uploadProgressively(files); } - 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']; - 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; - } - + 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(); @@ -933,6 +976,52 @@ const DefaultJs = ` } }); } + } + + 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; + var itemsCount = items.length; // save items count earlier, items will be lost after calling FileSystemFileEntry.file() + if (!items || !itemsCount) { + generatePastedFiles(data); + return; + } + var hasDir = itemsHasDir(items); + itemsToFiles(items, function (files) { + if (!files.length) { + // for pasted text + generatePastedFiles(data); + return; + } + if (files.length === 1 && files[0].file.type === 'image/png') { + // suppose for pasted image + files = files.map(function (fileInfo) { + return fileInfo && fileInfo.file; + }); + generatePastedFiles({files: files}); + return; + } + // pasted real files, not image binary + if (hasDir) { + itemsCount > 1 ? switchToDirMode() : switchToAnyDirMode(); + } else { + switchToFileMode(); + } + uploadProgressively(files); + }); }); } From 4318d7d7f0e65479507fc982a7ae9ea5333fe77e Mon Sep 17 00:00:00 2001 From: "jun.ma" Date: Wed, 28 Jul 2021 14:53:49 +0800 Subject: [PATCH 11/57] chore: re-embed frontend assets --- src/tpl/frontend/index.css.go | 58 ++++++++++++++---------------- src/tpl/frontend/index.html.go | 6 ++-- src/tpl/frontend/index.js.go | 64 +++++++++++++++++----------------- 3 files changed, 60 insertions(+), 68 deletions(-) diff --git a/src/tpl/frontend/index.css.go b/src/tpl/frontend/index.css.go index 4fb7215f..7f36d358 100644 --- a/src/tpl/frontend/index.css.go +++ b/src/tpl/frontend/index.css.go @@ -17,7 +17,7 @@ body { font-variant-ligatures: none; font-kerning: none; hyphens: none; - padding-bottom: 1em; + padding-bottom: 2em; } body, input, textarea, button { @@ -72,6 +72,13 @@ button { cursor: pointer; } +input:disabled[type=button], +input:disabled[type=submit], +input:disabled[type=reset], +button:disabled { + cursor: default; +} + em { font-style: normal; font-weight: normal; @@ -88,16 +95,23 @@ em { visibility: hidden; } -.if-disabled { - display: none; -} -:disabled .if-disabled { - display: inherit; +html::before { + display: none; + content: ''; + position: absolute; + position: fixed; + z-index: 1; + left: 0; + top: 0; + right: 0; + bottom: 0; + opacity: 0.7; + background: #c9c; } -:disabled .if-enabled { - display: none; +html.dragging::before { + display: block; } @@ -185,27 +199,6 @@ em { position: relative; } -.upload::before { - display: none; - content: ''; - position: absolute; - z-index: 1; - left: 0; - top: 0; - right: 0; - bottom: 0; - opacity: 0.7; - background: #c9c; -} - -.upload.dragging::before { - display: block; -} - -.upload.uploading.dragging::before { - background: transparent; -} - .upload input, .upload button { display: block; @@ -223,14 +216,15 @@ em { position: relative; } -.upload button .progress { - position: absolute; +.upload .progress { + position: fixed; left: 0; top: 0; - bottom: 0; width: 0; + height: 4px; opacity: 0.5; background: #c9c; + pointer-events: none; } .archive { diff --git a/src/tpl/frontend/index.html.go b/src/tpl/frontend/index.html.go index ccf7bfd5..252268df 100644 --- a/src/tpl/frontend/index.html.go +++ b/src/tpl/frontend/index.html.go @@ -42,11 +42,9 @@ const DefaultTplStr = `
        - +
        +
        {{end}} diff --git a/src/tpl/frontend/index.js.go b/src/tpl/frontend/index.js.go index 8c4cf130..bbdfc28c 100644 --- a/src/tpl/frontend/index.js.go +++ b/src/tpl/frontend/index.js.go @@ -436,18 +436,11 @@ const DefaultJs = ` return; } - var btnSubmit = form.querySelector('.submit') || form.querySelector('input[type=submit]'); - if (!btnSubmit) { - return; - } - var uploadType = document.body.querySelector('.upload-type'); if (!uploadType) { return; } - var classUploading = 'uploading'; - var file = 'file'; var dirFile = 'dirfile'; var innerDirFile = 'innerdirfile'; @@ -465,10 +458,6 @@ const DefaultJs = ` ele && ele.classList.remove(className); } - function hasClass(ele, className) { - return ele && ele.classList.contains(className); - } - var padStart = String.prototype.padStart ? function (sourceString, targetLength, padTemplate) { return sourceString.padStart(targetLength, padTemplate); } : function (sourceString, targetLength, padTemplate) { @@ -534,7 +523,7 @@ const DefaultJs = ` increaseCb(); typeof console !== strUndef && console.error(err); }); - } else { + } else if (entry.isDirectory) { var reader = entry.createReader(); reader.readEntries(function (subEntries) { if (subEntries.length) { @@ -569,7 +558,7 @@ const DefaultJs = ` // 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 { + } else if (entry.isDirectory) { entries.push(entry); } } @@ -631,7 +620,7 @@ const DefaultJs = ` } } - function enableAddDir() { + function enableAddDirFile() { var classHidden = 'hidden'; var classActive = 'active'; @@ -752,19 +741,23 @@ const DefaultJs = ` return; } - var elProgress = btnSubmit.querySelector('.progress'); + var uploading = false; + var batches = []; + var elProgress = upload.querySelector('.progress'); function onComplete() { if (elProgress) { elProgress.style.width = ''; } - fileInput.disabled = false; - btnSubmit.disabled = false; - removeClass(upload, classUploading); + if (batches.length) { + uploadBatch(batches.shift()); + } else { + uploading = false; + } } function onLoad() { - location.reload(); + !uploading && location.reload(); } function onProgress(e) { @@ -779,6 +772,15 @@ const DefaultJs = ` return; } + if (uploading) { + batches.push(files); + } else { + uploading = true; + uploadBatch(files); + } + } + + function uploadBatch(files) { var formName = fileInput.name; var parts = new FormData(); files.forEach(function (file) { @@ -808,11 +810,12 @@ const DefaultJs = ` xhr.open(form.method, form.action); xhr.send(parts); - addClass(upload, classUploading); - fileInput.disabled = true; - btnSubmit.disabled = true; } + return uploadProgressively; + } + + function enableFormUploadProgress(uploadProgressively) { form.addEventListener('submit', function (e) { e.stopPropagation(); e.preventDefault(); @@ -825,7 +828,6 @@ const DefaultJs = ` var files = Array.prototype.slice.call(fileInput.files); uploadProgressively(files); }); - return uploadProgressively; } function enableAddDragDrop(uploadProgressively) { @@ -847,9 +849,6 @@ const DefaultJs = ` e.stopPropagation(); e.preventDefault(); removeClass(e.currentTarget, classDragging); - if (hasClass(e.currentTarget, classUploading)) { - return; - } fileInput.value = ''; if (!e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files.length) { @@ -862,7 +861,6 @@ const DefaultJs = ` // must use progressive upload by JS if has directory return; } - btnSubmit.disabled = true; // disable earlier var itemsCount = items.length; // save items count earlier, items will be lost after calling FileSystemFileEntry.file() itemsToFiles(items, function (files) { itemsCount > 1 ? switchToDirMode() : switchToAnyDirMode(); @@ -881,10 +879,11 @@ const DefaultJs = ` } } - upload.addEventListener('dragenter', onDragEnterOver); - upload.addEventListener('dragover', onDragEnterOver); - upload.addEventListener('dragleave', onDragLeave); - upload.addEventListener('drop', onDrop); + var dragDropEl = document.documentElement; + dragDropEl.addEventListener('dragenter', onDragEnterOver); + dragDropEl.addEventListener('dragover', onDragEnterOver); + dragDropEl.addEventListener('dragleave', onDragLeave); + dragDropEl.addEventListener('drop', onDrop); } function enableAddPaste(uploadProgressively) { @@ -1025,8 +1024,9 @@ const DefaultJs = ` }); } - enableAddDir(); + enableAddDirFile(); var uploadProgressively = enableUploadProgress(); + enableFormUploadProgress(uploadProgressively); enableAddDragDrop(uploadProgressively); enableAddPaste(uploadProgressively); } From 6995103ec790b39bb6c28a92e1d12b94b2d0af78 Mon Sep 17 00:00:00 2001 From: marjune Date: Thu, 2 Sep 2021 15:05:27 +0800 Subject: [PATCH 12/57] Revert "feat(serverHandler/upload): parse form file path manually" Build using Go 1.16 and earlier does not need to parse form part's filename with directory manually. This reverts commit 34ae79c42a6e532c79f73b644c7966411604c206. --- src/serverHandler/upload.go | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/serverHandler/upload.go b/src/serverHandler/upload.go index 4d02ec2c..bba3960a 100644 --- a/src/serverHandler/upload.go +++ b/src/serverHandler/upload.go @@ -4,8 +4,6 @@ import ( "../util" "errors" "io" - "mime" - "mime/multipart" "net/http" "os" "path" @@ -42,17 +40,6 @@ func getAvailableFilename(fsPrefix, filename string, mustAppendSuffix bool) stri return "" } -// RFC 7578, Section 4.2 requires that if a filename is provided, the -// directory path information must not be used. -// Since Go 1.17, Part.FileName() will strip directory information. -// However, the directory information is needed for uploading. -// Parse manually instead. -func getPartFilePath(part *multipart.Part) string { - cd := part.Header.Get("Content-Disposition") - _, params, _ := mime.ParseMediaType(cd) - return params["filename"] -} - func (h *handler) saveUploadFiles(fsPrefix string, createDir, overwriteExists bool, aliasSubItems []os.FileInfo, r *http.Request) bool { errs := []error{} @@ -71,7 +58,7 @@ func (h *handler) saveUploadFiles(fsPrefix string, createDir, overwriteExists bo break } - inputPartFilePath := getPartFilePath(part) + inputPartFilePath := part.FileName() if len(inputPartFilePath) == 0 { continue } From 9241e814958ed15dbd432d617e2b61d4b68f92e4 Mon Sep 17 00:00:00 2001 From: marjune Date: Thu, 2 Sep 2021 15:07:41 +0800 Subject: [PATCH 13/57] chore: re-embed frontend assets --- src/tpl/frontend/index.css.go | 7 +++++++ src/tpl/frontend/index.js.go | 19 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/tpl/frontend/index.css.go b/src/tpl/frontend/index.css.go index 7f36d358..7a7d2175 100644 --- a/src/tpl/frontend/index.css.go +++ b/src/tpl/frontend/index.css.go @@ -15,7 +15,10 @@ 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; } @@ -327,6 +330,10 @@ html.dragging::before { background: #f5f5f5; } +.item-list a { + padding: 0.6em; +} + .item-list .detail, .item-list .delete { display: flex; diff --git a/src/tpl/frontend/index.js.go b/src/tpl/frontend/index.js.go index bbdfc28c..3306e932 100644 --- a/src/tpl/frontend/index.js.go +++ b/src/tpl/frontend/index.js.go @@ -831,12 +831,23 @@ const DefaultJs = ` } function enableAddDragDrop(uploadProgressively) { + var isSelfDragging = false; var classDragging = 'dragging'; + function onSelfDragStart() { + isSelfDragging = true; + } + + function onDragEnd() { + isSelfDragging = false; + } + function onDragEnterOver(e) { - e.stopPropagation(); - e.preventDefault(); - addClass(e.currentTarget, classDragging); + if(!isSelfDragging) { + e.stopPropagation(); + e.preventDefault(); + addClass(e.currentTarget, classDragging); + } } function onDragLeave(e) { @@ -879,6 +890,8 @@ const DefaultJs = ` } } + document.body.addEventListener('dragstart', onSelfDragStart); + document.body.addEventListener('dragend', onDragEnd); var dragDropEl = document.documentElement; dragDropEl.addEventListener('dragenter', onDragEnterOver); dragDropEl.addEventListener('dragover', onDragEnterOver); From fcf00780101dd4cfc5dd59b4131a5e237b82657f Mon Sep 17 00:00:00 2001 From: marjune Date: Wed, 6 Oct 2021 16:40:06 +0800 Subject: [PATCH 14/57] chore: re-embed frontend assets --- src/tpl/frontend/index.css.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tpl/frontend/index.css.go b/src/tpl/frontend/index.css.go index 7a7d2175..50aacbd3 100644 --- a/src/tpl/frontend/index.css.go +++ b/src/tpl/frontend/index.css.go @@ -24,7 +24,7 @@ body { } body, input, textarea, button { - font-family: Consolas, "Lucida Console", "San Francisco Mono", Menlo, Monaco, "Andale Mono", "DejaVu Sans Mono", monospace; + font-family: "Cascadia Mono", Consolas, "Lucida Console", "San Francisco Mono", Menlo, Monaco, "Andale Mono", "DejaVu Sans Mono", "Jetbrains Mono NL", monospace; } input::-ms-clear { From 4c23cb5edf7144c1141d002573da85280778db6b Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 4 Dec 2021 17:54:02 +0800 Subject: [PATCH 15/57] chore: re-embed frontend assets --- src/tpl/frontend/index.css.go | 62 ++++++++++++---- src/tpl/frontend/index.html.go | 12 ++- src/tpl/frontend/index.js.go | 131 +++++++++++++++++++++++---------- 3 files changed, 151 insertions(+), 54 deletions(-) diff --git a/src/tpl/frontend/index.css.go b/src/tpl/frontend/index.css.go index 50aacbd3..021c3ab7 100644 --- a/src/tpl/frontend/index.css.go +++ b/src/tpl/frontend/index.css.go @@ -104,7 +104,7 @@ html::before { content: ''; position: absolute; position: fixed; - z-index: 1; + z-index: 2; left: 0; top: 0; right: 0; @@ -198,6 +198,53 @@ html.dragging::before { 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 { + visibility: visible; +} + +.upload-status .label { + position: absolute; + left: 50%; + top: 100%; + opacity: 0; + transform: translate(-50%, -50%); + transition: transform .2s, opacity .2s; + padding: 0.5em 1em; + color: #fff; + background: #c9c; + background-color: rgba(204, 153, 204, 0.8); + white-space: nowrap; +} + +.upload-status.uploading .label { + opacity: 1; + transform: translate(-50%, 10%); +} + +.upload-status .progress { + position: absolute; + left: 0; + top: 0; + width: 0; + height: 100%; + background: #c9c; +} + .upload { position: relative; } @@ -219,17 +266,6 @@ html.dragging::before { position: relative; } -.upload .progress { - position: fixed; - left: 0; - top: 0; - width: 0; - height: 4px; - opacity: 0.5; - background: #c9c; - pointer-events: none; -} - .archive { margin: 1em; overflow: hidden; @@ -301,7 +337,7 @@ html.dragging::before { .filter input { flex: 1 1 auto; - width: 100%; + width: 97%; padding-right: 1.5em; box-sizing: border-box; } diff --git a/src/tpl/frontend/index.html.go b/src/tpl/frontend/index.html.go index 252268df..6d39b1db 100644 --- a/src/tpl/frontend/index.html.go +++ b/src/tpl/frontend/index.html.go @@ -24,10 +24,18 @@ const DefaultTplStr = ` {{end}}
      +{{if .CanUpload}} +
      + {{.Trans.UploadingLabel}} + +
      +{{end}} + {{if .CanMkdir}}
      +
      @@ -42,9 +50,9 @@ const DefaultTplStr = `
      +
      -
      {{end}} @@ -100,7 +108,7 @@ const DefaultTplStr = ` {{.DisplaySize}} {{.DisplayTime}} - {{if and (not $isDownload) .DeleteUrl}}
      {{end}} + {{if and (not $isDownload) .DeleteUrl}}
      {{end}} {{end}} diff --git a/src/tpl/frontend/index.js.go b/src/tpl/frontend/index.js.go index 3306e932..d9bb91a8 100644 --- a/src/tpl/frontend/index.js.go +++ b/src/tpl/frontend/index.js.go @@ -13,6 +13,42 @@ const DefaultJs = ` var Esc = 'Esc'; var Space = ' '; + 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; + } + } + } + function enableFilter() { if (!document.querySelector) { var filter = document.getElementById && document.getElementById('panel-filter'); @@ -27,7 +63,7 @@ const DefaultJs = ` if (!filter) { return; } - if (!filter.classList || !filter.addEventListener) { + if (!filter.addEventListener) { filter.className += ' none'; return; } @@ -62,7 +98,7 @@ const DefaultJs = ` selector = selectorItemNone; items = document.body.querySelectorAll(selector); for (i = items.length - 1; i >= 0; i--) { - items[i].classList.remove(classNone); + removeClass(items[i], classNone); } } else { if (clear) { @@ -81,9 +117,9 @@ const DefaultJs = ` var item = items[i]; var name = item.querySelector('.name'); if (name && name.textContent.toLowerCase().indexOf(filterText) < 0) { - item.classList.add(classNone); + addClass(item, classNone); } else { - item.classList.remove(classNone); + removeClass(item, classNone); } } } @@ -97,21 +133,45 @@ const DefaultJs = ` }; 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) { - switch (e.key) { - case Enter: - clearTimeout(timeoutId); - input.blur(); - doFilter(); - e.preventDefault(); - break; - case Escape: - case Esc: - clearTimeout(timeoutId); - input.value = ''; - doFilter(); - e.preventDefault(); - break; + 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); @@ -146,7 +206,6 @@ const DefaultJs = ` if ( !document.querySelector || !document.addEventListener || - !document.body.classList || !document.body.parentElement ) { return; @@ -194,8 +253,8 @@ const DefaultJs = ` } } } while (siblingLI !== startLI && ( - siblingLI.classList.contains(classNone) || - siblingLI.classList.contains(classHeader) + hasClass(siblingLI, classNone) || + hasClass(siblingLI, classHeader) )); if (siblingLI) { @@ -419,7 +478,7 @@ const DefaultJs = ` } function enhanceUpload() { - if (!document.querySelector || !document.addEventListener || !document.body.classList) { + if (!document.querySelector || !document.addEventListener) { return; } @@ -450,14 +509,6 @@ const DefaultJs = ` var optInnerDirFile = uploadType.querySelector('.' + innerDirFile); var optActive = optFile; - function addClass(ele, className) { - ele && ele.classList.add(className); - } - - function removeClass(ele, className) { - ele && ele.classList.remove(className); - } - var padStart = String.prototype.padStart ? function (sourceString, targetLength, padTemplate) { return sourceString.padStart(targetLength, padTemplate); } : function (sourceString, targetLength, padTemplate) { @@ -743,7 +794,9 @@ const DefaultJs = ` var uploading = false; var batches = []; - var elProgress = upload.querySelector('.progress'); + var classUploading = 'uploading'; + var elUploadStatus = document.body.querySelector('.upload-status'); + var elProgress = elUploadStatus && elUploadStatus.querySelector('.progress'); function onComplete() { if (elProgress) { @@ -753,6 +806,9 @@ const DefaultJs = ` uploadBatch(batches.shift()); } else { uploading = false; + if (elUploadStatus) { + removeClass(elUploadStatus, classUploading); + } } } @@ -776,6 +832,9 @@ const DefaultJs = ` batches.push(files); } else { uploading = true; + if (elUploadStatus) { + addClass(elUploadStatus, classUploading); + } uploadBatch(files); } } @@ -843,7 +902,7 @@ const DefaultJs = ` } function onDragEnterOver(e) { - if(!isSelfDragging) { + if (!isSelfDragging) { e.stopPropagation(); e.preventDefault(); addClass(e.currentTarget, classDragging); @@ -1053,13 +1112,7 @@ const DefaultJs = ` if (!itemList || !itemList.addEventListener) { return; } - if (itemList.classList) { - if (!itemList.classList.contains('has-deletable')) { - return; - } - } else if (itemList.className.indexOf('has-deletable') < 0) { - return; - } + if (!hasClass(itemList, 'has-deletable')) return; itemList.addEventListener('submit', function (e) { if (e.defaultPrevented) { From da13216f7afd05bfd19dd21ed641b72e4a904ac1 Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 4 Dec 2021 17:59:01 +0800 Subject: [PATCH 16/57] feat: patch goVirtualHost v1.3.0-go1.9to1.13 --- src/goVirtualHost/server.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/goVirtualHost/server.go b/src/goVirtualHost/server.go index 0ac4a6a1..8d8b5166 100644 --- a/src/goVirtualHost/server.go +++ b/src/goVirtualHost/server.go @@ -60,6 +60,7 @@ func (server *server) updateHttpServerTLSConfig() { tlsConfig = &tls.Config{ Certificates: certs, } + tlsConfig.BuildNameToCertificate() } server.httpServer.TLSConfig = tlsConfig From 6e80c3354fda75d8226a7c973465081d343f4884 Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 11 Dec 2021 13:40:16 +0800 Subject: [PATCH 17/57] src/chore: re-embed frontend assets --- src/tpl/frontend/index.css.go | 16 +++++++++++++--- src/tpl/frontend/index.html.go | 3 ++- src/tpl/frontend/index.js.go | 26 +++++++++++++++++++------- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/tpl/frontend/index.css.go b/src/tpl/frontend/index.css.go index 021c3ab7..1c652b88 100644 --- a/src/tpl/frontend/index.css.go +++ b/src/tpl/frontend/index.css.go @@ -213,7 +213,8 @@ html.dragging::before { pointer-events: none; } -.upload-status.uploading { +.upload-status.uploading, +.upload-status.failed { visibility: visible; } @@ -226,12 +227,21 @@ html.dragging::before { transition: transform .2s, opacity .2s; padding: 0.5em 1em; color: #fff; + white-space: nowrap; +} + +.upload-status .label.tips { background: #c9c; background-color: rgba(204, 153, 204, 0.8); - white-space: nowrap; } -.upload-status.uploading .label { +.upload-status .label.failed { + background: #800000; + background-color: rgba(128, 0, 0, 0.8); +} + +.upload-status.uploading .label.tips, +.upload-status.failed .label.failed { opacity: 1; transform: translate(-50%, 10%); } diff --git a/src/tpl/frontend/index.html.go b/src/tpl/frontend/index.html.go index 6d39b1db..cabbdf51 100644 --- a/src/tpl/frontend/index.html.go +++ b/src/tpl/frontend/index.html.go @@ -26,7 +26,8 @@ const DefaultTplStr = ` {{if .CanUpload}}
      - {{.Trans.UploadingLabel}} + {{.Trans.UploadingLabel}} + {{.Trans.UploadFailLabel}}
      {{end}} diff --git a/src/tpl/frontend/index.js.go b/src/tpl/frontend/index.js.go index d9bb91a8..d8314a5e 100644 --- a/src/tpl/frontend/index.js.go +++ b/src/tpl/frontend/index.js.go @@ -795,20 +795,31 @@ const DefaultJs = ` 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('.failed .message'); function onComplete() { if (elProgress) { elProgress.style.width = ''; } + } + + function onSuccess() { if (batches.length) { - uploadBatch(batches.shift()); + return uploadBatch(batches.shift()); // use "return" for tail call optimize } else { uploading = false; - if (elUploadStatus) { - removeClass(elUploadStatus, classUploading); - } + removeClass(elUploadStatus, classUploading); + } + } + + function onFail(e) { + removeClass(elUploadStatus, classUploading); + addClass(elUploadStatus, classFailed); + if (elFailedMessage) { + elFailedMessage.textContent = " - " + e.type; } } @@ -832,9 +843,7 @@ const DefaultJs = ` batches.push(files); } else { uploading = true; - if (elUploadStatus) { - addClass(elUploadStatus, classUploading); - } + addClass(elUploadStatus, classUploading); uploadBatch(files); } } @@ -860,8 +869,11 @@ const DefaultJs = ` var xhr = new XMLHttpRequest(); xhr.upload.addEventListener('error', onComplete); + xhr.upload.addEventListener('error', onFail); xhr.upload.addEventListener('abort', onComplete); + xhr.upload.addEventListener('abort', onFail); xhr.upload.addEventListener('load', onComplete); + xhr.upload.addEventListener('load', onSuccess); xhr.upload.addEventListener('load', onLoad); if (elProgress) { xhr.upload.addEventListener('progress', onProgress); From 037918ab1fc6cc523e58fee72003d284f66fb624 Mon Sep 17 00:00:00 2001 From: marjune Date: Mon, 4 Apr 2022 20:07:51 +0800 Subject: [PATCH 18/57] feat(tpl): add script for generating favicon bytes --- src/Makefile | 14 +- src/tpl/frontend/favicon.ico.go | 338 +++++++++++++++++++++++++++++++- src/tpl/frontend/index.css.go | 2 +- src/tpl/frontend/index.html.go | 1 + src/tpl/frontend/index.js.go | 10 +- 5 files changed, 357 insertions(+), 8 deletions(-) diff --git a/src/Makefile b/src/Makefile index 62c75f60..14aeff88 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,10 +1,16 @@ -define embed +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 embed, tpl/frontend/index.html) - $(call embed, tpl/frontend/index.css) - $(call embed, tpl/frontend/index.js) + $(call embedStr, tpl/frontend/index.html) + $(call embedStr, tpl/frontend/index.css) + $(call embedStr, tpl/frontend/index.js) + $(call embedHex, tpl/frontend/favicon.ico) diff --git a/src/tpl/frontend/favicon.ico.go b/src/tpl/frontend/favicon.ico.go index 9051a4da..47f62b07 100644 --- a/src/tpl/frontend/favicon.ico.go +++ b/src/tpl/frontend/favicon.ico.go @@ -1,5 +1,341 @@ package frontend var DefaultFavicon = []byte{ - 0x00, + 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/frontend/index.css.go b/src/tpl/frontend/index.css.go index 1c652b88..6ab833b0 100644 --- a/src/tpl/frontend/index.css.go +++ b/src/tpl/frontend/index.css.go @@ -472,7 +472,7 @@ html.dragging::before { background: #ffc; } -@media (prefers-color-scheme: dark) { +@media only screen and (prefers-color-scheme: dark) { html, body { background: #111; } diff --git a/src/tpl/frontend/index.html.go b/src/tpl/frontend/index.html.go index cabbdf51..a08d2d58 100644 --- a/src/tpl/frontend/index.html.go +++ b/src/tpl/frontend/index.html.go @@ -11,6 +11,7 @@ const DefaultTplStr = ` {{.Path}} + diff --git a/src/tpl/frontend/index.js.go b/src/tpl/frontend/index.js.go index d8314a5e..8adfa245 100644 --- a/src/tpl/frontend/index.js.go +++ b/src/tpl/frontend/index.js.go @@ -49,6 +49,12 @@ const DefaultJs = ` } } + var hasStorage = false; + try { + if (typeof sessionStorage !== strUndef) hasStorage = true; + } catch (err) { + } + function enableFilter() { if (!document.querySelector) { var filter = document.getElementById && document.getElementById('panel-filter'); @@ -183,7 +189,7 @@ const DefaultJs = ` }); // init - if (sessionStorage) { + if (hasStorage) { var prevSessionFilter = sessionStorage.getItem(location.pathname); sessionStorage.removeItem(location.pathname); @@ -748,7 +754,7 @@ const DefaultJs = ` optInnerDirFile.addEventListener('keydown', onKeydownOpt); } - if (sessionStorage) { + if (hasStorage) { var uploadTypeField = 'upload-type'; var prevUploadType = sessionStorage.getItem(uploadTypeField); sessionStorage.removeItem(uploadTypeField); From afe1a4a13d3e72d55307c2f6714f79dae1babcd3 Mon Sep 17 00:00:00 2001 From: marjune Date: Thu, 14 Apr 2022 10:17:37 +0800 Subject: [PATCH 19/57] chore: re-embed frontend assets --- src/tpl/frontend/index.css.go | 60 ++++++++++++++++++++++++++++------ src/tpl/frontend/index.html.go | 10 ++++-- src/tpl/frontend/index.js.go | 25 +++++++++----- 3 files changed, 73 insertions(+), 22 deletions(-) diff --git a/src/tpl/frontend/index.css.go b/src/tpl/frontend/index.css.go index 6ab833b0..84ce3e25 100644 --- a/src/tpl/frontend/index.css.go +++ b/src/tpl/frontend/index.css.go @@ -213,6 +213,7 @@ html.dragging::before { pointer-events: none; } +.upload-status > *, .upload-status.uploading, .upload-status.failed { visibility: visible; @@ -220,30 +221,69 @@ html.dragging::before { .upload-status .label { position: absolute; - left: 50%; - top: 100%; + left: 0; + top: 0; + width: 100%; + color: #fff; + text-align: center; opacity: 0; - transform: translate(-50%, -50%); 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; - color: #fff; - white-space: nowrap; + box-sizing: border-box; + overflow-wrap: break-word; + word-break: break-word; } -.upload-status .label.tips { +.upload-status .info .content { + padding-left: 2.5em; background: #c9c; background-color: rgba(204, 153, 204, 0.8); } -.upload-status .label.failed { +@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 .label.tips, -.upload-status.failed .label.failed { +.upload-status.uploading .info, +.upload-status.failed .warn { opacity: 1; - transform: translate(-50%, 10%); + transform: translateY(25%); } .upload-status .progress { diff --git a/src/tpl/frontend/index.html.go b/src/tpl/frontend/index.html.go index a08d2d58..91a93dc7 100644 --- a/src/tpl/frontend/index.html.go +++ b/src/tpl/frontend/index.html.go @@ -11,7 +11,7 @@ const DefaultTplStr = ` {{.Path}} - + @@ -27,8 +27,12 @@ const DefaultTplStr = ` {{if .CanUpload}}
      - {{.Trans.UploadingLabel}} - {{.Trans.UploadFailLabel}} + + {{.Trans.UploadingLabel}} + + + {{.Trans.UploadFailLabel}} +
      {{end}} diff --git a/src/tpl/frontend/index.js.go b/src/tpl/frontend/index.js.go index 8adfa245..147c80eb 100644 --- a/src/tpl/frontend/index.js.go +++ b/src/tpl/frontend/index.js.go @@ -804,7 +804,7 @@ const DefaultJs = ` var classFailed = 'failed'; var elUploadStatus = document.body.querySelector('.upload-status'); var elProgress = elUploadStatus && elUploadStatus.querySelector('.progress'); - var elFailedMessage = elUploadStatus && elUploadStatus.querySelector('.failed .message'); + var elFailedMessage = elUploadStatus && elUploadStatus.querySelector('.warn .message'); function onComplete() { if (elProgress) { @@ -827,10 +827,16 @@ const DefaultJs = ` if (elFailedMessage) { elFailedMessage.textContent = " - " + e.type; } + batches.length = 0; } function onLoad() { - !uploading && location.reload(); + var status = this.status; + if (status >= 200 && status <= 299) { + !uploading && location.reload(); + } else { + onFail({type: this.statusText || this.status}); + } } function onProgress(e) { @@ -849,6 +855,7 @@ const DefaultJs = ` batches.push(files); } else { uploading = true; + removeClass(elUploadStatus, classFailed); addClass(elUploadStatus, classUploading); uploadBatch(files); } @@ -874,13 +881,13 @@ const DefaultJs = ` }); var xhr = new XMLHttpRequest(); - xhr.upload.addEventListener('error', onComplete); - xhr.upload.addEventListener('error', onFail); - xhr.upload.addEventListener('abort', onComplete); - xhr.upload.addEventListener('abort', onFail); - xhr.upload.addEventListener('load', onComplete); - xhr.upload.addEventListener('load', onSuccess); - xhr.upload.addEventListener('load', onLoad); + 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); } From d9295705def761615646731e78bedb74c8427cfd Mon Sep 17 00:00:00 2001 From: marjune Date: Fri, 13 May 2022 18:57:04 +0800 Subject: [PATCH 20/57] src/chore: re-embed frontend assets --- src/tpl/frontend/index.css.go | 5 +- src/tpl/frontend/index.html.go | 9 +- src/tpl/frontend/index.js.go | 355 +++++++++++++++++++-------------- 3 files changed, 218 insertions(+), 151 deletions(-) diff --git a/src/tpl/frontend/index.css.go b/src/tpl/frontend/index.css.go index 84ce3e25..86fec399 100644 --- a/src/tpl/frontend/index.css.go +++ b/src/tpl/frontend/index.css.go @@ -120,6 +120,7 @@ html.dragging::before { .path-list { font-size: 1.5em; + line-height: 1.2; overflow: hidden; border-bottom: 1px #999 solid; zoom: 1; @@ -213,7 +214,6 @@ html.dragging::before { pointer-events: none; } -.upload-status > *, .upload-status.uploading, .upload-status.failed { visibility: visible; @@ -283,6 +283,7 @@ html.dragging::before { .upload-status.uploading .info, .upload-status.failed .warn { opacity: 1; + -webkit-transform: translateY(25%); transform: translateY(25%); } @@ -361,6 +362,7 @@ html.dragging::before { .mkdir form { display: flex; + align-items: center; } .mkdir .name { @@ -405,6 +407,7 @@ html.dragging::before { .item-list { margin: 1em; + line-height: 1.2; } .item-list li { diff --git a/src/tpl/frontend/index.html.go b/src/tpl/frontend/index.html.go index 91a93dc7..639c1b18 100644 --- a/src/tpl/frontend/index.html.go +++ b/src/tpl/frontend/index.html.go @@ -48,10 +48,15 @@ const DefaultTplStr = ` {{end}} {{if .CanUpload}} +
      - {{if .CanMkdir}}{{end}} - + {{if .CanMkdir}} + {{end}}
      diff --git a/src/tpl/frontend/index.js.go b/src/tpl/frontend/index.js.go index 147c80eb..05ad093a 100644 --- a/src/tpl/frontend/index.js.go +++ b/src/tpl/frontend/index.js.go @@ -3,6 +3,7 @@ package frontend const DefaultJs = ` (function () { var strUndef = 'undefined'; + var protoHttps = 'https:'; var classNone = 'none'; var classHeader = 'header'; @@ -13,6 +14,9 @@ const DefaultJs = ` var Esc = 'Esc'; var Space = ' '; + var noop = function () { + }; + var hasClass, addClass, removeClass; if (document.body.classList) { hasClass = function (el, className) { @@ -514,6 +518,7 @@ const DefaultJs = ` 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); @@ -547,135 +552,168 @@ const DefaultJs = ` var ms = String(now.getMilliseconds()); date = padStart(date, 8, '0'); time = padStart(time, 6, '0'); - var ms = padStart(ms, 3, '0'); + ms = padStart(ms, 3, '0'); var ts = '-' + date + '-' + time + '-' + ms; return ts; } - function entriesToFiles(entries, onDone) { - var files = []; - var len = entries.length; - var cb = 0; - if (!len) { - onDone(files); - } - - function increaseCb() { - cb++; - if (cb === len) { - onDone(files); + 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) + typeof console !== strUndef && console.error(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(); + }); + } + })); } - } - entries.forEach(function (entry) { - if (entry.isFile) { - var relativePath = entry.fullPath; - if (relativePath[0] === '/') { - relativePath = relativePath.substring(1); + 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(); } - entry.file(function (file) { - files.push({file: file, relativePath: relativePath}); - increaseCb(); - }, function (err) { - increaseCb(); - typeof console !== strUndef && console.error(err); + var handleResults = handles.map(function (handle) { + return {value: handle, done: false}; }); - } else if (entry.isDirectory) { - var reader = entry.createReader(); - reader.readEntries(function (subEntries) { - if (subEntries.length) { - entriesToFiles(subEntries, function (subFiles) { - Array.prototype.push.apply(files, subFiles); + 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(); + } + } + + 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(); + typeof console !== strUndef && console.error(err); + }); + } else if (entry.isDirectory) { + var reader = entry.createReader(); + reader.readEntries(function (subEntries) { + if (subEntries.length) { + entriesToFiles(subEntries, files, increaseCb); + } else { + increaseCb(); + } }); - } else { - increaseCb(); } }); } - }); - } - - function itemsToFiles(dataTransferItems, onDone) { - var files = []; - var len = dataTransferItems.length; - if (!len) { - onDone(files); - } - - var entries = []; - for (var i = 0; i < len; i++) { - var item = dataTransferItems[i]; - var entry = item.webkitGetAsEntry(); - if (!entry) { - 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) { - entries.push(entry); - } - } - entriesToFiles(entries, function (entryFiles) { - files.push.apply(files, entryFiles); - onDone(files); - }); - } + var files = []; + var hasDir = false; + if (!dataTransferItems || !dataTransferItems.length || !dataTransferItems[0].webkitGetAsEntry) return onDone(files, hasDir); - function itemsHasDir(dataTransferItems) { - if (!dataTransferItems) { - return false; - } - var hasDir = false; - var items = Array.prototype.slice.call(dataTransferItems); - if (items.length && items[0].webkitGetAsEntry) { - for (var i = 0, len = items.length; i < len; i++) { - var entry = items[i].webkitGetAsEntry(); - if (entry && entry.isDirectory) { + 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; - break; + if (canMkdir) { + entries.push(entry); + } else { + return onLacksMkdir(); + } } } - } - return hasDir; - } - function switchToFileMode() { - if (optFile && optActive !== optFile) { - optFile.focus(); - optFile.click(); + entriesToFiles(entries, files, function () { + onDone(files, hasDir); + }); } } - function switchToDirMode() { - if (optDirFile) { - if (optActive !== optDirFile) { - optDirFile.focus(); - optDirFile.click(); - } - } else if (optInnerDirFile) { - if (optActive !== optInnerDirFile) { - optInnerDirFile.focus(); - optInnerDirFile.click(); + 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); } - function switchToAnyDirMode() { - if (optActive === optFile) { - if (optDirFile) { - optDirFile.focus(); - optDirFile.click(); - } else if (optInnerDirFile) { - optInnerDirFile.focus(); - optInnerDirFile.click(); - } - } - } + var switchToFileMode = noop; + var switchToDirMode = noop; function enableAddDirFile() { var classHidden = 'hidden'; @@ -785,16 +823,37 @@ const DefaultJs = ` } var nodir = Array.prototype.slice.call(files).every(function (file) { - return !file.webkitRelativePath; + 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 (!FormData) { + if (typeof FormData === strUndef) { return; } @@ -950,28 +1009,22 @@ const DefaultJs = ` return; } - var items = e.dataTransfer.items; - if (itemsHasDir(items)) { - if (!uploadProgressively) { - // must use progressive upload by JS if has directory - return; - } - var itemsCount = items.length; // save items count earlier, items will be lost after calling FileSystemFileEntry.file() - itemsToFiles(items, function (files) { - itemsCount > 1 ? switchToDirMode() : switchToAnyDirMode(); - uploadProgressively(files); - }); - } else { - switchToFileMode(); - - if (uploadProgressively) { - var files = Array.prototype.slice.call(e.dataTransfer.files); + dataTransferToFiles(e.dataTransfer, canMkdir && Boolean(uploadProgressively), function (files, hasDir) { + if (hasDir) { + switchToDirMode(); uploadProgressively(files); } else { - fileInput.files = e.dataTransfer.files; - form.submit(); + switchToFileMode(); + if (uploadProgressively) { + uploadProgressively(files); + } else { + fileInput.files = files; + form.submit(); + } } - } + }, function () { + typeof showUploadDirFailMessage !== strUndef && showUploadDirFailMessage(); + }); } document.body.addEventListener('dragstart', onSelfDragStart); @@ -983,19 +1036,7 @@ const DefaultJs = ` dragDropEl.addEventListener('drop', onDrop); } - function enableAddPaste(uploadProgressively) { - if (!uploadProgressively) { - document.documentElement.addEventListener('paste', function (e) { - var data = e.clipboardData; - if (data && data.files && data.files.length) { - switchToFileMode(); - fileInput.files = data.files; - form.submit(); - } - }); - return; - } - + function enableAddPasteProgressively(uploadProgressively) { var typeTextPlain = 'text/plain'; var createTextFile; var textFilename = 'text.txt'; @@ -1090,42 +1131,60 @@ const DefaultJs = ` } var items = data.items; - var itemsCount = items.length; // save items count earlier, items will be lost after calling FileSystemFileEntry.file() - if (!items || !itemsCount) { + if (!items || !items.length) { generatePastedFiles(data); return; } - var hasDir = itemsHasDir(items); - itemsToFiles(items, function (files) { + + itemsToFiles(items, canMkdir, function (files, hasDir) { + // for pasted text if (!files.length) { - // for pasted text generatePastedFiles(data); return; } + + // suppose for pasted image data if (files.length === 1 && files[0].file.type === 'image/png') { - // suppose for pasted image files = files.map(function (fileInfo) { return fileInfo && fileInfo.file; }); generatePastedFiles({files: files}); return; } - // pasted real files, not image binary + + // pasted real files if (hasDir) { - itemsCount > 1 ? switchToDirMode() : switchToAnyDirMode(); + 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(); - enableFormUploadProgress(uploadProgressively); + if (uploadProgressively) { + enableFormUploadProgress(uploadProgressively); + enableAddPasteProgressively(uploadProgressively); + } else { + enableAddPasteFormSubmit(); + } enableAddDragDrop(uploadProgressively); - enableAddPaste(uploadProgressively); } function enableNonRefreshDelete() { From 136ffcac8b72b8a1cdd00312cb44564e2a856088 Mon Sep 17 00:00:00 2001 From: marjune Date: Fri, 17 Jun 2022 23:15:19 +0800 Subject: [PATCH 21/57] fix(util/str): skip using unsupported API `utf8.AppendRune` is not supported until Go 1.18. Use workaround solution instead. --- src/util/str.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/util/str.go b/src/util/str.go index 17876713..3de393fc 100644 --- a/src/util/str.go +++ b/src/util/str.go @@ -53,7 +53,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]...) } } From 4998e147568aea8e570d3ce828138553704d9a50 Mon Sep 17 00:00:00 2001 From: marjune Date: Fri, 17 Jun 2022 23:18:11 +0800 Subject: [PATCH 22/57] chore: re-embed frontend assets --- src/tpl/frontend/index.html.go | 7 +++++- src/tpl/frontend/index.js.go | 43 +++++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/tpl/frontend/index.html.go b/src/tpl/frontend/index.html.go index 639c1b18..2bde21be 100644 --- a/src/tpl/frontend/index.html.go +++ b/src/tpl/frontend/index.html.go @@ -88,7 +88,12 @@ const DefaultTplStr = ` {{end}} diff --git a/src/tpl/frontend/index.js.go b/src/tpl/frontend/index.js.go index 05ad093a..d0ced764 100644 --- a/src/tpl/frontend/index.js.go +++ b/src/tpl/frontend/index.js.go @@ -17,6 +17,15 @@ const DefaultJs = ` 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) { @@ -575,7 +584,7 @@ const DefaultJs = ` var relativePath = dirPath + file.name; files.push({file: file, relativePath: relativePath}); })['catch'](function (err) { // workaround IE8- syntax error for ".catch"(reserved keyword) - typeof console !== strUndef && console.error(err); + logError(err); }); } else if (handle.kind === handleKindDir) { return new Promise(function (resolve) { @@ -655,7 +664,7 @@ const DefaultJs = ` increaseCb(); }, function (err) { increaseCb(); - typeof console !== strUndef && console.error(err); + logError(err); }); } else if (entry.isDirectory) { var reader = entry.createReader(); @@ -894,7 +903,7 @@ const DefaultJs = ` if (status >= 200 && status <= 299) { !uploading && location.reload(); } else { - onFail({type: this.statusText || this.status}); + onFail({type: this.statusText || status}); } } @@ -1203,21 +1212,27 @@ const DefaultJs = ` return; } + var form = e.target; + function onLoad() { - var elItem = e.target; - while (elItem && elItem.nodeName !== 'LI') { - elItem = elItem.parentNode; - } - if (!elItem) { - return; + var status = this.status; + if (status >= 200 && status <= 299) { + var elItem = form; + while (elItem && elItem.nodeName !== 'LI') { + elItem = elItem.parentNode; + } + if (!elItem) { + return; + } + var elItemParent = elItem.parentNode; + elItemParent && elItemParent.removeChild(elItem); + } else { + logError('delete failed: ' + status + ' ' + this.statusText); } - var elItemParent = elItem.parentNode; - elItemParent && elItemParent.removeChild(elItem); } var params = ''; - var els = []; - Array.prototype.push.apply(els, e.target.elements) + var els = Array.prototype.slice.call(form.elements); for (var i = 0, len = els.length; i < len; i++) { if (!els[i].name) { continue @@ -1227,7 +1242,7 @@ const DefaultJs = ` } params += els[i].name + '=' + encodeURIComponent(els[i].value) } - var url = e.target.action + '?' + params + var url = form.action + '?' + params; var xhr = new XMLHttpRequest(); xhr.open('POST', url); // will retrieve deleted result into bfcache From b95aea494c0ade1e73d9fc50571c367225cf7d42 Mon Sep 17 00:00:00 2001 From: marjune Date: Fri, 24 Jun 2022 18:20:46 +0800 Subject: [PATCH 23/57] feat(shimgo): add shim for net/url.PathUnescape --- src/shimgo/net_url.go | 127 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/src/shimgo/net_url.go b/src/shimgo/net_url.go index f2a794ab..4cc52833 100644 --- a/src/shimgo/net_url.go +++ b/src/shimgo/net_url.go @@ -1,5 +1,22 @@ package shimgo +import ( + "strconv" + "strings" +) + +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 ( @@ -13,6 +30,30 @@ const ( ) 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) } @@ -154,3 +195,89 @@ func net_url_shouldEscape(c byte, mode net_url_encoding) bool { // 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 strings.Builder + 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 +} From 795047252f32d9d39429a32dad981d0a7d253f80 Mon Sep 17 00:00:00 2001 From: marjune Date: Thu, 7 Jul 2022 22:45:28 +0800 Subject: [PATCH 24/57] chore: re-embed frontend assets --- src/tpl/frontend/index.js.go | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/tpl/frontend/index.js.go b/src/tpl/frontend/index.js.go index d0ced764..f4f858c3 100644 --- a/src/tpl/frontend/index.js.go +++ b/src/tpl/frontend/index.js.go @@ -653,6 +653,15 @@ const DefaultJs = ` } } + 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; @@ -667,14 +676,8 @@ const DefaultJs = ` logError(err); }); } else if (entry.isDirectory) { - var reader = entry.createReader(); - reader.readEntries(function (subEntries) { - if (subEntries.length) { - entriesToFiles(subEntries, files, increaseCb); - } else { - increaseCb(); - } - }); + var dirReader = entry.createReader(); + dirReaderToFiles(dirReader, files, increaseCb); } }); } From 47b02798d0a23a237acef70a4006119e84ebcbc6 Mon Sep 17 00:00:00 2001 From: marjune Date: Thu, 7 Jul 2022 22:55:07 +0800 Subject: [PATCH 25/57] fix: make compatible with Go 1.2 - use shim methods instead of url.PathEscape - use shim methods instead of url.PathUnescape - use `Request.RequestURI` instead of `Request.URL.RawPath` to store original path - use `bytes.Buffer` instead of `strings.Builder` --- src/serverHandler/content.go | 4 ++-- src/serverHandler/log.go | 4 ++-- src/serverHandler/pathTransformer.go | 2 +- src/serverHandler/responseData.go | 2 +- src/shimgo/net_url.go | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/serverHandler/content.go b/src/serverHandler/content.go index 54afc24c..9b1f86ee 100644 --- a/src/serverHandler/content.go +++ b/src/serverHandler/content.go @@ -1,9 +1,9 @@ package serverHandler import ( + "../shimgo" "../util" "net/http" - "net/url" "os" "strconv" "time" @@ -17,7 +17,7 @@ func (h *handler) content(w http.ResponseWriter, r *http.Request, data *response header := w.Header() header.Set("X-Content-Type-Options", "nosniff") if data.IsDownload { - header.Set("Content-Disposition", "attachment; filename*=UTF-8''"+url.PathEscape(data.ItemName)) + header.Set("Content-Disposition", "attachment; filename*=UTF-8''"+shimgo.Net_Url_PathEscape(data.ItemName)) } item := data.Item diff --git a/src/serverHandler/log.go b/src/serverHandler/log.go index 43bbee71..d201fe59 100644 --- a/src/serverHandler/log.go +++ b/src/serverHandler/log.go @@ -1,9 +1,9 @@ package serverHandler import ( + "../shimgo" "../util" "net/http" - "net/url" ) func (h *handler) logRequest(r *http.Request) { @@ -13,7 +13,7 @@ func (h *handler) logRequest(r *http.Request) { 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/pathTransformer.go b/src/serverHandler/pathTransformer.go index 8770ad81..0b7f9e61 100644 --- a/src/serverHandler/pathTransformer.go +++ b/src/serverHandler/pathTransformer.go @@ -29,7 +29,7 @@ func (transformer pathTransformer) ServeHTTP(w http.ResponseWriter, r *http.Requ } else { urlPathDir = urlPath } - r.URL.RawPath = urlPathDir + r.RequestURI = urlPathDir if len(transformer.prefixesAccurate) == 0 && len(transformer.prefixesNoCase) == 0 { r.URL.Path = urlPathDir diff --git a/src/serverHandler/responseData.go b/src/serverHandler/responseData.go index 50f9bd44..c07e225c 100644 --- a/src/serverHandler/responseData.go +++ b/src/serverHandler/responseData.go @@ -332,7 +332,7 @@ func (h *handler) getResponseData(r *http.Request) *responseData { status := http.StatusOK isRoot := rawReqPath == "/" - currDirRelPath := getCurrDirRelPath(rawReqPath, r.URL.RawPath) + currDirRelPath := getCurrDirRelPath(rawReqPath, r.RequestURI) pathEntries := getPathEntries(currDirRelPath, rawReqPath, tailSlash) var rootRelPath string if len(pathEntries) > 0 { diff --git a/src/shimgo/net_url.go b/src/shimgo/net_url.go index 4cc52833..87eb5b2a 100644 --- a/src/shimgo/net_url.go +++ b/src/shimgo/net_url.go @@ -1,8 +1,8 @@ package shimgo import ( + "bytes" "strconv" - "strings" ) type Net_Url_EscapeError string @@ -262,7 +262,7 @@ func unescape(s string, mode net_url_encoding) (string, error) { return s, nil } - var t strings.Builder + var t bytes.Buffer t.Grow(len(s) - 2*n) for i := 0; i < len(s); i++ { switch s[i] { From 39f7e71019143bca0156d99a90c644dd0cb0bb70 Mon Sep 17 00:00:00 2001 From: marjune Date: Tue, 19 Jul 2022 22:49:46 +0800 Subject: [PATCH 26/57] fix: keep query string with RequestURI `*http.Request.RequestURI` is used to store normalized prefixed URL path in Go 1.2 branch. It should also carry with the original query string for further use. --- src/serverHandler/pathTransformer.go | 3 +++ src/serverHandler/responseData.go | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/serverHandler/pathTransformer.go b/src/serverHandler/pathTransformer.go index 0b7f9e61..9e6b47af 100644 --- a/src/serverHandler/pathTransformer.go +++ b/src/serverHandler/pathTransformer.go @@ -30,6 +30,9 @@ func (transformer pathTransformer) ServeHTTP(w http.ResponseWriter, r *http.Requ urlPathDir = urlPath } r.RequestURI = urlPathDir + if len(r.URL.RawQuery) > 0 { + r.RequestURI += "?" + r.URL.RawQuery + } if len(transformer.prefixesAccurate) == 0 && len(transformer.prefixesNoCase) == 0 { r.URL.Path = urlPathDir diff --git a/src/serverHandler/responseData.go b/src/serverHandler/responseData.go index c07e225c..e07e38c7 100644 --- a/src/serverHandler/responseData.go +++ b/src/serverHandler/responseData.go @@ -291,6 +291,11 @@ func dereferenceSymbolLinks(reqFsPath string, subItems []os.FileInfo) (errs []er func (h *handler) getResponseData(r *http.Request) *responseData { var errs []error + prefixReqPath := r.RequestURI + if qsIndex := strings.IndexByte(prefixReqPath, '?'); qsIndex >= 0 { + prefixReqPath = prefixReqPath[:qsIndex] + } + rawReqPath := r.URL.Path tailSlash := rawReqPath[len(rawReqPath)-1] == '/' @@ -332,7 +337,7 @@ func (h *handler) getResponseData(r *http.Request) *responseData { status := http.StatusOK isRoot := rawReqPath == "/" - currDirRelPath := getCurrDirRelPath(rawReqPath, r.RequestURI) + currDirRelPath := getCurrDirRelPath(rawReqPath, prefixReqPath) pathEntries := getPathEntries(currDirRelPath, rawReqPath, tailSlash) var rootRelPath string if len(pathEntries) > 0 { From f9d7e6ff3cad2a03b3f001c429877504df469433 Mon Sep 17 00:00:00 2001 From: marjune Date: Fri, 22 Jul 2022 22:25:18 +0800 Subject: [PATCH 27/57] chore: re-embed frontend assets --- src/tpl/frontend/index.js.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/tpl/frontend/index.js.go b/src/tpl/frontend/index.js.go index f4f858c3..bd0ae338 100644 --- a/src/tpl/frontend/index.js.go +++ b/src/tpl/frontend/index.js.go @@ -91,6 +91,16 @@ const DefaultJs = ` 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'); var selectorNone = '.' + classNone; @@ -103,7 +113,7 @@ const DefaultJs = ` var timeoutId; var lastFilterText = ''; var doFilter = function () { - var filterText = input.value.trim().toLowerCase(); + var filterText = trim(input.value).toLowerCase(); if (filterText === lastFilterText) { return; } From d565744fafb07f0119f1c523b6e6f2279c623b9c Mon Sep 17 00:00:00 2001 From: marjune Date: Wed, 10 Aug 2022 22:18:37 +0800 Subject: [PATCH 28/57] feat: add shim for time.AppendFormat() --- src/shimgo/time.go | 8 ++++++++ src/util/formatTime.go | 7 +++++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 src/shimgo/time.go 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/util/formatTime.go b/src/util/formatTime.go index 25f69723..256a630c 100644 --- a/src/util/formatTime.go +++ b/src/util/formatTime.go @@ -1,6 +1,9 @@ package util -import "time" +import ( + "../shimgo" + "time" +) const timeLayout = "2006-01-02 15:04:05" @@ -9,5 +12,5 @@ func FormatTimeSecond(t time.Time) string { } func AppendTimeSecond(buf []byte, t time.Time) []byte { - return t.AppendFormat(buf, timeLayout) + return shimgo.Time_AppendFormat(t, buf, timeLayout) } From ac67fb0c1c23b0383ab18da66f32b7d68e0e7366 Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 20 Aug 2022 18:59:04 +0800 Subject: [PATCH 29/57] fix(tpl): update import path --- src/tpl/defaultTheme.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tpl/defaultTheme.go b/src/tpl/defaultTheme.go index a9ea98a1..5fae5fcc 100644 --- a/src/tpl/defaultTheme.go +++ b/src/tpl/defaultTheme.go @@ -1,8 +1,8 @@ package tpl import ( - "./frontend" "bytes" + "mjpclab.dev/ghfs/src/tpl/frontend" "strings" ) From 18fa03d73243585d64e1b49e5fc7e60a7a6b1fa0 Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 20 Aug 2022 18:56:29 +0800 Subject: [PATCH 30/57] docs: add GOPATH location --- README.md | 1 + README.zh-CN.md | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index a7644235..89745742 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Simple command line based HTTP file server to share local file system. ## Compile Minimal required Go version is 1.9. +Ensure this project is located at `GOPATH/src/mjpclab.dev/ghfs`. ```sh go build src/main.go ``` diff --git a/README.zh-CN.md b/README.zh-CN.md index 6baf7552..309ac863 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -14,6 +14,7 @@ ## 编译 至少需要Go 1.9版本。 +确保该项目位于 `GOPATH/src/mjpclab.dev/ghfs`。 ```sh go build src/main.go ``` From 39434aa28ecedf4898932eb2dcd68ed3c45181ac Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 20 Aug 2022 20:20:39 +0800 Subject: [PATCH 31/57] fix: update import path --- src/goNixArgParser/optionSet.go | 2 +- src/goVirtualHost/server.go | 2 +- src/goVirtualHost/util.go | 2 +- src/serverHandler/auth.go | 2 +- src/serverHandler/mutate.go | 2 +- src/util/formatTime.go | 2 +- src/util/hostname.go | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/goNixArgParser/optionSet.go b/src/goNixArgParser/optionSet.go index ceb7a0cc..134eb4f0 100644 --- a/src/goNixArgParser/optionSet.go +++ b/src/goNixArgParser/optionSet.go @@ -1,9 +1,9 @@ package goNixArgParser import ( - "../shimgo" "errors" "io" + "mjpclab.dev/ghfs/src/shimgo" "strings" ) diff --git a/src/goVirtualHost/server.go b/src/goVirtualHost/server.go index 79e88c35..74d81974 100644 --- a/src/goVirtualHost/server.go +++ b/src/goVirtualHost/server.go @@ -1,8 +1,8 @@ package goVirtualHost import ( - "../shimgo" "crypto/tls" + "mjpclab.dev/ghfs/src/shimgo" "net/http" ) diff --git a/src/goVirtualHost/util.go b/src/goVirtualHost/util.go index b191eed3..952c7e32 100644 --- a/src/goVirtualHost/util.go +++ b/src/goVirtualHost/util.go @@ -1,7 +1,7 @@ package goVirtualHost import ( - "../shimgo" + "mjpclab.dev/ghfs/src/shimgo" "net" "sort" "strings" diff --git a/src/serverHandler/auth.go b/src/serverHandler/auth.go index c9640cd2..c2655fa5 100644 --- a/src/serverHandler/auth.go +++ b/src/serverHandler/auth.go @@ -1,8 +1,8 @@ package serverHandler import ( - "../shimgo" "errors" + "mjpclab.dev/ghfs/src/shimgo" "net/http" ) diff --git a/src/serverHandler/mutate.go b/src/serverHandler/mutate.go index 5f4c7dbe..22f1a2cd 100644 --- a/src/serverHandler/mutate.go +++ b/src/serverHandler/mutate.go @@ -1,7 +1,7 @@ package serverHandler import ( - "../shimgo" + "mjpclab.dev/ghfs/src/shimgo" "net/http" "strings" ) diff --git a/src/util/formatTime.go b/src/util/formatTime.go index 256a630c..1da790cc 100644 --- a/src/util/formatTime.go +++ b/src/util/formatTime.go @@ -1,7 +1,7 @@ package util import ( - "../shimgo" + "mjpclab.dev/ghfs/src/shimgo" "time" ) diff --git a/src/util/hostname.go b/src/util/hostname.go index 3149a2a1..47ad5db3 100644 --- a/src/util/hostname.go +++ b/src/util/hostname.go @@ -1,7 +1,7 @@ package util import ( - "../shimgo" + "mjpclab.dev/ghfs/src/shimgo" "strings" ) From ac068a32f5b5f4a4f720dcdacc624269e3e3f65c Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 20 Aug 2022 22:41:35 +0800 Subject: [PATCH 32/57] fix(build): mount temporary modified source back to original path --- build/build-all-by-docker.sh | 1 + build/build.sh | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build/build-all-by-docker.sh b/build/build-all-by-docker.sh index 119b288c..f7d3c808 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)" \ diff --git a/build/build.sh b/build/build.sh index a6be12a6..824abc14 100755 --- a/build/build.sh +++ b/build/build.sh @@ -29,12 +29,13 @@ for build in "$@"; do 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 + sed -i -e '/var appArch/s/runtime.GOARCH/"'$ARCH'"/' /tmp/src/version/main.go + mount --bind /tmp/src ../src BIN="$TMP/$MAINNAME$(go env GOEXE)" rm -f "$BIN" echo "Building: $GOOS$OS_SUFFIX $ARCH" - go build -ldflags "$LDFLAGS" -o "$BIN" /tmp/src/main.go + go build -ldflags "$LDFLAGS" -o "$BIN" ../src/main.go OUT="$OUTDIR/$MAINNAME-$VERSION-$GOOS$OS_SUFFIX-$GOARCH$ARCH_OPT".zip zip -j "$OUT" "$BIN" "$LICENSE" "$LICENSE_GO" From dd11c8f8426b951a3114072e42bb0f03e51a9512 Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 3 Sep 2022 18:30:14 +0800 Subject: [PATCH 33/57] Revert "feat: close server gracefully" This reverts commit 5a6ea9f13041d96742042f9e803c37ca1010ccaa. Go 1.2 does not supports net.http.Server.Shutdown and context.Context. --- src/app/main.go | 8 -------- src/main.go | 4 ++-- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/app/main.go b/src/app/main.go index 7af403f2..d1abb684 100644 --- a/src/app/main.go +++ b/src/app/main.go @@ -1,7 +1,6 @@ package app import ( - "context" "mjpclab.dev/ghfs/src/goVirtualHost" "mjpclab.dev/ghfs/src/param" "mjpclab.dev/ghfs/src/serverError" @@ -13,7 +12,6 @@ import ( "os" "path/filepath" "strconv" - "time" ) type App struct { @@ -30,12 +28,6 @@ func (app *App) Close() { app.logFileMan.Close() } -func (app *App) Shutdown() { - ctx, _ := context.WithTimeout(context.Background(), time.Millisecond*100) - app.vhostSvc.Shutdown(ctx) - app.logFileMan.Close() -} - func (app *App) ReOpenLog() []error { return app.logFileMan.Reopen() } diff --git a/src/main.go b/src/main.go index cfebf6d5..749a9c8b 100644 --- a/src/main.go +++ b/src/main.go @@ -18,7 +18,7 @@ func cleanupOnEnd(appInst *app.App) { go func() { <-chSignal - appInst.Shutdown() + appInst.Close() os.Exit(0) }() } @@ -63,5 +63,5 @@ func main() { reopenLogOnHup(appInst) errs = appInst.Open() serverError.CheckFatal(errs...) - appInst.Shutdown() + appInst.Close() } From 6c9090e2a28d3060d034a296a9e83c127b7047aa Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 3 Sep 2022 18:36:09 +0800 Subject: [PATCH 34/57] feat(goNixArgParser): remove Shutdown API --- src/goVirtualHost/server.go | 5 ----- src/goVirtualHost/service.go | 26 -------------------------- 2 files changed, 31 deletions(-) diff --git a/src/goVirtualHost/server.go b/src/goVirtualHost/server.go index 35152429..74d81974 100644 --- a/src/goVirtualHost/server.go +++ b/src/goVirtualHost/server.go @@ -1,7 +1,6 @@ package goVirtualHost import ( - "context" "crypto/tls" "mjpclab.dev/ghfs/src/shimgo" "net/http" @@ -85,10 +84,6 @@ func (server *server) open(listener *listener) error { } } -func (server *server) shutdown(ctx context.Context) error { - return server.httpServer.Shutdown(ctx) -} - func (server *server) close() error { return nil } diff --git a/src/goVirtualHost/service.go b/src/goVirtualHost/service.go index 8ab0e6dd..9318f02c 100644 --- a/src/goVirtualHost/service.go +++ b/src/goVirtualHost/service.go @@ -1,7 +1,6 @@ package goVirtualHost import ( - "context" "errors" "sync" ) @@ -134,31 +133,6 @@ func (svc *Service) Open() (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 _, listener := range svc.listeners { - l := listener - - wg.Add(1) - go func() { - if l.server != nil { - l.server.shutdown(ctx) - } - l.close() - wg.Done() - }() - } - wg.Wait() -} - func (svc *Service) Close() { svc.mu.Lock() if svc.state >= stateClosed { From 6e2926556586ba2b6cdbb9951cb52d5004a6fd07 Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 3 Sep 2022 18:44:55 +0800 Subject: [PATCH 35/57] fix: apply workaround for getting prefixReqPath --- src/serverHandler/multiplexHandler.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/serverHandler/multiplexHandler.go b/src/serverHandler/multiplexHandler.go index cbe31ba6..780c87bd 100644 --- a/src/serverHandler/multiplexHandler.go +++ b/src/serverHandler/multiplexHandler.go @@ -5,6 +5,7 @@ import ( "mjpclab.dev/ghfs/src/param" "mjpclab.dev/ghfs/src/serverLog" "net/http" + "strings" ) type aliasWithHandler struct { @@ -20,8 +21,12 @@ type multiplexHandler struct { func (mux multiplexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if len(mux.preMiddlewares) > 0 { + prefixReqPath := r.RequestURI // init by pathTransformHandler + if qsIndex := strings.IndexByte(prefixReqPath, '?'); qsIndex >= 0 { + prefixReqPath = prefixReqPath[:qsIndex] + } middlewareContext := &middleware.Context{ - PrefixReqPath: r.URL.RawPath, // init by pathTransformHandler + PrefixReqPath: prefixReqPath, VhostReqPath: r.URL.Path, Logger: mux.logger, } From cda1cad697a8aa0b5e6c2e4ccaa95771a778cbb8 Mon Sep 17 00:00:00 2001 From: marjune Date: Wed, 14 Sep 2022 23:54:24 +0800 Subject: [PATCH 36/57] fix(serverHandler/preprocessor): apply workaround for prefix path --- src/serverHandler/preprocessHandler.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/serverHandler/preprocessHandler.go b/src/serverHandler/preprocessHandler.go index 155f50f5..8a55a733 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 { @@ -19,8 +20,12 @@ 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] + } middlewareContext := &middleware.Context{ - PrefixReqPath: r.URL.RawPath, // init by pathTransformHandler + PrefixReqPath: prefixReqPath, VhostReqPath: r.URL.Path, Logger: pph.logger, } From 56b123f7119d933f5c0b49c28b604d43b6e872f4 Mon Sep 17 00:00:00 2001 From: marjune Date: Wed, 30 Nov 2022 16:17:16 +0800 Subject: [PATCH 37/57] fix(serverHandler): use alternative API to work with Go 1.9 --- src/serverHandler/page.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serverHandler/page.go b/src/serverHandler/page.go index cbff17fb..06297a85 100644 --- a/src/serverHandler/page.go +++ b/src/serverHandler/page.go @@ -66,7 +66,7 @@ func (h *aliasHandler) page(w http.ResponseWriter, r *http.Request, data *respon header := w.Header() header.Set("X-Content-Type-Options", "nosniff") header.Set("Content-Type", "text/html; charset=utf-8") - if len(header.Values("Cache-Control")) == 0 { + if len(header.Get("Cache-Control")) == 0 { header.Set("Cache-Control", "public, max-age=0") } From 9ebda14b74c689224dd3f38e65806ee033ac3bfe Mon Sep 17 00:00:00 2001 From: marjune Date: Wed, 30 Nov 2022 16:34:18 +0800 Subject: [PATCH 38/57] chore: re-embed frontend assets --- src/tpl/frontend/index.html.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/tpl/frontend/index.html.go b/src/tpl/frontend/index.html.go index 2bde21be..57cd2071 100644 --- a/src/tpl/frontend/index.html.go +++ b/src/tpl/frontend/index.html.go @@ -75,15 +75,6 @@ const DefaultTplStr = `
      {{end}} -{{if .SubItemsHtml}} -
      -
      - - -
      -
      -{{end}} - {{if .CanDelete}} {{end}} {{end}} +{{if .SubItemsHtml}} +
      +
      + + +
      +
      +{{end}} diff --git a/src/tpl/defaultTheme/frontend/index.js.go b/src/tpl/defaultTheme/frontend/index.js.go index bd0ae338..2341e9a5 100644 --- a/src/tpl/defaultTheme/frontend/index.js.go +++ b/src/tpl/defaultTheme/frontend/index.js.go @@ -246,7 +246,7 @@ const DefaultJs = ` return; } - function getFocusableSibling(container, isPrev, startA) { + function getFocusableSibling(container, isBackward, startA) { if (!container) { return } @@ -258,7 +258,7 @@ const DefaultJs = ` startLI = startLI.parentElement; } if (!startLI) { - if (isPrev) { + if (isBackward) { startLI = container.firstElementChild; } else { startLI = container.lastElementChild; @@ -270,7 +270,7 @@ const DefaultJs = ` var siblingLI = startLI; do { - if (isPrev) { + if (isBackward) { siblingLI = siblingLI.previousElementSibling; if (!siblingLI) { siblingLI = container.lastElementChild; @@ -306,7 +306,7 @@ const DefaultJs = ` return a; } - function getMatchedFocusableSibling(container, isPrev, startA, buf) { + function getMatchedFocusableSibling(container, isBackward, startA, buf) { var skipRound = buf.length === 1; // find next prefix var matchKeyA; var firstCheckA; @@ -337,7 +337,7 @@ const DefaultJs = ` if (buf.length <= textContent.length && textContent.substring(0, buf.length) === buf) { return a; } - } while (a = getFocusableSibling(container, isPrev, a)); + } while (a = getFocusableSibling(container, isBackward, a)); return matchKeyA; } @@ -379,7 +379,7 @@ const DefaultJs = ` lookupTimer = setTimeout(clearLookupContext, 850); } - function lookup(key) { + function lookup(key, isBackward) { key = key.toLowerCase(); var currentLookupStartA; @@ -397,10 +397,10 @@ const DefaultJs = ` // key changed, no more prefix match lookupKey = ''; } + lookupBuffer += key; } - lookupBuffer += key; delayClearLookupContext(); - return getMatchedFocusableSibling(itemList, false, currentLookupStartA, lookupKey || lookupBuffer); + return getMatchedFocusableSibling(itemList, isBackward, currentLookupStartA, lookupKey || lookupBuffer); } var canArrowMove; @@ -460,7 +460,7 @@ const DefaultJs = ` } } if (!e.ctrlKey && (!e.altKey || IS_MAC_PLATFORM) && !e.metaKey && e.key.length === 1) { - return lookup(e.key); + return lookup(e.key, e.shiftKey); } } else if (e.keyCode) { if (canArrowMove(e)) { @@ -492,7 +492,7 @@ const DefaultJs = ` } } if (!e.ctrlKey && (!e.altKey || IS_MAC_PLATFORM) && !e.metaKey && e.keyCode >= 32 && e.keyCode <= 126) { - return lookup(String.fromCharCode(e.keyCode)); + return lookup(String.fromCharCode(e.keyCode), e.shiftKey); } } } @@ -1255,13 +1255,13 @@ const DefaultJs = ` } params += els[i].name + '=' + encodeURIComponent(els[i].value) } - var url = form.action + '?' + params; + 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(); + xhr.send(params); e.preventDefault(); return false; }, false); From 9d1d48fecf3d1173005799077f927d5d9fc2683d Mon Sep 17 00:00:00 2001 From: marjune Date: Sun, 2 Apr 2023 11:16:43 +0800 Subject: [PATCH 43/57] feat(build): add dependent package to local The docker image golang:1.10 is based on Debian 9 codename Stretch. As debian removed debian 9 packages from official mirror, just put required packages into local file system and install locally. --- build/build-all-by-docker.sh | 1 + build/pkg/zip_3.0-11+b1_amd64.deb | Bin 0 -> 233894 bytes 2 files changed, 1 insertion(+) create mode 100644 build/pkg/zip_3.0-11+b1_amd64.deb diff --git a/build/build-all-by-docker.sh b/build/build-all-by-docker.sh index 072e5ec4..6b96a0c4 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/apk/repositories ]; then sed -i "s;://[^/ ]*;://mirrors.aliyun.com;" /etc/apk/repositories apk add bash git zip 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 0000000000000000000000000000000000000000..d15c22f2e84d62edfa7116ad3829305a052144ba GIT binary patch literal 233894 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

      P!2jLppwH!KZ(Bwr^O-2@+V3M*nBuYD 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ⅈH8%xNw0?euN~R&qXZUJEQd$8|80-NQBL)V*gOP>@cb{_Ks06h{ zS`2v!`ElnrO_b!pvXD#FbPcAzW3^WB=J=iKHVUKu@kEDS;s??}|Bd3z9MI zzS`a;fg1Apr*#7cV=qWy#9i=oL!88*9OB$Y+?NVOLyR@sCH0rVc?Mf3+kolaLmy;C z!vah3yD&om(okQ@7!T44$w2bte=x}(P+6ozJHr@JDiHh6ocRD{F$ireV&!BN+__iN zbfFUjyGK*80A9XWl7&<;h}r@nbgEH{k1MbV(NOBE6s=5!iln7a*eS_*-e~%Qp_M8) z5gDH!eHvUH9US7t6Awe7vnkwOEA+7qGmSkf(?|eM5^19a(H+FK4Ev;d4*W!jP(vGF z>pRWqUx+nj@tBA)-HVOsoA1Eg$B7PU-ZTYnWWF^nv3ZclG+36;~ysIoH?P@KV*p=Nz7*=&2vBILSQL&Y8eI>&EB-EGKj)tTFSFu7~nN=1> zq2-8vC8jYQM_{Vkn!BeE(>X)=JU2aG+NX~>_eVq9d75`QdEKCZjeinpqHyG?@$fAq zc=6soUP*eOT#iZj8eSrFq?v#=V1!L`c$4rPCstH(&ZgC((6Z_w)zuhbD4~et?qWdM zK(5tD8xsahTrVsTz^#fo-?Sn@eUFOTxsU;q87jy>?UbjNMq5SWMYpkAXl@Y~Br}GP zCbU8+)Rs!sbT4$FE#7BPW{n2!>13)#iZr7B3yGM85Mda#_NJ5VD3)wK9*~h4c)TB<7F>rRdFjD`_qzGPlhK!B)N`U; zZP#3-=>n3eBt-XoPLE|RBkQ;cQ z`t$8u`tSDE7XQySzG%p5$t_i|F?vT^4{weQn8s^z*Pm|Bu(Tk#E<+1YKN-6Ah1a}X z7Jd`B)fyNJd|T_}5fL_xi9!ICH7ag-wQoK?6PF%sD~RZO(uj|gbwchqJc8V>R@ua5 z5#gh%>ZLm@&q{@CE@sGH;zO&RB$1V##JFnJ*zS#YLAkaNCX8Zbs7_P{=&t)EBWW}R zV7^d1OzAE`5fhU0{m2HD%>j6{lp80N+;f~?-H!jywD5m+Th zy5}ffC1N!OK}&P99T_uV(srz9f(pVql0U0F?v^%h-HJ+B)Qe#Z27{(qm_nHvY zEG=_(V&ojkvb8ifw#fL_m-Tt+NiD5GQqfbLfi(QYRZ~z|TSUU7UZeC473al(BI&;9 zm*k_ztfzpKr(n zJbIa_ET(8h}Ly|ik(~2Vtp!r)1MMs8eTY4M?8R*8EOB!m} zw}ej2WHc`k2_x}yb?X^|d=uUmss>eZq0!E1M33A20 zAH3pZyTg=+4K1$+?0-qvUp;NLPqW1uEY3+AA(QNJl2G6=28&axa#88c*R=14n&Tdo zgT=KANEq3msPEvz=_x}7*h^b_^+djrA|wxB_Hf0>w1!fmP|Vd@9%y)v+$Aq2Nl%6& zXi|`}4Egs^kwsx*l8%-h>V!O%^xCuVV+FJ+#SH&jXB3cby~-vkh!)_ZRhO4`3%UW) zB+<43^2)_V)@RecA$w;{%s^3Ai@%kpFOI#r zU%^iXr3cBroBsPMrq>gS^hbn5HK0-<2EiZ3V|4a|vnOCrP?YWqlmN|(xtYyRwD z&$1NG09D@rsRi9pRfryDnvqxO-1%zn->Fojw$fIAO=3~_VMF&)&{Yr1%?KJ+Ru-+E zM@@(@S*9jS_~KX@A*Ie7^*T5`k#4IFI(FgGJVMPLg}37#g&e{%6}eU|)|A0N68q!V zk?&-XxJSDaRG+bSxuEr`hf4Mmhtq0oIHEeRVUPFeNX<=7IooVf!PH_$|6-Zf--r(3 z`fM=wDt3(%Vqy+KLi-f4sUfU^Bijzr(QMpm?5o`gn=u4s>ixOeKbX4TEVlQ&Sl?=9 zNzgp=w&bCxZIF!k@yY4YfI2w`?+$vue7GF+kIoLxuTOg1|C;ioA7}KS@YYADr_NNv z%)J-hMvvJFNkWyZ_E&~~Lw#G@-5Kvh^H{6hVJ{Hid1_{$bhXl)ajWk9`naC}^xHdh ze_;>vs#}|R$5}Bl+}vzMHrvhm+batoPqZ>Lf?@jTQ!2NUygbVxQ6s+o5D#q#K z6hSwu#PKDx$KE@+Ne1W>glFew4ueqApPLwH-3_}%v;e0Dg{0E1$kIN1&*#^J>(B2# zydQkJxccSb>f*!sVFwrSVz~mSeE^h=&6;yRsT_#&o?i?;?R2kC&W`$nlh4N|zan;E zGNuNu@uwkoXW;DGZmx>HeU5d=w9$IDE>Vs%%=aj)1slwOqjbp$daBzqu1hLJ0enj; z(eyjir!rqpHIirghSE99S)wLDK&Cqvp0QB8untY2cRlx62a>SL#}>+`Dr)eusqcax zs0L`aH2uUrP~6cWM;a0QEPC${Hqm>cJ2bosN`-bp7ypH{={i!Ax6k(4yV0?8Zz2#4#6me}m@YDp;SxE;Xm47i(#(_k><79YV;9%= zAH}y6+Lynh85|AS@$o^5SsIfl|6%lxJe;`kp|nu$b9uhkyc&=i=*XI02TB`8AJe74 z)VHc^Q`J_a=B9_YW*Urky1uCB{$4e7E8NC8L9=wpx8al#wf9J-W`OSB2%9HkV-kzh$;ZE+bjw6wf0#XxnNoqqM4Sy zbKB`*%J%v;>S>9%#0Ty>#l3r0?i#dQfLT&(jW6}&Wuz~&3PYbNgVlGPWS_78R7*iqBp-RRwNMGn2*>BSriRpa9hqJ za_&PYWj@n>P5GnCmG(*p7#efKk6|rhmbHB1=2$bbte!b&B_ce-?~EM7385^Pa=WIo z(%gruC)iP4;c_YJ0rN)@JL5w7j2s*@3#!Q*Axcj)CtrZkVPAmyB$QmYG5eMb^JU0FL~Mnh6v1Lz z>J=X?n@960d4r1k?n6_v2YNN+jMUzFudSm&vcjsK&z6%w~+7NXwWKF4%BC-E|rhoPpoNE7^^a++c0>r?H69_I@)lCTWFD_J=Tn}^hc`7)eFq@T-K-zl41 z!#TLzs2?dn6{olmK5NL@RzcQH+AvAXxf`GWUNam&Fs}00B7w|(*)A-r^rQ}PL)oPA z!dlx9Q?e zg^pV)1k98*<4nkwVfphrH|NIFso%Bfn)vkF-Y&lI63sg#NGt1aNfFGYzYXMj= zePnox#r0{SI!eTI%HS?ZSIc4s8E$_ji16?x&qU(H;1u{TWJ;d9i?_=kx4=+XwzZ+C ztPuxBfaKa^Dx`2ST`^#C!kCDqE$%jhh$}rsucLx5qUO*?ohZ*cz~Q_z7N9$DZ{Sn^ ztZn&k$hiZ2(?&JrR)_~t1>C+Rn+>xiF!Mu zmQLc%sJCNBY?r=tu|;Vrem*I3c!Yd2C{#LWM}FUzHh1l1OU-LT*MPL;uzOGR%0fe? zKlGTJ@{2P=RD;FB6u}D=3c)VvZs$nQ2b3#f;EF9nP@G0&H&Bcj$*ieN4WSjP@ElRz zq5j*qKHr7sV$bE^s`vBB$0K1b1!X510$|5WAxE9t{u<9~04sjRc?)QE$m^rnsnp~& zb0(zo%0ysm;?IEJXz`1%!3y4!+jCdAmQ?j3rr0IYzzfikqTV+dx@aC=OsW$3tynCA?O>B#x}agFP{G_BLM3=N5DepG(_t<*cP_V`ZlBzjVntEO-nx zM^UAQn@r!f^F$M0@ z(U+9a)34lviduKaji^yKr#&>8xarQ>#R+Pp!ay$MjKzX-FtRPul&e+vC@8`W&f5}B$ z3+z6jar4Qhh%;xUUN`1!wx7z`fR&Z}k!3;YSO~WmmXSWEo<#Z>E{>(MBWi@I zHSCMju;k2bVoTG;h`F1N+c(dP7C7^?viM^bN}qe6$BHtR>?@U3cJ!7N#Ttw=XNzVt z0UoL3Jw5wk&Iuw0gG>bs(!eji9ef@c-L-t=K2hK;<1Cxe)5`n_t#-x{xywfR#Q7R~ zyKQ8RdB^nbYJWAqaI2Zs8NWj)mf1x=}CW2J&=j=+ym)Fq{BI13N57zOSzo^`C15hHa}$1TKr z`v*WXbih3Cn@BtFb+(X?;l`4DBAFjSZkvD@d8Io_>S>=TFmy~Z!cxfOoq@*$CmGlu z5A@f3w{D77)4PEQ%d&U0%c0F?BRfNi&~R9osV}r;(e5rlTXpG`x&rwyI?_+<`UI`F zh8;0CrdIoXKaSn-VqAEg+m9KfzFMlNuf=o)ML*C2_^$3wg~#ZbUM8*V*NXgPY!TZ8 z16xVhN;s}g#jkDW&=UoXn_ul;U;2Ix&{l-UvptIJP5=690KJeUYyV2|1(aE8(SR?y zX!QWG?!1_fS9kWO<>pImW2s%AeSb)aDUy!j9s8RKS5gzvhPW^i#bNcctS>zHa$+VN z`C3h`7KdkG%BVS8WU@bj{6+Pg2o>f0<6CA5G-M#H0BtX(4Sfy>7;O<=_&iMkQWkV| z0IFTyjTW$sP2ebkf_SqftyiB;&Ud;4QcLvhUT%!=sUXSdJGG_3avYQautb3=DJ2fmJKd-?AzQ5Sn)VvU~Ff#LEQjYn{AWSp}0|(`40m4xaYSA18l-B zvKTGXVP{lj8iY46F7H~Vh9+O})=u9UO>84NTba(%r@@l99G>aCkR9s7^~ve_?sb_v zng@xBN#8i;+<&gu6D7x9G^!BwIWfMyV55-X9hAGgI-cy{T21ysr0)EMoZf&|t9U(E{K!F17h@ zZQ1slNUG}q7k0n!-=aEz>+9Ld^sC02{PWk8N-T(2w1|&YGFhrWU^9en_R_ujQY;L~ zPPK52H6vlW64{>P8M=B&ZR#?YtzFAsC)^Lg!i!}?&trvPxhYpnLmjhVs!egBD3bKd zpoUzExDg-DI}u?xc?78*$7xYLmQ(W@WV$1Nq+F+L$z@2lGEj^pR9D)2LO>%os}|9=vR1);eUSq(da6)r7m3D#hC3;p&-{CB~KTG!~J69uiscarViwWXuaS}Ity_Nz;EDA9RqJWt}B~4VAu1NuaJ`L6k10 z#yjWcH8e}n8Q37WH%d@hYCQ0Vo6bZo2#i}?0hAtQiJ#G|pq#j(dI*n<(^1*NOJaS7 ze|9nF`^T8RzyrSE?S+;7zFHM6cZjw#%kI^}n7`<}k|Q~~;#bB+4~3nj5(N0B-xaEM zFa*_$Xcvu=Dj8^^aLDs;09Zh$ziTJX!h#fu^_?lh-Dwx3VfMu1_^KZLrhSbS@m;Ct zzpSQf(>uH0!NH3BlRpgJLbtPx%0##GcAG)Hv{pU($1B4~Fgl;CBpvUC>8wwLcCq1b zk$uH^BIi{$Kxx;*Dw9RRN94W@6Xjqlal@v#ni_6Zi3m+|_`A<1moN(W!*+&;Z}S;z zmH}pgbfNG!1L}e6rjNs{nsBIWN4tJ!sSA*Z_DGN&(OuHptguB=U)C5YTleI=O%A_J z^C4X^-a>tjSF*oI{6^{Eaxn@Yf>aC_9MI|L?EVZ=Ga3*>oV&?5IUMiK5?d<0R)u_W z_>Df*cjhA_Efz?7m1q1U%AB`v(mUVezMFs|9 zLOIUp$J5q*a^Al_I6ZA8#4m7m)bgn#(afY{bnN)$hV-R46E4mhe(Nd+y>b|l3?{O3 z{?S=Gg>dkj(hVr6QzA^E0ydGKJ7?%Ny#qQrM3D=`Twh0cadCv{u8gn0j)vd(y+&Wr z_#yOc`1HQvR6bkXc+i?CSHAUuZpCvl1@n(Y*AG(Z;iGt~tN`rh(n#w#QT8)tK0~UC z-zL42#cC8>P|u#$7;J8LP0eG>UO*?o-#c4j)p9Lhyc%W6Z{5bXC2E8yv){{(!$}0d z9HNqL6V2b;^dW>WpZ+eJB%x{?ehLxhnku^38Ad_Frid|UqnP#(;h%8VH>56A9>1Ss zJ_swG#c3q2;x=QoWF$E$Ueywmh`%8@am*pNHbs@%XIypsP2NGV@QZB5yyT4T9c9LL zb9Er-Ukx7xb1==kT*fM5fH|2*n~q_;bavDEPzWeR2+FhMvig8?>59lmg=9u!Kc%R& z04gN@5+iXmeDWRmO}k)Kl^H$SO5A~PfIM$1v6I`#n|S#5j(3{XJ1ZrRdn3T}G56!( zH_ZSLYcH*&dX+bgHru1)!H4Ss^$4?tIKS>64vr3-z5H}?dN}A`UtA6jt_O!FSFMmo zY$c}$SMQGo=pvWhn-7mVp;}G(Mh|Ks-@`3U_PJ0$T!--pE0SHLT&Sw@%tLQ>DkC9n z?yN$9?#B^I>P5e-L#`Q+?f2LbGy_sQAz|+}xv* ze((gVeww9u=(u&wzq*~?k&6eO+Hfp-zk+v1FPMIGGa702Oh3*G{?uSDObOiIay)o# z_ZrM0Mgz%Zz{=a1lcfM?XuuP*^v-JF0T@iF4x*#8lbau@r5x`Qfk~%w&(|8 zF!{3l^XzqJOdE-d5dVQx#$VFARGQmHt3`X zB~PNzGR>^|4V=!};IxpJf5?#7alxXj1m0v)O815o(P^M1sX(MtfOkzfUdrLBq@{-% zEn@$fKcCV`-eChGN9yGy+N(>41Wqu6? zQI=Ni~?YH>9+g-*n@0NEXUp!lI0)H8&mY_dT>`aM2Y&Qaf^8K9sY?JZgCIU$C9o^ z(l7)>d5#GZSaeBB#$BhSrjjtnv-BT91(MRra$YKB<$O|3Xlie&zL zzWyO+5wfd%XnsKtbx4g zJd^Y}Z@<#{6i~%bNQerxvB_* zr9xUav;bb=tBDIHLbg1_OBISMI)I+${^p3Rx8a49facGZJ(I=#(bCf+`*qN*dU)-CF7cE}|0) z`}HyWR=;I?6mA(yrqnfuebXj!vDNuQJko?4>m>jQ#ImvCy}J!>zM466c`oJLd$UOr zoOhhArjz#$^~{oRp^`EAJH!^@?(vR7RXAMsF1S~jHYGl}XkD$P$t>CHBG)QwP%0z3 zS7&J=v#OL8lyE{PmR|(*)5i@(J>PiUyXtAn55EN_OJtPEjO2Rh{^?iT%F)1{dBA3f zM#7WI!_q<4fHx`<)X)w3EoS0tus7a4~T1di%v3(39n~H>&nepUw!`UQ7 zgdm})UFUo`az%7YQ>D` zVsBOTmxwfCJdU`Q&=DQ*vL^PU7a%9%bf-o#QS@FhS>%yBqdp|2$K<*=)Pf1!KK+yL zs91=0qw2m~UmRZ4@SOO))LzV~VxYz`kIeCLvoI|cAg)$(7?+s@oq$KvKhRggj1}sW zVCvE)8h9JT$`llYxEC!96LYsv#qvR)fSMtSwyilYEEeTIJ1)7PlDC8$P zmOyL^UAKhSfO;yZX+g!xGMmc^qC*+1%PlBT8VtS~b2|9;C#2O_lJ{iJq@R@JYN=`f zzQ08;lwimAJ3F4yrl^q2mds>2_ozU!?}#Qr?na`>l&ZBjK5P!JxV5UxJcM;vS4^938`gYsrHXPS(`a`?gE}- zXEClnMRy$qS$K>Pc1w$4wFOKW6q|bt+^$q@4XBW>)wWa$H_lizrbb<*`ot;cq2p~# zYys{dPIju^39S!m6Y)K{)XlzBUh`;$luxo?Np1=`0;L56C)+qaiSmVFJmn z&vn$m8Ny?uKKH~oP&8BIzR}%2@Y2N$nA8unR)@|jpRVH>V$EtGL5M^`#3)Lt>FYZI z^wjv`XpF3P<0*R@H-~sY_PAJvR?51NsX80h?+w9j#qp))I*Li|^KsT-Ck&$`(L*dJ z`}H4b{&2F$GN3vsk_EP~)1)fe*G^($S`lqMYD3=M)(pmoh6&TwW)xU5#1pVr`V6)2 zm=Ii8kc>WZ>(Y11L83>jK`fqQDsZ|Bul!y{-g^;Y?OPG?3Y}}fcz_?PND~9CidZzL@&UK!*XFP!vhMY1&teAY zV_7Zd2ILVIG(-(eahLi=CaRv;sY!#8o1j%MOkW-Bp*H0s(xHXQfvC>Z8Z<}38@hGB zKf7111ZY~qDnlzA?fHvG$yE7vN@(_6^bW7IFVtASmMHR3&<=N&?kM&fLNWmP7kSZM z{iRkD$Gxf$44;Aeltfu=>8$@mxALkyls=lzk=LI=Za7rfeW#QEyq=G#EW0ZAv<20H zDH#Z>-qHE>)xjy@vIf@&C#M7A@@tk7k@%LGRpZ9sjJYMS!*&=D$jMy)s^GqUIci$o;4cjn@XywQR2B-UTU33 z#dv4$E}0B4@TS_O<`tQwrZHkTgNC$13X71LoJ!#|mh7s#m#H?tH*igJqr3`nIhUz9 zpZw_KbCYXqR7TyN3_p8Y@lR?I!~`?#ZR- ztcuOGC4*yz=6fM#>=L)Op5zxKJ2*k!ca4%z7ucr71llK0Yv7ZITo!6!c^K^`vk8- zrA3DW^}(`ISb^)y6s)N}5IrBRrrfcFW7Xieq}{G$c!=zc9%9EwYsqU|M}G-og|R2n zunR&zqZ?S;0b0gi748vzc9E(RlHFyHRCv5=XsTsZWJ;#^ADRBox`6YX@CqepF5Fb+ zw{d)acJOQRhh!g3dit;3t^Mta%#5aX+|UNK6rwLK2RB7A=D$XZk^Di+s3nBjY)m&3G}F1o)UvKU<#jr8d9Dix;ZQR(m-e(;;nbbpRP`>j|M*<9ULBA zDe?DQftK*ZE4Ne`6Sw61G}YW^1u!FMG9lz25~yd?<%j5%>76L{7Kf{$T}6B;)S04Y z@8;SL%A8Bi$!M;|IgwKZzI{F#99GAPO;70A+<13=vQnS;KTN*Wqz^`}LF+V_9!ig{3J|0cvdYQ_CcbVhkX6O85ZgoSE znKaTqd_E=1aRX0%OQe9;{>km+$&bzf-D>ueUwiBrw>k;kPNmt(Z4Q^ee4;V~V&`Q5 z#cJvOpx-+=Y1Rd%;JCa`d5H6GqUFtrmeY%#i?H<1)1&idzr4ql|EG1ErAi*20}e}B zL?s^2g(J>4$0>4XIIP*X=eMs0n7v~F1jLFu3nQR8;iq9DV)39G$KNfPUx-huhT7wW zidPp>bKEyke8Hr3FQM_A#0yGePE2wl0=c^L+BL!xpUi2$l&^Q0kY1NW^I5l1f6{xx zY?ajcf+YcE6j}*t$@h7gF(GXjoH(#(&>KZD#nQg>U{_st4~mgt7BW|=Y&YM#ti=A$ zt>pAQTmIA2_wHSd7DZ5?lS4e9%nL-{O7tKEd;Z^%?Tzi%4zF1aDTK`nlZEqd^>g59 zXmHzIu$Ob@dxbP5aQ}F9GF2IVoe^nRW183ZN6Sx+-mI*LZQ*f9?Fha>bcG$g)xVPU8+5=kjqjET*N<7*C_p-I@;jQ8A@r4D+Y@PiT3;8Eq(R})gB_T|0~rpBE2ZoVga#?I&9|+ktWto7 z50)V*j4SZ0RQ$uRsOZR&@7GP5>YWMw{+(7Bqq2S`I8Fg}5qhtbz9RDPqrN0c0B}=u zfC*5;9X32hfiR&a-cL0AeNo=wg+rAs8Pm9@`_f7^K+lFnozP(x?ecbR6 zI*J(3D*Tmarn}b5G*hZX_vGt>@~>Zu=~oUva^Hfh=vxg)kVmMp2v#~yZ0D<+sap@P zw_x?Q9(ISAHZLw;;DZ;xykMmc*$hj=25|JQcX-m{*70>p&0+fpJ;P*W+Q)qrJerSu zf)*kwp!y0(B+0yqN>ac92)$JWs3bfjQYNT#2f7>j4@u;|X=-Vx@H*`WR9P7lL!wjr z-g5}M?`LESIYPXbTSQu?FtxF$Wuip*DsBUdU#c&I^RitKkH($q1<}_{8{#!u&dTJe z6>rXHBRA>kZ+UO~{CQ*%dA%ZK$xaGJJ zRj&U7ex9`5n`SwM)qLSX9r22snYvT))a^ZqrYV}D?N*OuDnCvwl7}^dt{Qd|x69A; zXKAI#yRn*2s2O$4?aJjw^klr<%|*vo-b|#O3#tz3$&v5f6RxJ5@%6(?W*HZ7uG~Ch z5!;qF%y~X$y$t@PBoZ&<>xJEb&YAD*?-9kei(IGKLVzd!Et4z~3SEd`(jlGALPOmd z2Gh}~la{lV`G`*1_}PdgA>{AAkXo5ra~sk76=6!!o0QxZ_k4K!xuOR(;{9{a-De+4 zeQt97`7m9keW@_9DmRnPxF1c)A6wn2;+Ln*l#bMkJ2&q>rAw?*U3c4^Jqk0*nfQY` zII`0d-Ca2@N`5SU()c+76pL#gljKYGNL-}pVv#<2fD)<_G@oi~rWMp@ShYZCdi*R9 z41i|#IL#4DK;kkY!ERJJMlHi+Xzn?nCafkzm|*_8jYq%n6xePClkkT~W85wB`EtTx z7)Y-wl+l=KoZDP!w>WUhOf2bED~YGriLN~4VYj#Uv2Qh9!q|=cJM%0nL&}_0J{$jI zo4147=iSC<#n(ochoIpYw*Q!v?@yB z5j~q(<^J=V(Wv&@d^oFp=1fB4@%P(Xwcps>X zOXc%rAj-Ikt$_--qvXKNB%uUL?VEF`;CWpOLpcF{I=b`_;TDPg#&Z`i$b z^0HW|yqAhlub)N%8bkVwj9)5O!{s7XYB-r1E;8H#S1J-li9`|7AC zwKrBl7PY~P-eGb|Ty|3I!pFEEzPdu2gA_$rGLkEB&KKF~4#@G7xutDYlmM1jZ<~$m z$n5&vyK@_*GvlAVZkkNm2SFoeagr)LW-z~4siKoE!URYHX)HnB{xqAQGlW}o?md~H zn>?koZOeSZn^u7jB%xF{aO%E+k6@|>TMye??*HUl_s`>Ff{cl|u^pq#by^anlCz^> zE}Qdt+fy?-$S@PP>STJ8{M(NS{ZEkH(juzjKo#IlKrs~KRW zsmyOSUs}DTr2^H3!Ig%HshlQBzjtsxc=zELGUe`)b{?J`on2i0l>jI(g-7Ry1V9n~ zVybI^4~~Ul#B{Gz38Z48%i!l}&kar~D?n$x-c^0(n**L$CbAa1S@7Dwf~$ofp!+e? zp9K=lu!GdzkwR$Kh_>0)uvcZ${MM$^{Co2M+j^MD8wW)KvBh)N{GNLex|}8T9b=_0 zi~8xndGC-1F+JAJT(k{)H+KZae0Y$%+oCcQ1HN_4xR9RMbN zDbn7?C-+b>4TYL|qL3Wq_sc*x4w6a%L;(uVjjQ}onceX2 zRiZ%6ACec1Pg-&LJ#QzCNbrbOwW zQ*@d#G4;e(N$`z>{@IV)!jOq@E95WXVN7Y%LJ{_!)p2O$bsAGPJKb8IAfB`=@H0)z z+e}&9z=|iIU}Tyah1O9FRKjZY)R1)$b5be}NHMkedlHqr>}i~JVI@dj8YBvZSYEBj zm}TqPj5L@H0yea_wU>3%eaca5bfEho^#uY&5)q83bRad`CZ!+T8%RMjCH!c?W+ zWJY7AjzJwuLAez%l2v&df}l!uEF@CO>Z73_i~!Ay3M4GxdYGW(!tK}SefBUyddK-( zzS0j-46A;sL<$2J#6;gnP;|_ToXlNu$NefoN3#%)A@)%4HV52--f0YM1^g*i!@vG@ zF>X*cm6)BMkgrR9SF>!Uh-<+RRmeTm&`fW1wwTB?y}Qe}!`z)m3KddvViq?a(S}N+ zB;mxZgRCoeTZQ>*DG4wT(gRDy*Da3nb3uKZA; zp5kFsqv7PlWwqlxBsY2&XWRf5!fsiMaiYiF%rEbRs9QU|w!8c8LvFjJY#!ZgIP-YI-qJRaT-Yl~_0UCP&U=YQfU#k6ig1FK>gvLVd(o+o z3R1reE{~Me*U0i#j$Wr){5^FfUlNLmDb_w0qes>}-Df$UlGgD(u6?}DQ-!9+I#k0$ zR7+bmAtIrgn{xAu!G^HwH)A6`H3U-Y>r?B$rP|ih)vu?kXDDt}B6k6=LIsfd%6|*4 z1@6fLoYL2YNU)L{!Ka`$b%!;zfvy48Bfz&12A zDmxxi(y}rg27eY}qLvp4mxRnB%gUfWK3_g9OrG!UHb|A<+L^^8a$94SSW6PVCW~;K z4Hrlw>^5c*-aL=V1j>R;UMZZkBufHk8re!^VG^9NHqx7znEiYfVGU$;Ahxr|&`IcI zk?iAb_Mo1s;Fd=wXYUIjOUoy7TSG5O@csGZ^62X7;;Qd1f!vubQ1S~c79LsBh_Kg* z+hl~jN)H*8k7xZhN-ay|5jINdF3*>b8zN!JSQW}*e|9eK(Z>PZnzpBkw+jIoP}}3q z++ACu>Jf0re4g5qDQE=eq3?K9xo_KF&qGV>!;>%_slOo-fGi)m%onPXTHcKpY%;u z%;FWEyI?qMkk3?LU2|zscFmG?Zg)MS=N-*cMFF@e{ILfy&Q5dg%PVn*4OoOoho1i# z(xXGSLo&0k`X$3x_Ls3oGyJx<`^p|?Sf&L!sA=CgVFPwR`h2h&mAeB9_SwxZzGhK5 z`Ae4FiMsGS^V^^MVt>oDrL0A?ysp+UI5MYX-(WNz1ZInfDBO@hR%)fTa4qo)B%a#a zd)jXhi5)ja2q$xQ&y*#}#zzmllrIZXpjm|daZ+jElBWnfB!Nqj76XoQKbzO0l6^_{ zauGQzMqFMn90VrhL@*7TY8c$Z_jO{uw^m_znB9ObgI;$nW(7Zs1dtR2yKM-x%z~Mg zR=~WhbSIWE!~mJ0@qk}oczZU{!*$3g848oBpJ=KIr3YbW&`VDq>wNQD7CHVsk6|;6TvAt_I<7sL^Pbu3=p*Nb08^r)2fh^H^rpn zkvFFol5au)?jrzu*p5}lUTLSh(Zx0nm|ykJIl|rUeB9s(KPj{lZIx?wH$g-(ZelQ< zbSC2|JdL|-MA(6mb8B)CN0N|8F_rVgzYk5iH8DUYEMXx)0$$(WcZffz4H3u1jq+{Y z7IztwWV_A#Yd%)_3pYhl>PUc-k(ZuwoCzyetP`m6PZe$QD_GvD?8xiyP%aAeOR*fo zcdU%+`e*YiS(icmc>7^U-ZU5hNpRM9=t86OjMsk7ux-z?6LtH(sfUmiFlE3Pb|P<} zQfcZL&RYRk6MuuAs(01fQGk>C`(VJ0Ui9aO3!^O;9K@|JQTwr&Zp$m=;9sqLPDI@=vsU#y<@@+>`32wB_prJ!k8#kN5r07v;lz z>He%9vF(pw;osAvgY&_``QhNq{lO_zkJ*wm5i{pW8%V8Y))14A)>V~0ltL5lsXLDk zu0um2TFc!~b)GBANl`^i^~w45(bf6j`hrx9J^SSpjCmM%ZF1H&pj(EAZ_ z0;jtM11yli056a~!(?=aub-Pd3^arI%ih)Xfai+5CVtgGIieJ<)I%(mJxl)Gg(j29 z))sxbGA2o`~KkIs`qmp|73gLVI~{yHx>D{B zk)L(*Jx{s; zjEc^9=EcMDZ%&1k$*d?nR|R`p@~n6uePU*`Qa%jUxu7gL%FGMr#*=OET?)wZ(o1p= zNg3WzwT1AR_Q7WK=abmain;YyrfJ2+KrS14Uut6bmEG_~nvw)Tvy2`9_ zO0cIoz1#xWvYZP>#=BNw)UcFQOIK26bk`H<_a+he+HV8(M@8$MUaNge^c>MErQtt< zDbWd8X4$ONR_aczxE%N<`rIQx>D%9(4c@u4Z+0f>@ONJa!@PK@SP}QF9g6a?{2iHG zAgz*=7t!O4%;kDRtI>ixRyl_If9?P7@TC9C6JEsjb~BAlol!U9qtLR*+A_&=_VR6` zz1)7?(7w3=ZGt}Mq_ck^6*?oOB;#obfNICzSjFZ0W%v=MRogTMfN4otl?Xh87%MrDUAUB-wlq& zj!t(}QR0A8`~Kbk-xmicIVI<3T~4goa8&7!Ue~f+ctEZB;n+3ergpr`F82*D=%G$tMIc zt16o^ah?)njG$r&fPQy&@XHa`;Wq#)X;0$KZsR3m(D6fTr1{Y^18GzRj-3h(NkG(2JFZ5m9IKSym zRbU8}(+ZeBP3`-{PvtBX&n)F=4bP?2Nro}55O_C-Py8V(;CT6}I(^1E>Wn%Z@;Um9 zb&N7@e90|r7~+q;cb}Vw_>EsY{226($lYWBj1+HuY}GunepDk2r4%r!Nt+tDFoo3+ zH%zJfdOCq5zX6V4R~w_AG?@o?i+q}NUpJb} zou^GEjc$89_L>S{y%WxeKmZ4vA9GN%wi?s`7-=T-6dwE_KYvBQlYa7Ja?l@~^cj~u zB`Cch>KV66t({{WHLAqE9PSd{k74kEpYdcKGVf{pOC=yKq5E;KodL6wz-Ev@n`ig_ zZ;*^As?cYbThx<~mZLnEkNj!;@8f(nPk#R;AR`9lcrp+EtVboy3+d3pZ3F#Eb@|1L znTu~TejW>Arm&$zHzdyTK3g8UQ8@4grB5z`X1B#MLSbw0~J(Th4MY0Ua)EWMbH zkKOIj$1;}A0%rQ}Q|GTyug=lIC*O`mCXR-KLNr`W>m7+H-q90&bNeh!S_6`7=}SAz z7yQmjT3PJ5}%qoU*BCy@B7?E3GSmKDpldL z9<`j=AL+ULS$vI!hc!&=<|*A`Q16sG6viHm>g5_fg=q^Ri$I$TtS4_2?iJt9x#@+J za&pP3wxo-zo6qn0Qr+y~Ue_2cd#bSbaaRzupSGMlE_{W^pSZLKj6loj?~CTOIW@oN zdrpe@CBo@0tX&$s77JS3%g%?tgHS7OcFJN?a_mT)1vqk{rs#Jh5Abw%Gf>R*Y&ekY zbBkMonPbCmAKDq__h0uxkX89md9J*X2-{E;htU#B5v%wfYJr4kB#~t#!2{*DxtG#XbBtk%#BHYH|4T1YIi{>hyl>7 zLuw^Sf(8~DNg$~@YbbQX=51hds|p1F2~2?f!L7}E#(HWEZUoCY$%L-!ReA`RLhf)s zlB_yAxbFS@X|18E6k)!{r)W-{?LJ>>pdR4@!LB$H?XrhnJ8G(nXu>_XS!iRiS#ga) zp8oo%e_ctFv>GGWhar_6aVjD>A#vAgU?|a5q7>OLrJlWWT-JO^>HFp zTzroqnv-CLy(9LGf@>qP6pNyOjz{u0uK4}kH!k>cLZyb+imINiH6>JO8xsO}Nq!HY zif3t`m5^Ecpe0?wh@bdY*04@XRxP+=sp+x{Rf^=ISWx4u}UdezLE+sDFSb z<#Mtp!u^xu&PmU&;**-mhAfZay9cNXuUyYld%^a!f?Y4& z>yuPh1zl>EvsXS}WugvTqvRJoP)Z4c|Caglw1L-byeh21pvIsNxr$WB>x|~6DO43c zudkWDL<2dhxVGCXg6g!fi;_yA{9EF;wW{D}%#LF^SWK4RD`1dgM3?0&wzxOZDqZNl zY*d1|4^Yllwv=Z*kde5UV^}PgR9E$&OhSw?6T3O73wXww0T38#2_~TVs~8U)pjwn} z{jC9HDP1N1gUJCp->IC-dCSLSyRnCE=k+r<9HZD{Mj2gAcbXxDoREgfY~M-hb~Md9 zBj=7a%Kyk5(Hb5N!D3#oyLn>K*lv2gsuYsE?3dZ91c z&h;;I0(p7XM$667Q1hXMrQXA2#I!gh%t==PAqbt-ZG?K>5GLkxxiK|gJ?1xk)aCL`Ar$^UE$$$TM56tmw$4ke}1x3ti}f7S(Yf6F2yJSvpyqTh<|Gi4hH1-qI~ z?fjqCLQ-_nETHyn9GX!(P?_8C-zjjx}o!8hGDM(icy77JpJanjp{2qZ=OX9VuPZUxarp+W_mk! zA90_Ie8`|5A}<^YUspa~uCPe!N*V6O>hrHmQ}?s>&x~#Gi;YoiHIJix`OIo7wO=8o z@43y3vVN^({EwTvyRTjDwJ%3)rAPN#54OjYuPKCn^R-h{_hHD}4cCmMw3KG3`F-%DE6O#-tbV$Sgxh zM2IXbntk2O20r*Dx3aoGJ6uajX3S{dp_=X~;2x%5-8(_668{7hBCw^o5O}HLvy>HY zy1lN~NDp^21Q86`vSqTj`->=OY?76CGc%v9W}=`=jSDYhA)sL1X!k@j;?P;jFG57( zLOD(ZX&W(qL9%$mi~!2i98;4H+f}hpKAH3$`;5`0>TRZnNOzj zmPh9qD@|TSx~Qtm9?4UfeKf?b62eq=UfLJ^WfvJSWo9V0-%~kD+wjqs-oR!ZEU#xx z49&yq?y0`tY7y6Y9yBEI!zTr(kLI8Jy4pNNY&g) zF(rKqc&iB}zkUn&%gUXuIl6iKeOrJIzEKKkUZ>6Qb_vQ?a~;)eEae}TU#8y1MLrXr zE6|SfZ^UfJ`6R7&HY9wi{^7Vma<9F@1-Z2Qq=c0_gdQ0>FX6iUcr!hd=-F|N75RnGioO9VXqLv3LA%RI91IN7SG(w_$ zq)~K3ZrI?geOw(T$aQf@v;fx^hZnT~ZT+am4ajFr4aj6P#G(s$$9eC8b_dQnDS&9P z9I1eifQ+%TlB)R5>Q60)aOj(l`q%D0&rZ(YyT2~3AP(SXAGRS1CT?N*m1SS{2gZ|D z;p%Vv$+c$Uesu9^aC~vq!`V6O0S!{77M3mAC>eNxTh5PgyaHiRg6sf$Ud#7a0I{kp zOB)fA!k%dW{`^JX^GpU-U`(KrXO-Ur(Tz?E%#8zgUET@>vzdKp1GvrnRQ!_NEm;^g zrR{|)$vBuZM!>HW4sOY z1sH{3E7ELqvzihoa<%8%_CHtJ08Gl*+eGysKiQECzmQBl^7F@2V(gt3H#{sZ{PW(N zzu4{*0=sU}1jSyHe&<9I=X5xvM2}n!UAQhtG&MO>C19~!@{HV&P^L^Q@TPz}34wtifXeDFu=BMW z`iC#v7-RmOdGO?5bwg3z_EzKO(@nm^Y2hvj&vQj@;PALp%Nc1y8!-mzkEs-Z@E(N5 zH%XN{q_VR_z})Y^+VoC8$iO9VJ&@jIVeus~uY3<<@&IgD@a&RCtURKNG^x*3K5t>7)UpLTQ$j*~Hh-zfx6(d{AeheWK zJ$Vn{4*ZKKH5H;(>u#|U;cZ1vFf@ccnK;phX)d|!J}r1J)6l;oeQyz!ggmKRqWU{^ zhv(8M`T!vf-gC5oRPITxAEu?QxsX=DE8WS$Hs za0i^})@CpY?b#pGIqFtZN%?lLq|ceQB=G3VbGg5BmV*)hLJe4C-Vj=qU@)LxGvzy0 zGH(wexC_UtaorU2AQ4aVbTmwIp#i!JVtnX$H5+#93USw3u0R`|4Z|TDj4W)6Wo^$@Hjz{%bUd&$E zoo*?vgk=vfapNaaObs{z_L8KOq1W?14;MapYDas3=S>_giZ6WkOKELqHadzEv1*Ej zOwa!J=Fgt9#5>KF`1R9)iNQFBqDEy8(2Zl3fpAeX9Uc=N_>!Zf2nBXBFWBU$nULc> z7luzrx*!rhJID6i+Neq&BGqs$wH^V%F@leN*ngalxM}C^F%ta(!^1bhncbp&sL+`2LD!k5Vo_JT{Vy9qrAy;wsF@5 zF-uYA0-VD_(!ws8=kAi(q{Ot#?4ilIejVdjlXuf}{^e>lr(^om7{j?`@wbNbZ5en~ z_;=hv!##0nAPJf>k2eG5g{_l(7k`B4W$>$^#an1qqoY|*hQC5q$k`W|`vQ9J3wM(lL(tZ=% zyFOzcRsvuXa+pW{k(3EG9z(lI=b&f9c45wCPEfhAx8CVV7dKy-&fNV4nJPEn8*T~y zKnHA8@(`(+!r2{m8DVFlF;rRRq*#nuM4QejTd``yu@$}ttTDUE=kt0VY76v9VXd}! zrRrk|^}2cZ`trwRRNsY)@thNtCEC)dQhbU1_lhxSaaHy{r&?Vhhy{LpK1{0nDj3w~ z=8l0eds}$Ha{y34ufNT~7E4TB5Nz?L#5XTf+gY`g-IU;|({w*@Z&lEH{tmcERI8voxPqaR4TeJ8NdF4WZm~ z{PXUE)lAX#1>-42IrAd)lz5FE6U5VI$7|1f%+<n3%HH<+~;fE92CY z%1pTj-md#~9)v7`V?MX4q(1HcOf!zOu2+=P8pqq&rPO9>p>Mvsdc1EjQ>GSv@_BIa;YxUIh%Z7Z zgM1|vW6-nA8EW28z`@r)U$#H|x+Ztretr>j8y7+Hd_f@cTJ*KXn8HeN;7QJ(9T6u; zIrx;+UQUeVZW_@paB{G>+o>xwB+V9A>o~Qy@%ot(V3@9cS}G`*$PECD(lgADW2gax?S+J0i}d+8h4D1&~qU@eM9euF}T;ktum|xv}f#K@pbHmeOzAmW1jvH;&zFTBk`C51MqF5G$ zoOo{i>m1zKYMg`Jrgn#dp1YbOKL)0Doz_hd6|zfN>7TA z@{zDIC7PEqlB4ExBot&%Rc^-;%~M7DAL&ACj3LGKJ{>v_n%ga{-LmZD z%a^gdRiHSeJLPK-!6C9KT%7f30LhMosF!!&2QJw>YQ2PP*dinmwb^U-g+LB>EN?-7 zP1$5c)Fkl|GjrS7$-P~877{#!UORBuxrZB+yd#OwSw-wh!baz5k+an<$03_dH%Gl< zfrOG}SYVCGrzAJp#vg8?*D~3!!TtKrRqhOyaA2h6mjDPaeSoMLZpsA>;adQ&47i|2 zVOG6S>i;1^GPilt%}Sggi@kBBwh~`Z4RmJNL#B_rt^gbIT+$UnHor722TH@j0A!$+ z6zAGX+8^1Te7Np$2Aw?(7acw&xnx$E&^mC0momQno>H#{^T8ALpZ7sxosAade;F@_ zqRZWVBecWLEn79@vsRc_2u^~hWRbHJ<-e2*IQ$EnSf_TANq~D9*hSCHCFc{*hUK!j zA5qfAXLOK@CF~X5dV4$63q!`A6$+L8>j+COn0@eRq-U>p#q7VAfjZnS^$zJK)oV@-0;zKrMXcT?u{ zW@{&Tng{@u2~nMB582QKBZe2N^%7Z|xvkrTk@O}kGPd3ZtiAtp7pKDgY$8d&+1gE> z331&tzaRLfUGY~Gl7lpb>^YK31Yo6{JcWgnv}!ftJutNKGE`)~qcQRuMdT+5b(9(} zueJRzjLvT3?)>_x(Lp=|tPqU*7~3m%1|$)SmA}LP7w%~9nfW%)ZWtv`D5~+$8O8C4 z{xhck+|Ykk^q;SuCZZX^-R%TI#wrU(Ox^@{ahgpyB~G~wLTME%C`5G{=>xuV<@u55 zHZQ$5-{CsZ&17tt=h;2tecJON=7i)K_XWw`T5DUWgYX(6@ZkR1oxL8WBb9FWXl#%# zLWq_AA86VTquT-dGwUEMd~Vpn0gX_%z&MNfgxw^q9Cp6B01iKy&*!p> z%oAv9ytVrcVwO^U8$`+O&2(s&FDDO*{Zl8Cw{5y?vsO^N5h9C8laJ_$?nqyPo4`~A z`?IKaC&X{%EU6T0=?DQJx@bEb<2(07>85&k5GL2+k<6QH>?Q2Ax>rrXm&py>)dg4N zca!(;8lG^U+4f-nU8AOIV`oFV4Vcf`c(2u`uySy3HgNCbi#=O+GmsY z0XMAtWo@4d`I^cutq(`RBS|?#85WOG^zCevOC*#c{B~W>4dC}Q-_;hl9=$sv|3g?`oQDfN(e1->b+tTT1MPUwBqpIm4MS;dcFY?EgXgIU= zA{Nslw^`(qrY}mW@T%NpeEHB#u#9^7LP@c#*PR&ENf%eoG9`oyFcT@KQEbMU3sCEU zb`yTFe5{s-um|&LhOl<(lAvF9tICa!Pq&pr756qUL**q5%cx#LnQ|RnE;EG@9zOck zH}?AQX))p6QV3xkmqzzYv`yi+E*ciri_8oY#rdAaD?>OtwnS8U`7?GCzNFhV2gsA~f*Ew<=+z6(dRM z{+}+Oy#Hsb`+&6+G^(hujGT8GEICYvEn${5yXlFqX;5@7hZ!2ec#4=qNh)bw%?PkM?yaZ$|)^o#$0u_o`y57@Cjoa6Uenki^J*z#{JpHr4$O zzY!)v{oQ);u_uJb0+|jj1CrU}V!>rC71MO%%KbhW`e!-q3Lq=9Pd_D$7Au_X|L;jX z!XDQsFLSf?c73VpAej)1z|?V`-qU%rOZ_Bu^A5{M>dK>8rGIz5jz&trH@S8?bV0#3%8+gX0ePmKBe9!A@k2C zmz}HgpAAIc=**TvbiK}h-(OQiK@SwC=_{Q`&zCjLT7Dtxrn62~3VC z%QDaX`hqZR!Vwe!4l!(Z!*M$dsBj0h7^yFfGtT#ATmr*o=L0cRgGz2f;o|tQm;MEV z2Uoe}M6~^uvXLunGhBmlp{3A-6u`Y0xl#k~zzL8`Q%_vNj1W$QZW3>r0~`NLDtjV2 z)nueK6pIEidd})IrVV>`qYob3LSp37trU(SJPr9kv#pf{TFtpaIpV;2YyO^5DD^Y< zYgTK{54`3l4NJQPXiAuMHhf3x8}e8ZY<(In>(QrH`gTB3A{bO{WO+rhz0a z*1hI}z!9|tPH6sLWh0shn^>MNBhka?h{z|87;n}ag3Zm$OW9op%fDzl6@=h;QK4@bWM-n&mhZl(>oP>F;0C<0EtSwBY<|nLP-Z64#Q9 ztZ@jt=sa8i-hAKdxtG1$*$w2kHQjkb%p%I;5kHGM?9a*cnvHg7*~uhRi_Zp&DhZj3 z2`}9=A_=3FuljttWl#tv7SXs7y*n$>c_<3~hi>BD{dO~^LkX?$LezH%#S_2g>6Wk&8YO`?sBR-AYsNwX zJpZr{1lezt<;1lJTw-?%XXYlG^a@%@r_*6AW}@$QW{oF0hcq`uaQFPsqW42?o7aH6 zf!Z2qN{zqKhv^@ZXCz3x5hst~yI}{SwK%=;Ajwf+CG&RJHfYMME~#)#g5v6|6$>7! zyewB?gUTmfPRgFBelYERQNDTW;f>qtlg*v(7a_(frIian2-(@uf?&Z{OvA*)5ZFzY zvUG5cz1=UNLA0-RZt{ci>@sCNz~4MCAEj;k^oiT32@=FaM2n2z40vLa`#^%fLmFw1 z3`Ph*$rBzC8Rm;$c$0)dWGWw!n60Hxz=p(AD6*KqYv7cAaMjqBMLdaceQqq{_9FeE z%t6~>zvd?1YEACmgTk&XAIaay8vZ@mbbfjE@G|1uIlSn55TbDMu9hCTB?tNgJXoD| z)d5QzX3j9?0-r;jA44{#h0XLRS4Z!UexH0HoP z0C1CR1Ouij?EJc{`jRXYJ11!cG%+xgcR+|%W zsUmKl@~*)lhMVBdi>_2)se?5Oqu3OK9nD1)#bV%?AqMUa>PusTn!~9XHLxs=WYCdm zENm7~ev@PB5PbPzK+Vb%u+nvf0_5wywM?0pQT2CO;)@8n9hi+!@a%2_vrm0{@Qu>9 z1di>K)%?4N=HE!tr-|UF&adh=>p^f(JRY{-Z^kL6X#WOEQ{Ysyw6_pk+R`wWhjjoc z9I6oODz5(OhjjpHHTf6~H9eTH+0lyamxg6t90dzzo;5>31|H;nJF~K!ms%MALVo$n z4yiW4=_NZ(+y?CPtgr4*HnN9zK?0nxZo1m~+Pf#c@Fe#?&i2m;~$BP#* zV9g&F)?;82yc>feaMt?mq4!Cqq%xLcSEae+<{k?)jJPeZB7a!UiB=lQ2x^wLF3c&< zgMdH=ujPbq=wri_`uS-OfK121POC~Dj2exGK2k&iu?3~urjxli6?E=4;Kz#v>HPqw z@k>jt1eM?8IrgASU>((S5V$zjT0Xn1RWA^eVT}TD(Ha~H<6Yymb{^H)F#}d8GmV^E zj|)#hIOKWX{+e&vPhF!V*+kebY64>x3P}XtHLV1@fp%@7@f>*ZV<*ZG)HF?OBIeIR z*y_MB0cSP<48E9F)43#`qi?zQB-2I`{wz>bu5adx5BNS?&$eNE9(Vvozmk9MmzH@FbP}>yl`x5eA^_lhQ%%v4A{bvV77s^i}Ld^se5C~H+dQZWRKbRP!c}6YRJxV zpWf>dTpSO3sHd+scPyHy7kL?9!ye*$OQn&%i2}H{30o4#s6xKYz@q~Og6Ql}Ln}Y> z)$*GSo@11YvIEWoU(6sLD`s=kN#+1ZwZcpf+F}S0-M|xB^O5!p4E(8oD)55f)m3j+K)WiiO41S`I`Qdp<4BxNHp5N;K{A(Sp^9!=Ay@moqyA zP6~?R$kyXjpRp;Y2tw%>TpBD2!zTc0i1b{Ivd`Avi%ASlK$K!e`b>zXeT_%^5=cRN z6*|sM0iPs<g?a!)=`wQnb;mg6G3?(K##qh;{y+nS9#|UazgUw>h z3^rt~59H{&u)_@Skq_$Wu09#Ei{9+#;oBHhhJr$*=&z>6>nc?kl$md3)$pc67gR1U z+<+IRdx>+}wa4#8V_W#J%d+M6;IV>fa8p={pefRrs1RKoi(kRalDCdfLxJ~rb#B#} zAE)La@n$?LrJ>=Bp6u?zDvxAsK`rePYg+-TN0cb$-Mc?_0|fj$;&DLyeVP_jRgaUg zSguu10)YOGHh4jR-pi}JLR<_d`mnh^fhSu=AJ1>-5~yIqDY5@{5kxUcY;YwH(3g@% zgdLRlL9{|#_Qa^yx*7iyJ@i{EaRarqrU!Kwve3>mzA2r5u)&b_UnQo76tBw_+pbOZ zRfe(_AN)%*>lEX#7tPuW?U0OkbthO&VxUXYX?5%m0B~2#td!T$Q-KEnh~TIrXq(l{ z3PVCEQ}`XxK?zx_M6F2Z%2VMvadTuEwz=Sad1+-FFx$Qk1trdI%Jo%_n>fd^0fb*&PEL3b52!6yif&puqMn&-n8@^!G!s&%dlX6X*Jy(YK7p zyQ}+cd*TG0N#QCuPv`LzM#c8|7G>gbSIJC8i#DW^Bo(+*odV)B21{CiUXeV!8E1fa zIPSM&yD{BU?6l^Xw&HB5o)fl=BgQS1gbgTK-*m%S#d@aIWIN!CC zy^<7MWPxd@5L;b@;!tQ1s^Z4?)3~R-yO&dqSr(LVYK~L)+0aayak5~yL9|u_hSyZz>EF8l5xDSofst<3NT@-2!(RJne@cR_J=)k8($(F_OKkS*^eWxL04-!O;(l zB)F9CFKD1Q7#b9MVU>WzqjF=A&_L)dn0cM7`R$6LTsANQ)qt|rfIpF}hufmXD00q$e7A$_E3g0Vw>P^2?#0_KMcVKf2gaK1*e$(m)U=KxQZf zqFf#hfK<1|PalcP__y<2G@DNgKYpC&-LVyfN6 zp?!bB4B|P`KL)JO^R;uLp}*h5aS~cw=xP?FG$7WM`wHO={qo~qG_!r70LvaUt>rjd zE9s*hga7oTK#PNSBk?alkg#CN_E&avhQ!LSBW?ckIUIqE*Jr$t-l_oU)6oR)%E*fW z?(-OVT*$lBM*M z+Foz5t(Nf$o=r?4U7&70%bu+n1y^dvV&ofcvO5GMMT(}w2baHxBsih#kW!Ib-C z>r72z7FP}def1}0MO!adrM^S+V({da19>deta)0Avk5sxoOFHA`DZ_2k<@I6kW zry)J&2{`#CU>vQ>noE~9^Tr=DExjuCQ5#uT#sLS4w`12P{W9XIg84~wrG8y!cu-GG ztUQ`i@a#(ZWQ(%$z*@m>FOkp5pKbG=j|q?cZ_B-h1rZhBSlpyW4Smu9Wg4Snh+)c{ zkgmu_Cpug^d_~ain4cx40+`E*dPFm-C>jcU6BE<}cQ({W0*=aW5Q%_%KJHOa?{bWH zSD=>K<1S?S5ek?sg}3Qa={eW_!?8tRq!Gs6>x80H{GW5=-ztLRd=ok4-rKzlFR~w( zR(~Gs`#p!yH5pFw)6m8Yk0XNEJm(}d>n8Ua zRyYhS;W*B#qiBa;6I+JU3ml6R^D<<-E(YUA+Lxr3=5F#EHY{C-X`p6Zgf^370ll5I zqp<9EaoPOzS?z{qiW~W(#*c#IcCy2xn}6U?L)Nr%$rVD)dnCO;%B&xw)lM&utPW!j zb~!?hWFTs+2L;P>+6v+DT!zbJU){_Dqe@r29F@8mZ$efD=x?QoTI zyNBBs@6g48iQZzf5jV3QzeA&UA|(492_inR$Rnr6)Aomb3r((~PkViGl|GW1TcJD; zVd}0luEOqV>Ryv?$YV^6mzk%TG(nhFXk+vKjSVz^Vgu>XKel-l*CR^HdEapt_4y*t zZ1m~Ld)hG5j&9|_p}8PX^GK~Tutep(PZS4JX?ms5gB$6~^^GZuHSX6~_bWhLU&^qr zVEKLF3$Xkcle@st1*#5@4^2gnTcacG@Ui7d}{(&3KfeSCi1KO#shtm=g;-UHI~yy24B>;IXMg{?AuSVpk? zuWF*!7sHgWN!H~ag4~Jue#xYF=m|WtB}D=;f|tBqbJjHfJ9~u#ml7S@aEK90aya<# z^EfqIGlM(kQ!B7OwT&sdEhBI8jwIVnH<2A>}tA-AC5R7uy^t-3Bb9yN<7srx}!B}UWd zAaVwzZuVjCj-5anIsUlv#=s$2JmW(@wN3F&0Sheg9d5Gk zn1Y84R=a{S*#i+4!!0GWw~!!6n{59a#i9IR>I$+JDE&-n^i7=RfaEKD!FJMV;|$q? zoRgfXenp+w&0!=Uh1(KyK6n{l_4*<#jls!=;$&8y38%8bS|!@L#Gm#r#~*y{jzfZI zSZ@xx;58!=2lHZLD&u$?m8}%(VeWcN%3SYX-KcrCIe;X4@-&R`J5%NyWKetMd>1_i z0M(8xcvSJ9uZ1i#{!L=$^fUQpicvDk-sB0^Yg5EO~9)wQ3MQj{ZcFY%B{8~LA61FydSmnz_7EjHaqtJ=;e zcG^yaox_PB@Zj_)ENdr0jBa*LZh?)MJGRnG%XH`IxA>yCNg}_y%BmSegzE;jy0)ir zJwv9wiq!4L;~@xVOP<25HwbBE*;T z5O9Fy4>iw6TXm7%COV!2mI$6# z*@gy=4fc@B!8AhPXvwDI|8ht92=-5Pl1mK_15JF4+{7YiqBt-w`i#*B!&vmu4@X8I zI%>tFeQcYLJ`5xXCxN_x>$WhRo-y7Nb@(E23`QS6f@9}*Ne;Yv2G6S>H%9G2g_G+f zS&1x9|D0ed)fTqik13RVijqyP-aq&fwzf@feU0IYHvgB_)JQJ^bY zlH@N+A9>cdKR)0S=Q&zEHWO6m_Nc(QWVrAj;|NMsELELzcJsyI z0LWzf7OKv~f>F#*4U81>2n8rEt#SnbA4Ka*PWQwMOZ9f?-tL+MUx<>)HT(@`DcSeq z7iNw5Tu6mlxD-|O8^TdMbBap^kHUV&&^1=iRrGh|G61YX(7c|MdCejK19x*|!suK; zcvZ5Y()>9r#^>jSQ?LhNkBcd6{=J5z-;36};B#_?am~R`6?QhrCOq^YdgE9(0D6w$ zaL?aU<&n`#2#5baRFJQ4vt-e%7)HNZD}3X~V2dVEBGv_j)?GYW|6AWfU+=BluD7)| zS}m7df}&B-Gs;{yu(@`cR&n!ZA`9V$&K<}y4JpR;u)zLuh+EO19OyMYG$de7S3Nr#C`*|=^9Hb7lDG;MFJkFKl25yOoxjTt48p^iVW z4SDnn=DBt^&MeWf$8ZJPAg%=yxZ@f&6Ri*}YXpaf>*WT%zL~ViJiofbwNk46DHsL6 z!lWv=AfIRdc$7bYg(rf=vt;ifj%ZJxuoti6j&~p=+}xrf{ks}fv0enh3MjaVhwUW{ zAQ)Z*x{0N6M%TN*ZU?pLAmR=MFr?(zZ8|!AMrsHQaK0D^2ZXUfP&ZIpgrUa@x6orF z4GHWaT>1GP`3EAoCse2(I_o%393uBrSIt5*Q*06|UC$UkBK>KQz&8#VT_x)_D`bPs z0@f<>k6oJw_(f?j8n4ScbGvojLt**Lnb?mCwECvyy^88OANa|7>!zKjso;?<%F&^+ zw@eKQZ#UnALmT0to=klVxP#SQp|PLc7WvMz~xKzP(#Gun-iw%UHmA zE0Ul8SiLWuJ$5LkV567z2U3ZN8 zqk#_F(DUMo#Ff;+aX!o6d;rA^nZqA!^PD}vO%y`#`WcI{hn8N`1*v1upbBLd4!4TP zsbpS=9pll{W2LxXHk`VFfET;rq{NCQ%^ppdn=qoyJdI`%4Duuxn(`)-P=|S9);E0G zWHY=4w=r*vsq46Gda@tOp_Fn&EuK{*rVccef96Q(~sL zmdrLqo)wUeE>c9X>E2W2*41H9`?sEMC>7@aX-SAbC6m}q+uUSZbh#s4kHuVRC!jMg zWkVJ)NDtUdeob(bGfZeD0p8bg6g7CnheZ7LOe_i~f54bTDPmZz=VTw`ut^c=w3-L0 z-BCUP^K(@1`Dy(4q5(N9-&Kfq5Br#dCr#6CFR!P`W%&pNq%xI5iJr1PH|0*QxxZDJn$LGvU}H5JDn}K?v(?N!#^! zCY0DVTtqUq-Zhqr*Jze}f_T1!xT%Ot_{^=IyFOC5U>>(YYPW!#G5OXpTFO z$0e!+TbzFyPZl5HLRo4G*m>eVgiaMz+>y>*vxc@(il2rN6lzdu>L=mSz1|Ta_rqlY z$zpa_hr5WYGEO3Hn7>of9iR27eyCr2|6`j*S_NYU6A`Xw!voTra__ zluJbN!RVWs7}zXNYxLXOeVKo6Q-x#lTVF4bSpJ_&b3$iZZhl=Wc4DU}Q6FLt8(<$y<$rfQ8= zTk?%lfs$M{)6_F(_xGMfpc|7I&}SKq!t1OG%3jR6(}+HFOzw?B$T_s4($|`D(~p}o zx}NCdxyUrto+d*BvqiXXL)KgRpI_W0_|yklbk;Tj*O~B!SD?O&b4;8s_o^VF(+@~O zM{BJZqYQ{zGmnhUX`Q;!`#xXfWu$Ble8tY>W%HTm&r>sF$jHX24Jq5}=0 z!(x$>*7GuwM@_9N+v{?`i^ujAKE2M6tcPOhsFXIV}1Zjn|AZM2s#96(7 zmazEO+#0XD5n66G&`WJb@ta}SQ$(kgch-VU9Y#^m{eLjkc3H_uNuMQ@@&Xcn+zK@N zkUb=F-3MoVOz^os56wh~InFJ#x2k5=rFHkQdKz+tj5}2Rc$urT@JoctA-dP=ZgJN5 zAD5mO`mf4j1A#Fv5GauYS&W`Z-p>ssdvWetjhSUcS~tQJR1w~X1?Qe4a7u8BfXSv) zyATHq>L?=3Stm3>M%uI4{0%AD=&?7E&c8Ip*<5-;*&sGC$)Nw8!vNI)HFI?%6F<5ckc`zfo~_P z8PA!SmwxD-y%9Jt=r~# zhf8!nd)-juA&#*MvSEv*P~KH^e1K85RK?)+ZWLIs6(5@~25N@f^1RJF}$VxnM&&*w?Se&;ifsS0fx zFkV4NDKM^&L#kFtJ%U4aumX2t4TJwLoWQ(G4(5);s#gy!^Y@SwD<(aQ%f~$5qhM?q zLP!w1QL?lOZnXQwVGl7_B}U}H3@JNcO%> zL1U)upU~9apl4&|>o6c`a`ZmTKfh7^6|psEW!RxTyf`L+tM(v!{hEXyvOD2X-bT64 z@Na-^Jp=7xe4&$Eh3Sv3@#5`mo{`~y)IpZnjY-u0Iz+zERtJFg!L2s})VUhNM;Pb) zPHl0=Kv=4X(4R1AMF_k`8xr?>(6%^$GhGvvG-CxD zqB*3LBOe_wq{AFB@2dylbH>q`nut}!=-e!hw7VlDMwezzU8DSUmsx7|cp4Efq#gdw z3BFUm1q@jf7OfZn&$vlggh*(OL-{c16%gXk><+v%m+{9%`KY>A57yPnp{cU~v&y6I z>#t}5^&wg3S%tVC%35l*Dgj0Zoj%&-VYvHQgm#5|*IuhCUs4+*^_DFlT&{x~6^<_> z5J9<@{+jAeNvq>7Ln&~M+_|zg{mQMETS8dq8ooTT|DAd$IG;H8OPzRcLaSSr4ob+& z@1C;dbI-7o)ZHhXZe!fRUVl7ghi5T>XHwfL3lIx@ z`L=HCeq$!Kskd0K=@B`)ukdixcx4qvd5b#v&`txZD@ zqYdL1ELI30$T&`0$OdJ@ZL}(G4z^s2=5M zEi5<$)lrPv_xx{$ZsH3be4$=h9lbriRg&-%rD>7%_3F174A?|;qfoY33#~jSJsi>* zdUCGL>7E#u9{NEhiMDhDDKO;8#2g~VarD_^D*ATPELx?D5`N#Ohd8x* zYFVw$)KVJ0PpeMmZBs55$WM+qVmy}|-j}dY>-s$1J5zg&3mS^ApxB}ZAzL?D9X>Mv zZPO{j#4m?00-xP)SZiWkn`OlN2|hviyW7ibvGD~>2gn!eDlmGlGgln~LC^%|ic3F9 zUXkq8_yz3ZGXJ=Q+o#xEI1eYV)*yCpFA0!Z*Ka8m6h=ITziNv>;(lWOH?J$6I~cO3 z=*19VN-7qfTly1p9|y#a#oQV%QdSCk8$vS%x-Eeq&HQAoRLZ_ zqLC_n=xoVM@y{z(5A|I3x)V(g1B9q=-((kzR=3@5i+Eklyos-rsr^(B@D=fidWZnp z4l2@?@hqR6)k7k4fS}umK@2<82yB|=pct_JkjK6TY&B{NMS0%vavYLq4ytX~_!R`B z1ah!3(=`J{B8AQLEX>q+l}Q+?opS?GY-Lfd)gg!}FOrv7zk>%@;y#J8Lh{y*NuFDe zWkxN&GswpXg%5M#mHwX%Jr!y=ci~%k8Ftcgv(Q2@SLF-d@Knau+4HHn9{t1l_62KY zH;MlgdHw+nL0aut^z!uth15~{A{Qo(cI#FYCG$rhuJyax({S>aob5UJ;w!?t{n$(j zD)mRn|Bi!hiDu8;4_pro|+;*txOE2M}o)C z%_CO<#!qf$XNDgbHFTq@71Fd(p@XG#89Dp;tqgN?u+36t=D znLwBSb*jw(19h81Y<0m zOj~*vTyjKXG=sf)6+kR$w!L7TlzuZ!!2^8;Md7yYsIp~_|IpyoyE9VU8Evyr9 z$;!FXE1m0%fZ#fM4#X~naEOshp&RzAqm>giS8o=OmM-kl5)KsoTn z<6=S`{f3Yl)G1lVG$f4ksY^6<7iwHiL>2STTa0=n3^y6gvUeCD?v{w9r3v*CF}Pz4 zTPUkA4dDsP0Ttrbu_+{9%}GL45V;NcZZ;Wug#WBkiiLBEO}fHTGqMD#tn=%79S9#! z+ARPv6!wfNP6V_o`~abIz-l?PY-@}JVhf$kScqC#?uvGOloY%t#mM%7rA$e|rcB&`LzX zD;)|cVIEEJ;8n#AX*R+{{E3T|ts(1vl)S3#UO`sv^n5Inbep-#EgTmutNeGC*zTXy zTi*3YQ?~IjcUCJ4sP3p4w*5zA0#1eWzb3$R*B!|EmMJM>bvyy_Ud&uVjG5`bu!kJ| z=NDtsVU&i!DiU`u`O`0VD$?@SE1#e8U>}BF!mO18_vwb;b3T2U$lD*^y(0r0@59PX z&MlCC358vXC&5l?`W1S@vN7I-gKGDFf&vjOpqSeQ`R$O`s7hLt{)&Z-E^aH<8=xd| zFje0phUleZ-Qrkc$^U0+3hT5A8HD`M$e%a|f_@6D%f_yU%L^5Y&-P7wFnM2HU%7&t z^M#bRq6?wN`#1(3T#vc;9E_kZ}Jp2w0(NGuO$oI6vN5XbaVEnRAt6eioN_~Ufr3$A;fe`*EUPF{aC8kOx~O*4kWgZ@DJl#+c0 zc6`U-f>7csNYGU+R%c#wg|TV92JsQ3q7(&>VfT?SgY7P^9$5BIjMQmIC;4N0C4Qy^ z1+=A;XKKo2J2#GOy3GyGf8sPRAjM$3r zH3W6BS}ODk`WHiu#*~fwp5E{TPQBv6i&4dT$P}u+Gx7lZY#BMkUw9-vRs){LgswLG z&JJsA&g4?Kn*N)D&61SO7Yz^ykmnWM)@H9|6x22&S2)8ZDhs$=4g6b@pw}5$j!de? ztXV}WxUpQ314i5XXvS|(PGy|lyY2e>Ml{4t2mu$klcT%!QuE;fW|}g}(FLM3s_ACH z7zHBtn9&Z0+|&b@IXW-or~xvPmz3DKLe7Mkv9n9|&t1muG26c3WQ4t`&vHa9g685nGK^g8u?YH3$PUQ&<)qw{iK4bp0812)=p3&%0koK!?M1 zmtV2Au|<7gX;}!x?Osd*I4RUg+t1k10)a!GBi;sHRPWESv zFS?bdc~^Fo)q;0?o17jl-!JrpKvjVW=_6e-HKR^pMvwH8LDgBSQDkVt%DX}g>1(KQ z+pbUD0(WYne310;T@fj~1Vjq zG;S0ZN3PcvaC@=I5^-xhWET*}+n`nUo*z`~P^w*mpK>n6K^81Q4`K}gk=0l(fMy*j z`o8T_AH9c*V_=@Va!C=kZ>&36fu;@f3piXE?!SD<74kk*w|y4G45- z3HqaAV;rq}W8l%jaP837E zzp!(ua;k%m`(kGdS8xB08zVhRyjCH|{7UNHE$GDv5l4D2G6O7BO#e1+*|i}0YGYc_ z8PIgEb{T=;IP%3@89V8DbP}OzdWYT)Ccs64GEkgmV)kVC^Wq`SjlO82ji+FCdt(+i zQo=%e4VZl}>7=Wl?~U1P@|m5hW8l?(=}wcTJlf?wN?GpUm@jPg*cUGQ%WXx)QpKk~ zM%2Dl-JSFnvete>$pdq{JBu2Du#dU0QxAw-qAC)yz|7OE$Gp5{9Qo@X#W&2u&5Hcl z3F~u?MFTT+8fGlWjG<_RG2=E1(Vnw?PC6l}8$~W#81NT8zy{4`mS^zNgC0oTew@4S z(GLy~JfnqEm}Z*d_!)o66++C%!Iq%E3I2b7R*wS6lS6Hmn(Gnpo`vgS9>de%lE5K( z>+o)##0vCw%YXBB`i9t9>OaT_(_h?RJPIB$+>s&}d#Tf+-zs@I6AtD#12r%04cw{v ztNGRLJ;o5@jGl*^n6I(k06uYC zDJXz^3I?MXIeinqqZd_C{M-)PE+ZMNZIgf!O-$zM%PkitPdw=4cr9b+J26g|+vlzs z43+?*-0j3|@v)AFF)Zuj=Cc@jNu%D`*MMGzWr@M9D2Zexjw$h6!_$o*9sZWONtJRc zNCDY2qK)EsVl!&D9yu%we<5GwG0R5wg=@K@U*KVvn>Xf*SVU7jl6;Zd;u)y+S0B8D z7yOZAO*Eby7QNVxu$+UgGS%O+L{xo~EDvIHLx^Meg;hoO1+3m&`b~Lt;!EfhyR^M^ z54oWK;RfxKei72=kA^wLU9kiCS4)wnpyjQV?@t<>hzBmQh3PXK(L}`5f|k>0YBc?g z^qKySn8{m#LCyWCYN(8bH&W7QpBYFl*}JnuzSl3#9Ox($AlFBvC31a1jaG2GYcxGY ze%8dKuk$1>K6V#0GplWD5o_ofkPoDsg}?>5>skq{$EjlJ=RlKvMKD+XO!nvFR`kOP zN}7q?*3CyeQ{XQhc9?2{tM}FtkGZ0qB@AR)I()OdRt(7sJ&GbGF$f#t*S*JKMLuKt zfg<2kD*CcjbWFzQBSYT%{Ux>$N8kZ>N>AO9%XoF&9SV6H)LdkRIZ0v z^)Wm&4+3t4sW^I1RMoT-^WMsQU%fsM38J!QZN`pS-m|?(o-Dvwj^%4mv+W)sIspA5 z?}w9&`g5T9EdtDVDN`mkfva_jL9>IVRN%YWMwGYVLPX$#$^*=qPu`jvoLHeHC!kBp zB-{hJm*>!oaj$)#Zu2>MZVHHJ2xo&Mt}HexMZXpWc~|S@z*De(Ey_i-Hc*gxMiCN+ zjV8dTG^^FRFx=iw#f-C&pfe12Y57j~ zNPXJx%Es)|>ZH<|3<^DA2FwWMQp9D=A5yr|)54mD8-dbu<+>+g2BfCRnJMr^hpLNq z01d=DEzG?*P{!k{5jDuG)p&EW+Tgj72&`0{!o^6R!yuAsNsV|6#Y0GL}cqu zbQwcW*Srz%NiIZw@kvL>DZS$TM7+defk+S1h;dj4|D7J#V`T(fVR>EfWKD&_a&en7 zf_R^&*caOQs+?Cq=D9%PFYc>z5tzhm8*Hy@+(^S#QB6I8?(ZD7;uP`y1&qk9E?zm) zauD%%%Hl4|xYd*1>l?cmtvQ?VnCsaCox$y+FFq&^#fY58zA1J;g2>LJ6k$$%hZH;> ziZA!@1^15orMV@|YJr9EK@HSVY5GLk&?`tD5Ii~JR_%sqr^$<{94M28XNNnEVZl|% zggD&LZw1g>pBW@sG+&_KMz9&mo?%W`qp-Bq@{~AE&L)`_%7zp&FgTl1BjicnRJG_o+ z*+i5Copvj0afE}6Ps{n#mT>5NA;YN~>KpYE>S zwLC&zQ)PS8;Y}13qzA?mxIr_I5T(UMl#B;mYFLNWWUk^qq61FlQ1UnnSIP&|*fZj< zM-kcAnBMv>CL<=!wOg{33S$)$YkGWC&@-MF1$--KQ$oe?20@+u#A)s zwZm`Vui*oVba6<{V_jjxMg*@F|CnicL*z!cHX;8U|2-jgWC4oI1H{i)*Cm|by0tZ^@^d z6!Z)FHnk3{-ZYIlg({KkRZDj`jeq|Z0MGInDETt*e9?bt$xLlWr9g5AI{x1>ky;w| z)A5vzFthAc_hz%-W+Xw`mMPe7S^ofrd4#F@5P1fSmIwe7kT`e=8-bu zV@tW^VXpORDgcdi(iR`V8<%otaQFKCy~0pn&7??!M(0KgY^~&l1GDY4;zpFka(Y-N4Ag1%^BeB{Jt~X#gmVvukJJE@gk4p{{eD-hY5} zysP6`<68lVI?;G1v9bMOt2nVC2=b6;b6%2Ovw1(;s_LoeHtPPo|IAU!8m>-}@iX3{ z)Jcxpu||S0;Q!C?h^_rj0+tZXnK&H!i6p5{C7lngUn$dwq5wY#sE1aW z0iXfW&?#3RZ?2Dx^O>?2S?1ZqP`12R6kn~A%}e3{ zKnuKXZ7T^hRcVUf`NyKy{@a|H9r^72+Gg=`84I`ha7G6uH}Y7*4;C>F+fQs5&_#Kp zq-sYJwJA@w`Kz%drx_v&@LUK~nZo!k3C6!E%f*YZ0r!mDUOYVD!(&u7W_}~8M*M5k zGNSs8Kwi)eI)2uI>5QWi@e|;_JELR(A7R#DS#q$<1k3IpnMa8#-z0?#$dQ+0a}jDq zwDfos)NMHwFV{9WqjoKFWQYmR?!g0%$#o9%31h@m{`m#T^SLia1fuz|euRvSC~8~- zs|kSrRA|TF6v=-07=_z8JNRFM9M-(57Y7uaepi)Zq}`2h9H+_0f@W(vo#Kaj++`|bm9hnG(c$Sq%G$Zr>gJ)(rncVX_ii_l zZMM#y`q+9C(t3P9AY)wd$s0zK@mYf~J;?*4_6uy$I3R51#Iae8efqO@ZEfJ%>A&Bq4c7q(ZIW-p2?SM^GbM45nq2q_hv|D~ z$~~SD+BFMtdD=O>Y19BA0?XrXGqkZ-v)T0Rw!m04H~Ai&qfDS+Y=ky`qS%r0(_PFf z)fc)o{3!xe)wL~)xJOI=9P^ht5=JF_yqCTC_$Q1j*G&X85dS7e&KclcvkdMf^5`L! z>3#^_xK-qg-&KMaO15acd2=r0+baGINWHiOCerKR&b~w57eI!qMBQ(dAx4{ZRJlLU zvuXa1hv;|hSM+u+8cPUbShy}QS&<~O!Po^DOvY4ykUn8_d^u`74vq#`BH&akeaJAJ zIylpV=}Qa6J%9)#qc`S~89eWug}lb~t#TAa^qBg#^_nXtf0=hEFH6P&SIo#9YyCoT zcA&l^W4)kmD(&L!(5<{iN#GU!wYRKUVoiwvYu-iHeUm1C#CQ|h3?{TATFcY^%9=)! zE+d|jsrrYX^W$+xxxPH>s)`shg=ct*#k}ES5B)K{Rd*4Q2MUX=-yCLu z=FE0by@?iE_p^Los6R_YnJj@p>4+;j(cbSAi|{y)kCCVFofAy)8k#e|#7q<13Vujc zx-|4;wapL*&y{Mq8twO9|3Mx(K4d+;ANj1-&=FEPyn0!Qd0YJDo;}F52+!1KtGsdf zE2{n9I@63gKvmoupEc>Om$uXJ?d~1)eG{%_2HPEhgt8$a2K?Y53^R}j>+-CZiX*tq zqH4THHXunuN4yX1x@dSi^ccqogDG%h5!Gpu$7rmA-n;keFWf7+gM*_RR8ULFz` ze+J!TFKTZq&yCp)p9H>I_fyboey~4Pw2&7XoKu)(hPmI69#$3<&Vcjh*gQCw7JEo> zStT-eo!*DrC51t;Kl3+h0ryMnDJ&Ch6lYMhUgHFlgQZ5(@gKD31)Q$LepJp$r&yts ztA=S=HH&e!S7w?c2+)SesEvdr(E}We=s!iCB9Tvj*$wO2M^tk{XM+NIs>w9CMw@z3 z>LWXuU%;hQ4qt>OBd=N@V)E#(uiR-0H07lg%LAlu6!!#=Ds&kXBc}g|H zApvQ@Fs*ntIml@u_dTjqT`n>F(;6`oK3`r`yvi>_08(j!BF)p;EZyVVNXcN>X3#QazwS48D)UNO}tOy2I8=Pqj7bRbc!2I-g3FyzwcZZ3MVG&&(ue2~I zMFQ7du9;if2eZN+O&{od*NSmcSDixsUd*zO zJ{4FQwhM{?nS9eDOJ`qemn!NjzM5HKN8hSwuD^2>M00(8*fR)dp_cj9+-tXBX9JXU zt>6yr{}~qfIUmt#&~46>g~Jak=jDDOL6f4NorQKM)p zJYKib@Qo~S>b_9Y?&owW$4^Ar-aJ}%J-o1N8E!D(plc=MWlE&fQUmrxMq)0r&~Ah( z#(!C{9CJ%KBa_Cd`Z=T%V3gzYGLF_smW<$Q@7^pv$p!bZzSYkxz_%f0`ZJ}R~sxo{ig5saRkA_;>Kvpus|8wwr1*+OGidE zykl;x4W!0zY-5kNRf?@Jj2S2wrL`w35!$u+wakwJIh{!JuzZ?la7Ss#OI>$*|B6ue zxW=?Av$IvHN^HdgCq zHw#Cqgju?Pw0xjoXc&aO1>Jlqemzl3Qjz30eJLVT@3Y%hFAu;FVc^^3&-+}F`eASehISdAcfOi#cRrYZ&Qi}WTw8!l6zxe@oNI$63# zo1W<`9G%||s>3$4jukHKA`eprDFmNjmR#ox6nvvxf5O;O!R=F@ z^9?PI(u|)9#Sb78K}iIhR~s1~vZ#O_PvueWf>z`&CE{Owo+j~N(}V-hrc1BXZSCAc zJ6dnGqV4;Yo?PMjPuDyp+q+JxvZoGp`Xgx!2f^Bwd$r4wb-!ZQhkuQ8@{g665_rK6;q~#Z}@=a7$ zaOlrxUQlR$hwpc8E;I#CLEWq$y#);;Gn(|~Z`@Sf2gfW0a;N8Nm!aEkPwLmPO<}=w z4^BH-bGvQz4o@npu2!2v-fTqhTxBz-;=1)SK937gTh|j#$dYh>k61sn<^EX037^fm z*WXrjx)F?vklh5Te%Lttm^z{S3((U@N+YF~U7l*~tPk7q=Jkl5<*q((6^52@od!6? zmNUy#MEEl)dFUP&+sFW>{DL7E>{QM5{vk?akM^=Ai#2;px*;rbG!j9N;Vh6RL zQ^_~PQ2fe z%maCBa}%(Tl{r+}K+MJm{k5XGG6ngl#n_ z>bV?+@ZqxRylr0*P2xu~)-R+TmpxgZRQ|v#yD&rU#UU}=6;S<=e14b(`v#MD45&I% zUW&Slbai|4S)w(^ISA7j67gIwvE~VG>8@+8zp->I1ucjImTALa6AEYRweo~)#v0X` zN2K8%q^!Fy|A?Y&(f9oD$)tAC(Gvva;=_KnlBd3BkYd*l81v6ZVsKfg#btf6A$Lhj z0PYK_=W*=+j3tT1$oRA6Wz;-9A9r4KW%KA;ELE+P8a|-W6B zohdc>3+i2QoZs(b1kI?*0 z-|Z>7J8Jf}K#x3F0&joR7;dxpTcq(eC=uY554_MppdkKZRte!Gg1mgD9^3Kt zkWyjkJ_-8Wf_bl+E~^5;B4Nf44O1R8=zY{NB=Y!~&& zd(+_I3fZ_6N^#S{sSDcHji_=fdec7*<&vDmAZJo=mX3gs+RIR4)csz@{~Q2*J4=P2 z1Hn<#z?}ff$xn}*3*`O^X7$XqXh5}f-WdBLti(0XCupe#L#czrKbAY!rqyQcGImKU z2td);Y;qdOaHOyLO_-$rI#y?BzpLO`G}!!KJv%U`Z(I=}wsSMZ5b7|X>RkM4`hW@7 z%5+Z@1pL;ed_TCg2*RiI_#ZM((vnM=ID|(U?X;o?bAHuaACL42*`K|$HC^+p#NVwjHMWOmO04hN=K}y# zGngov($Y|A8^UjYQyx+xP>JbG)^CVW2K_rt#)?@>lGDnbzn!`Qm4ZR!zsIffrvb(l8`F|TYAI$`sZE8pYap#Ph zWS*Qa8DmBJ#!;sU#2?`UG`r~%>P(15*O!3bF^O<&}i zY(;XAc*^WJO7mu-EtgC>w&j1}QR5G>u3L}Y3lgbOKiH)s$;x<$A&kZh68+pWA4r}2 z!@g4({y0R{aj^RCbVg~GIs6ERioROBW;5V5NFF$Q}2HXw)Jd zC{2GdvmVA+v6GfjHPBL5b1vVbY9)Q6k|4P@BYaku;W8_oZHu|cY;+#dXg4b64hw_= zhKe`LCu&K=TR!KGYVP0RM2-@*Vvf)ka7q7^c^rLzzbsSsixuLQvoMEqOFspn%KLN< zCok9Tk_r`d;ry$S2p26OQvRvq_MzDRvph=j7lZL59AO{+SwDhtNjR@G{==*bz~lb=SLM9k`qT>o zQ27_|+o<>(&N0_9Y(g$%^Hc_2G8N|kVN>X_T;9w!+rDV)O%UZTFY7SoUSSJ2`@n1a zJZTD{W#vupVi|M#eeAhu4v{*6Miq`x}u;sY`%G8 z9>usuO$GkTW(#Pfz65u)htRo=H9X@!@mNU=1By`h(f?@;izq{Vd!eGbg3~e^&(1~+ zcnG|d;8H(dA_JYAm+B^7sN^|>x`vLBJ;4)kZ+fN|5`dSpG|sKxSq7X@M>~&W&3Z~O z5~r!KACkFKWMWhcyQ(FB7c$LThC3nWQ=xCrOgR{Ugi`=%qH1Mv7^}?gAu-p%Ejmxh z<&4PQ?gp>_$+nyKeec=b5cWp7mRKwM$ZUi_t7FTM!|vq=#{4+t_msZiTtlf640*8V z9bitRJJJiv9N;5iZ zf8SzsK99S#E*n*=-6L&N@v_D=G%20C=gPrX{u)mp&}ck=m2Iby`!3!YWW1pbdAV*y zd^#1PUMbPy1BQThgcwOlaGGaGlG2Q7Z;Z*xEgSfemA#(~wxwulkw4aJhJFct&ra+h zoO|$_ShU67tO63;2!8ja=YMix@@DET!f>|fmRA0@;yxNBN*SHn&+`xFu$L1t9y~v| zsa*{yw>QHtF*&Jz#Co;-GO?(&U@||dBr{;n`Tc=)Mny(_G9Q1zNx(G@#fgdZASb!a zK5!BVTVW>-Jt3wQRt>|pFBa2|9w0|03Z^!tT4n@>MfNNyC0;5ZbL_dlmj^Iu7MfSQ z_@Yf$Snvu$;D_F2IaV)HvNJ=KFiS-j)L{7f3u-(eH}|_uvm( z2ICnKn4u}VGLwInSYXVjCl1REf-kK%=7H}}HJ3@)H9^vyTBK4xnI2l2lhN85d#Ut7 zl+&2~a&AWZ6$5E)fSI>|CbX=|)`d`%;*ZBTSPFQEa>LW#`fBS~XkQ%1r$f77O*xEpGQK zO6yMczh>+oHQu~*jT$d2v}jfZ?-g)2U3%R!K6t9e{Q-4MiY@vB)5k5vlb!uhru^_8 z@>B4BC~m%)P?t3LhlMSr`bhuvc%f3w3od34?u}9ps{$l_RE$FrBcV-s?(zW!LS%s& zH(%9@k&YLS8?6gS9VXP-l>B8p6Rvy%$PdO)#u!oKrM6gutXRXajT{YmOufZKlw!DA zl;h=kN8o=VMoBpa=3)y%ayP{#L?q(I%(5mDFa9782e5I1qE00OO^gP0h=wKN60(Nf#5Xw_3I(DjqqjocZYEo^Xji-w<-dwd%^{=O8mkN5K+f>kVfoYJt3{8Gs+WGC1dxtq) zQLoX!aPn}{->pCAtCpICkXY1xzrVvBeum=-bkgNMqq)|7$t)KMCXr~{);`=j?Zq#f z*)9&=)<&UU3&a@A(3*t|U1RPnpscE#S^hcu7X_<2n<%8MB1BQng1&m2u(pIB1X_5} zINvH}Ewj-FH>)^!1q+ab!=deRztStFg$4DM@ghJgvo+g_FdnHs3O2qzyHQ;nSqOI_ z6y6IaH9_;(PU^3r7A0~vG1#kRSu*pgz-WVxZYszIz&dlFm| znF7*8IuWo$V6!ac6z7XMtw9t|Wa&J|^EgvrAR?c(piSK@aqpebRWW&UtRzy7UZ(vY z>U1r1`!Ho@(_*;t3C1-7yy?IMa?&-AX^}hP>TAF{n|Xjv*Jt^O?~!Xi8}oMtF(6ne zRP8iw${Ck9HY%zgXyDQ#Ub>qe7BpoLY=>zE2rm9^y^x zMzCk_nvq2|L%&1onSrO2@iaf{I7z>;9aqn~3eEX4ufi5gq*YG~aLG~g*~czoZ${5c zCJo8du-T_nODV@Ro@)yXRwG|jQ2DmQa563CPa>NT+Jnt6W*BA3_BJfJP-bv z7lqf3kY`UIXg8jIMom|cyix6CkV_`P~+L1OqwfM<_V^+1ZrdRp5>mu zus*fG%FlUrW~RMfl1`zfVD^-UAmh@K18PIsU<$_;!$s-Q94MI5jfjf`Sjy#=rkC8L zx-K{8#cG0OiE))p?^SA@2!^hbRa0sRl`OEwz2n(@=b>Wn0a>P{s%8u%_^$viUBR?z_%U`zl){5e;&0J`7V$LLwks(?Y~e$+uyV zrS*%mG}-hQSW8+zQkZ`Zk1ySu&20*jP!OQqlsNE3`;UkPO(G@A5;G-_-*yc?K*xQe z(IEdrjq7K$v?9B^?k?D|%?_0FffJy&%Xv!ja^m3*W#8s$RDp|Z!GOlRkGlJln>Z|j zx#gII98I!8g4#=Q4Cc!Na?zU%gOW)s>ey)lij^D@w$|4<+>mS)wNr{vRQg<1D9`}7 zy|)H|cJ?nKl?A-*6Jyxgh#1tDItu1;s?1w{lxOoRqTyv^dA$&1i3J`|!}f_;7ss9M zQ5u_w09822>~MrX=^lI8G&%Dmfy6Q!uGN%CQP+^^qoL@fy5AOXwnU!nNmcz=(<<~s z?_i)RUDVJ_3cr@t$!OtPeqJQ(o{t7Ux2X*)p4qpO_|80Va|VlA&iqvB{LX^A&2aQN zij3}(0~U*nA=W(aVU?oaFuO)oQkTVl7=KA=tz#|`e`l0D)FK7s#EJ727YTMn?F;!3OD7&}t$`P>{)ADsq_;jhf z{1e3`3E@MM)B^?Dmt)W;k9f$@v}^bswz3eG*&ULLYbZ#i`)5K-2IacDtE`^6$LPcK zMIBFgN&^v-mN2dvyM1wb5D1k4tjf+K%lfh^E86H!;G%dBJyHpTTiToqiTb zArM?|Bh82rW99=S1fGcilv`Ooda*2t0r|X)y*@bMtI#F^593mK!m_#w^q$D|4!`-^ ztid86W$aqD)sw6eN-xI%6QjY?1eAXXUYA0$-rIab+NooV)N_2khHRp8J@MKuree;u=jHcWWh{8*?#J48vEE7!%N2`B*9_g)*p*YxHFeq<AX-(cjmx;DH`G&9ff);X~#e#G3MLsJGw=d?&HDWorkHq(P|yysXs4 z8`#Y*#emwJzZAO=F2)`3#y}R6Q*R>SBoauFeqI-)^o*dh=gfoF6nAPrGVu{GJ$ms zsHY5<(zjU~@Bu|Ey@aUzlzuUiUVzGya7gzLZPi16L5#ba%6qBSMyJP_)NoS!p9&?) ziFw)TBIN&mOYXm6=4wa|?`SKy9H@WEm|L^YJr5&2IV$DY8erY{>YKQ7dZrp#Y$54O ze^77GnhpX|iE90bRyi}aA}4%zCBk_jR%Vphy=hQJf)SWF-~oj&PC{Tm-_Xk2?2BB} zv^JFDs<*Rc!Qm4l8T0^s*bXuh)K~8`k}o>u;fnk-7e+KCy z72u%a<8_n&u;C(6&Q&xFEXm<%;Cp5u+hg<9)(TGWq6V{LtYIsTh6fa05%^82iPgJq zMkD}krvwERN|wJA|5BNG{x>OK)4O-O zcr@A%_|{GvBuOoQ=j=;a50Gj&kCMQbKts3R@?%BYZYXaXu$e2O#9DlPkuo zSY{x#n6goVF6Y^H0pMbn5yqX_!fH=O@Re?<{F`)l%^aq$#fV5sk#u2metc#K0Np4y zp`m+8NSTP5JAfc`Q&Ao8ejFuGx$03YHxCJS=CS6$f*JtRo2RzX1Vk9)PNl(15C%v( z<}mZ?+k+CeCz_4X3xBq1+#QX~R;e;&YN%vpg*`pe9W)iy-rtLd7n)~gyZdYh+$x0F zGnRsE)(4g#DhwtK!z0@U6bku1YV@x&VF0Rs!zJg5KnjS`7`t`EQ4OPOqmI@ zW9)ll?#_;tgq+z{9Tl)!J6z$D%QcVCB4E#+Y4}8+x$S6#hq4ZKg`NZcrbTzZ46YNz zCx3%W#iP=m>zUG6+S3qZttlaiM{+At>h#3WFt~Wd_zB!H)_GzX)l4S4oA;Z4%$+T& zTyqjj?6tq0B&%&@NWE`@uGD8NM2;6AWSb8~inI4Awrg`&?wb7-&%D#&v%?Gto9LSN z!aE2X@#Q_#DN4d_D@ar3$0(nIy>Y&!kV zKx8iZzD9GX(d@w+vSE0b;3Wgo35WP6?u+&uGvbYho;08C7%+!LiBpZjmNQibsJz~6 zf(c`|0erF&6Eg5TAfimw#K$YSz%#snmNpkNVg$W=vY=GVyh*ndR<=E)KEg31$8ike z&-gZ3FsS1{IIn(jHu1xV>H!Ais1H80Yn?dX^!?S)^ZzGnpZ<+*UU~7JBoVLL5C(-G z&Lzx7%s23}T-q2@UZ@u(d+zrRD|t`odHQtj=NeqJ>=tP%8)*Y8QMyBN5LEtZtDzEd zME<4tv@097Hp{$z0_^XJ%9GoFlFrF{3+PJ07!H(r4Q?p847+|~UCMQ(y9O+_Z5wRg zvw;I+s%LqR#>Vrdu;F`H7k=$?6W+w?TJo=>TKD!HPUBnpw^)b&`6WQpQg*CJCl0cd zO)h+%Vv^4?oTlG?Z={Qw6W5_$7(pZea030)Zb+s7pYF%Vhk>QeFuaxHb|_t{5C=qoGL^odS`@8@}Q&XId#e{cP_Xe=rohc;HJzcc1O!sZ~! zSeCy+J&1wY4(;=FZX9-)FH`~#G_j{<6em7Z74ya7WQ->op>`W&_Pihx>yhXHVR9#7 z|9dg1NmvXfj7L#Dy9${Rv**mXUh5FW9v%;}FstnLq;?IG#`s)N%bW|u_wh0%SwR?t zWRr!{iTfy$&j|qA_9<6Vguh!9D4IS>^tfy@F=$QF3lJ`UZ=R`}TuL&6Www^2NEx6w zR;7j1c}r)kW0$U0>X-@&#INThv2t7^KcSf2T-KHLv^n=pkp@=)OkteSCHoh8yOYap zeI>}ooxmHCh`c+X%{<)^17T|1O3Wp7f&!S56e+r`heH=h_vEWvgSE_{8oAf;X$#o#dSPTTj5~~l-_#|`!KaxM;))O&a!7;yBjc|!7TlXl&=dI^nN#wpGx4YCNaUCb9ZF$r#S*#OGv zw8eT+GuE;A-mX=`;*SC~gNKr9w@`&nTD)5|5+lg##_~XlpU2$%0gJp;I~$zas=EY~ zMzYyP723qV$ODGn*Fc_#xs-kBbuUygqrM0R(3Hm)af$17Hf!NL^BP7 z{k+?5pc-IMr{PuDZd~vS7@z^9&mL;|muld^gx*$;C}7vZMxk`D?ByPx*9p}J=}Z?G zxpvLq+qZdm4qd+S*C%ajb4YJ#eW~$o$3z1`7t_+ z8u@O&$km9Uht3b-mO=K}WU=4SX9gnHDG?x+z2zMmxa~k4X8~9PMUaGaQcK2G;ry7; ze|FL^%q9^P$u%pf8Bcu}-uYkhcv&<&u(b3>(?Y{-`sB<%R;%qWM1|vR$)a$`MOU&I zi#E5K)yw`sM1f2jR+4ui3uU7o?uxIuBK!k$j9Z49+BLOob)Q??B<{@`al)83WS8V? zWjHmW$oc6BeB60_1pEddV9^K_AO&>!M!8bwMzm8*lWa{Ii}J&*VCRc*{|=j0{*1vQ6nMD%w}!YAy4T9x&K`qar9l#&E8Yo!u? zyn)5Lq+)CY)rwC!?Z_&PUb0Z}_tzu=%aPTvF7ywJ3Cs*Z<<@gT_i#FmU?_Dnk5wIm zY2jE;0!1K|dUE;(@pH~<_3AQZNf-tw638lEd+dF_l(57;_36B*z}}8l1iA9$4{Dh0 zs9zOa)4c6+zR^t0d!0FXv;dT{fT;_o^sOD7VE=CqPt7&P^W0UUxNbELDNSgZwGV_1 z|1`h5@6KSvl4mOcARYDc{;LpI0VWc(l1%VZR*^c*M^>F+F(qko{xw~?E2??|r1#x4 zNacx2is2c(!m|fDzMmQ}&|i6(NJ<*Hy<3iEM!kmj$|jN_nV+99)(G(NEbaw*3N~_i+>Ql zs8FV?mT4e%x}iDI1INU3eSib<70(h{G348@OILN5nmP~Rshoks%;3R8`B=%2(ZEFo7@K7i8dR__xZ|_PMz-O!%DgT+7_HxJ`s&A_%TG z5qw+}>$Jt7L))FEN->xH*J?p8oK@@DvMR0RtiNi5An*mjB6jTD-?A2;27 zq7{zIZi{Vve&s;y;=9@^D7@P`bD&uKJr!4=HjpwVjEpPNr;c2tqx6gU*_M~S>5f+z z#8tDkN$?ECX9sH*GV_>2r(xcjX62(O zfAkMX98RTogjN%AK5?+0H*gQ#e@rIn^??l}J3Tj2FCLVmbhVTIM(WOGx)Mm6!?iTU z8eery2NW{ZV<`5paoPfhX6k0)JcS?611YR8dC5OxsBK%@>DeBXy6dMq9VQXme-LH0$<};wi_^mhrJCV)g4uV zGnbpZDSNDwO%UV+SM&>yA{1czB`k-d2lqe7d!HIE5gf(KzHdEcMDe2p)t^#IX&UXR zU=g3Q(+Iq{D=myZwPL=)3;vqV9M28$7ZML7y)7V`FS7pBO`q(wbkM#`Lzlxbd_Y&i zY2#iK#XsuTQoC3tU*r|`Z-(5>moeYK1@*$+VY`5S2wdPwI;2_Bsu3QueFV(9fnoK? zel@mW17w}ertpCBDbW^(ja$Xjf0&v#P676y)!ti=Fw(I#=rIRIpqd0YRUYjkpp$=39xn)fyn~ArrXO5h?Aj9Xs%NS z!i2=1Q!j)WG)5rT>cx3=@YT|~I(W)<;-x$9y^tJ||5h?#l5nJmgxUNsZTldq{5+K(9&x<#X7e+xHe)u99HKrnF}JDh0&%i(=^iWp^w#ks8}RDUn0GuR0U-s&Inoe@?Ca(k z)Z8NX(WdesF(XVj80RdcLvL#mcKsyPAw>?RFolCntpM}?=p@6`0gi3_Tkj?8ASqP2 zea^5x^7md;ROuQ+bNsIdzagk{(@YBLoEm-BL=ztGRLO>a z8B7LW9Gp)5XiZMbv(d#C+Sykr2aGK&pNvrYEaLz><>1r-aSVMgIl4EKV^wp=;X`|n z42TWa`~$QX%^o8mdRK=gXo8Kxj^ooY1_?`yo`a)8JzZ0_Pe(m^Kw9EYWOOLVDFO+K zLz*#oopIiTmOayPVprcQ$(L`uqo76qO=#t^%jKA`$g^8@RFM128rER-0&)!*%(OGR zx3pOofP(rTF;;v6u-tBzQrKmUsdQ7@`B!Jj6oq@N+HCH)`f!VYea)z79mT)f#dfEc zHuvCMml}vW$h|Mc7=M3BPRt0d_X7xeDykvxJ zS&K*Sim4f_(u&a_gx9w{a>9u|cb>;&qp3VokwrhTYhNQpUr{>P+lMHcbGIDNND6Bex ztI7b+ArKFo7uHpQcv-!k^%P4NZG)|F++vR6mF~%s95j?C;WDSY#LZ!|t4p#o8gqx4 zjjA36MGx!AEgaVKqa@bnBJ)_7CA4thv7bkG(USXDXUmMPC$|ndGf*FUieJNPe8MvS zQ9YB8@rxGu9#}XNI7!CpB4zqN) zK-;2p0Qlz57la!JckJXQY@5X-CAy8D_VzB?1T3h*iim)Fw=Noc6X82BUCA_a)0``u zeO_2TZGTeEn}J#-Hd`1kNMLhZ*;rxB&*6z4+AO;v~|<^pEJQ}Noai`|i> z7<4D>Q+-7A0w!eCAHaONwMX(!CcWMKK?OQcjUO89)B{^=(~=+Ij;;%I<#U9)Srb~ex{k$ZFy1v7M=|k{OY_o zBQBGt6JZzfJh-b3jYa~I?vMW!(E3G{U83rKyj!NE+fav3_&H@t=H$a2w#*oHJjTK7 z$U(P~q8xc9>KX+6_h7N_NqK&^E*|fdkGX*1^noQ9k@&FL9ogYH+xF3BGA5_7J0AB3 z-edJA!DoUA7ntIu^lE?~rJ77>!(^OtM6 z4(B3wd#e?|=VIX=Q^93{`id`(p8nxSS~$F9zUu=dzv_;rxQfMhj=ZA1%0HPgk;$D$ zz^{o`HSdai0}I4dM&}KvlgqKsf@mmVe`Z?0bhQz&uW(g8m9Am};AO_8VkcEG>HThmuK?L-K(sejC60b8GXE z)Ff}ajYW^0C@Hfy{))ph`FsCZl=D*xtxP1s)@P@3F-%l5TS+VxT!}OJ@){gFu!_{r zo7Pj4a^4;NMXwr}C__~W&{5cOT9S2H#TWNT@SJl6{l#cZe+rJeDcs*7j8D%GdWPV) zG=q!uS$w`PwI_VeW_U9iZnE9JIzTEY>Wj(zI&9LjE-G;x#{?bDPJ7#aU}@I zBG_B{NCX$@+M%Q2vUKGQkGb&d?mWtPq?@Wd6FlphM+eJahN#l7fB70;810rey3e#V z?mUl`1-(((cW6g;r9%KGIoG&gxFw`C*=CNQHY0z;WEm&cJhge2ov;tsh+`Y~%xBGSS)%qrmdTK7A|Kd+s*e*k@DR|ZhUm-`4x947H`?_r&XZn!7}y+6 zTVs)d$F^=KhYY;*ihR+wRU8EF^Or-^!nszp)Q z`&TSg@krr+qi0~H&E)8hn|xhOs-8%(3ewQc_Ea2y0{-5(U@XS5y*_sJ*c!GMGf(VO z;D>qM9ms#p@DgtXnhMl*3F7-_5<$OdBQ}Ld&K|N?sK12p+L@!~APdTlDAT_M{)NsB zih2~)`Ql;5I=H3johLZ&veQ=tfNBl@9zE`Mc$rK8OcGlQFp^v0yDYm|{3dODXDI9&%qkTN39*l5h znLkHs^hWkAyM?UQ)XdK)K{X+55qQAg?&iI*H#k5Zo@6|Md-y58y9A+o1kr8QY%!p-k02nlix#UAvpsm07K(AG${6H)r#l-R ztvx3?EAE=T+g5oB_Rf;h%6SL>CXux)e^NQdNe-tl1pfUf`FRBm`I(^0R;N01)cG0( zD*)@Lq$(R&uyd(lnz~k!VDMYH^eoN;lM<3WDV(}8D1Wl4J_~rAWy*qx;kcHHkxjxa zhfbI8vU3hN&@BXMIT5y1sAga(43x$I160UgmBtt0pE!pxg1?ZX=p6dQ^XfDtDd8-1 z#0d>6OkcG4DTF*p;n^7Gmoe+l6$%v{?4Dfcz?T0eAP0+}qz9#k#eJQkO5K9FD9nJE z#=K7;s|2PGTVnWf`hW+$1-s`pc$%lDmeC1Cz*&){ z&$<9}PpajFa2M74_6wg3)QWbQ=7bV~R|Khuzsvf)sF{IZ*(@pK273NCs1jVqL%BBlzho%kg02!o6FD!e>@jTX63e?S z3xib&ht=++-ngJgVFFib*eBNVrKahNlk$7#08+Q<^>gW1nN7>Tm15v#3>1)7&23kJ z3eFCz@B_ZX^-@gNG*SP4(Z+OEFFxo`O#!eA`+swAr{&oOm0bne%K0?`3(MymHy?e| zeE}AV@yT;QeIeui@iPPx1vBV>_(v*eMCU9;31~gmz(heM>CX9QG56e4m$Uzuv0;dY+SH~Oo@JFZ*S>hfHFcC*vGSYV9q1X&kFkfT5G zKG#XF;b-JPU~ZifA>AFnf$uhuqMM~%;+EI;3SvT%_(^i6BaANOjBw5JyEOB;=OJLV ztZEDV3L70xtpcKi*I^WbUd7YTkGy;ro|NdW;fq)QLPxs&`Un*IBuOhK(Kt0A^|R!w z7Df=4Y#Gvd#z7zNvqqd}+}KbzCzzSlEk#2gjvmSt6ucWjkrEL&CrhKshCEkrqnA=o zsu{j!N@W>tc=e{n;wc@G7(?ge5Qr7c@lOlQpXOTI#k2iP?;1q6sON*zd}>Pjh7+w6 z+LFZ{biXlJ*3xFJ3@dgnlyCX3xXet~X(XJt?i{6r9wXf+y|$kdiLuo>TM4?hbV54bh~n6BK=bahC(#Z zLb2Ktx%|Qs5jqT4n-1I05<-ul@7E< z1Ud5e@lB#!W7{3dLZA)lO^XiSAsI6>HK=lR)vE{$V~U<}{?g!9oatg2kuH43Y85O3{dv-#JmaH$&C54ux_lglxT z!!ZsP8fwCqTNjq72eGwzYY?%Sy^ELM7YMF9&?ie9f-Zn?wpL>Uivg<1R9oZ?9m!wv#NE1an=O%xD^bhs5Fi zx{zm2M8HQru)G8<2hOObitqHLu2c zen4LEvdB zzP4|LxN${rp=qXhevdw15g|Ixu{M*fmh(;7uqNy>xqk!#!D@}{lMrcar8zR=B2p(9 zhNeqW^BkLw+r4<>ln`?RtrLEN_`5=byi6-1jZY^+($8DZo%e!nDFQI%h&k)oiO?Q~-V{mKctMNWIYq6StK_;`1QP{pcO z%@Hs^k6G_Z>n2|_!tGr_kPCX~?J1!9dil1M^K|pTG|r4QFDndvZ_q0>4UyvTBM!2h zPtpxbH@95|LZv#tLOYqJA96P?DWmNK!TuV#dJ_D#CQH-z39SAGm0Ll|%&v?1pSmaa z{|%9dqg7vd!*@R_#ah@DRS5K?&pz@vXMoFA<1Q@ax*0?(T`NwK&e$tEM%BR6)fpg$ zNxEJyu{hz*zvl424`YjA`GjstdkZ_$nm48e>_f;q2%Mx^F8)ohsk#-3odgm(>M1;K za#qx5oi=`Oh-xjfp5&S)hlcVJ2*PWbmhxk68L-c`MfF|411n({E8c# zZqv@;pB{GfF#5eKc^tm%P609Sz<}q%Tl73QS7}ua(aV>t@H9t^jqUj>aL@){6sLmW z&ijJ~A}I$}pTQe{R+;@i+%RD=nS>kVx<|;FS*`s4yj<&kDO-0XusvO-)PBVw#_xFU zTfTF`%x?MK`K1wucThHu>BQ$|SQ>o8*xcGRCO#7(VYRy+Loh;T7oX7azJpU72R>V< zaSU#`StO+=WTT5O0BYpI>Wi!^F-fOLV#_ab>N&5b^%PH8nc zWZIPjV8X|G;JR5;bgL#3QuHxdBFkder;aA6>f0lPm;V()b{L5aRzRhouDyXoe{?~- zRvgNrU5>!J2tcDjS}TVn4zN7XKaDhYs@dD9;PE3Oty5^H3wF{02uQi{>a|S=$+Qp9 zR7=iB+!+&^F2BKn#uL;4_aSoPixhUOYbNa*w1#;E4P~1Ffs?=^#=TM;0(!VLOw~KK zh&s+Ty*eZa*g0lR$zAy-l|>A?SQ}b-e_I@d%k_bRF=H&^0qe|EKr$jB8RllI+fHsP&hBBlDeMXlsGI|e2Z5;!+dV4Nu4DI{ho%dK8*XqL7wy`@qfM=RJ z{S`)yeyz#Ohc8W5rHo+xP}ICt{XHem zBafz~b8)s>5?{5k`jMML zB@Q^C%yQ)WMM9idR?pUWocm_sV{>tCbp>K9$yP)!`3xPMHZUs$zX6)*0{Hwob8&a zCOpP(EAduIxAwN`_+`H+#svNSHo^|V8PPswSI#x8?J68ryFl1@08L_^A zZWC*I+8Jko+}$5$I2+@a=-0bVyc}t}_!(AcG%vMiwjwtIO>ichhsv@BXyhrYS+>U@ z4d2oXij#1aQh`*@={tHTCn zi7pm$wBuBw@N<-}=b4a%B|9d-oUkb6HCXR4KDn#mVBG6WfOtg(L0U)>K%*&fCti%O zfBkK2TUEI$>rHK5!NmJpJs}B@_o2{~k z3q5klW*;-^7r}d)r)Y@3^D{C?W?OMU3auDYX)6yqU6N^|51?-A?%V$ zUpr&^q4V7CBBdzfkM1o7q`zjUIn13c&<{C#cVa)@cz-ypkKIAMhO|MM#=9q3<)Et? zj8V!T_?1ni>S>H2lmg*U(b?*#$S4&AwOxq{H8&pV^xY*l2Q?k)_~zt8RE%#hirBQ3 zEP#-p#!o(iQIa(BFx#J@%km&-aMkKyvMlgPv!;cImbC;9^UpD7PqP)4muPR_-8b66 z0vZ4a5qvpDi>5Z9ZI;*s#bFqtpjR(H!S+?Ja~}-%n=CZ<7b6d5RND>U{jl6Buld!N zW57?|{`z2N1G#2A+tZjR4WH|Wc~_dz`KRY>0RR!^?Bq?GW>2ZHI@cQXez)Q zdCmAe7{!cVJJZh@a9n1f3wnTrVT1;CDc1xkpG|qe7;KtzyO!QSEtRJe819U#pPaeG znPu;{d5#>eY{_@ui;?%CgF~uxZ@ju0#BPh(( zxFLwUmBFunXCdSli^dIh>}-04#K#YP=DMcm7>LNX48gw?W>C!`kc2XZ`0K@q(t5oX z2rLr_jQeCe%q?gD?S7;9Hy}ZE2Uf8I6O7V7Ts3n`pzYjMJgYh~LM(h{w)?q2h_~-v zQRP$3EO{iJ7W6CoF-T=Fhp^=teF##JdXak^K`Px^^P(0pk_x!eN~YBxcSn1GLo-qX zQF?{-78RtMV(7eU6HbVv5BKsP)}PQUyH^<_;D?;kQfrN4Hfj*(sqLSrIJtU)OpWx` zAp`j#d4flp6j5Vi$>6*2Fw^8-ht4)>^%|W4fDkwMY~V9ey{>pI$6BoH0|-Cu;kJ*M``XBGtWt^}LtwIl|N0EtBb7=-(3*rfraShAi*G|@ z6MoHDX$!`Q;v6H%SwDQ{WEm0Kg^9Uf=OGM3GyA0+z)pT_4W@EuP0boG<=#FE&- z(IzCY&ofaQ9C2UEDAgQIPh~{urKu`}DAMzF2Oj}J&eetpmfMz^AihXqi&S8)YkYCT zM`&mh9b?&%B71Z@+ie$3NHO;G*O2jERRhZK;*c6Z$vC~{>e{>HwOawv&CSFwr8=R5 zGrw8osKPpw?tsi0STES;xn#fF&zKnSsrym^u6`qV`Kh*EEfUpnIS%GGcLSa(w4^%eKMG zL;t?^N5QuspE3qC;Jm03M&mD=k=4L?pD^Z=O%`p5M_a*uGw{eRf-+4&4}Ip1#ZjZu zHb<+n+FOfyr_9(T5Mbn-z~C?rbx8$#?(4=Wad+4J*m^TP3b2oe%;Mh)odBBx!@WK> zM1xP`Hs)MU@_6C3v$EM^OgoI69@KDyfYkOjRCTcU$2(8uU%n>t4Ew?tr- zLnz4uSZ4Px=Mxh3(ACua%QVU~#2dcmtW#YNDwA~)XXI67mI{+l0mZ-uBG^>TFzr6J z;U{k`g%huj`jrI&JREu-A4DT*3y{!S-#+~GWOu~y4>aQM*JZX`q5iN3LC7D%B)Lxb z39EjTW-w`TeAK)sWDHfq0`EkeVthHnRpbEJBr<=4iQ*h1$M%r2Qf?2z>6=LZV0ydS z5Xef^+U|B#N>a!pAaQ3=ypO}%W6z#UXYx*dpJgZw-kPei$#JkGclcdx`15F&oz>65 zCWgon!;U9ud=N(^+R~a9(oe023-T=GFr0U;B8H(SB$&m=>8@Wp+K5yRQOX-d?8NcF zb#qnitP1C`L>GKSmaYdsItI`8GbiGG^|!LU%Hb)ex$-LW81L33^iUB_D{JPg8OT@9 z3}icpa37bYb7XP>XDcLs#nk}sHnjBMNynGDV|vqIKZXoOBrAAs$;064(-tx zsq(q_OSdvns))Jy#1wXIXM$+mfPrTeYNptUh7GiY%9(~ZZz9^LHtPz%Z?%J*KHRc7 z*xJ6T$EPZuuWRgsE2vN!vLug=In`l#Wc7@y`tFIq=uv^{RYgTg?+5X`B30|y%EREow1R6dMF&!5TsPQ&+wcmaISM8!vl`t;a*~ zwVi6%ya<~y?x^zN_5nEW7}S{UbTE=dS$+?!4+;FxwYei0A{5&*+eB{CQ#I_93gH6W z>f`>kU!4Qa(hu%vfPd%?zRSDU{^0nGV(R#X@g+>$?DujU8~%p`L>zl_59Q#mW+EG@ zr&Mnc+0fS+9BVOW`0E3gyt}*yQX)5-{apiLZWBRRrq%y)7NNYksz$ca%7??4#ul2;@dAbbO0Bi;a9F64^fL&@=vc)T`1X#_E|9o z`k$0zQ+$$ryWO{Ex#`5}vnOR1T>IS((3Ek?8e2~8VDV?HwKO}ktK7>cb|+?5Rgk9y z??2LBqL6c3K6~96aq#(3L>-N(3XM?Dr|F* zx#HISb6GXIX+VT{;+pH47v}i?sfd&5p`7*Rp0zrUbJM`PBGKhrC{~}@XKX4q$2|2? z93}Y|AjoeZhLl8(D@+kNW8lz*O>oSdqB_)^aV~)>#ZsJER}E?C|!`)NHGe z$%^@E)XKUVfk~cQP>c)JkRuVwBl~cmpJTAUr~~phXm!MBM=l2im<^TA0#uM6;su&z zd+=wEhWQKNVe-mVV$;oDpkPMh+?igat|cxf{8^;F_*ZU_vVlRjIA>^A7B$8V-rd-b zk=(jR+44@t7dSPlg0LYX+g3aEzgZCQ7Vf+_YO9#5_J`RmWs4f*B9rGR1J`$VBm`SP zS7uNM#zI_p(cw*!PP{QOdp;9ToEFq<0C?vqP}|fcqqOudZPMO>E_3#p*az>U3%m~$2PTm|@ zx9EfqryU#{3i>?p2)>fsKyOr00s@C4kJ#JNbAMGl?>rf6lx7H4j4H#zc;<=Xlf5ZH zz~6*&JiY1d{yr`CmmDUs*P2erTNrOvttPili_;MO5B=)cswE0LS?k72_xWwNH)CS- zqwh1z)iL@uUlHQZ@$3I!!|sJNCu;2mpa|XUOw#g~8W>*`apeqStrDJ&pFys4z#g~_Euz`kdZsM(dyd`{-C6aijx4aIx$IpE`Zw+fU{6Lu%$OKJU?WE z1_gSUiTw}(#tKrkD+SZ$7S;Luh8JF6u!1`jp}tgZq3NiLEE^2OuuzVtxWIg3jku<+ zcF`O~pZ-?=Rcc}|6i;qe{ULxD(RFY1@FB!@9-QML{x@qyDk{WXGsL4m_F50bKq8o} za*mJ*uF7KV-iWH4dM%#wel%zQem-)sbb{wO@|$ru)x^}0l}0?@1n>7MGCAnvM>(p-K$nJVq!??pHdecDh{SO$UwwclAD>No3gXo6BFsn_ z_42!V130GHpLHUS@9*zHk6u2h5G30YhT3U*CqE}8Q-WoGcPu3|9#m8m1SD-tF)V9a zT07LmLf;UWOQ)6iA=ehee(n?Bb zqz}OIi`CYJgp9Z5rDe6gYlt1iiUm)OE*^Emr(?lN`sfrrj(_H4Vh%G5`e29?$WDSg zc{JU2`cMEh&TuV%I*t6j)74b$^R$zYepvKV(>SWW{9S=&;&*#DRMyy;wGbeDxCY7| zXPfUdMG39x$u}pn(VCgomPC^z)@k?*n&DJE`?P&S08h`|kcH&)YxUllB^y?YUX1z2 zzWGCvHH@}%bP7-Sa=u4Vw4HCD;8txG_0$k3XD~FDLO$-oh5Mo6=(e9!Ppw>bPVZ?) zm5}gY&WQO?c+dEJVe~o}Bl_-7fD_JN+(gTxEYLy09BeCc?2`F;9`%r9>zlJHWrN2w z_Od&`Kq6;_>YHZ`V$7)F9Y?+-B00wO)~o=x8>$zK3{rxk#JjJbVvYQGz61n8TCvEKOZgenNq)%nW2&^g{CO-Df{eCfmgCyT;laIr*fE(Y*Uo_! zKoVS?l;|I>9Z@Id)H%p;j0Ia-RQaC#>;6=3u5pnC?l39mzo6Zmn@<0`XCA zk5UVXr99vN;8dO!X&W60XemQsYusVjiUbAl`kztbW946|1?Os+Z3HEr5R~FN4aTtd zc~zc$j1hz|D8X6>o^B#gsTB-2Kular`zR^C>{WW*r{@wr_vQV4cR6fXSkQN%eBRHu zPBeI=E1jNd+GmC?s8G>U-T-rt$QWvw9z@Rs=mpJY(D)RKE|=O<>TXD}($%p^tU)R>8Ga}oJ?5*|tWo@H_)+T$x1HZ}X z+Z;eujI{UPmfjx~Zsizl>Bt2cpeWup7G$gGS#aj)<>aFz;HMRlYcbTlm0+Ef*SJPU zC4`x$K5;c=xoeygJ7<^aKW-Byy)7~cP|m$-#ywgMi=GW39t&dCh55x(u*P=U?UxEdm=>hQU*Y&dmfk559J4 z=U}fZuGAV_W91u(r`|$x04AZS@Q@mB=scphHVc_s6MfH_+rPG zxT%QdFC|GCbx)=_9X3lzk7%Z%a3czsJXrmBw?5y&tuvJ?? z$NA-_EtcKeOG|*41yyFJ4?@r>i9)0^1~H{t;I^&kR-ICWZPKM5+cZn?0~atbh1)=R zd*4nAZlDXocSytu*v<`7>hwNVH0nmZ>+V#pGoGRuuWGu;$DA+J->SNpEBDcjBY8!pe|&W}wc(e*7O2BPG@8P&OJE&B@;MDf=$cF9!vmMFgaER>zv-~3H)l~I z=0k;O)=Gs=R0XcY>Y%HJ(0=<|FOYut5??QJKcm4+>G;RvzbuZKFA~Dmx5?!cM@vV3dmFdLUg?%m=5aXgu3Zs z_`M~Zjap1>NEgMo;1&WE(8vfHx%_Z8X$ZXHO~_BnHYzoMJ+XxsXk0-CB?RLh^9)-fXF-_V(cSxA@@}?prHotaQ|gk$4@IdZ<%) z%bT|QSmY+qYRvn$8k-v5A?RnvV_oN9j)#;q5QGm9AukaC0j){gP)%4s`Hz*pQw%ml ztA7KXlCZbO1nu%n#rBEj2Cnnz-wNXuoB=nEGYVLOE{dtIPLWpWbL3RIn(M>RQKig5 z&6shEu)JXVJMs`}gZ;q!nQ0x(BS39IL?tW+M)hcH+TF=p*|uSJp8rwDQ%hdcLZZMw zDk8xXTY1mGYc(uk=XjX(p32NK)61yjH@?A3MEu`G3yH^yeTZFz^&^g@GO9Gks5(n~ znTn#d)aadQ4v)k8GHYC@uZu;Z>j}!HE30#$VTB5i2cGNNL{+|E4_*tzUg0k^ zzF7dVhMD4yligu&xy#D06Yo;NYg(MvJOzV^sEjwRgN-=(fg^^ zJEio2fa5uiyeQh1we*sgDE+1nfv9)m!M1A|;wj*8EB8Jn>&inS-EflV7sl1Y z+2bh-l|T^{7V{sCggd;?#wH@IN^J}7)9VcC0SZc^?r+d?MI$Yc&Dw3e!9$u@%2+YA z)Ik!($6O@5_}W9^z!QXDS|pq%#u||ed8%Rsazorku*w@LB+E3&=jPfiCZ1})_u|< zMrablVc38tKoI7U9@Kj5e=>Zv(fI>q7+Adnm{9 z@3!38ACiGo6_)}hvB6URnTbg?s=-)#AyWFVvA!17VyUx<;ZkxCOhwh7KJ`$}YExha zr3JpQQj*i)JM84db&hlaW|*Dl=%_0BMkDHCOx^f0@Ur~_v;5S{57CQVrM!L+AKFfG z<+9U)#<@^s^2ifP^$lA=ibl=RKT?js=er+Cklu}&3li6?Optmi{&w#RLb;DQt+|t} zF%p;Ki_=goxqH+|De0q6zDq}!6&aVo2KQm;bAh(kj0wrOvNHve`70)(SlN4iJrU^~ zjo>JaQr@?SU!lO;tOCF>T{q7eP|*3^sDg0=w3+irn%l3!pX4VM)fq^LYudJpOd#Ob z-08-_J=GQNzs4&e>u7J?72IY!1;F`7Ro56TD;v2=!xH|f+-4f?5D9^4^sb5Ps+W-^ z0B9c>{qyztvo#U2ik?^7*i2pX^y;0qUMwyUp#Oi$v~vQ*%OIJ6=#C)Fi?uD_o5#N= zcPkkItzKdEz4;mKD>-1*UN@ZCYEuK=xPN0U@T-fKcj^F1Ei&FyT%>~(`~%i-XVj@i ze##@oXVM+p*e)tG*A@8$C(*g~SFrW`{Hd$7UWc_DSrRqc%uGY?+T|FQ1< zTV_caMLSJG6x%nMPR8&qHq!_Tv6t|}GPx1u()~Q^QWoP)4kA80y>Uh|H~>#3oJS0- z;|Gn1uhC=4v!&ImOp^BF7Bo6S2&T74D$rBM4x*6IR=43=-^va9NHQXWyndFgt#)5k zB3ntOX`q_p4~qUjK;VL#c@c$s&4rOAgPj8W$#-IL5w%vn>$5&Lj}G}e9$3*r6{C8eXwC zD@9bZ%LQxK76SwoCbE|T#{M_&uVp7%A%+uKV9-DBl4hj+(w^VJ?@seAf8tyEHztdZ z%No8MsDM8RBJ`I}c>D>mv5O5)-AUxkChjA2@7;vT#u6gyyP6pg6!b-<%47ag=(Ddv z4QxU}R?;k#3hCy4G#U5E`%|X$NDu$K4J?IK6b9av3y7$)syG9Oz;5qVN{8om#jpYR ztu01Ek48#lVkD}T6bbXUe~to2=k`s4Wf>R8J*cX-+62(@}L;ov*~ntiaJ;2zN8vQz<`u{L4@@Q;OH>xg*1~e8F@Al zpSWNtv;Sz}N5H*YW1e6rUgwK`YAI!RpOdcLR*~Y>x|+$ciK0h05+NC__+SC56?t4U zIZctHP6luLf8GC4B)?5UNTNO-Clu4%p|iY+-t$Hz-6Hw;qtE417Bzj2pH}hh_j@fg zlK>Y&7JM_fi_!^+Mlu%eo8Y(wXup0C3>#v-V%jQSP8mrR(eW{c2;6cc#QJogHpS>V zcJop9Pgl7NV=JKNC6t_IW?cBG3$d&!Vmm8y}$$_9axUXj2e#Ab?CCji02Og&$L1e#MRYs zJf`bKqP7KlKF!#mipb?LtTmWQ$&(xGHk2E|A{_@aK^$9led372gNp4Sc>+%^KE5}JFV;V#XMCAHvhvH7xj~gE` z&&Bi4ao=Glkw)3jyjkNnwi4wv4Bt$DY(6wti_qEcYVWW3^%Yx`$V5$!$q8e>GK=1m zHRL)lLooW+svw!O0wR+logobO1N9NUY_PXTh53f)$N)(hhiJhioJ&>#9gI|)KHmE{ zZ3c?oW^(ZHNQyL1Nk8&GFCYJV2tM5&I{-8GYYIIKCEgV8=Y+~8#=RYNZCIS~*LtD$ z5)>t3i3=%3b8C5-wvF=wQrn&+wFlhuXT6yDG&~+s|Fa*~m*?P}>LfJ-dVo4h%=H(( z@9}o0uavRUEKq{ z_0LBKy{h1y!b}U31@1AzX#eDH2Uhv%OPeFos$wV)H)`<$`$p}rBvmRrh0eLI0BzlYgnm^r-r#sM0@ggJv;2h-pk~`8`Zw^ONRB0Nrp~|g>ODF9P=cVL4S=y^ zexbkMJn`MJkQ$MuYjasq!O_@1rej273LxSv{nYK~;BJ_3E<{+S#56H=bR zL&;uMdF{H4pqZai3a{d$RPL=qbJ>d@FS&o>AKPQ-vd9kFBBHn3`Eb4&n|f}eHNe_m ztKa3_aX94&YrG*dbB~*Y8&DWZ5oI3`#;y~zT+y8OklaEM_!WqpQ_{xbl|(A3ug1$ zq>nqu5yqK1(D{wv>a(~%Y8fu0f`-r)9)akhip;-Re6cG1q^X2Qg$9auzEk&Oq`Hb& zKeIZ8Fpq7rkGhRrn*lB~GtKlPm`p;bU&Y+}eUPKyth(xsHZfPVi|qU%)PHVVE@fI@sIy3Cf2( z0ElKrVld5)=_eD8K{9F|BhVl>0Yf>0AU?AfQ8&}LL6rOp=N5f<&b6el>WMf41> z4tFFp*PcPy?~eJ(LZ;XP6@MC0?8`y*a2n^K(wcTLkgz4rptg>lV)>>njC4P!pU;McNSc#?XRDqQXv2!(PKUlA&4T2k@AIBQGp09*1Vk$ z>^$8YQ!qlypG^`qiuAvu>Yyg^z>(ea)+v60PUrkir}2b9zH`f!MqqqJ?w+@{md#}| z;_T0v_N%|tA}MmVa{_BbG`1jDP(ur!bXk1GZCtmt?d{w9K`>lQ;3@CqYiO?KR{x7O z3WWv6TT#aUqxs27|00@{sw#&8>R)!AA@!e8tsRy@px`-*W3b9dQE5)MY_exIKqT^p zs3Mdj8x+XYI8LMcbSIQTQ(>Z-_!CuZy;4Cq-D9Z<3#aE_|{hv*!LnH?O;&Y1W_`{<`p4Vedzljx6i0z>%Mw|SA4v<96eg#HfpIP zaS&F~+y$&KY`%V4fztb3bS`El#iGElLR(ZdfODm|Fr}C;#p;7j0ybSuume!USoBho zho72)2sJ|y_RR#Nh1tz^{I8S-F+#bsVFf|iJ!vYbiPyOqTG|+6k^(oJxK!*V5>@qB zz`Xit+Bh%$jm=Fi8t%m0sBL-^Zt!HG`gs=XtKjg|9^rGhe$F@!BXxMJM3Y&z=O8-A zBzm#%-J=N>{2IG@OmqM973_=~)Ii9WF#N&@(f(0(xe&JcgX~dcXwG$eljmV}YN4|> zf1zvUcevAj!fn*Bj8V?}+&EX9;G!tuzr-lNW`H`vVFBR4ebdd|z;sy^zm*rC`vm?r z*GA>@r8)of5+fD&8%>1b9o)I~0fEr4JtVz#tN?H+UFgnKL62m`K+oo|w!K8oM<=6^ zxv2GFcRt>^o+k%e8?eVC9&ScSy1E?!XRzwY9Jla zbE`B56!{W(2}$ygm2t*B=xvSn(sh z!8SZ%h>BXTq8lNl#UBTf^+Rz!{Jf@oJ-Crb28h7nIpviBXxyd#4U0Uid82qxd5?$E z?hwu~-p?dqVSLG85O4vowrxW{@5!ld$vX>V<;7^44f|Fxst9>PMrh}rQsPHyV_V34 z*+R8nJ-qD@MM(tuLjZkqGsh+@nVL8t=S3Sv2WG!7g|ABb;12`*E!Dlbq0@pvy%xx< z{w>T_1f)H+A7|zYL2qg#iFujl7K#2i_13Bw4U#s=4H!qF4o2%<4s$TgMD<&p2Tt(u zwG2;M96=kXa-|4&b(eaY_|EOh_5(7pOf>AQKC2WMUM_nn*PMgPf3k&#-wS`%K(q8~ z*Dps$f5deqWzDOiM#^3wmQ+S`5&;s)M3H}FXncvUrjk$5RTFi4h@twpCa=Cc2z9!2 zM?6PnJ&;EVza>qz{6^VP{2>k`c>rD+MpPJ9&S`y>5m;56< z>j4>N!X1$@)O`;w1@nYXjX4>iew_p4gKgESp!;JzD1@rK^57lnnd9_=s2S6R&rjfR zZrZTG6Y_N(MpMArFLKP?X@|zWGmtCJh(`}H2`MLhHN+w(|5h_+v&!bv*US+V*U)49 zj>sPZk;q9pu>omNjCLL4U`ti|I}}LpatB$^JWBu|xIslYQ~*nj_E9|Xa&i5%677WE z6c(g3$Z{YkmBY_i5EG$Oe^!64S?ZX zb3v_JB3UTvP(xP&bh9q$Yb}IoxLDhl;zh zr!4V%Qv8^8#_hM#=#xhjrFzkdHuy~L;v*mxJ;=lZwWfBNYopbFtkEHFJ#&QMKY9gP z1LR=Kn+8K2N*4we>LNtDUN_L^<9w9Ct5)fh6oLg5n?R}!VH2U!q8lXQR6YDAgk%F5 zi*dE*UHC(0?nbONA(JGe?vKN+=FmN`ZnyjZUv)c_le}6}dFLiq^$Wp`pX?itttnbI z91WxT%pcI`Un@N>p;7VLd2P^zT#`|1{5Bt&)AH2cuPFeL&8y$2#pf!RbEC;}2LUnj zPqLl*us>BI;57D(n_&{=A6f(c5SPSQfPg-JN>h1|{$u86kaGQ2nkKAX08C8_g9XDH z{SS?4@JonEWB9W}!H{|paU%-Wq{DmqEck~Vo6Ou_a41()JASP{yz{WW_FTBo=o0$J z?7^C=uk{tV>Vi(W3j1W*PNT)QaIY!=|gum+$CO}1zV z7i-Pp>m*5;A^cS!>6*YXrz9MyKu?7T;?Oc?dvX;H>uq|@@F~p<~doI__pB zKiSt`fdRGzmnfP6LE^ztam3(~Bu(hmwPolnR_n72U{Y=W!QcHmHk8CX*zS9zw z#aqt0rvgn%6U%(<7^hQm2Tq z;4x-r0UX-lI-`XYRdT%u$+@W|S#e-Op7+$O|LFgj{}je&>Rt~ZdAKKpA?jlZQO)7x zk{ASVk}kr8Rh_lhySXyXVd9nrO^{5I#=XyY(gLf|v!nbu3j90G z9u`DDjx!atbV5wjT+eJTdE&Kenle&MuG_R4DYHpbfN+C0(C%q{_J*<93e>P=Ma*7v zQX^*&O#QWQD{tVfIy%|)u(8+Df}`l8GX1}c4(mhPwzim;=8tk>mYu7`m?U$xPa6&s zSBpb^w^wK8-|*K5o(F)cG{3t}HuTR6iv}~~%sPs6At5nVMu)_$zZ5~-B;W|7=1kcqMX@gT^AF2$lBqv-SeVFZ3cts!@OD8x-f;=^wyj<4Bkl^lXBP>%A4cmrhNQ+0yF34 zq0H2$fTo;gLl=Y!idT!J{D*nvmCd-ywofxh=`$`YbZ3*lS;wC{a{B@Pkklybn9hki zHj_tM920hDf(K?i-5zVI4ON;{HjtJT)RW2W)^+Ty+)VeUTEF4mT>Z>5q{$9na*|RYf4x)xI(XI{FJBnE94xId}c0+uT^{uilo0%U^TrOz)piayGN@fO z0WSdd#g$1SpD*}!M5BqX+@L)}@m^NTT+R)Dc1KZ<)HIm6P4v!GCkK6x4X=sbn6~2^ z%K?1pVd5=fmoQ^F^eCp-D21pA$O#4L3~_GP$h2FS$3JNI!AoT$5)w{T2icE!^rrW_ zcz9-Faw*)*#+%*}Ev5?R4QiD(n4>%UA+-I1`aOtj<#-qzuVs6qg|#o}^B-{E z|MYS`XgpLeBK|q^y^z*1e6jN}g?Yriti}&fc8_OOCYWBmYIyj@ui{W6IeSH?wL?jf zSSNBEqpc5CZ-Hbg8wAJ#zCU|w6>-6n%Yg;qB}o3x`%WFzfm$*n30zbYV{t=tVK%-#%oVeAIn!S%0J*|G~VVpzeG9m^R7qq`rkC<0X( zlm=Is-);&}EJGp+>w-fTwS`x`JLaDX=jLpYN$UZoS%v^V&U=A)1_{IH2Zj%z2KPBL z8y#AO(9o#VziHt|g6iq8{4d1a5V8h$^P#Psr8$r@BhXnL+3qx`($ea4a~0>Y zU*nZnv7^D^(L>|lKe8+^4vp^{XhKa6=MF+8G@VQP;XD>> z8bGZ4Au=TB2NIMZ-#b@gVhddih}8Lq&3+u~tl8W?dP(^;A~`y(G;+uVqi@$=@mT%` z^0!`3`u$Uh)u#^d8HhnYr%Gd1!pb3hejRXLKYbL3*;qP3hU^nMEXH9p2au~h5L71R zPGE&<>iq&|evmbA*Ut^Rm$BxwYn2u$iCj_xynK`aW1`n0ObvY z4}+o=^(7Yb*@&SYnV_LD!EVhdSr1p$twurp;@tCvQaV$bw|A1aLfFBjOofKwI4f{L z|8fBL1uNgyksi)&t~8nawoOM1o}ef;7e+_`l#M_&Q!FSE!wRR>BBKvA#kG!KTIPQ5 zKlYiXf{lTS9gYWmJ1K-VfDotH)}^Mlg)3bTZ~teeoEdBE_gig;czPuyij#?imDfL( zy819>iO=iSm&l%s*w=RcBu(g5S}R&zdbmE%e-ku2>dVax4B#s?a*bMdcjqA68i^iA zyTvG@fgW7n3*Z5?P8z&AC;FuD3f?+10_wUGBawkdy0*Lj--CxXI)|?ck;Vki*h0Z~ zu}k)2#x+qJ$=JssmE|nl%|__`?c=fRd^Se;O~*mH{8U|gXDr?WD)(;(1#GNEQS^+~ z1S2}{#x8>Y+Y-0!i0w%eVv1dcW<>zoT)cMI%8bG^O3G`pN%zAr#)tLbjsaX76dCO9$r=y+PpJP0q9<+nY}zVKe2w?puir$b94gETBN7?g z@?8~LN37m5M<1Em(FevmCvnKHgq()zl?N?Of8zjsvx?WW7GrfX#lZr3z$XC`Bm)av zB#6v1;n{Z9Eo2b>nB6oLlWm?^yqADIQ$y0DXyc(Fxoxq-`!KJ`C@cO`8I^W9!y^vq?e*P?Tof zW#f19;XxGpIp|_I%c4rXo9r(}v*G+SPOv3Vsa-|87JZYoTVo%Ge;I_%L zq{h3jTIWSQhKc}0EqICkmn`5Sp|Y8$Vs~zk#@G8swdbzS<79j>DCN*{KBeO-^!~D0 z*8hz2H0>i0AsjrJqR37tj%ZD=uvpz4;hq=Shl1f~ybH)VC2Sjd-wJ{cQD9Le8TPLb zl3-;spbr2OtwD@{0M%c^T@ebVgB&f_q4aK$c-pEjpRw;&k52+Jx>pGx!M`u8n80S! znR?hVc@)lX1(NdcjRarQlUUa&5IYN(xx!@Mn|p(>`7Et;>s3jP z&p58s7D9J_<^d!Mhy(`5?PVxdU%D)A<`?0n{IoIl!Y*8BJmW-4lBkryar zn|*@Lyvq*x=c-#*+J%6o4)I(}&dH?&Uf=@TkFS9ltAL>TX@Ee%8AhmsM>-nxhBV-G(85&-$3U>zHw!umW~2Hm4)a@pVKsQEgbFK(5WUt zV`|ka-MyvB>itDPT1v}AF4tc1-QP#zH@B-~D)A=mH|nff-ZE$HCwM~Bx zDe|JLvCu9pUM{4?rW`GpdssZ3z6Yp7W?873Mztb>Wq4EhJvu6c9diM65C;)%7R=qe zorgb@6UI6|yb1bFaS%P?VY)rMS%mg85|`_QYIh`~}G1Qwl=0ma7QWx-hs z#o&!w-c_4n%}TO9V~Yy~G*_7HTl+iq(STSn)WPMv5@=lg(oV62O_)l-@Jsr9n*!2T zRDP9R5y-OB0CcV@Z#?^cRRfS_jdNms+UFvlT+q;KOKW9Y0y$n`8REs(A?P>lF)vHf zt@VLEIn6Hxi%ghS_psp7KepTg6$WDZKFubQU(O%S5i3STez{t_AYP(?DO3jqQug3- z?lX}3$hA=+ZmA=&->G3anw}pVT9)0V6r1`GQ13=O2FwH%Wwn)NG7#9K?jymsd=n<; z97uL3NA#~0EmELvzOZQ(RInemS5&%5jv6%o2R4=3Dwmco6!hOA!cJ9( zzS%G`Bpr#CN8WjAge!n2hCIZB-i(87C0P58lQL{p{V*Jykj%^5u#~oo({vRzZrSPs zhIYkpj+?BU+D_N~TVK+gnNx`SxxRUSg*s*=LV?w!&AN<$Tz3Y$h3oTV!MYMzMkeUq zg7tpNPln66^@bnDuhhXJ+ex}p537_bT29luHBgamkd9E;KmY&$0Bs_#Bj5%;xc~vp YnGS%ECW8Ny5V6E(`vL#}000D8S_K_;l>h($ literal 0 HcmV?d00001 From 1e2137b14ed881eb482a14f5af6eaf9df3e779e8 Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 10 Jun 2023 11:54:57 +0800 Subject: [PATCH 44/57] fix(build): add missing license file --- build/build.inc.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/build/build.inc.sh b/build/build.inc.sh index e8d1818d..26f74f0f 100755 --- a/build/build.inc.sh +++ b/build/build.inc.sh @@ -4,6 +4,7 @@ MAINNAME='ghfs' MOD=$(go list ../src/) source ./build.inc.version.sh LICENSE='../LICENSE' +LICENSE_GO='../src/shimgo/LICENSE_GO' getLdFlags() { echo "-s -w" } From a185744af83f4605fede35272492ee3de296524f Mon Sep 17 00:00:00 2001 From: marjune Date: Wed, 21 Jun 2023 20:21:12 +0800 Subject: [PATCH 45/57] chore: re-embed frontend assets --- src/tpl/defaultTheme/frontend/index.html.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tpl/defaultTheme/frontend/index.html.go b/src/tpl/defaultTheme/frontend/index.html.go index a22053ff..9ffa17e9 100644 --- a/src/tpl/defaultTheme/frontend/index.html.go +++ b/src/tpl/defaultTheme/frontend/index.html.go @@ -128,7 +128,9 @@ const DefaultTplStr = ` {{end}} -{{if eq .Status 403}} +{{if eq .Status 401}} +
      {{.Trans.Error401}}
      +{{else if eq .Status 403}}
      {{.Trans.Error403}}
      {{else if eq .Status 404}}
      {{.Trans.Error404}}
      From 4a55524b7f2cab6a7e1d2076ed3789c7582011ff Mon Sep 17 00:00:00 2001 From: marjune Date: Thu, 22 Jun 2023 15:16:42 +0800 Subject: [PATCH 46/57] chore(build): use static link --- build/build-all-by-docker.sh | 4 ---- build/build.inc.sh | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/build/build-all-by-docker.sh b/build/build-all-by-docker.sh index e27f8be7..05ad6185 100755 --- a/build/build-all-by-docker.sh +++ b/build/build-all-by-docker.sh @@ -42,11 +42,7 @@ buildByDocker() { "$@" } -gover=latest -buildByDocker "$gover" "${builds[@]}" - gover=alpine -builds=('linux 386 -musl' 'linux amd64 -musl' 'linux amd64,v2 -musl' 'linux amd64,v3 -musl' 'linux arm64 -musl') buildByDocker "$gover" "${builds[@]}" gover=1.20 diff --git a/build/build.inc.sh b/build/build.inc.sh index 955d27b5..14382f70 100755 --- a/build/build.inc.sh +++ b/build/build.inc.sh @@ -1,3 +1,4 @@ +export CGO_ENABLED=0 TMP='/tmp' OUTDIR='../output' MAINNAME='ghfs' From c1f15128f9ad813c18f24d7842f2195c8691243d Mon Sep 17 00:00:00 2001 From: marjune Date: Sat, 5 Aug 2023 21:59:02 +0800 Subject: [PATCH 47/57] chore: re-embed frontend assets --- src/tpl/defaultTheme/frontend/index.css.go | 4 ++++ src/tpl/defaultTheme/frontend/index.html.go | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tpl/defaultTheme/frontend/index.css.go b/src/tpl/defaultTheme/frontend/index.css.go index 45fb9730..b01ba5d2 100644 --- a/src/tpl/defaultTheme/frontend/index.css.go +++ b/src/tpl/defaultTheme/frontend/index.css.go @@ -605,6 +605,10 @@ html.dragging::before { .item-list .header .detail { background-color: #181818; } + + .error { + background: #663; + } } @media only screen and (max-width: 375px) { diff --git a/src/tpl/defaultTheme/frontend/index.html.go b/src/tpl/defaultTheme/frontend/index.html.go index 9ffa17e9..4a1fff9f 100644 --- a/src/tpl/defaultTheme/frontend/index.html.go +++ b/src/tpl/defaultTheme/frontend/index.html.go @@ -4,7 +4,6 @@ const DefaultTplStr = ` - From df001c5313e4e05c76bfea81a8d0ffadff915324 Mon Sep 17 00:00:00 2001 From: marjune Date: Fri, 5 Jan 2024 23:10:13 +0800 Subject: [PATCH 48/57] chore: re-embed frontend assets --- src/tpl/defaultTheme/frontend/index.css.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/tpl/defaultTheme/frontend/index.css.go b/src/tpl/defaultTheme/frontend/index.css.go index b01ba5d2..fc3488cf 100644 --- a/src/tpl/defaultTheme/frontend/index.css.go +++ b/src/tpl/defaultTheme/frontend/index.css.go @@ -519,7 +519,17 @@ html.dragging::before { 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; } From 9229e65b6e540cbc2462290b484c56cd7c64eda7 Mon Sep 17 00:00:00 2001 From: marjune Date: Sun, 7 Jan 2024 18:42:40 +0800 Subject: [PATCH 49/57] feat(upload): add back parse file path manually for forward compato This reverts commit 6995103ec790b39bb6c28a92e1d12b94b2d0af78 --- src/serverHandler/upload.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/serverHandler/upload.go b/src/serverHandler/upload.go index 35d3a30f..4601a94b 100644 --- a/src/serverHandler/upload.go +++ b/src/serverHandler/upload.go @@ -3,6 +3,8 @@ package serverHandler import ( "errors" "io" + "mime" + "mime/multipart" "mjpclab.dev/ghfs/src/util" "net/http" "os" @@ -40,6 +42,17 @@ func getAvailableFilename(fsPrefix, filename string, mustAppendSuffix bool) stri return "" } +// RFC 7578, Section 4.2 requires that if a filename is provided, the +// directory path information must not be used. +// Since Go 1.17, Part.FileName() will strip directory information. +// However, the directory information is needed for uploading. +// Parse manually instead. +func getPartFilePath(part *multipart.Part) string { + cd := part.Header.Get("Content-Disposition") + _, params, _ := mime.ParseMediaType(cd) + return params["filename"] +} + func (h *aliasHandler) saveUploadFiles(authUserName, fsPrefix string, createDir, overwriteExists bool, aliasSubItems []os.FileInfo, r *http.Request) bool { var errs []error @@ -58,7 +71,7 @@ func (h *aliasHandler) saveUploadFiles(authUserName, fsPrefix string, createDir, break } - inputPartFilePath := part.FileName() + inputPartFilePath := getPartFilePath(part) if len(inputPartFilePath) == 0 { continue } From 1e85b002b1a416100656dc235f28324646f55f93 Mon Sep 17 00:00:00 2001 From: marjune Date: Wed, 6 Mar 2024 21:10:52 +0800 Subject: [PATCH 50/57] Revert "refactor(pathValues): extract `pathValues` as generic type" This reverts commit 0b3da296b09aea4e1ca8a92ea5d08daec9251908. --- src/serverHandler/pathValues.go | 123 +++++++++++++++++++++++++++----- 1 file changed, 105 insertions(+), 18 deletions(-) diff --git a/src/serverHandler/pathValues.go b/src/serverHandler/pathValues.go index 110a5346..7ec778fd 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(includeSelf bool, matchPrefix prefixFilter, refPath string) pathValuesList[T] { - var result pathValuesList[T] +func (list pathIntsList) filterSuccessor(includeSelf bool, matchPrefix prefixFilter, refPath string) pathIntsList { + var result pathIntsList for i := range list { if !includeSelf && len(list[i].path) == len(refPath) { @@ -55,20 +55,107 @@ func (list pathValuesList[T]) filterSuccessor(includeSelf bool, matchPrefix pref } } -// pathInts +// pathStrings -type pathInts = pathValues[int] -type pathIntsList = pathValuesList[int] +type pathStrings struct { + path string + values []string +} -// pathStrings +type pathStringsList []pathStrings -type pathStrings = pathValues[string] -type pathStringsList = pathValuesList[string] +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 + } +} + +func (list pathStringsList) filterSuccessor(includeSelf bool, matchPrefix prefixFilter, refPath string) pathStringsList { + var result pathStringsList + + for i := range list { + if !includeSelf && len(list[i].path) == len(refPath) { + continue + } + 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(includeSelf bool, matchPrefix prefixFilter, refPath string) pathHeadersList { + var result pathHeadersList + + for i := range list { + if !includeSelf && len(list[i].path) == len(refPath) { + continue + } + if matchPrefix(list[i].path, refPath) { + result = append(result, list[i]) + } + } + + if len(list) == len(result) { + return list + } else { + return result + } +} // []string From ea79c187af2d6a4226b40499fdf5bf99520d48a2 Mon Sep 17 00:00:00 2001 From: marjune Date: Wed, 6 Mar 2024 21:11:20 +0800 Subject: [PATCH 51/57] chore: re-embed frontend assets --- src/tpl/defaultTheme/frontend/index.css.go | 7 +++++++ src/tpl/defaultTheme/frontend/index.html.go | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/tpl/defaultTheme/frontend/index.css.go b/src/tpl/defaultTheme/frontend/index.css.go index fc3488cf..2d845687 100644 --- a/src/tpl/defaultTheme/frontend/index.css.go +++ b/src/tpl/defaultTheme/frontend/index.css.go @@ -165,6 +165,13 @@ html.dragging::before { display: none; } +.login { + position: absolute; + z-index: 1; + right: 0; + padding: 0.5em 1em; +} + .tab { display: flex; white-space: nowrap; diff --git a/src/tpl/defaultTheme/frontend/index.html.go b/src/tpl/defaultTheme/frontend/index.html.go index 4a1fff9f..d859baae 100644 --- a/src/tpl/defaultTheme/frontend/index.html.go +++ b/src/tpl/defaultTheme/frontend/index.html.go @@ -23,7 +23,9 @@ const DefaultTplStr = `
    1. {{fmtFilename .Name}}
    2. {{end}}

    - +{{if .LoginAvail}} + +{{end}} {{if .CanUpload}}
    From 7977b8b809055eb0cb0a27fb1d0fba659937990c Mon Sep 17 00:00:00 2001 From: marjune Date: Fri, 31 May 2024 21:05:47 +0800 Subject: [PATCH 52/57] chore: re-embed frontend assets --- src/tpl/defaultTheme/frontend/index.html.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tpl/defaultTheme/frontend/index.html.go b/src/tpl/defaultTheme/frontend/index.html.go index d859baae..54440651 100644 --- a/src/tpl/defaultTheme/frontend/index.html.go +++ b/src/tpl/defaultTheme/frontend/index.html.go @@ -25,6 +25,8 @@ const DefaultTplStr = `
{{if .LoginAvail}} +{{else if .AuthUserName}} + {{end}} {{if .CanUpload}}
From a9cd399d009bef0e79b81174d971873c5594cb34 Mon Sep 17 00:00:00 2001 From: marjune Date: Thu, 8 Aug 2024 00:14:03 +0800 Subject: [PATCH 53/57] chore: re-embed frontend assets --- src/tpl/defaultTheme/frontend/index.css.go | 16 +--- src/tpl/defaultTheme/frontend/index.js.go | 93 +++++++++++++++++++--- 2 files changed, 83 insertions(+), 26 deletions(-) diff --git a/src/tpl/defaultTheme/frontend/index.css.go b/src/tpl/defaultTheme/frontend/index.css.go index 2d845687..75268ef6 100644 --- a/src/tpl/defaultTheme/frontend/index.css.go +++ b/src/tpl/defaultTheme/frontend/index.css.go @@ -426,10 +426,6 @@ html.dragging::before { zoom: 1; } -.item-list li:hover { - background: #f5f5f5; -} - .item-list a { padding: 0.6em; } @@ -499,10 +495,6 @@ html.dragging::before { background: #fee; } -.item-list .header:hover { - background: none; -} - .item-list .header .detail { background: #fcfcfc; } @@ -594,10 +586,6 @@ html.dragging::before { border-color: #555; } - .item-list li:hover { - background: #222; - } - .item-list .detail, .item-list .delete { border-bottom-color: #222; @@ -611,11 +599,11 @@ html.dragging::before { color: #666; } - .item-list .delete { + .item-list .delete button { color: #f99; } - .item-list .delete:hover { + .item-list .delete button:hover { background-color: #433; } diff --git a/src/tpl/defaultTheme/frontend/index.js.go b/src/tpl/defaultTheme/frontend/index.js.go index 2341e9a5..b54840e6 100644 --- a/src/tpl/defaultTheme/frontend/index.js.go +++ b/src/tpl/defaultTheme/frontend/index.js.go @@ -7,6 +7,13 @@ const DefaultJs = ` 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'; @@ -68,6 +75,8 @@ const DefaultJs = ` } catch (err) { } + var lastFocused; + function enableFilter() { if (!document.querySelector) { var filter = document.getElementById && document.getElementById('panel-filter'); @@ -103,12 +112,6 @@ const DefaultJs = ` var clear = filter.querySelector('button'); - var selectorNone = '.' + classNone; - var selectorNotNone = ':not(' + selectorNone + ')'; - var selectorItem = '.item-list > li:not(.' + classHeader + '):not(.parent)'; - var selectorItemNone = selectorItem + selectorNone; - var selectorItemNotNone = selectorItem + selectorNotNone; - // event handler var timeoutId; var lastFilterText = ''; @@ -231,6 +234,70 @@ const DefaultJs = ` } } + function keepFocusOnBackwardForward() { + if (window.onpageshow === undefined || !document.querySelector) return; + document.body.querySelector('.item-list').addEventListener('focusin', function (e) { + lastFocused = e.target; + }); + 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 || @@ -379,16 +446,16 @@ const DefaultJs = ` lookupTimer = setTimeout(clearLookupContext, 850); } - function lookup(key, isBackward) { + 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 = itemList.querySelector(':focus'); + currentLookupStartA = container.querySelector(':focus'); } else { if (!lookupStartA) { - lookupStartA = itemList.querySelector(':focus'); + lookupStartA = container.querySelector(':focus'); } currentLookupStartA = lookupStartA; if (lookupKey === undefined) { @@ -400,7 +467,7 @@ const DefaultJs = ` lookupBuffer += key; } delayClearLookupContext(); - return getMatchedFocusableSibling(itemList, isBackward, currentLookupStartA, lookupKey || lookupBuffer); + return getMatchedFocusableSibling(container, isBackward, currentLookupStartA, lookupKey || lookupBuffer); } var canArrowMove; @@ -460,7 +527,7 @@ const DefaultJs = ` } } if (!e.ctrlKey && (!e.altKey || IS_MAC_PLATFORM) && !e.metaKey && e.key.length === 1) { - return lookup(e.key, e.shiftKey); + return lookup(itemList, e.key, e.shiftKey); } } else if (e.keyCode) { if (canArrowMove(e)) { @@ -492,7 +559,7 @@ const DefaultJs = ` } } if (!e.ctrlKey && (!e.altKey || IS_MAC_PLATFORM) && !e.metaKey && e.keyCode >= 32 && e.keyCode <= 126) { - return lookup(String.fromCharCode(e.keyCode), e.shiftKey); + return lookup(itemList, String.fromCharCode(e.keyCode), e.shiftKey); } } } @@ -1268,6 +1335,8 @@ const DefaultJs = ` } enableFilter(); + keepFocusOnBackwardForward(); + focusChildOnNavUp(); enableKeyboardNavigate(); enhanceUpload(); enableNonRefreshDelete(); From ffb8e8b8ce8edcf5262a8bf73e3ddd7899591438 Mon Sep 17 00:00:00 2001 From: marjune Date: Thu, 8 Aug 2024 00:01:30 +0800 Subject: [PATCH 54/57] fix: make TLS config works for Go 1.2 --- src/goVirtualHost/serveable.go | 17 ++++++++++++----- src/goVirtualHost/vhost.go | 29 ----------------------------- 2 files changed, 12 insertions(+), 34 deletions(-) diff --git a/src/goVirtualHost/serveable.go b/src/goVirtualHost/serveable.go index 957a15d1..806f14d0 100644 --- a/src/goVirtualHost/serveable.go +++ b/src/goVirtualHost/serveable.go @@ -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,7 +102,6 @@ func (serveable *serveable) init() (errs []error) { serveable.updateDefaultVhost() serveable.updateHttpServerHandler() errs = serveable.loadCertificates() - serveable.updateHttpServerTLSConfig() return } diff --git a/src/goVirtualHost/vhost.go b/src/goVirtualHost/vhost.go index d8f5dd9f..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,29 +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 { - 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) -} From 9d2da60ed45fa908d1ac8899b0c8b612935be657 Mon Sep 17 00:00:00 2001 From: marjune Date: Wed, 14 Aug 2024 20:24:35 +0800 Subject: [PATCH 55/57] chore: re-embed frontend assets --- src/tpl/defaultTheme/frontend/index.html.go | 12 +++++++----- src/tpl/defaultTheme/frontend/index.js.go | 18 ++++++++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/tpl/defaultTheme/frontend/index.html.go b/src/tpl/defaultTheme/frontend/index.html.go index 54440651..6ce083c2 100644 --- a/src/tpl/defaultTheme/frontend/index.html.go +++ b/src/tpl/defaultTheme/frontend/index.html.go @@ -131,15 +131,17 @@ const DefaultTplStr = ` {{end}} +{{if ne .Status 200}}
{{.Status}} {{if eq .Status 401}} -
{{.Trans.Error401}}
+ {{.Trans.Error401}} {{else if eq .Status 403}} -
{{.Trans.Error403}}
+ {{.Trans.Error403}} {{else if eq .Status 404}} -
{{.Trans.Error404}}
-{{else if eq .Status 500}} -
{{.Trans.Error500}}
+ {{.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 index b54840e6..0dc8fc70 100644 --- a/src/tpl/defaultTheme/frontend/index.js.go +++ b/src/tpl/defaultTheme/frontend/index.js.go @@ -236,9 +236,19 @@ const DefaultJs = ` function keepFocusOnBackwardForward() { if (window.onpageshow === undefined || !document.querySelector) return; - document.body.querySelector('.item-list').addEventListener('focusin', function (e) { - lastFocused = e.target; - }); + + 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(); @@ -1299,7 +1309,7 @@ const DefaultJs = ` if (status >= 200 && status <= 299) { var elItem = form; while (elItem && elItem.nodeName !== 'LI') { - elItem = elItem.parentNode; + elItem = elItem.parentElement; } if (!elItem) { return; From 6d89d7ebe6281128aff5628a10c72c39aafe99bf Mon Sep 17 00:00:00 2001 From: marjune Date: Fri, 27 Sep 2024 21:37:59 +0800 Subject: [PATCH 56/57] chore: re-embed frontend assets --- src/tpl/defaultTheme/frontend/index.html.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tpl/defaultTheme/frontend/index.html.go b/src/tpl/defaultTheme/frontend/index.html.go index 6ce083c2..36514e22 100644 --- a/src/tpl/defaultTheme/frontend/index.html.go +++ b/src/tpl/defaultTheme/frontend/index.html.go @@ -15,9 +15,9 @@ const DefaultTplStr = ` {{$contextQueryString := .Context.QueryString}} -{{$isDownload := .IsDownload}} +{{$isSimple := .IsSimple}} {{$SubItemPrefix := .SubItemPrefix}} -{{if not $isDownload}} +{{if not $isSimple}}
    {{range .Paths}}
  1. {{fmtFilename .Name}}
  2. @@ -101,7 +101,7 @@ const DefaultTplStr = ` {{end}} From 1a548ff342e64354b41096b0f57fcafeea9f0c2e Mon Sep 17 00:00:00 2001 From: marjune Date: Fri, 23 May 2025 23:23:39 +0800 Subject: [PATCH 57/57] feat: remove Context status check for Go 1.2 --- src/serverHandler/archive.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/serverHandler/archive.go b/src/serverHandler/archive.go index 9ebf797c..e181a1ca 100644 --- a/src/serverHandler/archive.go +++ b/src/serverHandler/archive.go @@ -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 {