From 4141844ec668a8ee8748ecfa7b6daeff33c28e1e Mon Sep 17 00:00:00 2001 From: Michael Jarvis Date: Thu, 19 Aug 2021 07:00:31 -0500 Subject: [PATCH 1/9] Check the return value of drawBadge() --- main_test.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/main_test.go b/main_test.go index d94d7a8..734c255 100644 --- a/main_test.go +++ b/main_test.go @@ -25,9 +25,15 @@ func TestBadger(t *testing.T) { } func TestDrawBadge(t *testing.T) { - drawBadge(22.7, "test_badge.png") - drawBadge(88, "test_badge.png") - drawBadge(66, "test_badge.png") + if err := drawBadge(22.7, "test_badge.png"); err != nil { + t.Errorf("error drawing 22.7 coverage: %s", err.Error()) + } + if err := drawBadge(88, "test_badge.png"); err != nil { + t.Errorf("error drawing 88% coverage: %s", err.Error()) + } + if err := drawBadge(66, "test_badge.png"); err != nil { + t.Errorf("error drawing 66% coverage: %s", err.Error()) + } if drawBadge(66, "bad_folder/test_badge.png") == nil { t.Error("Should respond with error when saving to invalid folder") } From 030ae578cf645f1d20237c90b0855ddf0526e58f Mon Sep 17 00:00:00 2001 From: Michael Jarvis Date: Thu, 19 Aug 2021 07:07:00 -0500 Subject: [PATCH 2/9] Make tests consistent, add comment The "success" conditions should always succeed, unless there is some regression bug that creeps in. --- main_test.go | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/main_test.go b/main_test.go index 734c255..3fe52aa 100644 --- a/main_test.go +++ b/main_test.go @@ -25,19 +25,22 @@ func TestBadger(t *testing.T) { } func TestDrawBadge(t *testing.T) { + // Test success conditions if err := drawBadge(22.7, "test_badge.png"); err != nil { - t.Errorf("error drawing 22.7 coverage: %s", err.Error()) + t.Errorf("error drawing 22.7%% coverage: %s", err.Error()) } if err := drawBadge(88, "test_badge.png"); err != nil { - t.Errorf("error drawing 88% coverage: %s", err.Error()) + t.Errorf("error drawing 88%% coverage: %s", err.Error()) } if err := drawBadge(66, "test_badge.png"); err != nil { - t.Errorf("error drawing 66% coverage: %s", err.Error()) + t.Errorf("error drawing 66%% coverage: %s", err.Error()) } - if drawBadge(66, "bad_folder/test_badge.png") == nil { - t.Error("Should respond with error when saving to invalid folder") + + // Test failure conditions + if err := drawBadge(66, "bad_folder/test_badge.png"); err == nil { + t.Errorf("should respond with error when saving to invalid folder") } - if drawBadge(-34, "test_badge.png") == nil { - t.Error("Should respond with error when coverage is less than 0") + if err := drawBadge(-34, "test_badge.png"); err == nil { + t.Errorf("should respond with error when coverage is less than 0") } } From 3591046a7af96de0d2b5e4f7e024cf36b3be8a7e Mon Sep 17 00:00:00 2001 From: Michael Jarvis Date: Thu, 19 Aug 2021 07:09:24 -0500 Subject: [PATCH 3/9] Remove Gopkg files, use modern go.mod/go.sum --- Gopkg.lock | 80 ------------------------------------------------------ Gopkg.toml | 38 -------------------------- go.mod | 17 ++++++++++++ go.sum | 16 +++++++++++ 4 files changed, 33 insertions(+), 118 deletions(-) delete mode 100644 Gopkg.lock delete mode 100644 Gopkg.toml create mode 100644 go.mod create mode 100644 go.sum diff --git a/Gopkg.lock b/Gopkg.lock deleted file mode 100644 index d78a74b..0000000 --- a/Gopkg.lock +++ /dev/null @@ -1,80 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - digest = "1:4bb94bb2d837b5c7489d9e5e1fcffbc81fa1cb43024cbb4fe827787378f01e3b" - name = "github.com/fatih/color" - packages = ["."] - pruneopts = "UT" - revision = "507f6050b8568533fb3f5504de8e5205fa62a114" - version = "v1.6.0" - -[[projects]] - digest = "1:d45d0ae9aa93470f49280bcf0953419e867f8f26a6ec3218aafc31fb427d5bd0" - name = "github.com/fogleman/gg" - packages = ["."] - pruneopts = "UT" - revision = "6166aa3c1afaee416f384645a81636267aee6d25" - version = "v1.0.0" - -[[projects]] - branch = "master" - digest = "1:62c57507df491b657e9ae2645f30958d9964c8eeb380600469eedc951ebb3a0e" - name = "github.com/golang/freetype" - packages = [ - "raster", - "truetype", - ] - pruneopts = "UT" - revision = "e2365dfdc4a05e4b8299a783240d4a7d5a65d4e4" - -[[projects]] - digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67" - name = "github.com/mattn/go-colorable" - packages = ["."] - pruneopts = "UT" - revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" - version = "v0.0.9" - -[[projects]] - digest = "1:d4d17353dbd05cb52a2a52b7fe1771883b682806f68db442b436294926bbfafb" - name = "github.com/mattn/go-isatty" - packages = ["."] - pruneopts = "UT" - revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" - version = "v0.0.3" - -[[projects]] - branch = "master" - digest = "1:53e6f54885d63f2c9afc898f10481d28295471dee95bb7faa74cee8a1df85e56" - name = "golang.org/x/image" - packages = [ - "font", - "font/basicfont", - "font/gofont/goregular", - "font/plan9font", - "math/fixed", - ] - pruneopts = "UT" - revision = "f3a9b89b59def9194717c1d0bd4c0d08fa1afa7b" - -[[projects]] - branch = "master" - digest = "1:bcdbc1c6f88196580500afc96255fb81b89e996ea43917c4973675c567f825ae" - name = "golang.org/x/sys" - packages = ["unix"] - pruneopts = "UT" - revision = "2f1e207ee39ff70f3433e49c6eb52677a515e3b5" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - input-imports = [ - "github.com/fatih/color", - "github.com/fogleman/gg", - "github.com/golang/freetype/truetype", - "golang.org/x/image/font", - "golang.org/x/image/font/gofont/goregular", - ] - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml deleted file mode 100644 index cd2648c..0000000 --- a/Gopkg.toml +++ /dev/null @@ -1,38 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" -# -# [prune] -# non-go = false -# go-tests = true -# unused-packages = true - - -[[constraint]] - name = "github.com/fatih/color" - version = "1.6.0" - -[[constraint]] - name = "github.com/fogleman/gg" - version = "1.0.0" - -[prune] - go-tests = true - unused-packages = true diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a6fa06e --- /dev/null +++ b/go.mod @@ -0,0 +1,17 @@ +module github.com/jpoles1/gopherbadger + +go 1.17 + +require ( + github.com/fatih/color v1.6.0 + github.com/fogleman/gg v1.0.0 + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 + github.com/jpoles1/gopherbadger v2.5.0+incompatible + golang.org/x/image v0.0.0-20180314180248-f3a9b89b59de +) + +require ( + github.com/mattn/go-colorable v0.0.9 // indirect + github.com/mattn/go-isatty v0.0.3 // indirect + golang.org/x/sys v0.0.0-20180316202216-2f1e207ee39f // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..97e3b72 --- /dev/null +++ b/go.sum @@ -0,0 +1,16 @@ +github.com/fatih/color v1.6.0 h1:66qjqZk8kalYAvDRtM1AdAJQI0tj4Wrue3Eq3B3pmFU= +github.com/fatih/color v1.6.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fogleman/gg v1.0.0 h1:O2ToZn8ijCP2gXhVY701P1b1jrxKoVPh6CkaX2/PACE= +github.com/fogleman/gg v1.0.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/jpoles1/gopherbadger v2.5.0+incompatible h1:yey2mSCoeWrPE/Q+6sz8CbJDjIRtx6wqc+DCf4VV4/A= +github.com/jpoles1/gopherbadger v2.5.0+incompatible/go.mod h1:DVwxsf5adYLiDOj955t/ejfCRWjKA5tme6Vejb72Ro0= +github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +golang.org/x/image v0.0.0-20180314180248-f3a9b89b59de h1:moc8EjTGZXlnKJcoDZDWCDV1Vn3Zt/MZDpIRmIs7qt0= +golang.org/x/image v0.0.0-20180314180248-f3a9b89b59de/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/sys v0.0.0-20180316202216-2f1e207ee39f h1:KjX81lL92yfj4utcAnxT/sgJt8XTuOkDN7Rr3HJmmZ8= +golang.org/x/sys v0.0.0-20180316202216-2f1e207ee39f/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= From f4a2f1ca474f9f3e40df05215dea0926c44a1159 Mon Sep 17 00:00:00 2001 From: Michael Jarvis Date: Thu, 19 Aug 2021 08:23:45 -0500 Subject: [PATCH 4/9] Makefile improvements - Use .PHONY to indicate we're running commands, not creating files - Use target dependencies, e.g., run depends upon build - Remove the deprecated "dep" command and use "go mod" instead --- Makefile | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 6118732..d19b948 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,23 @@ +.PHONY: build run test cover coverage configure dep + build: go build -run: - make build && ./gopherbadger -md="README.md" + +run: build + ./gopherbadger -md="README.md" + test: go test -v + cover: - go test ./... -coverprofile=coverage.out && go tool cover -html=coverage.out -o=coverage.html -coverage: - make cover + go test ./... -coverprofile=coverage.out + go tool cover -html=coverage.out -o=coverage.html + +coverage: cover + configure: - make dep -dep: - if ! [ -x "$(command -v dep)" ]; then\ - go get github.com/golang/dep/cmd/dep;\ - fi && dep ensure; + go mod download -x + go mod verify + go mod tidy -v + +dep: configure From 52afaba721f0f07c7613684c85d36edd3d7d28cb Mon Sep 17 00:00:00 2001 From: Michael Jarvis Date: Thu, 19 Aug 2021 08:26:50 -0500 Subject: [PATCH 5/9] Run the .Close() func in a closure This permits us to check the return value, and print the error if it occurs. Also removed unnecessary return statement. --- coverbadge/coverbadge.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/coverbadge/coverbadge.go b/coverbadge/coverbadge.go index bad8255..10d9661 100644 --- a/coverbadge/coverbadge.go +++ b/coverbadge/coverbadge.go @@ -31,7 +31,11 @@ func (badge Badge) DownloadBadge(filepath string, coverageFloat float64) { logging.Fatal("Creating file", err) return } - defer out.Close() + defer func() { + if cerr := out.Close(); cerr != nil { + logging.Error("Closing output file", cerr) + } + }() // Get the data resp, err := http.Get(badge.generateBadgeBadgeURL(coverageFloat)) @@ -39,7 +43,11 @@ func (badge Badge) DownloadBadge(filepath string, coverageFloat float64) { logging.Fatal("Fetching badge image", err) return } - defer resp.Body.Close() + defer func() { + if bcerr := resp.Body.Close(); bcerr != nil { + logging.Error("closing response body", bcerr) + } + }() // Write the body to file _, err = io.Copy(out, resp.Body) @@ -47,8 +55,6 @@ func (badge Badge) DownloadBadge(filepath string, coverageFloat float64) { logging.Fatal("Writing file to disk", err) return } - - return } func (badge Badge) WriteBadgeToMd(filepath string, coverageFloat float64, isSilent bool) { From e5e47888043cd99e87d38affeddfdc99cf25fcdb Mon Sep 17 00:00:00 2001 From: Michael Jarvis Date: Thu, 19 Aug 2021 08:40:38 -0500 Subject: [PATCH 6/9] Add "all" target to Makefile Also add "fmt" target --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Makefile b/Makefile index d19b948..6b4d2d3 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,7 @@ .PHONY: build run test cover coverage configure dep +all: fmt configure build cover run test + build: go build @@ -21,3 +23,7 @@ configure: go mod tidy -v dep: configure + +fmt: + go fmt ./... + go mod edit -fmt From e2ee641eb0ea6f12668aac364e10b359bb7cd5c4 Mon Sep 17 00:00:00 2001 From: Michael Jarvis Date: Thu, 19 Aug 2021 08:41:49 -0500 Subject: [PATCH 7/9] Use backticks to reduce quoting --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 370755d..4727712 100644 --- a/main.go +++ b/main.go @@ -31,7 +31,7 @@ func getCommandOutput(commandString string, isSilent bool) chan float64 { reader := bufio.NewReader(stdout) coverageFloatChannel := make(chan float64) go func(reader io.Reader) { - re := regexp.MustCompile("total:\\s*\\(statements\\)?\\s*(\\d+\\.?\\d*)\\s*\\%") + re := regexp.MustCompile(`total:\s*\(statements\)?\s*(\d+\.?\d*)\s*%`) scanner := bufio.NewScanner(reader) for scanner.Scan() { lineText := scanner.Text() From b282fcaebba6acc903e8cccba9a122b198ee1063 Mon Sep 17 00:00:00 2001 From: Michael Jarvis Date: Thu, 19 Aug 2021 08:48:05 -0500 Subject: [PATCH 8/9] Update go.mod/go.sum --- go.mod | 1 - go.sum | 2 -- 2 files changed, 3 deletions(-) diff --git a/go.mod b/go.mod index a6fa06e..d6b82cc 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ require ( github.com/fatih/color v1.6.0 github.com/fogleman/gg v1.0.0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 - github.com/jpoles1/gopherbadger v2.5.0+incompatible golang.org/x/image v0.0.0-20180314180248-f3a9b89b59de ) diff --git a/go.sum b/go.sum index 97e3b72..160cb15 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ github.com/fogleman/gg v1.0.0 h1:O2ToZn8ijCP2gXhVY701P1b1jrxKoVPh6CkaX2/PACE= github.com/fogleman/gg v1.0.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/jpoles1/gopherbadger v2.5.0+incompatible h1:yey2mSCoeWrPE/Q+6sz8CbJDjIRtx6wqc+DCf4VV4/A= -github.com/jpoles1/gopherbadger v2.5.0+incompatible/go.mod h1:DVwxsf5adYLiDOj955t/ejfCRWjKA5tme6Vejb72Ro0= github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI= From 58ae3ddead8c68bbb4928d47b7052df14a2f7fcf Mon Sep 17 00:00:00 2001 From: Michael Jarvis Date: Thu, 19 Aug 2021 08:49:10 -0500 Subject: [PATCH 9/9] Update README.md and coverage_badge.png --- README.md | 2 +- coverage_badge.png | Bin 2199 -> 2286 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bda5df5..cd4bfb8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # GopherBadger ### Generate coverage badge images using Go! -![gopherbadger-tag-do-not-edit](https://img.shields.io/badge/Go%20Coverage-72%25-brightgreen.svg?longCache=true&style=flat) +![gopherbadger-tag-do-not-edit](https://img.shields.io/badge/Go%20Coverage-70%25-brightgreen.svg?longCache=true&style=flat) One day, I noticed that there was no easy way to generate coverage badges for my Golang projects. So I made one (see above)! diff --git a/coverage_badge.png b/coverage_badge.png index a7d2fcd75fc1d89aaa1dab030fb344618d26dc8d..5e3661a1bc604dedc407fae7b47d1c7f2c13e2ad 100644 GIT binary patch delta 2261 zcmV;`2rBoN5$+L?F@LB@L_t(&f$f@WOq5q1#((c^MrMYYVd%7sfLIs?DHhS%6ho;S zcTK%e3mU6jl+=x3BZ4iBt-D>DNNKm;x?Q`gm42#gSIfqvZM3%AOR!7b2&>gp2CZUT zt5U!VFe41iFlRqdC%Q6FcQ*l3pX7X*ch2*i^E~hWyl2ik(tqN`i^uA8y4NL1ngQ6k zi`zzL>EB0GKZt0T5MOlnc`H;+)3yK$gb*V-s5==W?VSX6kQR+mBUKfcIno2V(=l57 zlO$%ULJ0Fn59ChAXbBX7SsgWlxq~s9JiHs|{{f@P!yyAz6ouT}T(YyXvDs|2x3_cX z&>=qf-~)Pldw*|BNKq8>^76>e&c;^g&!#wG4R-xl znmmWu{OvPb?)x5q_y{KzuHTbre1PU_ZZ@4PRABH zY7{S~R`Z+V`SgoG*s;h$2*S0Jk`g9PoXEO$>zF%tE`O_6ucouJlPOcCgzYmFS6W&c zFTL~cnTPOk5wj_K@XgbY1l_^UVoF`lFd(8t{5q!f$!=^Oy1W_YJ8XwnAfKVtC|{ zM<^;P!hi4gW3gE9`FzyW)SxH|27`gglP6PDR77-iG|kP;R99Ei+S>Y~xH>vIc2bb!}jglLvv_qYGT{AZGUuib&;8wNnv3jnx?UL?_LTD3MeQj z0KnyPh1D3ULSt1Y7q6b9N&O1bWSPC+{h41*UCo$N28^nOMAHM5pPr9CJ-}a1ZJ{7z z1y=PQuKL^YdxH=muuaww0{qv4OtNI*?dayT?g%>MA(!~D6&fEO&xH#Y=&6T$(Ai!c=E|7Id<$ArKP1mnoCtxtX3;gQBh%e_U+q8W@aXm zBq4-g+O%nW`Q?|$vdpq&%UHjDJ+o)ermCun<;$0&XT44R4evc93ycZJiP$0>-d z;H@JsqeV)?YKN`RKww~g(%qyWKQ3H4zyZ$-D2q%YRc( zJ%wJc$LI6i#MR&5e-qb@a5|k~dAwdPXV0D`BO`;uhYvG-`gFE#-AYPI3ggF*r@FfO zCN8_(&iV7_0ob)`7m<;Xp_`$stc)2mW?;2ik!6{Nh6a+7lKA@TuQ_w(3`V1o9Xoa~ zckWz-5V%~fVKu^4=oRUEsy=>}XMcXa8QT~;e{HJfTAzo$zFvZI5P<;chkg=Bl0?6M zAP~tC;JJPI_`3wUD4Ft^YuVMXok^)vcp>dg1cD7sD>>G2aM0Ys2HM=*Ol)i{QBhG` zxpIZ$$B&bhl|_DjJ}#GwKp=o5N$B-@U|>1C9^QX)o<4p0CaxPX6pt*+e1G!ECrqC{ zoz~V?A|fJaZf?eAvvK6e5z5NSZZTWaG+^N7xo)=0C z=yW;&3@AJ2}_7L<7CO+^W3sXw?zWY0TvXA>B$D&F){J~x{ zS&!WmLu>bWgfy2pI7&-PId|^dkUaJE^`xbxk&~0d{{8#WG!3`gO;S=4g@1*GBqSu@a5!){ z9H^=qGWU9A3L%gr3BTWuPNyR!C55F+mjck(*hqSMI;p9tA?@n{4W}_&)88W#HCf}q z=`LP)bThmDxt*ZS&!yl+PPMsN9AAz>iDYqnIgJ;O&=G9Ag`*^K9h(mP8hx}(un$ZL z3dRJL{@(Dq(){`J!+$)n%74mu?6JqVbmn#+$#DuPF*3J480$97hgj1G( z4C=F#mzNhdP=6r=UavP~qAbhk^?FPu6N;kH+uKW5S667WW3gCJRrN=4sj7<6Xe1&c zVpyKe&Q7|!ySew?dr=f66q3i|!SDBnsxT%d27s29790-8P5K=j9r%1c6h%R=*AoZ? zu-R<%^z`8IcrX|Y6c-nB|NZx~Y15`*HEzUUfp&c3Cx74#BB>Jkdt{6W3X&`V5aKUreNN+IwOVia>~;ehErAN?QiTwo0t<%y_FaU<=m}JOs``Asa=l(30Pg+;<-f#8 j2PzQllHd!kzpLWkaR#f9qw;|T00000NkvXXu0mjfRYzym delta 2173 zcmV-@2!i+S5tk8=F@I4>L_t(&f$f@WP}J8M#()3YuDdL|3uIGJ3J-tMinVCQ z8S32t)+n&b$kZ_-f>WGHwP`YAyo|SG9BpI7Pg)#}ZQ8~OF_|#LVzpYie*HR?m6cRiSO2eb7;@a7!zj&0#gESQ=?e%y zi#{7iK=_&Yy*w6lqHwzfVLm&@g1 z>(;H9&1NP|n$#~(Zf-6nlZk@|4+3B^nb@^!7sbWJBqStISXfAWd^~M!ZB$fLaN)uQ z0FE3vLPbRdbLPyUs;Y{kM~|{^-@ecs8X6kdyMK2tZnv9^j0_423eYr-_uqe?{QP|K z^Ya04I2>U$1~OFA!1m)2q34|OOL^nedN9GY+h4M^t_;IS1>InaP3$3%GRY z67%QJ$6~RtV#Nx!Y}rCyULIz%ITW+eXn!0~<6&EBG0j6v7?UsQDwY+ZX;TxG^k$K9U2Vw)@fPpT@lI2 z$!y-d8Gx#)Dr#zKsIRZ5p`n4u$Vd(yI>d`FzKCA0$LI6);p*=0?!$F2>~?!t9)GXb z%U550MS6NVXV0Ex`t<3%_10UYq@*xr%oxhc%lmNIY&Nc4y9U7F!-t8Cj0`P?l9Cc; z%$R}IYDJc1YHMprN=oAV`SV=8dXD8h)~#FA)zvX|>QwUb@^CmD1cN~&NkXsJ1HI)Cdd<6^v$3(U z57)gIh)0%XKKke*rca+vYilb8gMp@|CZeOGId|?HB_$<&xNJ5Xnx+B0i+|^CvK@7cpI}TOUP)%JXA^s$`+zm?X>q$*bB|SYIy#qmosi~=9+_-Vfn>UZ+$B(0F8uj({Bqb$LP*6ZZ zLIQDdam2;Np{i;qF?V;S5CTb(2m}J?bUIQ}QdqWZ8330qT_P4K8ELx3M6z?)!VWdh{_eJzZc*P>4uS>Gp@$ zlyY-(!`2Ir$Ai=9WaiA7#KgpK^X5%zYil`h-~fR@faK(4N=r+z*=$_Ce3|Xrw}<^X zu`@G$|=5VR?iQ6crUQXU-g!En7xsXD2;9J=knE z)~s2B-EI$+`GSH10N#D~T^24}7}DY}8iglW^J(ca!pb#*lkhlAH&f1R|nG)hWJ zP*s&<$BvPclf&}m%LmoC7vV1F_oRQwftua?UH3t#FEL^q<$sg^+Gkw5zl9~I#`o!) zH>wb+eFT4Yzm1}o80*et!>r#TfLD*Nbl9<2EU2pbP+Y325)l!B!C)Aar=z2TJ9qBz^wUqHC<@SPlE>pA5D0{J zVQg$H04*&o#DB%b_0e~^T=;xG6h%R=*Aol|iH?q@v$GSA$Ai&mq_D7%XPo^CLX{Lg${J$RdX&ow5y ziq0a_AEfN;?BR3GF$8$|<(HWkz;>Z-FbwtUvwQKKzxrFZZXJHV zA4!tXG!3)a9Jb1Y!*I%>Dui$Y-`O`VR;%@azDG4^xELzHtqLJN1{MxF`U%2f_!ufa zR((ESsa~%S0#E*e@?T=84HbwsN${yR;4b?&Q&p>1bth0000000NkvXXu0mjfJCQjC