pax_global_header00006660000000000000000000000064143063535720014522gustar00rootroot0000000000000052 comment=50407234dce52e233c96b748504890cf11d2706d mango-0.2.0/000077500000000000000000000000001430635357200126225ustar00rootroot00000000000000mango-0.2.0/.github/000077500000000000000000000000001430635357200141625ustar00rootroot00000000000000mango-0.2.0/.github/FUNDING.yml000066400000000000000000000000171430635357200157750ustar00rootroot00000000000000github: muesli mango-0.2.0/.github/dependabot.yml000066400000000000000000000004231430635357200170110ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: "gomod" directory: "/" schedule: interval: "daily" labels: - "dependencies" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "daily" labels: - "dependencies" mango-0.2.0/.github/workflows/000077500000000000000000000000001430635357200162175ustar00rootroot00000000000000mango-0.2.0/.github/workflows/build.yml000066400000000000000000000011171430635357200200410ustar00rootroot00000000000000name: build on: [push, pull_request] jobs: build: strategy: matrix: go-version: [~1.12, ^1] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} env: GO111MODULE: "on" steps: - name: Install Go uses: actions/setup-go@v3 with: go-version: ${{ matrix.go-version }} - name: Checkout code uses: actions/checkout@v3 - name: Download Go modules run: go mod download - name: Build run: go build -v ./... - name: Test run: go test ./... mango-0.2.0/.github/workflows/lint-soft.yml000066400000000000000000000011731430635357200206630ustar00rootroot00000000000000name: lint-soft on: push: pull_request: permissions: contents: read # Optional: allow read access to pull request. Use with `only-new-issues` option. pull-requests: read jobs: golangci: name: lint-soft runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: # Optional: golangci-lint command line arguments. args: --config .golangci-soft.yml --issues-exit-code=0 # Optional: show only new issues if it's a pull request. The default value is `false`. only-new-issues: true mango-0.2.0/.github/workflows/lint.yml000066400000000000000000000011011430635357200177010ustar00rootroot00000000000000name: lint on: push: pull_request: permissions: contents: read # Optional: allow read access to pull request. Use with `only-new-issues` option. pull-requests: read jobs: golangci: name: lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: # Optional: golangci-lint command line arguments. #args: # Optional: show only new issues if it's a pull request. The default value is `false`. only-new-issues: true mango-0.2.0/.gitignore000066400000000000000000000005131430635357200146110ustar00rootroot00000000000000# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ examples/cobra/cobra examples/flag/flag examples/pflag/pflag mango-0.2.0/.golangci-soft.yml000066400000000000000000000012701430635357200161570ustar00rootroot00000000000000run: tests: false issues: include: - EXC0001 - EXC0005 - EXC0011 - EXC0012 - EXC0013 max-issues-per-linter: 0 max-same-issues: 0 linters: enable: # - dupl - exhaustive # - exhaustivestruct - goconst - godot - godox - gomnd - gomoddirectives - goprintffuncname - ifshort # - lll - misspell - nakedret - nestif - noctx - nolintlint - prealloc - wrapcheck # disable default linters, they are already enabled in .golangci.yml disable: - deadcode - errcheck - gosimple - govet - ineffassign - staticcheck - structcheck - typecheck - unused - varcheck mango-0.2.0/.golangci.yml000066400000000000000000000006051430635357200152070ustar00rootroot00000000000000run: tests: false issues: include: - EXC0001 - EXC0005 - EXC0011 - EXC0012 - EXC0013 max-issues-per-linter: 0 max-same-issues: 0 linters: enable: - bodyclose - exportloopref - goimports - gosec - nilerr - predeclared - revive - rowserrcheck - sqlclosecheck - tparallel - unconvert - unparam - whitespace mango-0.2.0/LICENSE000066400000000000000000000020671430635357200136340ustar00rootroot00000000000000MIT License Copyright (c) 2022 Christian Muehlhaeuser Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. mango-0.2.0/README.md000066400000000000000000000100361430635357200141010ustar00rootroot00000000000000# mango [![Latest Release](https://img.shields.io/github/release/muesli/mango.svg?style=for-the-badge)](https://github.com/muesli/mango/releases) [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=for-the-badge)](/LICENSE) [![Build Status](https://img.shields.io/github/workflow/status/muesli/mango/build?style=for-the-badge)](https://github.com/muesli/mango/actions) [![Go ReportCard](https://goreportcard.com/badge/github.com/muesli/mango?style=for-the-badge)](https://goreportcard.com/report/muesli/mango) [![Go Doc](https://img.shields.io/badge/godoc-reference-blue.svg?style=for-the-badge)](https://pkg.go.dev/github.com/muesli/mango) mango is a man-page generator for the Go flag, pflag, cobra, coral, and kong packages. It extracts commands, flags, and arguments from your program and enables it to self-document. ## Adapters Currently the following adapters exist: - flag: support for Go's standard flag package - [mango-cobra](https://github.com/muesli/mango-cobra): an adapter for [cobra](https://github.com/spf13/cobra) - [mango-coral](https://github.com/muesli/mango-coral): an adapter for [coral](https://github.com/muesli/coral) - [mango-kong](https://github.com/alecthomas/mango-kong): an adapter for [kong](https://github.com/alecthomas/kong) - [mango-pflag](https://github.com/muesli/mango-pflag): an adapter for the [pflag](https://github.com/spf13/pflag) package ## Usage with flag: ```go import ( "flag" "fmt" "github.com/muesli/mango" "github.com/muesli/mango/mflag" "github.com/muesli/roff" ) var ( one = flag.String("one", "", "first value") two = flag.String("two", "", "second value") ) func main() { flag.Parse() manPage := mango.NewManPage(1, "mango", "a man-page generator"). WithLongDescription("mango is a man-page generator for Go.\n"+ "Features:\n"+ "* User-friendly\n"+ "* Plugable"). WithSection("Copyright", "(C) 2022 Christian Muehlhaeuser.\n"+ "Released under MIT license.") flag.VisitAll(mflag.FlagVisitor(manPage)) fmt.Println(manPage.Build(roff.NewDocument())) } ``` Mango will extract all the flags from your app and generate a man-page similar to this example: ![mango](/mango.png) ## Usage with pflag: ```go import ( "fmt" "github.com/muesli/mango" mpflag "github.com/muesli/mango-pflag" "github.com/muesli/roff" flag "github.com/spf13/pflag" ) func main() { flag.Parse() manPage := mango.NewManPage(1, "mango", "a man-page generator"). WithLongDescription("mango is a man-page generator for Go."). WithSection("Copyright", "(C) 2022 Christian Muehlhaeuser.\n"+ "Released under MIT license.") flag.VisitAll(mpflag.PFlagVisitor(manPage)) fmt.Println(manPage.Build(roff.NewDocument())) } ``` ## Usage with cobra: ```go import ( "fmt" mcobra "github.com/muesli/mango-cobra" "github.com/muesli/roff" "github.com/spf13/cobra" ) var ( rootCmd = &cobra.Command{ Use: "mango", Short: "A man-page generator", } ) func main() { manPage, err := mcobra.NewManPage(1, rootCmd) if err != nil { panic(err) } manPage = manPage.WithSection("Copyright", "(C) 2022 Christian Muehlhaeuser.\n"+ "Released under MIT license.") fmt.Println(manPage.Build(roff.NewDocument())) } ``` ## Usage with coral: ```go import ( "fmt" mcoral "github.com/muesli/mango-coral" "github.com/muesli/roff" "github.com/muesli/coral" ) var ( rootCmd = &coral.Command{ Use: "mango", Short: "A man-page generator", } ) func main() { manPage, err := mcoral.NewManPage(1, rootCmd) if err != nil { panic(err) } manPage = manPage.WithSection("Copyright", "(C) 2022 Christian Muehlhaeuser.\n"+ "Released under MIT license.") fmt.Println(manPage.Build(roff.NewDocument())) } ``` ## Feedback Got some feedback or suggestions? Please open an issue or drop me a note! * [Twitter](https://twitter.com/mueslix) * [The Fediverse](https://mastodon.social/@fribbledom) mango-0.2.0/builder.go000066400000000000000000000006071430635357200146020ustar00rootroot00000000000000package mango import ( "time" ) // Builder is the interface of a man page builder. type Builder interface { Heading(section uint, title, description string, ts time.Time) Paragraph() Indent(n int) IndentEnd() TaggedParagraph(indentation int) List(text string) Section(text string) EndSection() Text(text string) TextBold(text string) TextItalic(text string) String() string } mango-0.2.0/example/000077500000000000000000000000001430635357200142555ustar00rootroot00000000000000mango-0.2.0/example/main.go000066400000000000000000000014561430635357200155360ustar00rootroot00000000000000package main import ( "flag" "fmt" "github.com/muesli/mango" "github.com/muesli/mango/mflag" "github.com/muesli/roff" ) var ( one = flag.String("one", "", "first value") //nolint two = flag.String("two", "", "second value") //nolint ) func main() { flag.Parse() manPage := mango.NewManPage(1, "mango", "a man-page generator"). WithLongDescription("mango is a man-page generator for the Go flag, pflag, and cobra packages.\n"+ "Features:\n"+ "* User-friendly\n"+ "* Plugable"). WithSection("Authors", "mango was written by Christian Muehlhaeuser "). WithSection("Copyright", "Copyright (C) 2022 Christian Muehlhaeuser.\n"+ "Released under MIT license.") flag.VisitAll(mflag.FlagVisitor(manPage)) fmt.Println(manPage.Build(roff.NewDocument())) } mango-0.2.0/go.mod000066400000000000000000000001171430635357200137270ustar00rootroot00000000000000module github.com/muesli/mango go 1.17 require github.com/muesli/roff v0.1.0 mango-0.2.0/go.sum000066400000000000000000000002431430635357200137540ustar00rootroot00000000000000github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8= github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig= mango-0.2.0/mango.go000066400000000000000000000105221430635357200142520ustar00rootroot00000000000000package mango import ( "errors" "fmt" "sort" "strings" "time" ) // ManPage represents a man page generator. type ManPage struct { Root Command sections []Section section uint description string longDescription string } // Command represents a command. type Command struct { Name string Short string Usage string Example string Flags map[string]Flag Commands map[string]*Command } // Flag represents a flag. type Flag struct { Name string Short string Usage string PFlag bool } // Section represents a section. type Section struct { Name string Text string } // NewManPage returns a new ManPage generator instance. func NewManPage(section uint, title string, description string) *ManPage { root := NewCommand(title, "", "") return &ManPage{ Root: *root, section: section, description: description, } } // NewCommand returns a new Command. func NewCommand(name string, short string, usage string) *Command { return &Command{ Name: name, Short: short, Usage: usage, Flags: make(map[string]Flag), Commands: make(map[string]*Command), } } // WithLongDescription sets the long description. func (m *ManPage) WithLongDescription(desc string) *ManPage { m.longDescription = desc return m } // WithSection adds a section to the man page. func (m *ManPage) WithSection(section string, text string) *ManPage { m.sections = append(m.sections, Section{ Name: section, Text: text, }) return m } // AddFlag adds a flag to the command. func (m *Command) AddFlag(f Flag) error { if _, found := m.Flags[f.Name]; found { return errors.New("duplicate flag: " + f.Name) } m.Flags[f.Name] = f return nil } // AddCommand adds a sub-command. func (m *Command) AddCommand(c *Command) error { if _, found := m.Commands[c.Name]; found { return errors.New("duplicate command: " + c.Name) } m.Commands[c.Name] = c return nil } func (m ManPage) buildCommand(w Builder, c Command) { if len(c.Flags) > 0 { if c.Name == m.Root.Name { w.Section("Options") w.TaggedParagraph(-1) } else { w.TaggedParagraph(-1) w.TextBold("OPTIONS") w.Indent(4) } keys := make([]string, 0, len(c.Flags)) for k := range c.Flags { keys = append(keys, k) } sort.Strings(keys) for i, k := range keys { opt := c.Flags[k] if i > 0 { w.TaggedParagraph(-1) } prefix := "-" if opt.PFlag { prefix = "--" } if opt.Short != "" { w.TextBold(fmt.Sprintf("-%[2]s, %[1]s%[3]s", prefix, opt.Short, opt.Name)) } else { w.TextBold(prefix + opt.Name) } w.EndSection() w.Text(strings.ReplaceAll(opt.Usage, "\n", " ")) } if c.Name == m.Root.Name { } else { w.IndentEnd() } } if len(c.Commands) > 0 { if c.Name == m.Root.Name { w.Section("Commands") w.TaggedParagraph(-1) } else { w.TaggedParagraph(-1) w.TextBold("COMMANDS") w.Indent(4) } keys := make([]string, 0, len(c.Commands)) for k := range c.Commands { keys = append(keys, k) } sort.Strings(keys) for i, k := range keys { opt := c.Commands[k] if i > 0 { w.TaggedParagraph(-1) } w.TextBold(opt.Name) if opt.Usage != "" { w.Text(strings.TrimPrefix(opt.Usage, opt.Name)) } w.Indent(4) w.Text(strings.ReplaceAll(opt.Short, "\n", " ")) w.IndentEnd() m.buildCommand(w, *opt) } if c.Name == m.Root.Name { } else { w.IndentEnd() } } if c.Example != "" { if c.Name == m.Root.Name { w.Section("Examples") w.TaggedParagraph(-1) } else { w.TaggedParagraph(-1) w.TextBold("EXAMPLES") w.Indent(4) } w.Text(c.Example) if c.Name == m.Root.Name { w.EndSection() } else { w.IndentEnd() } } } // Build generates the man page. func (m ManPage) Build(w Builder) string { /* Common order: - name - synopsis - description - options - exit status - usage - notes - authors - copyright - see also */ w.Heading(m.section, m.Root.Name, m.description, time.Now()) w.Section("Name") w.Text(m.Root.Name + " - " + m.description) w.Section("Synopsis") w.TextBold(m.Root.Name) w.Text(" [") w.TextItalic("options...") w.Text("] [") w.TextItalic("argument...") w.Text("]") w.Section("Description") w.Text(m.longDescription) m.buildCommand(w, m.Root) for _, v := range m.sections { w.Section(v.Name) w.Text(v.Text) } return w.String() } mango-0.2.0/mango.png000066400000000000000000001033301430635357200144310ustar00rootroot00000000000000PNG  IHDRekRCpiCCPicc(u=KBajQPCDEDR6Hd-^%5hiކAAkAADS%v J54St8CbY= \i[JSk.oZvaYeOb0t}Y59<Ի6g}> pHYs+IDATx[O*QӎtQc&4+*b+6Q vT*" ;2 ;,`I{=fsbfFx4%C|gNOd!CEg̐%Zy0K5& EEEwe'~X~AQrrskjj٭u۶ŀeee%%%{۲eիWABBj&;={:ٻ./)֮]^zRYg]9##nݕRn{(QORٳgՙȘnl^8eTİ#-,:_MN m?O&Ǵaar(wG_g/^CY]rU&pBbbŋ/􌌀޽.X0@eǎ)̝T][ot k*%%e߾}r֔C ש<&SE/qܘ*J*VN|rRqNN2U3@΃ݳ^/N(GKD^Z2r+aQK;wF ȑZN`v֮䠼{:|d2H Cϗ>}ĉrqThG,$&:u@3R~~~llr}ce2Tگ11,QҮ"cǖ[d2L5ctɕzҥ2s9Iye˗Ҫiֆ~^_ZzMddDcǏ;-N*g3iig۶rRcZ1CU/d9 WvM7YUcUn=3(hyRW/[UUr,p#/ B>ʻrNቼ\̔;wjԂ9uIhYS2Au'j(֒gp"5fTs(j~7Y$;1fYgW:V^ʟФIL{e,>})h) %4LG-U%}A|:5Ut!e9][fU)Ӭ T픏1)Y굞 \Nv:)|_kfŐ #Kiݏtr,p#/QZރ=::ZNቼ$3|ȁ}?vlRr~=zm9qFEEIÉ2TS\\?N3gڭ Rҡt"Rŋ>[n_߿_43/ɁK[ 41觌0hkk2Lt1]\dI!W J]AB:Պv.4JN'LВ>?)TKBCePGrT:wXڽ:ZeŐ9ydSWy,hj^ZjU~A䍜\iyo$ir8ec2C),m֭$ *$ _SSju nԔ;1VKBBX?90WOvd|5!߭N+++en V4Ȯu+ҧSYi _R*,Gk3)~1ܛUvZ 0rmzvNtr,p//EFFJǦ͛yo͛7 kKEEE'57OT׹s׮R9ْ3֩su3P?ٳgeL QXXs?:FQ;1VKyyy]IvegHASr@_@~<iֆ~^~,G+.^t5\[fpan/9w6i"/hټŀҪӷ6/Ͳ}^RSH2ݍ M:-[Hu~=Lƍ;vuK.əCys?H'<_'RMJw;/o89Kr(+//à8sEV qǣ- cCdA ҽbEx+Nfm%%rrڐӇT߿  IN>*mpo:_ GW/\(6.NyE^вyI{c~y^v=)ޗˡn}|JKKsJ̙3%%%r@?a:H+)իW[T2A;rbhxAߏ+}~<@+O?<33v޹3ҕ0h`_)aĉmW?˻ eiֆ~^K9qBN%7V^Ja%xI>c+rcS GKΌRWw?TGv^eGy׳ iii.7lB(8كzԌUzKݺuVff+-={V(wFIIRrrπ^ԆysK^Z/;y%p% /y K@^% /y KT% /y K@^%y \K,^vԙL;Yۙ> gVDOGL: KiPüלokK(Gm^;ObB%C-ކF&k4zvyiN{kʒy]# KKMG-4)6/MڼkkA^7K{-$Ah5&6Eߒ%DGxXo u;GfbPo yIbBM^c2*7 0γtϖ|4i9ϼ>/MmkiTq/l^_[[Ks_)g%OKm#Logj'/y [Լk^c`V!&fFy 9/Q)z>xOkOF5/%ąxR[!Q^eJ_h'B/+yNW.7x% /y K@^gB.]*3` }]-_JSYyIf~5+k5 ?:+@>IK>۶mԧvc:_ 0dشy7&Un=3(hyRW/[atG9ZKMKfէt0-TݳwTܵ:rnn˗riiiЗJiI+ QGlM.GħSSJwEE>vtt 4kC2U~Am;ćuuu"tzʕ+Tk׮wyvo:_ 0"\^~o%hY /5!/8[1)M̨(eAΖ][_&qd*;4'K`mmrԀ_*!DjŊp#/7cƌ0AKv 4kCvS- yC-QvEb/@k b(ڵN S#F,\8/$$9hZZb7CU/ t{ee+.Z~N(yҧYSSs]wJB4x/X*++'Lvk{̟zSYy)///ĉEEWq<$uL1Õ_y1CU) t{ %IΝ;琡CQ%sGRnzhjkk>L~YU/ 䥧DIIRrrπ^{ƍ<ӹRW/ 䥧j ՛rssg͢ZZRW/ 䥧g@!Cv܅x!% /y K@^% /y K@^% /K@^%x0ΎD>_"/sR[N:ڇf$,Ѡ^: ]˼:Y,aަwN!6T}N楯,FI/|ۙBLcVwC~_֎h_-aIrKP;Sü4: ʻtiTQ)mM~fn1ėan{k֚$_֧8yI2Ne÷[Dpvqil}$琿E%IS1~M?}l_28eP <\sʕ4v]Hcw_n_v%{|W?HRoڛyc[R/(omPKcl> )N^r:ڴ1HHd^RvX%%H祱tPx'򒱍(I,b18/t*p?/) L-I]Po AE撑6/K6DcѼt*hn^Rx [|G;Y4)wioStzWޒ'^3>O(Ğ>&ck:yIg*p?/ 0v3=ֻN IJ-J^21D7?GOճݍnTf^ |HL`[?FԼ$fRF{Xj^g4鈿eUv20(IM2y?u2[:Cymiп-=]_5XmI yuWÿ#M7y6I; wMvۼa1)r壴eIs٫a߾tWN{~jMKym'.2$,|n+&XW/e>ڼdkJ YA-oOZT>W,IM29KJv7T5,Lf3d>.cTW[@^jB^aj4Hmmٮ8Pmx5flkW=~ڤO_o=D*Vf.y7x[]%ɖ]V:2?2CL[dHҎ#S)my;)ߢܪQ$SzI^/mHzKWt!\WM$n%:՞e:yg[@^r?/5>ǥK{(hxbYp߲Hp{|tK3]G_B7ͣ>UlxN.1C{+;H_o@k6rƭA-^>Pqr%/)~_3񕷌,ȜO.xGI^I^Լ92(6uMnkaal0afzed렐i=2kӿ)vGlY-ӖHxxu&~7D1r>ٳ9Z0/Yʹ}%$4r?^y)չ_[Wy' Pg'aI̫K/*ӕ_FVi_2?ż /yɰ|_ڛf7z'/,4S޿lOSh۵/Z_:oK^;Ic:4}b_},חzeO*Օd,w5sP v$YӋ^]+s~O>IBk#z[uW'Wu/mun˙a2k?v1/lK,x u3$z59Mv-gj%te25@^S~hh}4^䥆N:ԏTyICk1E#_cǩy?P1׬ތ#g뵱_N[ތgwOb46 T?Xȯ=U@^% /y K@^% /K@^% /y K@^%p//5d1~u}MFuv&e갿E:ø9"sXe6<ek#|_Y3 uYzc[f2hٓSy5Zio_<ż&˻tYDR-2%hV?./Iaδ9eX}~POmMyI,SI4ã4`$QDBL}9| t00 I&KusmHtY$/%O5)"711=*v*lԟOk7 /-Cռ$35/-Bw4G-yIcG2Na÷[Ⓞ>T] yIm> SC=g悏,mhiG E:S9dlc3o\k~fS}^lvߢ\.#/;[̖FtԶA!Oކ`jtvy&1>6[ķ~jA]G-G^KR[q^>oYmz>S 2Zp;yIof;]v:6/z;%tY,Gjґ6A|$#Mօ4AKSۚ$c(|dXe:oILnkRҬ6}y Wv(_RSw .O)yil}^ 6 $.$/%/:iIc>g ?5~pt?׶4޼QQFdlB(rz? 㼤+x߲ncÎ~y6{14x@/`}xgKyI?4)/}͛|CƠK,TJH^yigGHԶȎdP`*"I&iv{Sec}2lC%8{-2iҿM$KKLw#/pyxmV<")#/輤.耟 }t_P`("A눿%ej%R{ۓ_fƮ/Q|<%Z7^jw6j^u#/ /y K@^% /u}*5}ƌC<͞˵kjkkKJJv… W\y!]E<<j^ݺ%۫f ݻw*^TuuuG*u۷?e9Jv'N̝7oݺs}ўRRRn޼YVVoWQQoM3D#yx O^"/y٣g;555O-/mݶoZo~1``YYYII}lrVu?.{-;e#VZz].Z$MRF׫ב ٙ]6 կ(G۽_x6TSS]b^QG$;IJ^ڽ{T0Q׍y+*6/yo._O?nlR~~C{퓎˖)-ri@,^$**G=K9zЎ[nSSyʘ2Ռ3d#2#dPҥ2s9KIye˗;-䄉;a$gsDDPp  eNg^O2YYWǝ^u"ϤIm۶K#ƕ{3YebHCJҪ}c{hYv^޲W̝7OJLN"tgs,C&3uKWZWnTo/Kٹ3ѡ}au*J'rc}»wY"\ٝd ʻtd5ܹ#3Vv49:VosqY/5/]J;o[ K&/͚=W`}޽Js׮ȹ/_VR%nI5rVNFN>]lN3 WXj]^S]]݈Nj{z=͊*.. ouKvǘd5E,Q kIỼZ7CU/4Md5EzK fwߚӝѲڳgLz5z590P\x[ٳQwjaEGvl_x76t/~SI\KIQoW{_s76 dEdd '6s+|+;y䥟(f?#xTT2 GGgggIήA=8j"4wK`mmrŀ_*I!۟Pg!t{eeҐ]h4wGl-ZoY3HSJ;vLj[fǟ4 96\kΎ( ( V_x6XW/[ܹs.>J.***ZvݢŋA_]]TSAukނJ>Orfaadv^-~uV{;Z /}癙555ׯ_ߵ{Ν lwǶ_ #Zy3DJt˩Wf%;w$%'wYYQ'~h5^楝.29O1ÕI1CU)3D +O:;[VZVvtt̙g'LpeKB|ro;G9WUU8.>%_޽mѲe_?~'O ON )N)))wWn>T꬗_b[%Vk{߄:~gԌۿxV5ϦċrHƫ,[jSrRPkOJNKN{oظѽ7x5ϦċrH2g筑8Tyɦt /nͳ)!/@^% /y K@^% /y K@^% /yZ䥧n  l/6x=}K Ο@6s555%wKk~ѡ'LpBUU͛7u_xREe0[ݳ`[2Tũ3T?VUU- 2U_ FQ؞]dy%DIK[dɶm޽{1e%I{fPyd)))ҭ0yx222$%%%mڼ911MI+eA#"oPXX(hWARp%Wf^Ҿl٢ /(r:ڵ$ty%uU{e[o|ޏ4/M>n*bH`IF R I\yͼҠ]$< BF-9G߾}yɓvWyyy2B~~~\\/Rߏgx#)Z>~2t^HHmmm||@ -On$/0/IKT a0[f̜)Bcb5R%qҥk׮)?=RÉґOOO%!i*66nw9y-)i^/D{c$\iL'OfK-Fu/Xp^HHrѴ4eХKCCv~|ExEb]zJX9"BWVVCԍ7rrr6l2ⓏvPp=䥖Ka%I.>c?SSSs]wizTQQqΝ?sС3w%Gtѯ$77Wb,()9h'\| [ % /y K@^% /y K@^% /K@^% /y K@^"fڵk%%%vvq>}la.^a|yuރ-_UUURRSSS 3b䨺'N̝7oݺsuq p4f#GK /۶=xwm&=Z.Fg(/P6J폎Vd d0[n޼t CvTNtjj3vmn4XRRM3f<_P 4 ݓS-_?5$nF'/././EEE) 6|deMKb UUվKKx6z Ȩ9}{233 ԏYYYϟW/i;z옄K]HIVǛK%t;_6Z^]^R~ӥz[۷o99%L1C3gV^sI5KDsƍ 7̟aQߗd`y!!GҞSBGyIIw˖/?w\=|=l%-JKK! %.Z_[[_PT/CRJnn sNRrr>&򲲲j?yI:yҶĞY߸Ǐ%ڵN._1?2أKr}LU<2g۷WVVn6KTVVv~@^% /y K@^%y K@^% /y K@^% /Aխ{V]܅ \̋XRREJJJ;֯43(H$9 S.@^yZٿ]ׯ_7yx#[楧\ 'REEqIhĒ#F{ũ233Տ ./(S;z#sxbee͛7#w2-ڼ{w&9ו4~Zf,m ?כFSX؊+¥ey$7<1sfzzt/^dʬe􉊊AGKYYW+KSLΤ m.An*"@ncΖKrv^n祃 J5zL;mte̶s׮T85/H1iGn2.kI|;$ /CIPR^^^tߏŽN^ ]*/^GπkkkzV4x쪪*n :Թ ^I@^:yꔚ N6?/UWWϞ̠_SP4/7ֽRuVPp:ڼO{{iGy)|J|A:0yxJ1NҥK塡K=Sd) _׮uZ#Gݿ .|4--m R^]JKK%]|Y#.wl 0Gyiv?+45aDh555ׯ_ߵ{Νڼt̙)̍kָR %GK +++ 6} )KxN:tHGM>saj%I@HJNK"S@6nS)5ixfQ- / 5dNP /y @^% /y K@^% /y K@^% /y KFxwt4'[]˼M;YıN8?K]ۙ$C7o1;]A?hgxq)ߢaijy&yiQv&y3['b?H8]%?a^bjm/$lBm 1~M?}lKڋ<<iPa3\sHg$/I6;oQih'KkJ%>6[SzG|k EB]^cyIYz[cO^ 6<O3/$mD^212w4Y,{yIY$#ox"/iczj}#@\2R2}lCY;fS$/z  E>dXe:oILnkbx}ij>O(Ğ>&cB-KKK{]yK%|ŏ{j^21D7? ?m%WB ey`afzJ[}!^܌%y K@^% /y 7{/׮]-))ٵ{vPtttqqqZdAgKd&8m޽{1 /5Y?UkcH`VǔC6y)v5\t5x)mAЊgϞ:GCWZh^IM1rQ Q*ޒY5~ 7޿[}|$mٺU$s׮꘹/_nN^lvuڵ$>uy /c dCM%^&(t5/y vK奓'O6Wyyy3Ǎ̼{KYz(tҿKO1hR۷K:wb?l5z4UZXyIy%CCe+Qw}`BB̖3g0:&>/ѤI0͕ .+-$6>>~r`ӧO$5K&O$)pUZ1%tXs?^yIlhk6hfզڂyIrǎIۤMG)@RȠ`^^^jj1==./)?0Km;w=c<˽Mj~<%I7nٰq%HюoKYhQl\ݺRB9%%%sҥХlff6\y~Ò}=ZudRK#F,\8/$$9hQyIk>oo=x$} ~M>aV-d ^_ѤnndI8I?zId琡C])M {3?SSSs]wiįkזJa._ܘлwzFFuuuvv#G.1L23% /y K@^% /y K@^% /yZ% /y K@^4dd{s6yx>ԼuAm,343(H$9B^yK'/=/yInzKLgᐿ%r ˚1$J)w3IM;ø,][[n^~=66g@/u .\PUU}ͨ:z HJJΟa$uМssrskjj]2E_z:=##wou򰰂k׮9KA̠ τϏ'KUŋeR] fӼt޽ظ8cVVVff+b0 04JF 6Iưy[G3Iޚt0o`diQޥ{b֊L+%6l ^aCaa%KAS>xLZٶmݻw; qΝ۷ooڼ9tҴ| 2CR2Kռ$Eھcǖ[%P:uQ1VX"#˻tr})@~LN>*OC11R(YӜSyɡh?~/e7x]JZaC}1iyIz&[Vw0#K!KV*|LL]]݈oM4rڵ$0tyNJNӧoӺvU&r:5U/ʵKTǎTee:˗]K6n{tUUUK SV͕y6'/@^rc ~^vk1K@2u4~`$5Vz^>}韟?nx]QGŒs0K',lW GV6r쏎&1@YrK$u+׵/̈́PYDvvvUUn%KnRҬOBr3x[v.agmP=`̘9`BB~Ad蘘7lݖpɟh7n7d[ 2a^RҰ#d˖55/ )aNn2]?/$6>>~r`dӧO$46Kw߲x,:e᰿ekGaz␿epݏ'YB{c$(}.^t5WIjR:RN3@t˄+yRѼJJJRr-/ż4%N* Vjn LOOK RΝ;'R%5SZZޏSy}k;,ښzz ֞|zRto1k/(-2}iwi[`qFNNΆ%l̟/b}P1rϟ?`y!!G%]nŒ c<~LH͕ #)9hCEzz2IgP'OJJP!)bO?i˵=O\%um27)C\\]K6m8>(>s:Rׯڽ{H$~]TVʍy{gdHΖxy:% /y K@^ /y K@^% /y K% /y K@^f3d ng :&T!^&IS;لF^d352%PL2\sH'/b̛|G>g6% Bv׻|lבdnG;Y_S_/x:yiv{kVipK{S+奏֑ J[OkOmW/+W^\4B K{}JYmܒv^]2XM:R( j~Lu7I"={7felyyil}^F0oדW L-ImMlB6xݼ[YVuxL>y˜{}OIPѾ/S{n% /y K@^w]\\ܧo?gu:OS1sfzztÆP2s9JynGm 0IUd|9mHwjj/psDDPp  e,Kiedd)V if9i)9jĉʭrӞ,yyKϹIOi) PZ.gҤ۶mzөy$ %gHiI3rUnj?x֭[z"9Z,KJ:ٔu3Cvl$|wifN%GS鬲N1t ҙ!eHiii?Uvrq)ʴ.]jt-Vܺ+tnm 踡Cv;wȲd1_|)b8:蟉UT}nFz:G OFgΜoٮݻ-m@^Kfէt`AVK;w{e]ZZUQ͕6ШѣՋGNSSJwEE 8\9~Ji(*s~ QWW7b(_ԓy\{QRiO7z珣A`֮]'E9Լ~^ygAYSY_ 30K~'F0ҟݺ;Z#%t7N:{;~^*wic{tt+y9[Q^r4*C:Eg ̟oEc~E8=L ] QwAnmt*J?/9 I҈>@D&rTQSsktQgu=GZh-<%S9K4- ?::;;[Z92۷]Ƒݔj;%Kz ?xV[@ZYuֿ"tJ(Eq0rԹTI(//OϏ7~p,Yɓ'u"yIY/9׼CX*3TnS͛7eKI[?t)/ʲJFoJ7{;~^H#8'7wͯ:Kʮ~nFWY:-NGE%9D$7nk꯲{y71c;>bL([9:6'/9(5z! %k)陨ъҟʽӭ^^jjWYj2ٳg]li=3>>~r`EN>萭[mLWUUWVV oݺ8h![>,O>UrQN˖/wzN $0c̃ Ґ?&F648K2yxʙ^ڔ]||kr,Wq |;i{ܽ{Wjەeٕн:ٔ:hNRddtlڼ./Ia[ٕ*Qu6 ]Y^]]˗0ŝ_=ߔRT{ o*wE>TV֯ GnܸX^9VӼWVv//5O+qҥK555'j^K\OOOwkWvvt=LN?-KeeeʡҶEir)'9F{r:z옜#ޕ,B|M} xҵkה;S ze*s쫭yic۷_g+{yO[NzJBۆѩsªb׭[)~hʦԩF7{;Ӽ%iasD(..6hkVzpAշtYeb8*Fљa3ң֭WⴢS)SSbNT)ʴ 3S&^s:H(FtvQǍFWJ뼨hu/Q]])i^jrVnQ(<ڽ[וyC.'ׯ!uHWك;\NT&NT ʵ=TlJ!w>9j~ޱstK]SB9cIL";w$%'=YjN^K1҆Cu:Hr,++oDYЍkjǟXW\sSMs+]_r)uczNȐbvv4֜,-WɷR'/_VҙJguSxhKMԯ0///ĉG3˖/ڻ7o6hQԍNEle GOtrM>ʡÇYʕCUCk]0Q(bEQxvrtRrrπ^r{ƍM}|09sn߾rsDRUWtAE]C nBB~Y瓯wFĸ%亱M l .Vg@^z 5d/Q6@^% /y K@^% /y K@^% /K@^C^0BL{}͇->,Fu㎎DKx'8g 6kfgr[t?9Roh} f:.F1~?ӣK$hަ#d77ż&=WR[A$E^ۙ-3(fyz;KwF5/$= 6ݾK@k;~4⏗n^h$}f;F5Fjґ6A|"/z$Y0[Jj|Փ~w`֏7_Y}FHiG٦ /KZ2/jwKFڼ4>/iSJ' ;:>Ÿ*ۤ4/)݊L֎ FE;gYEm:^s?>/2(Qئz}m1msZxv?LQqԼxZ+/-hi6h_'Iwv_jѠҺǗw6:jm($Dٞ'.ij[ӚE牯1Kyx3ҿM$Kx}yd9E}ͳڛ5mh-FVK˴j7hWmf^zxJ.$ɴ ~M>/,N_-y @%y K@^% /y Z}se .\rEg3f 2ĽȄ999|1?sСmz[pSܘs[&χW=ZK-ɫׯWUU;)ϰ0uuuGl۷oF1qYYTi:(rԩr N/s׮TUU;wnQڡ&NUAäIL?C7vfڛ)]^n̰IzK͛7>EEEwm43(H$9B^痏47lTTTϪF^R[KϯЯ}zV̝+Xynm{N+...++KJJ+4IgPTӦOW>VUU- 25++6''GY|ޞԯm!,\_PPWWp1Zhr)&=#C/1/iR'R >2HRԩ?йkW{̷JB.U>8q";;GS*ԩSNz)#"(*% t{Ы䍋/VVV޼y3r. j%:^zUҠ]Ҟ{={yI(&QK\Ch*U)~(3Vyݻj[܎%'Yh%.˖/WsjVk"##5vqe:oݺ^u6VFF4d6o2hĉI?O.9$:&f̙-QŒCj֛vزu:e]yyˬΛ'\Yh鐸"l+J%[4˯ Q>ڽ[/Rwq:\_/G\.}6GD߰P63CIo|dߐ>j%Q8*N^RGyJ^R4)ƶmۥJ<u򒣩tVY:wQg}ݺKS;#Ͳөj鮨P-Kvʠꔋ/6ր_*7Lmcɘ:aVZe&V4|بѣW$G(*ڿŊR.!-'*U$Atղ5rT \zWRZ2*pR'%5{eW dgw J^k;Q^r4*C:EgwK;v4$Gx|q`Ѓn%21c_ܼy3A"-~md}lqqƏof^CJ<2ۮ^'/R$'H͕ 4/uEad{Wjtm~ӧO7?p $Gyܳ]{.|J$(oPUUOK;[icLHhR#[2J- QQQ%g!Y+ꉶ0mҲ~6]&毶(v]RRt*8^76g̜)J&^q}{5r/+(/^?/EFFJǦ͛ĉC S-_?WJ^Nh:EwXX+O~hX%]Rv|ܾ}if^ܵKyAǔ9mJRVuRXXs%)FQ Ϝ9$=t]ǎsrr[ کs /y K@^% /y K@^% /yZ% /y K@^ҋPֽsRKoY|SFGGۏ=Yy) \WWWRRxݺO43(H[R7oTI}W32>̔{y+**R*#***<{/7l(++;wӮ[JyI^#G}#%(4_w>kڿ_MIIQ>9ϟ_pἐiiii6\!}9JFyyyhRq63SO7nٰqcPppb}љal\4_|s\|ރ%YX"Ӽ,r;/}yěݔ:yVTT]noܥS@Ku^vIYj3:==]BNYY$3fMڵ?._hO?\IMMw޽sgz}I*rsseVR|m7:CKvKJJdǏzNȐ}vvă#G\KҩK_m3M(/}|I f&Щ^v$X$,lG%% /y @^% /y K@^ /y K@^% /y KC|gNOd!C.ܵkUUΝ1rv脉\"I\J:-Ҷ]X؊III.Mg*K{뭇޼ySSTT$}~]ϖ[϶m۵޵|;)&$TTTC{JIIٖ_~:((8X=;ϚհH?X:jtz 0-'O*//D^8پ}~~~aaᆍ-^,"9teÆ߻w/ĉ4&GԟJ:-Kt%s=/9Լ$rV>jRNnnMM͵<$mݶa^bmٲիʠy!! y)???66V&N:.[&C%,G,^$**J+}Լ$!wزu&1e3gKLdRn#ҽlr<x|WrX|,))ٵ{_###ܹt*qeY-+!@K䣼_~]vc0[ʔ%2޽G$2Ue)^P ?_|?]zՍS+WaN//͚=WBVOyy/_VEǎ5RQGl&}$}NMUg(ݲ5+3'w{_^]]kV^-5r传3On߾Sxs{tt6/IR$Vid蘘uW@\LϞ׿E7cXo }|SK퓓HOSl7)筨(eAήҞ$/I,Sg'TJxɒ=UnS.I$SZ"RӞDvkY&p;wLyUd] $&hIחh.,u Kr/(_ռ4a[쑈!iBJ^:|8[Dx%/I 3gڭ$8_P:;Ӣŋ>[nyI}}0慄Hډ׫OӧO;K2$JETVV oݺ%'$AtKC3$9쏎rb%%%Nr:QN5m^M7kK%/СCJ^3@F۲uٳQr5i) SԬ߰$)K-p})///Us\zz+y)r.ge(IOʠaa<@) JHH+YYf۳Λ'Gf>`r0OIIt!E3 :f9j9S* FeGg*J%mJ^R.̟R~IKb˖-_KC&ƍ;vuZ +4g\?֭[/I׮]ss㻛>st555ׯ_ߵ{Ν%9hIL8Q*\nOW ^Ǝwe0TNge~