From f7c2a51c9f9295c333ed002a5bc2b72e8e117ddf Mon Sep 17 00:00:00 2001 From: John Date: Fri, 1 May 2020 00:18:45 +0800 Subject: [PATCH] fix issue in zip feature for package gcompress; improve package gres --- .example/encoding/gcompress/zip.go | 67 +++++++- .../gcompress/gcompress_z_unit_zip_test.go | 97 +++++++++-- encoding/gcompress/gcompress_zip.go | 60 +++---- os/gres/gres_func.go | 4 +- os/gres/gres_func_zip.go | 153 ++++++++++++++++++ os/gres/gres_z_unit_1_test.go | 3 +- os/gres/testdata/data/data.go | 2 +- os/gres/testdata/testdata.go | 2 +- 8 files changed, 324 insertions(+), 64 deletions(-) create mode 100644 os/gres/gres_func_zip.go diff --git a/.example/encoding/gcompress/zip.go b/.example/encoding/gcompress/zip.go index 1d5e0d41e..c827c1d4f 100644 --- a/.example/encoding/gcompress/zip.go +++ b/.example/encoding/gcompress/zip.go @@ -1,15 +1,68 @@ package main import ( + "archive/zip" "fmt" - "github.com/gogf/gf/encoding/gcompress" + "io" + "os" + "path/filepath" + "strings" ) -func main() { - err := gcompress.ZipPath( - `/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/test`, - `/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/test.zip`, - ) - fmt.Println(err) +// srcFile could be a single file or a directory +func Zip(srcFile string, destZip string) error { + zipfile, err := os.Create(destZip) + if err != nil { + return err + } + defer zipfile.Close() + + archive := zip.NewWriter(zipfile) + defer archive.Close() + + filepath.Walk(srcFile, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + + header.Name = strings.TrimPrefix(path, filepath.Dir(srcFile)+"/") + // header.Name = path + if info.IsDir() { + header.Name += "/" + } else { + header.Method = zip.Deflate + } + + writer, err := archive.CreateHeader(header) + if err != nil { + return err + } + + if !info.IsDir() { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + _, err = io.Copy(writer, file) + } + return err + }) + + return err +} + +func main() { + src := `/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/test` + dst := `/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/test.zip` + //src := `/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/README.MD` + //dst := `/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/README.MD.zip` + fmt.Println(gcompress.ZipPath(src, dst)) + //fmt.Println(Zip(src, dst)) } diff --git a/encoding/gcompress/gcompress_z_unit_zip_test.go b/encoding/gcompress/gcompress_z_unit_zip_test.go index fce4d4b51..66ec5a515 100644 --- a/encoding/gcompress/gcompress_z_unit_zip_test.go +++ b/encoding/gcompress/gcompress_z_unit_zip_test.go @@ -24,25 +24,88 @@ func Test_ZipPath(t *testing.T) { dstPath := gdebug.TestDataPath("zip", "zip.zip") t.Assert(gfile.Exists(dstPath), false) - err := gcompress.ZipPath(srcPath, dstPath) + t.Assert(gcompress.ZipPath(srcPath, dstPath), nil) + t.Assert(gfile.Exists(dstPath), true) + defer gfile.Remove(dstPath) + + // unzip to temporary dir. + tempDirPath := gfile.TempDir(gtime.TimestampNanoStr()) + t.Assert(gfile.Mkdir(tempDirPath), nil) + t.Assert(gcompress.UnZipFile(dstPath, tempDirPath), nil) + defer gfile.Remove(tempDirPath) + + t.Assert( + gfile.GetContents(gfile.Join(tempDirPath, "1.txt")), + gfile.GetContents(srcPath), + ) + }) + // multiple files + gtest.C(t, func(t *gtest.T) { + var ( + srcPath1 = gdebug.TestDataPath("zip", "path1", "1.txt") + srcPath2 = gdebug.TestDataPath("zip", "path2", "2.txt") + dstPath = gfile.TempDir(gtime.TimestampNanoStr(), "zip.zip") + ) + if p := gfile.Dir(dstPath); !gfile.Exists(p) { + t.Assert(gfile.Mkdir(p), nil) + } + + t.Assert(gfile.Exists(dstPath), false) + err := gcompress.ZipPath(srcPath1+","+srcPath2, dstPath) t.Assert(err, nil) t.Assert(gfile.Exists(dstPath), true) defer gfile.Remove(dstPath) + // unzip to another temporary dir. tempDirPath := gfile.TempDir(gtime.TimestampNanoStr()) - err = gfile.Mkdir(tempDirPath) - t.Assert(err, nil) - + t.Assert(gfile.Mkdir(tempDirPath), nil) err = gcompress.UnZipFile(dstPath, tempDirPath) t.Assert(err, nil) defer gfile.Remove(tempDirPath) t.Assert( gfile.GetContents(gfile.Join(tempDirPath, "1.txt")), - gfile.GetContents(gfile.Join(srcPath, "path1", "1.txt")), + gfile.GetContents(srcPath1), + ) + t.Assert( + gfile.GetContents(gfile.Join(tempDirPath, "2.txt")), + gfile.GetContents(srcPath2), ) }) - // directory + // one dir and one file. + gtest.C(t, func(t *gtest.T) { + var ( + srcPath1 = gdebug.TestDataPath("zip", "path1") + srcPath2 = gdebug.TestDataPath("zip", "path2", "2.txt") + dstPath = gfile.TempDir(gtime.TimestampNanoStr(), "zip.zip") + ) + if p := gfile.Dir(dstPath); !gfile.Exists(p) { + t.Assert(gfile.Mkdir(p), nil) + } + + t.Assert(gfile.Exists(dstPath), false) + err := gcompress.ZipPath(srcPath1+","+srcPath2, dstPath) + t.Assert(err, nil) + t.Assert(gfile.Exists(dstPath), true) + defer gfile.Remove(dstPath) + + // unzip to another temporary dir. + tempDirPath := gfile.TempDir(gtime.TimestampNanoStr()) + t.Assert(gfile.Mkdir(tempDirPath), nil) + err = gcompress.UnZipFile(dstPath, tempDirPath) + t.Assert(err, nil) + defer gfile.Remove(tempDirPath) + + t.Assert( + gfile.GetContents(gfile.Join(tempDirPath, "path1", "1.txt")), + gfile.GetContents(gfile.Join(srcPath1, "1.txt")), + ) + t.Assert( + gfile.GetContents(gfile.Join(tempDirPath, "2.txt")), + gfile.GetContents(srcPath2), + ) + }) + // directory. gtest.C(t, func(t *gtest.T) { srcPath := gdebug.TestDataPath("zip") dstPath := gdebug.TestDataPath("zip", "zip.zip") @@ -75,13 +138,14 @@ func Test_ZipPath(t *testing.T) { gfile.GetContents(gfile.Join(srcPath, "path2", "2.txt")), ) }) - // multiple paths joined using char ',' + // multiple directory paths joined using char ','. gtest.C(t, func(t *gtest.T) { - srcPath := gdebug.TestDataPath("zip") - srcPath1 := gdebug.TestDataPath("zip", "path1") - srcPath2 := gdebug.TestDataPath("zip", "path2") - dstPath := gdebug.TestDataPath("zip", "zip.zip") - + var ( + srcPath = gdebug.TestDataPath("zip") + srcPath1 = gdebug.TestDataPath("zip", "path1") + srcPath2 = gdebug.TestDataPath("zip", "path2") + dstPath = gdebug.TestDataPath("zip", "zip.zip") + ) pwd := gfile.Pwd() err := gfile.Chdir(srcPath) defer gfile.Chdir(pwd) @@ -116,10 +180,11 @@ func Test_ZipPath(t *testing.T) { func Test_ZipPathWriter(t *testing.T) { gtest.C(t, func(t *gtest.T) { - srcPath := gdebug.TestDataPath("zip") - srcPath1 := gdebug.TestDataPath("zip", "path1") - srcPath2 := gdebug.TestDataPath("zip", "path2") - + var ( + srcPath = gdebug.TestDataPath("zip") + srcPath1 = gdebug.TestDataPath("zip", "path1") + srcPath2 = gdebug.TestDataPath("zip", "path2") + ) pwd := gfile.Pwd() err := gfile.Chdir(srcPath) defer gfile.Chdir(pwd) diff --git a/encoding/gcompress/gcompress_zip.go b/encoding/gcompress/gcompress_zip.go index c36839fed..34076e413 100644 --- a/encoding/gcompress/gcompress_zip.go +++ b/encoding/gcompress/gcompress_zip.go @@ -10,16 +10,12 @@ import ( "archive/zip" "bytes" "github.com/gogf/gf/internal/intlog" + "github.com/gogf/gf/os/gfile" + "github.com/gogf/gf/text/gstr" "io" "os" "path/filepath" "strings" - "time" - - "github.com/gogf/gf/internal/fileinfo" - - "github.com/gogf/gf/os/gfile" - "github.com/gogf/gf/text/gstr" ) // ZipPath compresses to using zip compressing algorithm. @@ -85,11 +81,13 @@ func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix headerPrefix = prefix[0] } headerPrefix = strings.TrimRight(headerPrefix, "\\/") - if len(headerPrefix) > 0 && gfile.IsDir(path) { - headerPrefix += "/" - } - if headerPrefix == "" { - headerPrefix = gfile.Basename(path) + if gfile.IsDir(path) { + if len(headerPrefix) > 0 { + headerPrefix += "/" + } else { + headerPrefix = gfile.Basename(path) + } + } headerPrefix = strings.Replace(headerPrefix, "//", "/", -1) for _, file := range files { @@ -97,23 +95,15 @@ func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix intlog.Printf(`exclude file path: %s`, file) continue } - err := zipFile(file, headerPrefix+gfile.Dir(file[len(path):]), zipWriter) + dir := gfile.Dir(file[len(path):]) + if dir == "." { + dir = "" + } + err := zipFile(file, headerPrefix+dir, zipWriter) if err != nil { return err } } - // Add prefix to zip archive. - path = headerPrefix - for { - err := zipFileVirtual(fileinfo.New(gfile.Basename(path), 0, os.ModeDir, time.Now()), path, zipWriter) - if err != nil { - return err - } - if path == "/" || !strings.Contains(path, "/") { - break - } - path = gfile.Dir(path) - } return nil } @@ -203,14 +193,23 @@ func zipFile(path string, prefix string, zw *zip.Writer) error { return nil } defer file.Close() + info, err := file.Stat() if err != nil { return err } + header, err := createFileHeader(info, prefix) if err != nil { return err } + + if info.IsDir() { + header.Name += "/" + } else { + header.Method = zip.Deflate + } + writer, err := zw.CreateHeader(header) if err != nil { return err @@ -223,23 +222,12 @@ func zipFile(path string, prefix string, zw *zip.Writer) error { return nil } -func zipFileVirtual(info os.FileInfo, path string, zw *zip.Writer) error { - header, err := createFileHeader(info, "") - if err != nil { - return err - } - header.Name = path - if _, err := zw.CreateHeader(header); err != nil { - return err - } - return nil -} - func createFileHeader(info os.FileInfo, prefix string) (*zip.FileHeader, error) { header, err := zip.FileInfoHeader(info) if err != nil { return nil, err } + if len(prefix) > 0 { prefix = strings.Replace(prefix, `\`, `/`, -1) prefix = strings.TrimRight(prefix, `/`) diff --git a/os/gres/gres_func.go b/os/gres/gres_func.go index 9b20b4fab..10d04bb5d 100644 --- a/os/gres/gres_func.go +++ b/os/gres/gres_func.go @@ -11,9 +11,9 @@ import ( "bytes" "encoding/hex" "fmt" + "github.com/gogf/gf/encoding/gcompress" "github.com/gogf/gf/util/gconv" - "github.com/gogf/gf/encoding/gcompress" "github.com/gogf/gf/os/gfile" ) @@ -41,7 +41,7 @@ func Pack(srcPaths string, keyPrefix ...string) ([]byte, error) { if len(keyPrefix) > 0 && keyPrefix[0] != "" { headerPrefix = keyPrefix[0] } - err := gcompress.ZipPathWriter(srcPaths, buffer, headerPrefix) + err := zipPathWriter(srcPaths, buffer, headerPrefix) if err != nil { return nil, err } diff --git a/os/gres/gres_func_zip.go b/os/gres/gres_func_zip.go new file mode 100644 index 000000000..5d784b4d0 --- /dev/null +++ b/os/gres/gres_func_zip.go @@ -0,0 +1,153 @@ +// Copyright 2020 gf Author(https://github.com/gogf/gf). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gres + +import ( + "archive/zip" + "github.com/gogf/gf/internal/fileinfo" + "github.com/gogf/gf/internal/intlog" + "github.com/gogf/gf/os/gfile" + "io" + "os" + "strings" + "time" +) + +// ZipPathWriter compresses to using zip compressing algorithm. +// The unnecessary parameter indicates the path prefix for zip file. +// +// Note that the parameter can be either a directory or a file, which +// supports multiple paths join with ','. +func zipPathWriter(paths string, writer io.Writer, prefix ...string) error { + zipWriter := zip.NewWriter(writer) + defer zipWriter.Close() + for _, path := range strings.Split(paths, ",") { + path = strings.TrimSpace(path) + if err := doZipPathWriter(path, "", zipWriter, prefix...); err != nil { + return err + } + } + return nil +} + +// doZipPathWriter compresses the file of given and writes the content to . +// The parameter specifies the exclusive file path that is not compressed to , +// commonly the destination zip file path. +// The unnecessary parameter indicates the path prefix for zip file. +func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix ...string) error { + var err error + var files []string + path, err = gfile.Search(path) + if err != nil { + return err + } + if gfile.IsDir(path) { + files, err = gfile.ScanDir(path, "*", true) + if err != nil { + return err + } + } else { + files = []string{path} + } + headerPrefix := "" + if len(prefix) > 0 && prefix[0] != "" { + headerPrefix = prefix[0] + } + headerPrefix = strings.TrimRight(headerPrefix, "\\/") + if len(headerPrefix) > 0 && gfile.IsDir(path) { + headerPrefix += "/" + } + if headerPrefix == "" { + headerPrefix = gfile.Basename(path) + } + headerPrefix = strings.Replace(headerPrefix, "//", "/", -1) + for _, file := range files { + if exclude == file { + intlog.Printf(`exclude file path: %s`, file) + continue + } + err := zipFile(file, headerPrefix+gfile.Dir(file[len(path):]), zipWriter) + if err != nil { + return err + } + } + // Add all directories to zip archive. + if headerPrefix != "" { + var name string + path = headerPrefix + for { + name = gfile.Basename(path) + err := zipFileVirtual( + fileinfo.New(name, 0, os.ModeDir|os.ModePerm, time.Now()), path, zipWriter, + ) + if err != nil { + return err + } + if path == "/" || !strings.Contains(path, "/") { + break + } + path = gfile.Dir(path) + } + } + return nil +} + +// zipFile compresses the file of given and writes the content to . +// The parameter indicates the path prefix for zip file. +func zipFile(path string, prefix string, zw *zip.Writer) error { + file, err := os.Open(path) + if err != nil { + return nil + } + defer file.Close() + info, err := file.Stat() + if err != nil { + return err + } + header, err := createFileHeader(info, prefix) + if err != nil { + return err + } + if !info.IsDir() { + header.Method = zip.Deflate + } + writer, err := zw.CreateHeader(header) + if err != nil { + return err + } + if !info.IsDir() { + if _, err = io.Copy(writer, file); err != nil { + return err + } + } + return nil +} + +func zipFileVirtual(info os.FileInfo, path string, zw *zip.Writer) error { + header, err := createFileHeader(info, "") + if err != nil { + return err + } + header.Name = path + if _, err := zw.CreateHeader(header); err != nil { + return err + } + return nil +} + +func createFileHeader(info os.FileInfo, prefix string) (*zip.FileHeader, error) { + header, err := zip.FileInfoHeader(info) + if err != nil { + return nil, err + } + if len(prefix) > 0 { + prefix = strings.Replace(prefix, `\`, `/`, -1) + prefix = strings.TrimRight(prefix, `/`) + header.Name = prefix + `/` + header.Name + } + return header, nil +} diff --git a/os/gres/gres_z_unit_1_test.go b/os/gres/gres_z_unit_1_test.go index 5c185b936..d4d30d447 100644 --- a/os/gres/gres_z_unit_1_test.go +++ b/os/gres/gres_z_unit_1_test.go @@ -35,9 +35,10 @@ func Test_Pack(t *testing.T) { t.Assert(err, nil) r := gres.New() + err = r.Add(string(data)) t.Assert(err, nil) - t.Assert(r.Contains("files"), true) + t.Assert(r.Contains("files/"), true) }) } diff --git a/os/gres/testdata/data/data.go b/os/gres/testdata/data/data.go index bf304c6c0..b65c1a1c1 100644 --- a/os/gres/testdata/data/data.go +++ b/os/gres/testdata/data/data.go @@ -3,7 +3,7 @@ package data import "github.com/gogf/gf/os/gres" func init() { - if err := gres.Add("1f8b08000000000002ffb45a095c4cebfb7f51d2284a5159721a295a669a51619a86346d68c1580ab9d3cc9966325b3353aa1195246e214b9622912d89b812652b0975c97265bb5952ae5b5de45eb2deff67662ae7cc4cd3e8f7bf3e9f31cd39e7f97e9fe7799ff73de77dce3768463f1d53300000f016e60401c4bf21401f30047c16271caff8c249043cee5c9a2ee8d34462854673e06542ba840db943583c5bc083f1cb962dc34b609e904b97c0622c66a1086672c48b311004414c8e782924bb92409c8873c239e10824d70913273b3861e5a71974061b56739a800d9aa13720bb7c23930500907dba77d7f0bbbbbc581c87cff9fff594a8d9d309724fdb133ddd543dbd151f85f2b47f97a772171fb94687ca8c9197741fa64597b123234a2c11f0febbc171d61cb28b3c641ad5f551cf8363aae2f57f3146ae9a1d9e2877d849af31b9e731325476b817433500e803264744c08ba3c2ba02d5de7c18c25cf67194c06209012789917481751d851802be04e64b64e8e74f6e261903008c35a2633ad1e5f65d882a68a9fda67c3394274453ba743ad07a9f25e2ff9625222a4b44b5592222e3926eb0eca7759688f22c11515942a1f94f3951a5759688bdc89201d0071cc2243e1ee6a3673a860d73b90259b5fbcafec0629609445ca6ecf77cd91ff292672c739c0a010020ed2822e8dd5134246e6e48dadc9078a42131b721f11882ec4549e6cbad6972b659e150b43d00c05e3b365154776cb539b7126a4b6a4fd49eba9584a0aa2dab2db995a0086cd2d9a5e30000e334520deea48a633b7a06a0d9bac85e9cdbd3b8ff9cfa885ed55f4fb7020058694d439bffff46a3ae886434bd28a2811da68e4c8e080ff37b39db100878795c9a0b52062e6a8e601801008c7e085c9e23257035d5bdcb38cab6677054ec11f4ff35f6087a47ecb17495d849aa1345c652c6b20bb690dfc17f84459104148bfc1009553abb3d967007cb6b50eb1c88a27a9183a168848e1c206fe4ea67af8c81bbdc6adc3079843fc2a0881fc9a06e21809b5b4b7bae8141486cf962d08b1458a880746421422cf83ea5a4f22711acfc0c96f47ddec7cbefd05603cff65c096a8814c95047243f83fd5e140a224ceb8c6f3d1329a78536bf1769315701e9484b0ca272c95362785c281a16893902be3b968073c242309f216072f8e1eed82809cb7112760a0543960151e48191e5201445fac80a480a868c975f21f3ce286ed886400040e08f7aa7c8e5ffe89d1c84a2c839590189f2ee93cdccadaade292fe90310def5625937ee346771b8f07ff88080e689a06bb9f661d4ac57a657aa178c07008cd748688422144569b1d0a87d4c289f8dff6a0b00b0ed718ff29d4df1aca032d55466b403a6dbd94709c2173b00001c34d29a28d3d2e6ff277346ab7abd36f5fa1d0e0080a3b15ef5912ef7f2915f241048f00cb1b8174bcd1084395e2c89e5c23824901da458135902bec451cc898349d004a230c64d7e5002c7481ce95c4e389f043160be0416b92906cbae3eec4f220080d8e37e404ecde1d1c3e15ef86e8202c07305e1029c901fde85b43628c0c710331c23db4bf8f952677778441cd01f00603925b50800d0473cdb671a28bc31f2956c2c84bec16200069ac83e7dc0ce6c7300fa1672680b240bfc679218021e8ece1484c1b8189e50ee00398614c313f260091d8ae171f962528c3b567e05892f26c90ee3b190fc12c95277ec02ff20c853208221179c33ce092b2f22b288c922cda67a77988b982c772c5b221192f0b22d3b6ed9049c40148e274c9e3c19ef44c413898e2226cb511ccb97d0631cf9e2310a904e1c2a2c668838420947c08764bfe9618228893b16db718de25f879f3c6117115fdc111543c0c3c7d0857802ce09afce88c9e8b2114689b872d7980c3ccc8579305f22c6137004b576120e8ba59e4d76464147f96e478ee109499e22982e81a974094c213a11263b3ab9383ab9d20844d2042289e01242c62b5da4ce5c20a209045c8a878c0ef2e688e06502d15231e439c71961de719192bdbf80c961c5aad0bb905c5c49132675d0232e42983319249640c4a34b288aaa14f2c3c9f8ef071157caa227058a38305f42970d1a8540c6ab1ceb1c60bcd2082bca07df513fb275a7ab162998370beff60300b3d28fea4163ebb62e5828a0d5592c0ee787f38babfad7549adb9a37180dd19d3647c72e69e3a1b9736e7b4f9f8b9d3677fcdcbbbf04c6ffc1384231a51d1e3cebb3dec3f33ebc7549d8d543a067117b6dacd61b44fbcf844e9dd16148b9371b6b76bc0af95c33d9d2c0268031637c5be6fb9a1df1c14f4e9f7f541f5e3025dbbce029859dfb396155eef1a92f9a9baee96e708861ee76386e14f28e79ff5f8bf7e7dffa328b6d8e97049d2b7e35ddc9acaeefe8ba7fdfc3cb2dbee0ad9f9b0853f3ff1acfcfa0e95a05783fa8d8b2e8fdfe956b05a34b699538bd0358d7c8b072568ee17bf7b5be1b6758e9be4f11eaf26e116f1b072e2ae23e9b373e392b608049f686392792df45cef35f0a9bd3eb56db2db0b41fe3d932ced69932fdf19100731366c6d3ed923366efd3a8d6e30453edeed35eee7199352d29c9b9d0a676c8b5b4cd3517993a66a259a693d937cb9366dbf9b4a4f8ea06e68d2c48ddb6d1605bfa3fab8fdaf463cda0ff1d488ddcddfed0e47058736c5ca97d86d16fd9799becd9fb7fdd411efe4abfcf36fbcc8fae10f5e4fd0904b30d277ffee370c624efe9996f6fcc7c068da586453dae9c381c73a5a27f563ec9252bf977a3c69d693f3746eb1cf4e60dbf47cc75181320389fb82ad2f045097dac5fcb822d9e29d6982fad9b9277ea6cbf11dee7bafd20e9c9d630dbba89b7afb7a59d0e713bb0738d61817f49fbbc3983fce2ee570d9b97b0f8f716c6b199996f687376f7cf9ffad1d9241af21b9897dc469fc1b024f069b87187c7e62dc23db977aade0cb7facfc3f75921c1feeb7e731dbd903a5a70352b9e98b0217d7aa36b0b66a5defdc2d55ece77e7850d5c462a7ef1f89931a19eb6843a6a6b9bae3ecd7dd8cf5619bed08e9958cbd3bf6ebf6268e432f415eb8ad4adb46d29a964533bbd89ba89c9e46504bddb52dcb7854a5eef6b9d84313c7820ca6b1387de5e1848b2711efaed94e35563fab09240ab53492346a66c72783ed0f84d6dad51fffe38ab9c9b8c5f7746ff72ead4a5c8ec9fd2f7acbe53defeba7a56c670bfebab4cddcbeee27690ef905c9eada9a037a40fbeb9abe2e95368f8040b497434b6e2755891af7bd96f7b4fa5a4b44f2c9a713770ff836d9159b77e79e3b12935443261fe1f05b56b8d31ab852faece5a2eae9ed7527f528ff180903d297648557dec9acc3be39fbbac35395ec6317970f2a04fc0ee1bb526fa2947d7a508ace9331eac1c3929a17a1b7edfb163836ffecb9eb8e2535bf51f17626e5113a785342f8e2b5a3fb9745dcacedd6bfa188f2f8c3b973ad417c366ec5845704ba9af0ffdf262ffb6b4e20b4f2e0c9e525f6a265db2dc586fb0e5e5d5f59494e0c70b687f05e579713e9aa7cf4a27198ea8d1a9aa18f921ab8cfec8b59e22d2697810d9b23f63c5b7ebf6eddf0a5fe736b748ef9f164cf1f6f6364af74e7ff94b2006bf7f7dc41cdfdf9c3221fffdc1d5262dd8fd7345870b223fd5580cdac83cd027fc86e4d9978fefdab7dcfbfc68e9b1dcd2d24735fa153ef74ec61d85fcab27ad78e769b7adfad9d1d383e84fefcc2899e494601996d3fa67b9e75237e1761d695c5cd9f28cb9254bb6b795f04d4fb57bacf78dfd77fa9e84dbc41c5fd72c9736337c70523f4159e2e6aa275e078aae655fbc6e9cf1cfa92d27d62d195bfc9aaf6fba775de21ade5383f3e5d3cd577eab5ef2f64611c35a7c6d266689e38c40ddf4a9c9ae072fa48e7bbdbca1fd44445ddccdb98271d7dc48a49a05a45dde3e52b73083fd4c3bf84ac8c285fe83ae9547cc9e54859973a829d1e2c59a80c6822b738fe6176fe943d3adbbfd29e2306df8919090b489cb751f3d9ca74b872f9e09d84be6b0b23e0e20ef1d727055d0bd5f8e9e28ca263f3f5bf06461f14f75136e3e7d9a25e8efa6772cb462b75934a321c5f0cade15f0ada4accae3934bbe34af4bce2f4fcbb86afe3ae870091f137adfee5bcee74be2987f36ac2cf719bd72e4d3e667a72f7c7479c829d92332f6d5810dc696963d9fe8494d6212f46fff3e9ed3fcf48ecd10fbad332d1e5f78bdecfed9a881013914de55dea362c39b7f3d5cedecde204cb7be7a0e9353fdf1f82593c227ce07834aca6f9f497b99b67349d1bc632b8caa368caa7cb264e5a8af5fbfb2d9577faa5adf7abf28be34780c63fab6889d8fe9e3e8c1dfa6a48b3ee86c8d71985b6e537f4c62beeedcce726f2b9be36fdf4636dc23a5ecb8e2456bb84ec89acbf989b86edf69ee9c3e2eaf37eb9b5a352d337b59e39efffee26f747b87b117986337ebc79d65b6dd6cd96f39db4754ff8d9c38c2b944f4b06ab088baeddd24dbb8d83b2359ec43c9119b77265853fd0ecf71af2c7c1932e4ec8d34e32f5f8bb6cf9f95af0b9962f4269b8619dfcb95ae5f9a7c747681e09919a66cc5c6923743f9ab971320ab519360c9d9f285ef8d2a4e662637f5c336e9ad3df4b0ac2aebc0f35adb0aab3133fb36b2a26e5276977a4dd35f91b2dbfce596d807271aac8d529a63305e0cd702dfb42b768c84dc0f97d8d9db0d5ee55f72b04cc362b96240e4a4db8e5bc4e459e64d1c48ff623fc2e518e6f6e962dd6b851ee30b46340511921b2af4b98d95844ab197eec50feb7da65e66eb86d0324b66a53e6df1ad29711b9efe4607d7f070b5f88fc99103c6d45156ed9ab9af31b7aaf6e3e5e8cb668e5e052ff648c9359f17f41dd17cb0b0ad70ea7e9d2cf29e059bea68e30a377f79bb30f2e6c539d53521f18fbda9fd30845d6f72864e6bb765447a2e36aede917de2ec70429a8371f5edcaeb6b77af1d30d2bec6057618752ea96535aeec53f592edff9c929efffa22a0eccdc925f4bcc659b4bd84bf033385fbb65f1cc339bfe86d44de36fbc80c0397df9d4438f84de39f63a2178b5ff0d23f2ffd25a0751076f8dd6919b386ba950b39ac1a5c033cfbd899b68450618a5f58ea19e76b41273827986752331397dd22df4b3fe9fe52775554b3654a45bfc08767e6e9ac596f7969f04467faeffbdc6ed57db22ea099d86c9756595cdf11794df8ebe70dcf975851a659acda42984e8c8cf3b666de78656ddd5c4875b6223e3cb462b3dff2f43d117d6fbd2ab03b78c69451a7ef554b6eef43ac0bc8dd189ad87884f4f6ef26c3498fffc97dd0b0b2e5db8de8bbf8d754a6040c367df7c7920fe4454dfef9b35d0579e7ce125e2eb7a83f9d914b268ae2f3dc2eac6a93bebc7b3775cbfcf9474ea5ae3be27b78d9dfa3a8612d2625cf74f4e705fdf46ae4d9d881269b6343ef78b27dc716e515591a873ed88539121669ee7924a7f2e9091f23c7d8d0d25283c003b6f14d372ddc67977a5d3ff299f7e78ebd3bb6c276f37d1d3c3ebdfb302be0f2c7db5401e1b1e582873a33828f5c9cafdbb0afbedaf3e98386a6b23376879c0e0a052bdf37d6374be751ffd2dd73c6c89321acf4a666ebe7ad29fdc8f209f4da7cfc790b3df4d2e2dd1e671cec2afde6dcfe5d38b2c23ee7ca3f95a306880b332f9a5ddbc9f976c424f79463e642db30c69e78dbe73fd731ceedaacc6f322d38746388e5aa6cfc04db946fe2a139c75b02582119fe71f527d83a0d453b9cb31bdbe7db623dac4dec4ac9f31d161d7bd9ead20065dcc8dd636fde3aeaf933d6bb849a82e0348f4cc9ea85792d316ff71dcf5ae53a919a973a2bf5ccb36119d56e03de06261d1a7f2f54d7e04e1b3f6365f9db279ea384438fe68c1874c540ec932ccc0f359ef7ea4880ce365b06190a7e127c294fbc766bbe947ce5dde5cf772efae6546c986cf37c97dba7c0f637c2c70b428fe911cbea47df95e06abc4452f69c1cf1f4cb6b7e9bb133343feff820a27b7b72d3aa646acdc08cfcbf3eb5dd9e8aa367e18794bfff6b54dca7298281d4f3fc418bde5c4df269bad6f7833ffbabd9c73185531293f5ab645b253faf006ae1b49f92e4cdcbd77b12b6180220fb687e05a0d8ddf199700c8e2d41eee365bf28187d321ba63329187d7d3297c35f0a8960ae3b56be8915b361588285d82298e58e456d6db190245608bb63659b57bcfc375e0684ef4022870998b1b26f26279a42e6f0c221b188e18e45ef30b114325e761ea34f6373c410470c49d83024f7136289043c285c048b713254051a192ff757163bbdb59d560c0028eef1bd842cf65ef403649be2ce57bdea52e727b145badb7929c4e270619c8ce65ce638300a00f947733ba98b864b8f1544215e7c6aefed6835307886802fa173f8b008edb954ca84591c3e0c61bb2ec0c6c763c86c02c5333080e6e117e0359b8c67132818a914e633e3e5ad88b17a8f5e130000048d6e8c54e7064b209074ef83e26ca703de81813435ecb42b6ebe3dbfbe53cb2eabc7eed9156765ec8a261581e2ebe54155e3c127e9c63b780000fec73d507c2b4d3c2b6aa0272d38c80b52cc4072e7977cf6746c6b255c98e223f016d1793034530e22dbd8ca8ecaaf904abb8a0e1147e70cec98808abd34271a6270e962b13b62c8554150e5a0d82dcb67a73246c790a9027c1f4b84b59ac97bfd4686d52700c0a71f9d1ac45e4c0d356342545b934af5276308e1fefd6bcfafb0d432a8ab3ba5fa923138b83f20f792415d5d49a51c3e831bc5ec2a09f9692c848b8fc77c3f87e3d1397c9a90ab74188bc88adc44e6a0cec7977a010080801edf90a9382863e9c58041dd61c9ff23a8a6d4dfc32f80d095d11aff56c620f91ba4de9310d59310bb48c2a6c436aa92a87b87d249a2e116d4a7af69bfef5e22956543807ed7757989b2ff3588df948190c22f4314d0b1ef404a922724863a8958e74b173035b80f50158ca11d40cab02c500e6476196b128c29e3215552a628bc997d81662997a6b80c51717d5586ea363ce591ee5cb55a3d3cfa0175222bb4395212350c154d02c2bc1b919532185211854181d57782a135559a12a2834a88830e509651699b8770852951631e90a227741e0e20ccbb9151298321354fe83ce8e80275aa29edf330bb03a0db3c205f581aa0b8d375817aa194320452a6848678d309a12c8452f102213f424384f607ead54dca1048cdcf6014c4b54e0835aa25ed519cf440b7a224edc7635b078a567539105597b73b4c5535476804a444085d9aa603404f9a236530a424080d16a904a64663a47d6c379060284d111a01a9fc41bb63a40f7ad214298321a53e68b068253035d2a11f183724184a2b844640aa7a86a2c70d037ad00a296321553c68ac68252c555590a6c806a123436229ab8094ee1b08a10efaae6a361068a10252c643ea71d07809aa786ac43eda07f94a090fa5e94183201534e628a77006a0674d8f321c52f28286ab51855315e1685a9406a016a50843a04e35d3fd8dc218e5cde14e73b5aa19651ca460058d633c086850c528e320a52846289c24148e92d8451906292d413f9ebd41c1a851b1284321251f2628a8f0c140a33245d350e9a3866ab811502b18d1f6e126c408a8138ca0cd910a0ef4c3fc0e84b91ac188263f30283f4c8d817af987d29a886816a2533a1705a02aff504642b6ded037f609a341b7ad46ed6fec78082837edd00e203b6be8502220a0b169a729ab46a8acde4222a9f6e5d030c8e6d8689443e65640ebbe9ccaf609d1f41a8942cd5187aaaea5a1b20e22ba5868c85158a05def4c1912d9cb51f2521da4baa685f6a3d23206686a09a16190cd1bb46713ac81762d21654864b7060db9551da436f943f657d0901fd441fe68fe86a2f2b77d2ce8b14d83c642765320947b2fbac352d7a6518645f64fd0b07e3640fbc68cf637e642042c6261d1ed2fbb800228406a0c40ab8decd7ff050000ffffc14244877e380000"); err != nil { + if err := gres.Add("1f8b08000000000002ffb45a793894ebff7eb2af214b2a21629031b648b214b28c7d8b521a0c711861ec2d2865494aa1d27650a4639b882329957dcb96b4280a917d44847e5784f71d63c9f97dbbaef8c773dff7e77e9fedfdbcb7219a928a03d0013a3088753404907feb003db075c5d93b3aa0667e49e05d5d9ccd4ca9c19a8e9df687c42a7491282df132c30c33c3ba9ad21abd46140ad584d2ae42966a8b6b23cddbc22474f4cac4cfb71b1b1a1a6a9589579b837bb2b2d24d322f655eca6449cbc8e534481952a011086187449b8b72a6145400fcfc6988a6a5bbfeec829d3900c01e00b0b83ce679792ebe128e38c7ff5765c6f3cacce7957d0f5453245506805ad04d98329a3965d39254c6530efd1a0cfd93c5cbda30371869ebe9817775f99f996f345fa2d97c89a6ea726f97379f6381caffc133309917b86f5ea0246dfbe9e59f0133a9c0651f050097dde01874801ed839ba4ba13c3c6da68737bffb9327c90519feeb3f128ff5c04b49e07df0f32e49e8d521b5911252a65ad535dbb4abb6ad992bb3e0c1a59deb01006c4b7230cc724c63cfe392c70ca15499629f366729eba87e63aede31e9ffe69834cc3169f28e192fa8ce3f929772c58e494f3b260d776c21a69e0aa164c58e49af62b933017ae028b50387c2e2e02bbcad5cabaaac6c5f8699e11090ba9c5b4e0c7737569d38caaa46cf3a2bced61ba9ca0700e05f198313663106bf773bc6dcea3f9744dce7939738f62ef750e8fd5d4f4410d45b897625599d26fe97c19a594e23077e2f2900c0b69571ba7b2ec69927f9d3e679f0e6f572075ffb656aff2614cfef7c763e9c592700ccd5b823ef2f24004064493e96593ebf2348357d38e57c9504efc2fa3bfed1335e3ea550bcab74eb4d0215dd2c55574b7984100060cb8aa94cf7fd3f52919f56bfa856b110197f0f45da39baa3b0b855ae450802ea08d6d9d975a9293a3f47dcbf3ad972000058ff88c0dbd5ddd98e8440ac0655ae6d946166c8400b25b8c1e689202558c60327cc7ff5c009f3db035fcc020f728c17aea1f9759a6f2f66c93f7db4ff09d98c1f30b2693b328d0dfd08b66f88f79420cbe4e66e6b67aee9d9b96247dc3d57e108271ce1b723d0837f91053eef86f3b12d229ba7ebfd13a2193760378cd9b9919741ba6960bff63e5abfecfc580ba598de385661c8860520bf3d71f270c5cd694de9f875cd319cf186603cbf3f38ad999bd4055b18f3969f2564f866ac21c7376311617ec25865cf9bc4d08b9e22e55bde24d37dab30897b01c86f937c20939b90995e5a652482468a5557d63c30936e903134d6aa42571b9455a273ccc490daf5d986849c4f8432d9acd2079f7ed5975136bdf6fc67cc7419deb24b62d3f10c06d5b91259fdb8220d0000067faa6ec6d2ffa84e747ab5facf582f37ceca1b1ba16c41cd3f2b6e5c58375a9f44dcc233800e226e15d70bb6d9e1f68eced8ffdd1d034ee38459e91e3973ec17e9ecee2a3bef58933422b286629698a3b8c2e2d745437449625618b1bbe74ab6a245ef1acf8c5193e20000c4b2af3ef39433178e858b6fc152c7ab06b58f6928881e2edc5c7fd3a0d7a82d857aee96a96c887a280100105f92989d94d874dffffb020ad1f53d61a41ff6fed2b4c8ccdab303b9cec3857ef3bb54996a793d0600e0b8e4aca5874a5de57b84bbab2b1e65ebe1b18afd661d6438ca03efeb8c959805fa65549d71f2f4fea85551b3ad1659fd8f4eb6b1a49c5872060d634ca2f9e52fc21d76773b2d45b72675442772597a3452cccd49b1169beeed0000e925c533ccb23bba601cb0ab90cf0e034039bb3ab84a1cc539cce9778ef5ddd1f0d7a69224e9e850819d312fafa85bda579ee656c3488eb8941acbda97958adb0bfb3797b81bb2373fe0288bda7ec054e0b4020741e847946db957d49deba3eefafdbe359e2d44ab266249ffd47195d1d182f41f539da1990f65b9a8b4830008b84d4fe3c20800eba3d18f2700e0f750cea300a007f366e3574a9d47777e9ddd2a9b3fbda0026b437b5a94028675ddc06157d10d5f4bddb32435db1c3944ceab7a20f64c8ae09ff6ed1edb32298267b8184cf9c3283f5937f1d6dacf2cd451e5ea7d6730ac037ceb5e6ddf1c9210bcfd7540317f50e3df4e86662112744c3409dc54ebeab85c86291d58b576b2b270859f3f5d78ecf8f1bf0b1cfe962d36e3b642a319ef86056c611563a2d00eee32c0b64e9826575e3a293ce6ca2b7b31d4e14297b8740443cb64f1bff5690ff0fc17f8aea9d444ee141d7e722eb992ef60ab23c715bef36b4fa999617ed2b00d9c941afeca94aea223f811a38e1208d6c24a618e8a4c582b705d551ff7ce79af72f24dd754a4da98d1172d4a1ab612817837f178893d9c6977e253d2e2530283052f38b069e5e6c9308cb0d43e6995a589d94bac6b7c9b4db9e9e20675eb8d9f36b23b1f4e1a919f38fb852f9f3a425578ece7adc73b8d0f52fa9a13cf4e7e503ff99cde676b68f1ed8f1679760c7d626c7b930e69144ead9f8873cff14fe43ca59b4838fa48ad3e38e1f0cff53ffa03303faf0cdcfa4af92353258f9fa327fd600335f2d1703f25502d143ea2f40fedc0a50446664511b731b16f62d9778fabe49859ed3eb6ff8b88e187f306523d2382fe8f0e099af887144c6ef831853097576e0bf7d4c80cd6747ec8726e97fcdd1767760b44062194fa2b2a84e9be5b5c3975ffebd840e021a507efb2a83b5dd262ce05e40bb5f4543a0ded94ef3d53efd34b1cb5dd87ae76088bd5fde2f71977f674678cf515cbeb5f418bf188a09d682ca3423adb9913b116270b82b63494c63659aadcb79434e3dcf4cedf6660d4d3e6c20bf92bef2ed329e57d216e10a365bc9c2dbb11a79d9775938f474db136c02598d787ae76c0cb5518cb98f6f5c5615c5c194553339ebf1d19bfef75b7717053e2f3ab214c15a704aee6f48809becadf2c9ec656e476ea62d879691d04b34f1267035e4f331c59a441773dd4d4fcf16b3f9efd7db2bd416dac5eca9aeff7aa88eba69a4e55d59ecf55c7b1071a9cc308a6b4d7d6f3d8df3f52696b1b60ee6b2c542b9a436ddcf6445d39e683a6f4f349fbe091ea37dc6ca278eb619623866d748f2b2a1f257cbef813bd51c73df0a44198f1d05d1aee83dbf15c125ef7bb3b238379f404eb3f47e388da03a2593fbed5bef288bafd3066728386d6b773212c7b1e74b9a9d48c0f70721b6da565fdb71c8174ac517bfe98daa1fb6892aecf796d1a6785973906de027563c68fd2fbba4c77f2587c2b3b8819b072ed74b24a7d30f27c58a4705d781e33eda3e7c26bd47a55144e5b4d3d7d1e7b1581b2ed258cac3ff8da947d704d1c4f79b845d1d556ec4753f1617cebbd7cf4cbc1c06e29a9239fd383d5b63a20c25f7b6f4458bd441c4997c1f1efc115c5553b0da816d29ed111646e1cdffc8e654ce02ffbbd88e0565b0bf9ace1f766fc2ae69d49b7b00adc47af29a8df1d896d90dbbde59b2d63e243d5de338d7f95e6296eca5518de4c11f82cf3103aa5b9422d619da43b86bf30e86c1373ff05b74d77ccb57cb36d151bc5d283dd541a2dcbcccf6e8eb5f9607473e7d6fc898e8897539386cd3dbc13a82e658394fbd67e0e87426b427bfe6ab1e826b46a5dc39f09ef961d51ab373caef5ad2c99eb1d7ee2e24d7f243bfbe1b207ebc4f9f8b42aa2fca9f7260dbe9f7492f3ff64156cf9c46cea689877f15b44859f77fc0d4b07d409715f7641a6b0c49afc87f4365e0a03c5296b3f9e6dbd7a6d4af36dc94442d48f6add7b252197e5a334cedc6738877c90f72164e0015f09c1d17dc783d6c3a25517d2385e9f221004959ef85f7ff46ff69b6f83c11f0ee0930b886ded016154a9672cbcfccc1b785b65eeaca9898fc4a8f27ecf3a9a2be7ef5cf9edadee091dabaaf0c1f59ad591db43a8f3a8e9f9760810c5dc75637b65bb43269d6f3868b57044e6846a32f0760e65e7681daf3af2e27113773d76408fc59f38a420efbd335ace4b27d67dbd6fa05a761671efdebd7b06f70e120dfe51cd98a03250ac546cb4cbd0283089a5638972ad11111f6c69d3e129d0f3c9ed7492ff6be86dc79bbd754f477efc85fd9799b9ffdf096431a5d99ac842ae83d7e49b98384cf284f99a788bf586af363aa69c29cd7538399eddfcf19a9c52344a92ffb65488ad75674cde7e4dced49697e8a7df7fe2aeb1d78597161fb14b4e0f2bbcfe6ca476a31afbdb12663e73bc9d9c2783478129c2ac38ef468a65fc50784b247344bc2edd2e57394e96962ef7035d694f2ba4142b77e3c4eccd9f7e6764db488d8a374051ebb99afaada5197e5dafef7d44f0a295e66725c14faa2ede81c7820432ab9a8b8ada8e6a3e484ab5572cedabb54a7ea17bb9dd593b6ef253fcb544258b8f87fb631cb698135e372bf459b10e4c8650b26a3aa7e4e4470a5c92966389efe343d2e5f0fa0ce51204d8b77fcbb27b77a7a3fc63f3cdd050a637277a29b169484b1be5ef8e0f0fbf9d8c7b9183d990dabedff30397ad60d8b54f3bd28b62ff61fc9accdfb4a5e8464f6facee13544e505c8401155a4f5cff55c16b53be2d4ded92a7a58ea9079a3047987432bdc450ed38d97f56e67351a8f258828e7795d05e6bf1b1b54a8f4f944a1f881dba3654b037a393a89578ad5a56e950df371943af26fb31f4c53ab76c8aaf791d2de3b963b9f81c86b384b83dbd3989074ade07dd7972f2675febe0b88effb3a4bfc33631eb2306ef8adeec4ac8addf91748338782efd98f7e4e5deb8f692728bb6cc9abab808bbf68a7de6f949b4177ab2e4d47af0885dcf6f1ea366fb71fb55052e72dc58e04972cff5f4d7bbf6251d79dcb5595f7bac81f1d93df5a980a4d38dbc870acea54ad93ad372fa59a59e97aa3b713a50dfb2de946ea0ff9280efaeb0015d5d968b6a711c6fbab262aa15f98ebfd98c98e8f5d7e8d68813e0b7e0c0aba21b0efaf0cb4bb6ee7f61fb76dd9b44eee4c18edebc76db8652fe1d16e6fb2f95fabde92148341847f348e5b0487bf377d46ad9fa173fbf27cf802420aa46aba3d246bfd86fe7ee267eb07308ad418cb1ecd3afa0cf5c3fa97ac627629dae559c80f2d6d1afe8c84ad3c0e0f8d8726937d690f5ec01fc25dbae17a8df2efd7c43f1f48fbb78abc74c0d070e50f688342a9ab81fabdec82bf5fe59fff6b70caed88d147105c2dcd63eed6bf0c5c24dcdea060392ef76ba947dc72a7f19d6da4a4c88192dbc742aaf75b492afb2e3e193e663ed441ddda20c3b61046bd17baf77fec7326fe3b387f7285bd388950c56f38fe01ddb7238d7f7df147e2491468c30121c56669d68711f919a64a6cecf29c4b6a665559627450decc0b6a6b5bcaabef2cf9553c63a569ef184e1079287b666b9ddaf407e437b7e24f6cbc4445498e172f32d37f51cffee6a5e364c7b4f0f5156834af5e9b823e2eb41d5a0922c7dfb457bb3b5c1b8957db5615b4eba52e6049e5ba039bd2653e1ee7b5dc4a5dc978ef12e96934e21db6eb8b4f11e4c7f8539a89db6b541137176bc4083f9c5beae4acae7e9a8f28c032396110d8a031a42a5f9bbdcf599475b0347de1622ff5df74fc831a7c38fd41dae79d34ec6f61e30c111f2c6d7b56a1f3539ed1d7091e76fffddfab84c8e54e1706e5fbc4ced5611e5128ffeb7c1eb8a82fc8c26f89fb46e6a28e67d711bdbe7d2f4b2d9e673b9ab47d0b5046bf7b349a77c15df2b4f6608c90652ef10c81ba9edddd65d775de3622a0db2bfd9e4fbb10b2f2c9088f5c187df95d69f602bd8b8e3c307be1bf8411b374fbcb3d4dd97a3f28e598a0689b8a8c80f85e3e5410d263fd50442a7d28ed3f05e31e1f4e5947e96f67c54b5a8afa58da6a839953dba788fd8541a333385390b27aef29bd697d772dc5e5cae2627f41eddf28a4df6614bf827277ba4b178a8d11e758d862fda8da755c6430c974777fd84e42baca4d42ea5268bf4ef5ad901fa8c876e6d3ec084573d49d3d1c0b8e16357eade2fba53f9c967f4a232a33136631c2c9de343ee31871e136cee871eeca7cd330d37f67a1b6bde75aab2eeb370e679fc907ea6162e5b87101ea4a8dc79e65943cda9ef0ea3fbc33bd4d1bc9e7cd1f435a76f981dee978cc4c612c5b5ab79c2033275580abac264b32b9b23c219589514d88a681a34dad158e2ad86a4c2eb7def7884060dea4c2e2566b3e2424dae1f92de562714d99933747b97a0d5279e9da837c279278610fab123859cf733341d68ac02298edf37d53f4a2ccf0d949d7cfda9e7d3d9b754578ad98605f661ce06dba00b38a87731f4c8f60d4b476ef0c811616d7c38e2f4289dfed27b7734fa44f7cd9198c662e9e30db5d93d20dead475d85b17cbb1d95df6bac8c9eb5c66319b437b27c9bcab997cd21571823553d58dcc2945d53470e05b4491fd68c6b5241d33adf48dabc472589b7206b6267a54f9a6dff3ec6c87e9b3804bae6ecde819c7ee5685d2664ed9df17dcfa6d8e7ba7efdb703329800b8ccbc5c737de6cd076787f591388287bcde8a57d7ba14f333517d74900e2e0283146744f35437f264306c79661eed6c7d71ca20a63fd140b3687f4478c2b30361e11ea6ed138185db7db293085cf644431abec2fe94ef77bfa67517de0c3f255fc0fc810f719a2fb4c0dfaf436f6893f67e9acdfe03750f2b2dfcfbbe7adaf3d13b3cc94d1760883f1cbcbbfa853c4f827ce929cf1bdd4ff67eef9b649cad08d3fbddf41c00e0e1b23dfc5f15ada277f3eb35108f7539ea8cc163c91932246e84321729d3322bad446ba71a8afcfeb66aa65551a9dd4839d75c781c23020401009b977c6965859239637c5d3d7f7f4efcb357573e3230285b571c1ee388c3bac3f5a7a4e96beb5554a2cd0c75aa6bb6695756a291c629a9ed8432c92c8f915146b7e1610f66426d8d64d6a79434fd2af4bdd4f9868910eddb7e790080d4926278c889b17775c52fa1a4a206a53d2f8338cae2b69806d36245ade5bf8491d570048bb15b5c43b9969eee8c86991e8d6416f1a8277e511de3fe17eab70300507fae63e6375c07c1083fe8bd3694e9a859a9485955e62742a0d1bd50512f2b0606060639a1ab420af7bcfac6701aa1ffde63500e8d1ebb232437ce6a9411d6dd1dd5f02ee8fa8b28536aa10b050d0277deec97d8743c64839cf69868b46182b174054794c7baf07097e8282251679d0cd138fcb224f3eed2c6577b64bb93ec6230d72ec6dcb20e6a04c95429b84dc743d0cec38527a8e68a2cafbeb8250a0030fea793587a1593988c57d264e70dc91c995f73fb9d87ab38493ec7ac9087dcdc20c0e7c03c8fb852f3ae55f2907bf62969d595e86a513dedd94958572152566564fcf27e6afb9ed2ae7661fb8e608ecfb7e9b7dd69ef8ce5ff6bfe3339d55827edaf39a8bfe4e3e124a7c305e3b89acf93fc8b614dff9022e39fe7f0b04c16dcbe4abddee90f956bff0395f42254244fca46c5b79d948a7cb77f966a8913630d0507e5bc56685c6a1da09ffbbbc4c05f3f974870910241d34dcc30a05bf34024399f790cf239a8d985f973b7c21ab03015051700cd1e6d8009f09a1bbc542a8a140f1a15e280e1f15080a5f34b4bd5c50cabeb31291499f2c877b867317a77afa104e49246f06aa089202e5835aa90e18b248d48c1a05120061858e22c183c52b49421543043beff0658850f3254805c7e082e1d9af381fbe00e19be487e88140c1af081fbf06a160c1e145ab90f62d480341504e7867e5b63827163a901f954102904348e0387289985208dfd2c500149d8c021146900f9140f290434cec20283b83f0b412698b372142e5ab068e666e5cf23f037ca8ae625236c5ee6ff1eba304e032f019a7c814fcd293802b9380d291834e50207b3a603cb4567565edb5328182c260397034db1c0e550d083e56232a460d0bc0a1ccc95048c4c0c66e5b5d541c1608117b81c68268513268783012c137821c582864fe058c749b016665a96aa6c2dacb28f502cd2f00ac9b9010996c04f552146b082f00a291e343802c78b5e8847269cb2f222a999c0e2e113b82868d4831b264a67010899f009291c349c0187fbb2106e615a64a94d890eb62905330372f98ec50f0a36989a17b3c3c9e63b4871a0990a38ceb6b560890007290e3428c10abf3cc07048f218a430d0d803fc7ab69e052c9db1208582c612d861501748a14852134b3d2a7ad8a352640564430d2bbddcf8b30272a1067821d08801fc329f07194e26d4b0940e06988e1d6c807c3e81644f8474ece096fac20016e6134891a09d32f8c1eec10b16edf7adfc60d7e003a43d36b800680b0c5e4a001f58b2c7b694abac30577ba1480b1b687041d0fe151f4c902c3f5871036dc1eb13a423c503432d24874aaea3b1601f843497e0901a5bc0ca1a5ba490d0560e1cb28a1c24b93ec5ca9f0a41002cd511822b83766de0cac6c8c0acc83f6883060e8911042b6bfe9042427b2d70c83272907fea1f27cc3fa3ad60d9960d5c1eb4a7c20f937763312c722d1b525868ff040e4b270456de9e59f9c1ec0181856c2cd434bffe401928037f360008bfde57c0ff050000ffff8ec4b6f643370000"); err != nil { panic(err) } } diff --git a/os/gres/testdata/testdata.go b/os/gres/testdata/testdata.go index e9cc38ab2..cc6b69515 100644 --- a/os/gres/testdata/testdata.go +++ b/os/gres/testdata/testdata.go @@ -3,7 +3,7 @@ package testdata import "github.com/gogf/gf/os/gres" func init() { - if err := gres.Add("1f8b08000000000002ffb45a0b584ce91ffe50d210a5502e99464ab7996674619a8634ddd085c6a5d8ec3473a699ccad99295d8452897f216c2e45b259245156a2dc6a136ac965e5b6b9a4ac2d8becdae4b2ff674ec939d34c338dccf30ccdf9cef7bebfdbf9cef9ceef0d983348cb080c0100bc86b80100f1190f7401218a2126ac58b18210c6b69370a510410a49a404a650c0e6862da06b8301cd647648c01c9d21c889ca2127a980b463464aa442be06c8f64a91d1d05dbff052219fd74d13c585568818520ed6158b2370847c084691427c118f21852438cc1231c4e24abec360b1582c8b2b598e959d492439e3edf1f67822d969aaf3745b071c3ccc643039908261479ccc193acde93e1b00c0eed5191b759de1c7e0b9026efffae1d4bb1fceb01ff63a4d49aafdb052e5c7b7cb867def5e10612fb22b36b3547b61aed28b6f910652ef0e4c851d684f707751edc058a50eb0b862a20617db44e5119121122491a11aa0daa946957ded6487887869b4b49ba3fb2896291448218154467af6f856b20100c0a057523315a4306c37510f92d441333ee90100f4344f00a9df1340fa260920a11240529800123236719b4c077d6d0248f09f2454025024be338aabbf26015ce2348106a132ed15d08ec5156b008a531e8acfa80448d0bf8945001338108f2744afc518f8986cfdf196fd012f3ae29670a63e0040bf3f385708c53c961c277c4cc6b948f607ccb9db20d25235a73a010c677ca3008633ba0218c3e811403216d798b0b531716b63c2e1c684dcc684a3b057e56ceb20130080497f90774612450e1f2263714f4b339ffd900653ee715bc61b010018f1d58114476a10485bb580bb0289bca776d7615dcef53575a575c57527ae27c21ef1569a4d190d0018dd1fc49d4144127717635d795de9f5353025d4f2a24c75354e5683329663e7eed7bf8fbb68ecae50864b845f168e38f8c902078fe064e571666fd3fe33384c3c7cdb341b7a5a754daacfdf195145fcf008ee4b7976f2635eccf9a49a5fcdd8d21769105b82bad85db18d465c719419d17c1e360a124bb842812b8e88b7c761210153c8e20ac25c719152b6dd34dc0c2a862203a2c261a0c020d4ce1c503a21a9180a4c459519ad1f3b7a933f00c0bf9f8cee4cc8571a0d83503b1347e9844419dd6131f707d5464fecfd2ecae6f2200df23745452864b00448d0fb8d4ed14d88b9c26e26160080fd7afa70869ab7098c8235dce862cd622b787bd59b1d96ead8218e546395c5285a032be6133e5ac2341aee64bf18012f143d97881e0b942d46e9aa410d2094d8c2cb7c6fd658ab690d7dd137b9a8d5ba722ecfbc72930b00e06af8220546fa86e5ad8a399ca18c597169cb4610b53d2f0c1b650317ced718218e546684eac2664e3bbd7c0a7c1df76681850a0b3a6b1a6544b70d9fefb78afc7fde7025dd0cde167d253b7dd1376357be9b120b85d2feddceca10094c894403542bd5a80489348607e191f8d6d8cec713b65020b59370632132762a4914ed021f9442d1523b068f1b2620639990400a895d3ad71feb86d03f49000092a67b5dd8222e9f11a6c91dcf5a1d5c024f1826c48b045fdedbae0ff0f3d2c38cc5c8b6cf3edeb4f95df693860c96ed7067a41601000648e67bcd028557c73f0700e88abc8324000c35947d07805dd9c6000c2ce4d2174b17fbce2533857c3c83250c85f0d17c116c17259a1ccd17f12129031bcde70924e468571c7c06592021cb0e137058f814e97257dc62df00acbb500c611df10e787b1cbc5c52c42c36793ecdb36bba98c576c571a4521199207315bf622a5e280e2310a74f9f4eb0271148243b318b6d2789114819d17602c9a44e90cf383448c214734552ae508095fd66840a23a5ae385cd7399d9f2e3bf9a26e2281a4cb2ba6904f8866880844bc3d41d12416b37b8e2852cc834d633109100fe24302a98440c41315ce9372d96cc56cb2914e3aea97799468be88ec2e86185288c6904254923d71ba9dbda39dbd139d48224f2591898ec11482dc498aa60bc574a190477593d1613db962688550bc5c82750f74404cef3a496ebeaf90c565c7f4a077243b3a91a74eeba2479c8498ce6292d942319f21a57656a5481046217c39883853e63dd95fcc850452862c69542285d0e3d8e70413e432dc593e84aefa91dd61bb6b918a79b5e4d6200030ab7d686e748ef68bc54b84f47a93efc204618292eac1b555c696c68dfa23b567056a59276e3eb820f086e7ec05b8590bac16dcfad93ffe0fe661aa11fdd08879ef75ee9df5e26f48c4258fc43e0edf6761b6715894ef5cec89535acc38deb5a6da9dcf83dfd74e371d66e1c79c63d596f9b676677cd0c39367ef378415ccc8362e7844e5e4be5fb336f7d8cca72dcd97b537d946b3f6d81ed30f7ec3baf39fc9dbb3afbd592516c74a03ce943c9f6d3fa67ee0c4faffde422b4d3e10cc9f188a52f3ffb21264d0b5cdfc3cef566e5bfa76ffeaf5c28965f42abcce4f38a788d00a768ede5bd7f5de9be79869bf4d1169f3af936e18f82f2de23d5e689594e537c4307b536071d29b8885becb2163467db2f562539b49eead532c1da8b31f1cf6333664653cda213d35e66d1acd7c8a70a6f51dfab3bd8ef36625263a145ad48dbc9cb6b5f63c4b6b8c789ed174ceb58ac4f9d65ead29dedafe79e30b52b76f1eb63dfd9fe4231683d873187ffbd322f6b4df333c14da12135b6693a1ff5b76de161bcefe5f7752c63ed71db0dd26f39d139676fcce54e2984dc7fff7c7a18c699eb3335f5f9dfb183b99161af9a0ca792ce662e5e0ac7cb26356d2effa4dbbd2fed714a575c0933ff63629d776929ff06cc2da08bda7a58cc93ead8bb7b9a798633ebcd892b44b6bc7d5b001576c86c71d7f116a59ef7ce34a5bdac960979f76add32bf02d6d5f1838dc27f64ef5e8856bbefbbd9579746ee62b7ae09ec1f933df391846617d86e625b531e6304d89023a7ecaa1c9794bf10f6f9f6818834ffef3d01d767090ef86df9c262ea14d145eca8a27add9943ebbc9a915b35ae74e61b287c3ad85a14357904b9e3e786c406ca02fa34df8a14d5b97ee3afa7f6619ded89d7371a6277fdd71514fdf71d473f6c53897b2b6e5e4d22ded8c66da16168b9f11f0665bc9c0561a65a3b7792246efc04f911e5bb88cf6427fb285c3a84f27ec2e19304697fa9b9d481c373e658bed93a106afeaeaf4070fc69be55c63feba2beae713272e44647f9fbe37f96645fbcb9a7919637daeac35722dbf85df49b949767cbcae92d1983ee2daeeca478fb063a79a48a3a270952f438bbc5dcb7fdb772225a5ddb968ce2dfffd77b747645dfff995db96d460e9d4457f14d4ad37c0248b9e5e9ab75252b3b0b5e1b80ef32e317b5accc8ea8698759937ad9e38ae373c56ce35bc7bfc8097df9eab7586ba294736a408cd1973eeae1e3f6d4dcd76c28f478f8eb8f61fc77955475bcd1fe7a2afd3126605b77c175bb4717ad986945d7bd60d30b02a8c3d933aca1bc361ee5c4b7449696808f9f074fff6b492730fcf8d98d15036266ed94a039d11a6bf24375053821e2ca6ff1590e7c17d679c3e2f9dac37ae56abba72fcbf59e58cfb4e0d54b156e3dd88d6fd19ab3e5db169ff54f832b7a535eece49e10c4f4f4ffd74cff4673ffb6308fb3786077aff669f89f5dd1f5463d88adbbf407ca820a2a3d664f866d64f03c2ae4a1f7f78f7a67ddbedf7f7971fcd2d2bbb5fab5be975fb78ec11ac6fcdb4556fdcadb7d73c3e727238e3d1cd39a5d3ecd79886e6bcf8b3c27db98b6887565c6c6cf9ca8c05a5cb76b4950a8c4eb4bb6df48ef96ff6de35374839de4e598e6d630841898384e5095bab1f7afc547439fbfc15838c7f4e6c2bdeb06c72c94b81aed1be0d09ebf88f869dad986dbcfa53cdb2d7578b98e692cb7331cbece6f86ba7cf4c723a702e75cacb958dedc5e1f5b1d71608a75c7621936b1793777b7ac5b9840edbcfb2862e062f59e23bfc7245f8fc69d598c083cd09264fd7f935155c5c7024bf64db00ba76fd8d8ef043f4b1878383d39c576adfbfb7509b019d3fe5b78fc26567bd1b42d937f2c0da80db3f1f292ecaa63c395df07049c9f7f553af3d7a94251ceca27334a472cf982866638adec57daba0eb895955c7a6977e68d990945f919671c9f865c0a1520126e48ef5a79cf71724d1ff6c5a5de13571f5f8472d8f4f9e7be7788f5bba576ce0ad050d9b5c56fec4d99d96c822eadef8dd8adbf2e8a6c5489b1fe69a3c38f772c59dd39143fd72a8fc4bfcfb257ad7feba97ece0da284a37bf74069353f3eed805c3c2870e07024a2b6e9c4a7b96b66b59d1c2a3abf4ab374da87ab86cf5848f1f3f723897beafdef8e24e517c59d024e6ecede1bb1e30a630823ecd4817ffabf543b4ed820a8b86a352e30d677655789a591c7bfd3aa2f1363965e7450f7ae31562d602eef7a40d3f9ee4050e707cb955d7c8ac79c59867b5aef96fcfffc6b0b19d7c8e3579ab6eec6956dbb5d6fda6f3bdc40d9f2809e31c4ac5f7aa478869dbdf4cb38c8db9399ecd399814be75d71a739acfa140d7aac267c1234f5f4d33f8f0b168c7a279f9da58238cce74a35083dbb9711b97271d995f207c3c0653be6a73e9ab5182e49544acd9846990f474c592b7fa95c733939a07e19a75d61fbc575e9df5d3933acb4ab349730736b123af51f79479ccd25d95b2c7f8d9b698bbc58de6fa292dd1180fa6538177da456be69adc7f2f70b2770c7b9e7fc1d6340d87e34900899b6e3965298b6f9ae73c94f1c1669ce351cc8d9325da970bddac0ac6350710931a2b75794d55c42a8987f6f97f377acdfc85a31d4ccf2c9d97faa8d5bbb6d4656cfa2b2d7ce3bd64c91fd323864caaa7aedd3df7c7a6dceaba77bf44fd32c6cea3e0e9de384aedfbc503c7b51c286c2b9cb95f2b8bb277f1967afa94c2ad1f5e2f89b8763eb0a63638fe81276d1086b8fb55cea859ed96cc08f7ef0c6a7666179f1e4b4cb335a8b9517565fd9ef543c6dbd43a42b613ce24b626e3cb3b6a96edf8e744dcd98f4ffdca5f1d5fc6c86b9a47df47fcdb3f53f4e38ef393b86797be0ecfdb6e139131ccf1777b311e7ad5f4e7a4a8ef244ff9e9ef97ffecf762386eecad5919f346b95488b8ec5a7c2334ffe8a9b63521a2149fd0d4530e97038ab9c5ac53a999092bae536ea71f777da6bd36b2c534a57290ffbd530bb5d66d34bd30c2d981f1fb8f2ed7eb3bcc0be886163be2aa4daeec8cb82cfaf5fda627cbcca8b34cd66e23ce2645c47a9ab3ae3e37376f29a4399891ee1d5cb5d56765fadef081d79f17581f3865c4acd7f5a8a3b40f20d5fbe56e0e49683a4c7efd77b3deb407ffe4de6d5cddfae96ad42dc24b1a4b0a4618bdf963d9bf94a5cdbef9f39d8479674e139fad34693899914b2189e3f35ccead6d8b7b76eb56eab6458b0e9f48dd70d8fbd08abf27d0425b0d4b1f6be92e0cf8fef9f8d331430db7c684dc74e7784f2eca2b323508b9bb1b733834c2d8fd704ed5a3622f7dbb9890b2b261fe3f59c6375f33719d5fe671e5f07bfe9f3bf7edfc01b25ee46debd6f1e6df797ebfbcbb4113121f982ebea73527e8f0f945da8d3f36d4b83fbadbd85c7ecafaa0fd019170f5dba68696b885b4bfb4f79ed277678aaa3c69d9ba79ebcadeb1bdfc3db61e7bd2ca08b9f0dd1eb753b6d6553e81377e178dafb4c9b9f84fd5842192c2ccf3632eefe27e3a6c987bc22e73896528736fbce593ffd533cfecaeca6f362a387875a4e9da6cc254cb944f925139c75afdd8c119beb10dc51cadc6a29d0ed94ded8b2c716ee686d6659445b64b8f3e7be1d888cdb89abbd7c6f8c584278fd96fd6d41604a5b9654a9397e4b546bffef158d65a27675a5eeabcd4538f4767d4b80c79ed9f78d0ea7688f6b09b6d828cd515af1fba4f108d3a92336ef8c56112af24517e88c1c2e787fdb4b65b3229d8a0874117f224eb7fc88fa35c7cf3cbfb9be7bd732a374db778b2dba5c3bffd95e8c1e290a33aa4f28689b7a4f85a0f711c27304732fb9775bfcdd915929f776c38c9b53da9796d12ad766846fe5f1d6d3766e219598491156fff9a10db314338947656307ce9ab4b895ecd9707feebcbf938e6dda4c2190949bad5b2ad928f871fad70d6f7897047e3e5de35dbf400907d357a07d0b9e913b0a0683c478a7c9125fb45c5e85238108345c5e8ea52785cc172ac18e2b9e2e09db0840341521c962386d8ae38d4fe188795c68820579c6c074c807f136440842e244aa8901523fb9fc58da252b8fc30ac44cc74c5a1379e382a85201bc7e8d2395c09962bc14a391016b613cb160bf9d8303124c1cb503bd12804d85e5948182fdae9250080120dbbb29fc517fdbbb9fe8caa28d63e524ba47f9f4fc5b2b93c082f633f9339054c0000fe6af416b79b9dc78811464a35117238a98f4e600a055206570089d17ec6c5b1203657006171dd27e0e2e331140e91eaeeef4777f3f1f3984f217088544c5c1c2460c5c3af4b26ebdc7f490400107bb56e6a1fac630b8552e5a6758e7eb6cbd3df9faec028fa45176fd5af1efb6294ece2506e54e7a8cca8ce57c644aab7871b4d81611d719b6f12e01e4f7f19d6f9bfdce26046f377a7070578603b5709cae7ffe02bbc6b472ee541542fa1a798c187b0736110d99e5c76143e232eaebbce11ee7d5e25ba1689ced700dc282c93c790485c1175d3130455539d1b7d780591c7e84a704f802f9947cc56b0c05cb99a61d60100e8e8a7ab5113558ffa192429ac77b9da961107f3fefe5575bbbf2fc48a6a5aae7665c4b6ae7729fd4baca866e3e2b802262f92d55d6ef0300e8b8f8fc77c19c3f3195c015dc4933b8c43c4109e22b35bebdd331d3f00809fa66a821e76cbc8352806e73e52c0ff107be6c5d7cdc78fd89d965adf17cce10080e1fdcf4d52cc4deae60e9d11d384e6967daec747a2b8472be586a1ef3b45857c315c7ef228659311739525401e4b5f019606304310301a4cd7ea9aae62aaa2480e904d45cc1b30d0689072a5f767a75fb8c17202f574dfca2127a120035540f6d47da39191b269fb6e6400f2128e28455643f72d4f835435dba0686207008d14d9f20c48c5b1158a61d640a081565a1e1f29083647e10f1904faa662ee2dbb6351d9bdac145a4e5fac1c70220a70ac16e883be188d8a94fddaa12220528daa445f2ccf8154fd9aa1389a5470a0e5c4ea8778b636504f41ac6e88b3b4411f14c46854a4b0171de2d7aa51952888e53990ba5e7488d983411f04c3ea87b84629ae9c465839a0290a70bc0e505f23ac1c1487028d500aaa44238c06466a77d1a9bba216b0228db03c0752ab8be6a00e011a6a82d50f50b11a1c280d301a1829c9451b3f541768a80196e7406a70d11ca9ea712890faaa1fa0f76a70a0b4bd6860a4dcd616653c1d0334d3f6ca5320e5b5688a5fd5a3e8a9e2ed2d3c9351e1993914f459b52b7707422868d10f2bd9ea622b52edcad32085b2689af1c380e6e25cf52395ad1e0d4a838bc6464a5b092817dad5c556a0c19567416a51d12c47f480c6a259f56fb5a1c3411f54ae6854a4266f0acaf6d2e1a0ef2a577978a492140def3c02f45dc52a0f8fd4885aa2e0cfa9032f274e9547476a3ed14feb347da091ea549e01a9c5b44631dc5093414e49da5b7a27a1970a03d02781a73c32524789461e3d12f449c0d9c366843e128d9ca502595e95298f8c541f5aa090271882beaa2dd507cf520d2e2fa654ffa9d2c408a8a79554773509570aa8482b894645aa14d1bbcff3aa511568257bb3da0c65f5fc51a04fca47b9670e44430c7d1de6ab83db53f9284f806c2fa18b236712e86b974dfd1d42b13950bf5f850645768fd021d1990c34e957f566b525caea6435087ab6a4d0e8c8069013cafc46f5d195b5a47abc3d423476a6a2c8122cc05775987a3c6a203a3568a6d196e0abda46f24cc87e059ae9681f9814bd5357bf100cad8006dd10343ab24181f623427d74b57283ec48a099feec03933ab941f610d04c4c6bf055fd8ede72638bcacd381ba06987024d81ec1838a39c59d5470a451d0a7936648f00cdd6a1091b49319bb2be43e7c700809951b6407517e28be98afa105fc08e2b03530b4b1f85f59f022cb56086a0603ced80a2ae84f2e95aa8e9c95dd37b4c55d687f832f5bc6c2a629ef660d9080dd040a631007fd8c97efd3f0000ffff63060bd894460000"); err != nil { + if err := gres.Add("1f8b08000000000002ffb45a093894db1ffeb24742a1cd2e0619c3104996b21bfb16251a0c11238cbd05a52c49148ab68b225d6b4492aeb2afd9b295a2907d1911a1ff8364bec930e4ef79ee6d7bcefbbee7fd9def7ce77cbf571b414ac60850010070d3f19e3680f3c3026c0660ae4827989b9b1bccda0aea6c8341c13028670cccc2016d65636da04f0e6c6a7e9f68aa8da0a4c21d4818927b1548a8858b33c6c17e55642a60046503421626880c86fef527218c83bddd3c4dd7412b53817275284c45b0543bd540bbb6baa45aa301068335c2542ba125aa82aa50c38e4021358d52c16b9dbadadada2aa5825586c063313178a3e85bd1b7a2197051f1ac7a111d120404c26b1d671e2a6e404206003f7fce89d757106f350400c06a45f1fb88156fef216483b6d950dd7a4bba8f2ee916a6ecbcb4ba6efed574ffdfdcd65e52adbfa4faceebeb96ababdebbaaeaff83cdba4b820d97047ff79197c217fce753b39ba0604b1b2791753c86ec841d98438439bb98afe31184ae8e3af71f74eeaf448430ee98258385346aa1aa5021117d95aaea7daa95fb36fd7628efe98d833b00006058919a7315ea79ca25bae5a9fc496567b7030040bbfe62c037bc18f0ff4b31e0a062c0972f86ee1f0e7985b091fe6d31e0f3bf85838bf12795866c7af1df14c346e4009a8862e06b675b11106a69e3f45b38f115e6226cc8222a0c85ded822e300c34ea1ecec1cc07b7047994a6569e9d15403ed5140e426b069d176a73e5b0b460000e83782d7cdc1c9ce128f57a01a56a6aa936aa04d4d89cb7b97c10582cfbb3e236d91ff27236d91bf8cf440fe616496aeb6e7fb03938e755f8a839fb04b089d7d9f6dba997e7172b95602c61c0000ecda080d0ba68234cc7b9aa6abed996ed1827d2cade60d2c32df3b6c66c70c0000dd5fdbeae4b20e5b058902fe652bee1bf7f7eacc11fe69fec68f7587f88926cf34d5254bedce72f2b10200c0bc11fc0b9682def88bab3427b5fbf5b5205a1c4b517d032f76acba52798860f63c0595d7dcd8a32e18fb97b1b6ce0ee8df334bec9a3ba4682f189c3eb766dcf2eb1e7a8567db6efafd30e671d2e4acbe5e8997b1e0ef7232167c4e5f5aba26994b4e530f2066f165acdb69fda3eb701a462cf62fa7dd711ecaf4b494924a1d3e0454a0aaa2faa901bc5e545b57a51251a5555a81c8321080aad6656aa7677d4e2f15cb2879fa79ce8dd4d2f9adc46ba122f6639c8784f69c4ba596fb6d08bd2773881600005a1b247aa12e7f299a7f7ef3f15aa89ff8143d5b64b08c1139c7a2e6295ef5704d3ccd6b3903cd4bb6b2b143ada37c7cab3831070b43a1577a33669761839c74e5a6cfd0cb2f6d3e166e503976000038fe9edd1649eceb24e0c9a1577c9042b5c33da5d76caae3c7f936912cea612c2a371299bf8eada407428c1e271762f6e1052de482b9f89be36b5dd88ce03cd73aafbb4b4ae6b78e65368d3f762e8c9c6fe7a4a224ffc97cd6ba7b5a033a1d89e4bf4f9132dab06742f32f8295f40810a947ffe8863fe1feea1ee77534033fdc98d79e56736538db6e2cdf73692f2e952bab43020060b3e20cb8579ec1ff6f91af466c8b24444c608193efc55a166774eb79e11c0e75ac395c45e6d7cddf487172212485c8c56d7120e73474fec15e4906ef2a3216d63548c992278b2fe3f982fc4722f548fa7e4b2c19d5a2829eb6b2609ef91bd65f2ad03fba810ad6722d737270c06cec1d790e1166e1ecbc8ef703ffeaa830678c871d4a68117fceab5add84f9c38b4a79f5be1a68d5bf6a99bac2e20209a9143411718637bff276593eea36e6df1bdf151ec76cecdc40f27b9b166833efdd0f00007cc5a972ae22cac61e69bd9e97a10031b8303b076b07a13368ebdfb3b58bf438507f7a4f713c3c3c80eb60c4db5b0ac656159776ca2385c7ed4b74c5ac4a4b04ad78bd9a8b9db4b7373f652c0ddb7f5c9feb9224633acf8f308b32d7b08777269c34873caa5ddab0268dd8e2a1d973b2131379293f66bb03d29e893193a9fa0280f783cd14f6340040ff62e2d37900e07096c92101807e64cbee3e52b5170fe78ef8b2ac9f0bc880ad01fd6dd2de63ea8ec04907fe5d7d254e19c2ca1d368c7cd7e49c214766f830ff0d1e9ee49ce1c35087fa91fed0c94d508fbbbff50b1d795899c2e06524fd30fbb677fb59fd63fdf637791771f836fc63ab6de02f44b585227627d9b65a66fb31526b7a9583f474cc41d72ee59f3d77ee9f3ceb7fc48a0c769a2010348f02bd39e905b690a8faf568a1daa7f5132a6e5ce09d7460130b0db0bede23080fa66e9b297a5e97fc14c3719d3d4ab63ae420ffd8abab0915ec27da6d186fb15fdb7a51de00f9938261f882c858df96145935ee4f480518979f0a4a0479866fda4c92f9b6c2945bd607d90b2d3db321f2933a5f554829188ab9621c0563848e30253f8c494c8e49f4f1e3be6ecda0929d234a3d4e57f3aa5d8c2242095bdbd09a49ba27749782d9eecfbbb7db9d8c1f9798bef2953d973c588e77f2e7fd9707754f907a1862afcc7c54b8f066b3fbde80a2079f8c722ca907051894e24d15f367774c473b6579c5315d548f4b3ff342bece2ff6e4cf1d3f86bc913f6f0ddfef23fd91269bc3c1d89f72a29e1cfa626c881490cbe73d25fd2fe5f08d581a5a293ec749816f02998fcec96619981c3e7bec2b9ff6c76b5a22fde3dc5e2f4cb9f5bcfcf36676fd9885184ac87404b928a6f929db3da3bb7a48e251c1e5c35c21be10e9a1f2725eaaef46b72e3ee99b1cf631957efa3e83bcdb3e39e2aa772e4f5b7f85ede8418981cb75ee03d8098ba3882aebc048f5af9e5fd0572e754798dd32bed307b4e98e735bf247d248a6305c3e1f697421cf97b3be24b2d158f689b1b001d39ef75ee6c3132ee6d70b246ebdbf49259df315bb4b8092e666a6d86eb46a4ec63d761679a91a6f7b3f3677aa9a6157075e144d725fc14974742949633386a3131a73b4a957d7af31eecd6dff2de517b96e67f50b70bfcb65154c662874bc181a780dae06a1758f67aac7682807410b15a9ee04e81bbe6cf26439362836e0db41ef2aa3fc414956503d497fb6b2e65ab6027abb8fd655247762674d1d8bd59353151616de861eba3c35fc59e4ba1daf1464223e2ac3dfcc58f98d57b5ec64e0c7988dd19dd2eea07a595ef122f64be84fc46e35279f0b5a81baa38f28769ed88f6116727dd2db1de2c7a2c15df7251c8d551de6cff8f1ade69d73d883671133bb1455be5df5a73bf2b4c751b67a6a9869a7ce5e4afae76510a84db5fc9b97e4d6bd67e2d5ddafa952d849becdd272e3aa9dd47d9132d8a37f90c5e85be909e4b08943b7ad49d2d3f137637cf9db827268295fbce1dd243f202b79c964f6bf3791b721308b81f4f11d279af4b78f6c8a66290b322abcdd8efaa42f3886697f9c8b783be2d32b2272ea4b8a9ffc5e6b485093db6e88c95bc8a9145134c71174617495edb05c3ee565356eda8629d6f774935ca7ad94207eed16461219631f0c38640dbbe3efa324779e89925478341e592f7e98f39b054ddc33b981cb0da74b72a4f6644b8eb192f8bc4e3345243697cbc76e13764272e4fb5e69a41dbaeeb8e7a1a18a47a6855483408a9fa36c8371a9e115d648f38f3af70eeecd9dee0a7e3b3ba3dddccf360deb91d14a7c62e6696d1a501dd07fbacda837bd5d250a7339a8576c5cbe4efb9ccab7d204e6f798e9d07b5ed0eddb4f963edd26c8ceae521ee645ae143ff261c656dcebb3899ff12b83d933816e45ad90724fb798bbc6d6b0f3821edbb9b704c655e73edb6cee2a395c94b8f5d395f6db51b3caadc5d3b1613faad41f17fbdf940853bcfc84fa2af469ce47ffe1a7ecc5e9364e079eb69fe4afbc9eccd874313d9d5bfa95d79d17cf335bbe8df87d3c8e49c8c376747a0792255d3672f534ac676b177db8a93a260429c7f63de34cb6b8975dc5b756f5f36a269541233b94ab42f6fb93e7906f663fc0851570528f1c10ebf59fb1bb6badd2c6189215a04ccdd63d9a99a572aef254c1cbc69d75a8610d3a2feca8a484dbc1707157b548a71d1e3ef29919582525a523234a2358ad7fe552a7c9b4a42aa41a2c5315f3f422a9e8c21caaf90447da3ad458f234dcb3bb6d254e8fb676b528d5fe37fee334ea392dedd0f3696811a9c1a6907ce61351128d5b18f57278d91bd98a34c66e37d8245e2ec9b6be3095d9fc294a5c3a1c26ccf140c4dfc2ac3b22e798325352db5bc47fdf7fa2a3b6d70695149db24c4809ccbff37abc66b7fcf6d6625a76438ca5b80bb5739e3ec4a028e76ea271cc68505b086d708c3ad521077126bab61ea7e33dc9ff958b48551c460b5819fef79d866137392c460b46aee1a0efb99562aca94ed3ed1477a889f21769eecf72f66e3e677db9d22a9b0b0b3bce283f8d4fb2922a19ac31492850bfd969a71a3df339262a4edae8d3c9a1086b4ec3f4a666c94113fae1197f527a65bbc4acdc10ae1b7071ba9841762855169bfb68763ad7f6fddf322cdf3fec2afbd47c2f20604bcbf901525432d4d85ce6bbcdb393ad33d10559c85d499dc75c3e325b7007467d3e905218f92f4d5f02472367e1ddfe8148f557b02cdfe8602d328486a0e6bbbc267d76cec64ee14b2267157cf46883f5bab7bc45921db8307445f44b6180cc64ac9a5b258f9299e0e456e997e74be0c72347a346f39452bbb12a71515562d2a683df44b55d1bad2611a1b58e99247d395d6d53d993d9982cea2be9d14706b2e28e177ff07df8eac2cfc1f6912935afd7f1ff04eea1d5848c3ce2bfd7139b5d7720fe2e76e46aca59b7999b03d19dc565461d69d5b5d1c1969de5470d73e329aff76788cbf7632087dedc3b4bcef0e3c1bb7274c8942ed7ab84fe3b294d878ec69f7ad9c3aaa93a594ff3fab1c2ac77fca50636d3bcab49221676944c9e2649d7446acf5ff2d134aed3a71a1ebac1e5712870585d9d2e543e9ab1a52723a24a8afd5c0b2b647ac04bb157319a8bc388112387a83fe1ce2121dc7eacc0a2755b4bdcce8491ae819c4e8bfa128e034686c76e9478b6f4a70bd5eb86b38864d1c1dd38ba6a542cbc8ade3c96a086a6432a27aac29227be5aeddfd98bfd68691d500d99a43baa59be396dc78cdc65f7e06dea26d15c327b27fa102115fa3e7e31916570477aff1ddbbd398af7ddc9537850f2e5aed4a51f8f30262fb7d41f3f4edacfd720a5e774b66a379bc887d743fb5ba91d50bb49a2f378779ab9776ec214f136362b680d0bbf3f685ffa1d25f3754c652f36366222ffc6c59cf6890af68aae67af9acf7662d5d40b532d7921f4851f5cdf7b9d4d7b80c91c3b22634621503c52c5318eb1e9c862da31748ff78550323658877b4c867ebacd695c6486963c372b1fd59e9c5151161f367c00d59edcf6aeead6bfb72eeaaa99b8c4a48f3d1536dd9be1f8a41cfa0de1f2093b241a115c6e80cece35ded37feebb8361e918e5630d4869352cc9bdeb219f873359bd6c02fc414167b399d6948955957647568a74da34662757734a759ae4a30fea901bd96f6d62ec8d676cfdf7ddb5ef603b91f20e794235796fbd32e4ca549e226dc1d19e0ad23729b0b2d4e3e3c6c1f552c38a3c25b9879c346927da7dc65bf3a1cfb7fdeb7fd6f6e40b05eb2837ca99c881e37ae8f49ca96dedaa67f42eb97987b2fce37558139dc698c41bb4d303235ab3974fa6d879a8d56f5ba1afa7ce34c7abf63df5456c050f5083f68d6f9bcdbf943938fb46c59a395d89bfe821f54166269547cc87fc0057ce78cdc0bededa3b8aa14914d0a166bdef67af171841213bfc4ebe2fa93bcf90b7fbc0c78fec773123e68e2e183b91476f27246c32a4b4e2d061211ff3a7ca7cebf57eca7305cc269fa360bba5c7e4c1047f9dfc6642ae70b0ad83a2b039697b78d11181d9645a5a12433a2674c53795af4de23b5d991df4ce6bbcb8ef1a99e0ce10fb6f56e67843d16883152c8a823ddc91a55dd459009d4375e7bcf03b94b0c821e946a394ef2a99de9a34a6f7598f6fc1c85da0e8aaa7d9f5a92749e9abfa6c6ec2658db0b470a4f924235df7d4a85384e9cb74f3270127862873f483745d5b230d7b2e56d47ee14dbb8619d54c534167aaa507f94ac9745f7e5d5f7df1bbf5c4b1a02e05049b0b7bf8e6ea4b770d4e0e0987a022b182aa552c41de696a74793d81629915cdc141d4f4d2920c8514f58a9d0814f67e7d7cfe9dc1f72c3c235ab57a37e232e9d1017a774ce1fb6a7942bab3461f1ce236f9cc7210d6c29b737e14a219399ecff42455d99ac2c487e4dc137dcd33d8b26c1fb199a6cffd9fafb492dd2a6218e33a8abce2678ec863243f44dd2f3638060fd9e59cc547dff06cdcf645cae61b1f9c1088f3bdf7c6231a8ae0e7ea6b32fb8118c77e05599ab2fd96649e4d28510d33c597a2083768d93ed9ab6f9bfd6fd184c839d33906ca38248d9b7a77c04f2a4737ca2228edeec6b31e918d67cbcb983e58e19e6c3174942664c83c1a82a8bea2349c352413aebe055af370eae8ebd9edbf9b03430fbc53b700c04dda755e93172e44684b94bbd0290cce3559b0aac6be88630bd9276bb85f21304272993f476e374b2a35e76bc3703bb3d059ad88a1382de5c263c141b1af8f070639eb774efbe4ef77cf8c4f67b6c26a53b0e70f257e7fd497dc9b7f2fe8a2441eed4776c825f6803c2fcf2e8dd13daac72858bd866b9f5518790df6b958b16fb67e959dc2451d73d2ef705581044bac44c94597bbbdaf94be0fced02c4e1439f05dff2a0000cf56bc5112ee696250f667ec90980dbe4e2ea22ee7e0a8a00ecc90af54c5a0a402a19aa4cdf72b4361a0525ea1da40fafbbbddcb083e801b0000d61527062142831dd2c3c10523b28e198a138f0eb3704063903668941378b689c99aaa1ae51508036db5aaea7daa151508a86e6252677aa97086f3f8048de3d898336d7a4db570c6e7c464cd4ac4e3a4a52f973c94ad4312000088aca851740d1aad1c1c302b082caf86a92ea9c34ed0391292a65f24a5b2fae7b8b5483b85425a129656a6a2a1be206de11baa7006f68c0b86a0bc29afeb75fbe7fb201b256fe157b0bc741dcc88dbd6802d670c4af84a2bd33ea7fbe83c0ee07735a1a6a6a616e7b9cd23f9d8757012ad18f0fc31b54c40f8e4431ef1297a9dd4c0dedeb0faf7be770ac2f4c979aee7d5733d6c3926b4e79cff2e71d549fe70ed585d78396398f3b6a020fbf0302c566d9b285637e8a630ede192867747c47ae32d239051a111f7cd7c1b8004b244f49e73fe08bbb1fcf364bfe75e5615ca190600c0d4063d37f0753c37c43b0b5f764de2adbfa54de198dd5825135e33fbefe8975b77e9e0f5b5442f28dd7c6863e9975b5789c95515882a7e0dd5c5755f5bce575aa9a3fbf64952e791929e4e5eab2e3fc62f0f36ef7bd8d91dc9717a29304336d94d39b7ec35572cbde01ae4d9236dd6134a915823c5fcff44962982cbd8986806b806151a03f3f194ad1baf004e4001de2a3097f5e8042b98fb91f705dbcc4c50c13c81ecd49ca18b35c21fcc446830ce58421fcef1b1e897c15a070c150ecc3a8693fd1abecad0e59cdc34371467dc26124652c271e5c5490f1c9eef8413175e260cc90d82d45b05f2cff0f222f2c212c5cd020bff460680389f2482c8448497f16970a3bbfb4034b69b8075c58cf1197063b6fc20062e12601d81607c7cdc54ec5e107ed3aaf804a52fdfa55aaa6e0029405cc89630203b08b08520e072215bb003b8a95728c8016132609d215b7c0edcb82b2788e3c92a1ce0342df116339303c4456789b5d89a1c584374163c7ddc2c2bd8e297aba31288cee273e08658c1161fa000d6909125dee25882b87881d825c0e522b04b80632b02e2056209abe40281aa52026b0bc4826dc50da9824b174314f07281587c0edc402a98633715b0cef02bf1068511c1010aba82c5e3064ec1e2fb88025e2ee88acf811b2d0573386c06d6196425dea01e2238409155b078dcf8a82048fc116a607d91557c0adc9c2898e23571147fa65257b2870764cf211a60cdf153bc37104e06147c58b9452cf672f1537c1adc8c2798867d0bb0fe7829f14e3d228e06141f054f01379509034d81841658777c149f0537470966c9229ae5cfbc27f1afdad35b81352434c1da71a3647c20edf95b81b52734f1e171e38f6078593a60ed114c7c78dc4c2304045f4d0c3c5ea2121f1d37a1083ead1bd303eb4a49e233e0260805400c3d4432e0e51e572a2f37f820c900ac2996888f8c1bfc0323efdd06ac2977f887669c2c1f1839651564fc18213e326e428e17842cbe1d586b329078f0ecd5c1f1437fc49f2a0f3202c4e5f988dd4d8208022e97e7037b801ba303df3edb57475d26cfb7926a4e906a5726604dd13cbc33074e570afc1c561183fb67340f9f00b71b045e1c1fb980b5b6ba5672057c4328e106886f2f8115e3b679c096b0ee05d6d35e5a493504a4fa1f2208feec1d81e5e3f668c441f27f128f4ea877f4c7d7239cae8b28882c9607f8ab26d01f470d9c060a98498617f8ab9e0e3e136ebb02ccf4610d4ccb7d46277e21344380753443c0f3c0ed4c80e721c107fc5533049f09b70901667ab60626626a83db4f0033ede707feaac5b1526d0441b5a95f03135eb7023c19dcbe8104b84002c05f772bf0d9707b0460b6e7eb61832fcf46a8efb068dfcfc352fb80d5bb104bb558ae0fb104e64e088c282c7a1056c1325844c1508160680481e5ba128487938186abfd1afec750427d88a5a17e734371c69153ccfd8b02a00044ec0480a4b9c33cf0bf000000ffffd3531d4259450000"); err != nil { panic(err) } }