pax_global_header00006660000000000000000000000064130044051270014506gustar00rootroot0000000000000052 comment=aebf8a7d67ab4625e0fd4a665766fef9a709161b logxi-1/000077500000000000000000000000001300440512700123325ustar00rootroot00000000000000logxi-1/.gitignore000066400000000000000000000000651300440512700143230ustar00rootroot00000000000000godobin* v1/cmd/demo/demo v1/cmd/filter/filter *.exe logxi-1/Gododir/000077500000000000000000000000001300440512700137215ustar00rootroot00000000000000logxi-1/Gododir/main.go000066400000000000000000000125041300440512700151760ustar00rootroot00000000000000package main import ( "fmt" "io" "os" "path/filepath" "time" "github.com/mattn/go-colorable" "github.com/mgutz/ansi" do "gopkg.in/godo.v2" ) type pair struct { description string command string } var stdout io.Writer var promptColor = ansi.ColorCode("cyan+h") var commentColor = ansi.ColorCode("yellow+h") var titleColor = ansi.ColorCode("green+h") var subtitleColor = ansi.ColorCode("black+h") var normal = ansi.DefaultFG var wd string func init() { wd, _ = os.Getwd() stdout = colorable.NewColorableStdout() } func clear() { do.Bash("clear") // leave a single line at top so the window // overlay doesn't have to be exact fmt.Fprintln(stdout, "") } func pseudoType(s string, color string) { if color != "" { fmt.Fprint(stdout, color) } for _, r := range s { fmt.Fprint(stdout, string(r)) time.Sleep(50 * time.Millisecond) } if color != "" { fmt.Fprint(stdout, ansi.Reset) } } func pseudoTypeln(s string, color string) { pseudoType(s, color) fmt.Fprint(stdout, "\n") } func pseudoPrompt(prompt, s string) { pseudoType(prompt, promptColor) //fmt.Fprint(stdout, promptFn(prompt)) pseudoType(s, normal) } func intro(title, subtitle string, delay time.Duration) { clear() pseudoType("\n\n\t"+title+"\n\n", titleColor) pseudoType("\t"+subtitle, subtitleColor) time.Sleep(delay) } func typeCommand(description, commandStr string) { clear() pseudoTypeln("# "+description, commentColor) pseudoType("> ", promptColor) pseudoType(commandStr, normal) time.Sleep(200 * time.Millisecond) fmt.Fprintln(stdout, "") } var version = "v1" func relv(p string) string { return filepath.Join(version, p) } func absv(p string) string { return filepath.Join(wd, version, p) } func tasks(p *do.Project) { p.Task("bench", nil, func(c *do.Context) { c.Run("LOGXI=* go test -bench . -benchmem", do.M{"$in": "v1/bench"}) }) p.Task("build", nil, func(c *do.Context) { c.Run("go build", do.M{"$in": "v1/cmd/demo"}) }) p.Task("linux-build", nil, func(c *do.Context) { c.Bash(` set -e GOOS=linux GOARCH=amd64 go build scp -F ~/projects/provision/matcherino/ssh.vagrant.config demo devmaster1:~/. `, do.M{"$in": "v1/cmd/demo"}) }) p.Task("etcd-set", nil, func(c *do.Context) { kv := c.Args.NonFlags() if len(kv) != 2 { do.Halt(fmt.Errorf("godo etcd-set -- KEY VALUE")) } c.Run( `curl -L http://127.0.0.1:4001/v2/keys/{{.key}} -XPUT -d value="{{.value}}"`, do.M{"key": kv[0], "value": kv[1]}, ) }) p.Task("etcd-del", nil, func(c *do.Context) { kv := c.Args.Leftover() if len(kv) != 1 { do.Halt(fmt.Errorf("godo etcd-del -- KEY")) } c.Run( `curl -L http://127.0.0.1:4001/v2/keys/{{.key}} -XDELETE`, do.M{"key": kv[0]}, ) }) p.Task("demo", nil, func(c *do.Context) { c.Run("go run main.go", do.M{"$in": "v1/cmd/demo"}) }) p.Task("demo2", nil, func(c *do.Context) { c.Run("go run main.go", do.M{"$in": "v1/cmd/demo2"}) }) p.Task("filter", do.S{"build"}, func(c *do.Context) { c.Run("go build", do.M{"$in": "v1/cmd/filter"}) c.Bash("LOGXI=* ../demo/demo | ./filter", do.M{"$in": "v1/cmd/filter"}) }) p.Task("gifcast", do.S{"build"}, func(*do.Context) { commands := []pair{ { `create a simple app demo`, `cat main.ansi`, }, { `running demo displays only warnings and errors with context`, `demo`, }, { `show all log levels`, `LOGXI=* demo`, }, { `enable/disable loggers with level`, `LOGXI=*=ERR,models demo`, }, { `create custom 256 colors colorscheme, pink==200`, `LOGXI_COLORS=*=black+h,ERR=200+b,key=blue+h demo`, }, { `put keys on newline, set time format, less context`, `LOGXI=* LOGXI_FORMAT=pretty,maxcol=80,t=04:05.000,context=0 demo`, }, { `logxi defaults to fast, unadorned JSON in production`, `demo | cat`, }, } // setup time for ecorder, user presses enter when ready clear() do.Prompt("") intro( "log XI", "structured. faster. friendlier.\n\n\n\n\t::mgutz", 1*time.Second, ) for _, cmd := range commands { typeCommand(cmd.description, cmd.command) do.Bash(cmd.command, do.M{"$in": "v1/cmd/demo"}) time.Sleep(3500 * time.Millisecond) } clear() do.Prompt("") }) p.Task("demo-gif", nil, func(c *do.Context) { c.Bash(`cp ~/Desktop/demo.gif images`) }) p.Task("bench-allocs", nil, func(c *do.Context) { c.Bash(`go test -bench . -benchmem -run=none | grep "allocs\|^Bench"`, do.M{"$in": "v1/bench"}) }).Description("Runs benchmarks with allocs") p.Task("benchjson", nil, func(c *do.Context) { c.Bash("go test -bench=BenchmarkLoggerJSON -benchmem", do.M{"$in": "v1/bench"}) }) p.Task("test", nil, func(c *do.Context) { c.Run("LOGXI=* go test", do.M{"$in": "v1"}) //Run("LOGXI=* go test -run=TestColors", M{"$in": "v1"}) }) p.Task("isolate", do.S{"build"}, func(c *do.Context) { c.Bash("LOGXI=* LOGXI_FORMAT=fit,maxcol=80,t=04:05.000,context=2 demo", do.M{"$in": "v1/cmd/demo"}) }) p.Task("install", nil, func(c *do.Context) { packages := []string{ "github.com/mattn/go-colorable", "github.com/mattn/go-isatty", "github.com/mgutz/ansi", "github.com/stretchr/testify/assert", // needed for benchmarks in bench/ "github.com/Sirupsen/logrus", "gopkg.in/inconshreveable/log15.v2", } for _, pkg := range packages { c.Run("go get -u " + pkg) } }).Description("Installs dependencies") } func main() { do.Godo(tasks) } logxi-1/LICENSE000066400000000000000000000020711300440512700133370ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2016 Mario Gutierrez 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. logxi-1/README.md000066400000000000000000000211431300440512700136120ustar00rootroot00000000000000 ![demo](https://github.com/mgutz/logxi/raw/master/images/demo.gif) # logxi log XI is a structured [12-factor app](http://12factor.net/logs) logger built for speed and happy development. * Simpler. Sane no-configuration defaults out of the box. * Faster. See benchmarks vs logrus and log15. * Structured. Key-value pairs are enforced. Logs JSON in production. * Configurable. Enable/disalbe Loggers and levels via env vars. * Friendlier. Happy, colorful and developer friendly logger in terminal. * Helpul. Traces, warnings and errors are emphasized with file, line number and callstack. * Efficient. Has level guards to avoid cost of building complex arguments. ### Requirements Go 1.3+ ### Installation go get -u github.com/mgutz/logxi/v1 ### Getting Started ```go import "github.com/mgutz/logxi/v1" // create package variable for Logger interface var logger log.Logger func main() { // use default logger who := "mario" log.Info("Hello", "who", who) // create a logger with a unique identifier which // can be enabled from environment variables logger = log.New("pkg") // specify a writer, use NewConcurrentWriter if it is not concurrent // safe modelLogger = log.NewLogger(log.NewConcurrentWriter(os.Stdout), "models") db, err := sql.Open("postgres", "dbname=testdb") if err != nil { modelLogger.Error("Could not open database", "err", err) } fruit := "apple" languages := []string{"go", "javascript"} if log.IsDebug() { // use key-value pairs after message logger.Debug("OK", "fruit", fruit, "languages", languages) } } ``` logxi defaults to showing warnings and above. To view all logs LOGXI=* go run main.go ## Highlights This logger package * Is fast in production environment A logger should be efficient and minimize performance tax. logxi encodes JSON 2X faster than logrus and log15 with primitive types. When diagnosing a problem in production, troubleshooting often means enabling small trace data in `Debug` and `Info` statements for some period of time. # primitive types BenchmarkLogxi 100000 20021 ns/op 2477 B/op 66 allocs/op BenchmarkLogrus 30000 46372 ns/op 8991 B/op 196 allocs/op BenchmarkLog15 20000 62974 ns/op 9244 B/op 236 allocs/op # nested object BenchmarkLogxiComplex 30000 44448 ns/op 6416 B/op 190 allocs/op BenchmarkLogrusComplex 20000 65006 ns/op 12231 B/op 278 allocs/op BenchmarkLog15Complex 20000 92880 ns/op 13172 B/op 311 allocs/op * Is developer friendly in the terminal. The HappyDevFormatter is colorful, prints file and line numbers for traces, warnings and errors. Arguments are printed in the order they are coded. Errors print the call stack. `HappyDevFormatter` is not too concerned with performance and delegates to JSONFormatter internally. * Logs machine parsable output in production environments. The default formatter for non terminals is `JSONFormatter`. `TextFormatter` may also be used which is MUCH faster than JSON but there is no guarantee it can be easily parsed. * Has level guards to avoid the cost of building arguments. Get in the habit of using guards. if log.IsDebug() { log.Debug("some ", "key1", expensive()) } * Conforms to a logging interface so it can be replaced. type Logger interface { Trace(msg string, args ...interface{}) Debug(msg string, args ...interface{}) Info(msg string, args ...interface{}) Warn(msg string, args ...interface{}) error Error(msg string, args ...interface{}) error Fatal(msg string, args ...interface{}) Log(level int, msg string, args []interface{}) SetLevel(int) IsTrace() bool IsDebug() bool IsInfo() bool IsWarn() bool // Error, Fatal not needed, those SHOULD always be logged } * Standardizes on key-value pair argument sequence ```go log.Debug("inside Fn()", "key1", value1, "key2", value2) // instead of this log.WithFields(logrus.Fields{"m": "pkg", "key1": value1, "key2": value2}).Debug("inside fn()") ``` logxi logs `FIX_IMBALANCED_PAIRS =>` if key-value pairs are imbalanced `log.Warn and log.Error` are special cases and return error: ```go return log.Error(msg) //=> fmt.Errorf(msg) return log.Error(msg, "err", err) //=> err ``` * Supports Color Schemes (256 colors) `log.New` creates a logger that supports color schemes logger := log.New("mylog") To customize scheme # emphasize errors with white text on red background LOGXI_COLORS="ERR=white:red" yourapp # emphasize errors with pink = 200 on 256 colors table LOGXI_COLORS="ERR=200" yourapp * Is suppressable in unit tests ```go func TestErrNotFound() { log.Suppress(true) defer log.Suppress(false) ... } ``` ## Configuration ### Enabling/Disabling Loggers By default logxi logs entries whose level is `LevelWarn` or above when using a terminal. For non-terminals, entries with level `LevelError` and above are logged. To quickly see all entries use short form # enable all, disable log named foo LOGXI=*,-foo yourapp To better control logs in production, use long form which allows for granular control of levels # the above statement is equivalent to this LOGXI=*=DBG,foo=OFF yourapp `DBG` should obviously not be used in production unless for troubleshooting. See `LevelAtoi` in `logger.go` for values. For example, there is a problem in the data access layer in production. # Set all to Error and set data related packages to Debug LOGXI=*=ERR,models=DBG,dat*=DBG,api=DBG yourapp ### Format The format may be set via `LOGXI_FORMAT` environment variable. Valid values are `"happy", "text", "JSON", "LTSV"` # Use JSON in production with custom time LOGXI_FORMAT=JSON,t=2006-01-02T15:04:05.000000-0700 yourapp The "happy" formatter has more options * pretty - puts each key-value pair indented on its own line "happy" default to fitting key-value pair onto the same line. If result characters are longer than `maxcol` then the pair will be put on the next line and indented * maxcol - maximum number of columns before forcing a key to be on its own line. If you want everything on a single line, set this to high value like 1000. Default is 80. * context - the number of context lines to print on source. Set to -1 to see only file:lineno. Default is 2. ### Color Schemes The color scheme may be set with `LOGXI_COLORS` environment variable. For example, the default dark scheme is emulated like this # on non-Windows, see Windows support below export LOGXI_COLORS=key=cyan+h,value,misc=blue+h,source=magenta,TRC,DBG,WRN=yellow,INF=green,ERR=red+h yourapp # color only errors LOGXI_COLORS=ERR=red yourapp See [ansi](http://github.com/mgutz/ansi) package for styling. An empty value, like "value" and "DBG" above means use default foreground and background on terminal. Keys * \* - default color * TRC - trace color * DBG - debug color * WRN - warn color * INF - info color * ERR - error color * message - message color * key - key color * value - value color unless WRN or ERR * misc - time and log name color * source - source context color (excluding error line) #### Windows Use [ConEmu-Maximus5](https://github.com/Maximus5/ConEmu). Read this page about [256 colors](https://code.google.com/p/conemu-maximus5/wiki/Xterm256Colors). Colors in PowerShell and Command Prompt _work_ but not very pretty. ## Extending What about hooks? There are least two ways to do this * Implement your own `io.Writer` to write to external services. Be sure to set the formatter to JSON to faciliate decoding with Go's built-in streaming decoder. * Create an external filter. See `v1/cmd/filter` as an example. What about log rotation? 12 factor apps only concern themselves with STDOUT. Use shell redirection operators to write to a file. There are many utilities to rotate logs which accept STDIN as input. They can do many things like send alerts, etc. The two obvious choices are Apache's `rotatelogs` utility and `lograte`. ```sh yourapp | rotatelogs yourapp 86400 ``` ## Testing ``` # install godo task runner go get -u gopkg.in/godo.v2/cmd/godo # install dependencies godo install -v # run test godo test # run bench with allocs (requires manual cleanup of output) godo bench-allocs ``` ## License MIT License logxi-1/images/000077500000000000000000000000001300440512700135775ustar00rootroot00000000000000logxi-1/images/demo.gif000066400000000000000000011561641300440512700152300ustar00rootroot00000000000000GIF89aw! NETSCAPE2.0!,!% (9((9($()9,&-! &0+0!(  *18;((>"8(3/7:"#" +0,/0..='9!$6:*6782$4445UF/R-d5s:z9&G0G>[>B:$s4#z8-z65s/*DW.IZ;BB>JN1DP5KZ7S_;T^;UaKA#K2Y:M?,C?3M?3V@Y[ OE,CC?OE9T@#ZH+\N6XJ9_R2DdNd\l Cl Kl$Ms"Rz!aGaRi[aV9dXldllplFGEKMJALPASZMRSH[]VQL\TB[SLQY__YQA[fN_d[aVNaeRefUhfZcd_jff]Fec\heQhjTcaaaifhid";,;4;3;;=:=F7R-W,[#[(P9Z6^8^8o|| ~syyzd"g,n2"n/n0b04=ACCCCCCBH*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ Nȓ+_μУKNسkνËOӫ_Ͼ˟OϿ(h& 6F(LDbJ)VL!jha.QB &=BL'2L0,ʆ0hÉGh䐍4g `D sx#A @"J(#@$HBF%(6@6$d5@AdC4m4DjbB`#*06g[g 5ڐ)@h h#̞ 94h蟜h-Ҙ1.칃6.ih2,ڸ!P60ȥlhĝ6 |I2,T4$K6+V~ @JЂMBІ:D'JъZͨF7юz HGJҒ(MJWҖ0LgJӚ8ͩNwӞ@ PJԢHMRԦ:PTJժZXͪVծz` XJֲhMZֶp\J׺xͫ^׾ `KMb:d'KZͬf7z hGKҚMjWֺlgKͭnw pKMr:ЍtKZͮvz xKMz|Kͯ~LN;'L [ΰ7{ GL(NW0gL8αw@L"HN&;PL*[Xβ.{`L2hN6(pL:xγ>πMBЈN4!,zZ$! &0+0! ;>"3/!$! +0..=$6:*6782$4449938Q 5H*;I.IZ5KZ7S_;T_;UaA$C?3M?3V@]O6dXFGEASZMSVVQL[TA[SLQY__YPA[fN_d[aVMafRefUhfZfff]FheQhjTcaaajfhid@pH,R)qI~vPVH]F,rym$.)Dt~[h}&V;9{6wI `bf37 3%Bz+5;DRA+H<(C?7AB=TE,XC#ZN3ZN9_T9cV 75@$,@:6@/ ?>?9A@"ފ?;++* #Ͻ濾@`5@! 0+b; Y&Mң8Z+!ÏY.l:%_D@T@ QE0 sϢFJz4(S}!,Z$% 59< >!%.?%%  8&#&!%&)%/4 .: 1=82- @5J5E%1H >U.FX>BB0JV>YdC"F0F6$A?7A??DE>ZC#cV:cXi<'E 5i Dk=0%*wC69B C=/2U6DV36g]eCiYLMA!,Z!%! +0"*<>"3/!!! +0*/04445B:.IZ>JN7S_""# ..=$6:5??;90 @1J8O;T_;UaA"A+C?5TE,ZN4ZN9_T9FGENLFJKIAQZK[^]SAQYZH_dMafVefZff]hff]FhbHhdThf\hiShj]caadiehjd@pH,Ryl:s2.,ʖ2nn5En-0`dj(-7Nw86,4 n7wrro uG61%%$ TB1]EoF'6Pw*72$%)E673'"BD,7شwCSDӳSfVQA!,Z$% 5;= >!%&0%;  >"8&%&! .:..="3;;90%1H.FX;T_;Ua>YdB"F6$C?3A??CE>ZC#]O6cV:dXNZ>S]>YfA+M7T=C2-C?7V@#VE,XC#QLH17HC?*#͹ԇ G?FFGς!ÆG|&"6"ڨဠ $źY|QT:z <acwI. pnŒ@ (}"*U*ժObͪq륫^ !,.Z$!*;>%:!-&- *;+;+ & .6:1+)52-5248:7 @*F1J5I8Q;Q$6B ;S*DW5BN>DR>LP>NZ>S]>Wc>YfT=H<(AB=V@#VE,XC#QL<]O3cVCk!_yj ]ibBĊp!O.tC,YdJ|2$C&n<a3N E=mFiFTN2t*եHV!,IZ$#..< ;&0!.9  !>""# ..=$6:5??;90 @1J8O;T_;UaA"A+C?5TE,ZN4ZN9_T9FGENLFJKIAQZK[^]SAQYZH_dMafVefZff]hff]FhbHhdThf\hiShj]caadiehjd@pH,Ryl:s2.,ʖ2nn5En-0`dj(-7Nw86,4 n7wrro uG61%%$ TB1]EoF'6Pw*72$%)E673'"BD,7شwCSDӳSfVQA!,ZhL!,#.5:< !;"-!"&-.?&0+0!#!,*:  !="5+3/8&;+9+"#!%&)!,1 .:+/0..="4:*67.6:1+)52-82$82-4445>?:93!@*F*C1J5E5I8O8Q9Q$6B"3H*;I ;S>B:*DW.FX.IZ5BNJN1DP0JV5KZ>DRNZ7S_;T^;Ua>YeA#A+F0K2M7T=F6$C2-J=*B?5A??M?3V@OE,BD>OE9U@#TE,XC#ZH+QL<[N4YL9_R2_T9bV:dXEFDALLMKEKKIAGRAJRARZMRSK[]VJBSRK\SA[TM_YNRSQQY[]WR_YQCZdK_dV_cX_c[aVMaeSefUhfYdd\ife[Df_Oa]Th`FhbIec\heQhf\hiShi]caaciehieH*\ȰÇ#\0NjĂ.SǏ3n0 R H' D͛) ӠN=MH53ãI*\HSQCR:U` ,Y!@%.*xo]8Eәj0`D}]X 9dnF!Maj ! .|! MsHAI -c4/V{-@h 'V?>h$wjJDsp Yr˙7.zxϡG+g-ܡ w_hŃŏ'H0Aw[c>C#Iib4%mIR@P@}%UTRp d!M R\!4D D& -$6ȡIŨ&"D9㏤(%iUp50H%$Ō5HP %RR&N&S&gB[ E lհZ}PmQ"WI,1bW*hW!&"&l&͵I1$DoJ |АªZg)g*("@ Q۩ڪ"tvEr*l4mmPl{kV}x`%P_k4;qR=|cDjQi"uH]M- GuF,x]ɽ96O' ,fmue-v:U.PKttÖ{@iv@裣~:{ Y#t4^G{EyF=[Ym&b(@;.4jWn ;Si"!a ЈHܮ|SRe CW=@[=- $ SXs_EzKjԆL|C&>j[41<0n8CJX,(JĹL%P@ !E Eb0M!@D#jQhq\D@$Rc,c‡F;Qv ##9J%ICaPp@XR>)~`WP5K/(Lzh҃maِ4iBR)2?Mi: 7%͂r"j;iE5*}jI٧;kxSb@W  s s(FQX4^ Ģ+D)JV(uHKuRD6N] ѢHMRԦ:PTJժZXͪVծz` XJֲhMZֶp\J׺xͫ^׾ `KMb:d'KZͬf7z hGKҚMjWֺlgKxͭnw pKM._76Wutk[:s;[2.xeM7=/lӫ^ײ}/|U+5-~KW/h,`=05!,Z&"%4+4 ** !1ENF7AC=aT9]_XK_dRffVhfh`FhcKhjf dihlp,tmx|pH,Ȥrl:ШtJZجv[x_n e3HaP"W>Oz|* oz/.&  p%vy#h$ $'%d&!!,V$!.+58%-!-!%"2+4"%**<= !5/;+>2./$.2086$444;:5>?= @5Q5Q:R;S 8M ;S1EN;BBA&F7M7T=Q=C<7XCAC=V@#QB-YC#XC(aT6bU;cXT|Xp^ QtpR@b Ha"GR 6=RZ P1@dA?Xttʴ)A~ВB 6tЀ,FfVr@!i,q$! ;+0! 5<.&>"3/ #"!-1*6782$4438678978O8Q 5H*;I18I.IZ5L[7S_ASZMSVVQLZUA[SLSSRQY__YPA[fL^c[aVMafRefUifZff_jfh_KheQhjThj\ajfhie@4 ?3?#7< )2?6;( $̻6ς'ი?:7!~`0|D!9~ dP@1`- X h~Tcf)р6D^H"tiN!Y !,^"*---*,;,H-SD]G*oF)~NO+gpew1NwG(SMRMVnQ<<Ioo0*.5BQ#<326 Ԧ1߁=( =)]y ='P = AG!*\-!Ç9H⨉3j$qǏp:IȒ(S\ɲ˗0cʜI͛8sɳ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ Nȓ+_μУKNسkνËOӫ_Ͼ˟OϿ(h& 6F(!,$"--*,; +T,?T1PO+@<[TZw9og/og=YTdUwO<I~-p.<@^MZ`BLbˌ#5߮..:04>cc`bJ]I[ba@pH,Ryl:s2e&"XNMl3 =$8'+Ȁk$ +/v2N(/F#B).FB uvEM1Nk,*%DN0l"PS eOTTgG֮gA!,)$&**.)5)9;=-HwE=~N=~Q@P\@+@<O;[<o<OIOTN^0[T(Zg2xgxw1=MTeImYvU<<IT^go)o1w1~5g33;.@P^XWa`BYFEICSdbbьթ*ڮ2ڼ:0AгGиCڼI2>V\ZPa`baMHIQMU[W[baaaah$U';b("=36=2.Vb5/0, cga+#b1D^FgI9gQ N->gP .F!/ eXa f܂8 W0I3]~DYlqc bTt )BDgl\ș/L~HA'TtpL!J&(CcKeL@:y: ԪrAT/vزf-Mh-[DުU!,D$&**.)5)9;=-H<HA+g@*oJ)wJ>wE=~NP@+O;[<o<OIOT[T(Zg2=MTvU<^o)g33;@PXBYFEICbcթ*ڮ20AиCڼI2>V\Z`baMHJQUW[baaaaĀI'"$'! DHBC .H0&H6 3(H5F;B GǵICю :ֵ H@),*+,#%Ȧ?E6h$7^EƸGƸN˸K24_ac`bNVI_aaa7H@G;'G0)"   EGG+/(G3!&G.5Ώ FB#ւؚ$<1H G: G-ע,A6*~ @aHz"R)l yp $&GLi%KH._)S@!,z$"*&;.;<--+H-,H1wQ)~Q@P\@<pg+N^'fTew6ZwB(S=RMRMVdU++<<^^IT^wox >+@UMCVEMEWădžƌь֒֒Ʃ7ߣ&У0ƸN˸KڼFcc`bNFJOW[T[babaa1//$Q3P9P7 % -$-& *(!POPKNCH6F2PJ.P'A)+PF˺4 P87K#@K"QKKEo3- 3| bxXMD q06ܨ.Ȓ0@!Pq ! Kf J !'lF$@2$Z,tZr@AkUGfӊMKu-[N !,$&**.)5)9;=-H<HA+g@*oJ)wJ>wE=~NP@+O;[<o<OIOT[T(Zg2=MTvU<^o)g33;@PXBYFEICbcթ*ڮ20AиCڼI2>V\Z`baMHJQUW[baaaaĀI'"$'! DHBC .H0&H6 3(H5F;B GǵICю :ֵ H@),*+,#%Ȧ?E6h$7^+@UMaƌߣ&У0ڼFccbFIOW[W[baba@pH,Ryl:s*2ZiU>jkUYN<Ţ !y{}tuw&&ew BVw~Mu+(" Q'*n&Kk$B*S DTѦCІ!nL GTPueA!,$$+**.)<;.;>-H-H<S;,H1HA]GwQ*oJ)~Q>wJ=~NP@+O;o<OIOTx^&nw9(S=R=MRMVM<++<<^^wox :3!QIXBCVFEICW_bc̆džь֒֒թ*У=ڮ2߳;(03AH284>?V\c`cbbbJQNUU\bbaaaa20fdObM.1e 4/ +5*5, Ye `^)"ece_a'TeG#>eF3eQ !e\;e^6e-fdP bW^$?eBA։"h^ ~}ć/&< MH(9tdCmt `BDd)RI_JZ(e )DwE>wJ=~N=~Q@P\@+O+F;[+[<gpg+f<f<o<OIOT[TN^'N^0[I$[T(Zg2Zw9fTf^+x^&xgfg/og/og=ew6nw9xw1NwGZwBs(S=Q.i==MRMTYTeIgS{NmYvU235˪6Я5߹%6'+6<<+<<^^I^T^^gowoo*o)o1o>YGKWbcac`bbbaKDFM@HISFJNU[V[babaaaaH*\ȰÂRyxPJYPq!R:*- omD<四0 (/\rɳa~6{ e {tTu/Ҙ[Ažj`5t1^" ;p4a@XXI10@O({ s7^~ nH J` O- ςV|p"'Ks fZ^ #kW~H}h1ѤM`^sj4aTAqӮ|e=Dvm9O+lBlg@84P{s> 1=  Ae5~99`Lv*9-?" @ N!3 ]u1LR@M %/0S*lc A, E JdSViWBXjr 2C,}lЇ) 4B}n;t}lB(k¸oh@>0 4} } r4 0!xÆjxѥ} a4 A-$ 4e7F,ݣ ^zT̀AN0!za "ӠE˞RPe2;yN]ՠzZ'BQ ! UB2LXE5P!k#'0}(^E˾1!^IQB `J|IN*dB@/~w8/2˜|̑'J2LHAr8)Z$ͨ`Bh?BYpӛ 8r S$A9rNm&D$@A;1Ax0>:$>-~G; 9W>GQ071VKB>x)=G%/2>5/* <>8LY6B3>,`W HrssA!,h!.P-B,]P]A.\BO\O\\f)('=K-n\o-@fOxؒPg*g?q(ypyo<ӟΫȶӕ@pH,wd,*(" ! P0(#.+J xlԼLNibv7$|sfC9},8 6}tu.J,4l-t 0;2!%f 5)BT6:*+H4PI153B RGtLNDeUIA!,z!..BP-B,].NqBP]fBfB-AOOOOO\O\A[qfpyY.c-\A@Oϑg*Pypyxn͓;ҙXסXҦmܬmØɘȸײ½Ƚӕ؜Ϊ7G@G9/G"(*)%& E2!0G5' .G 1G: ȎGFЂ,D#GG8Gы3A6+?G$-;>G!<H@KCT Mq#GL?jD'$ɒ#L)!Y,!|1-2317+593HTFS n.L+r+5O:;j OO1r &FVKQqbPms=KS+Jd,Ks*Vk,Xv=Vk=Vs<`uKCV]R0cj9a=*LLK=KQC KJ:rLmQ4zb'OPLKW`A[qXXbPevrjOaaibjriqrra`zrjvuw%'89-%NJSUnp+_-i2twTuUsqt.izz7285˪6Я5߹%6'+6V@K\WfyzzqJJOWW\arw9,=KKZ KXX(ac'b;h(i(MJJիX& ne:!@ZbhRZRAŨٴkhUՋyP fѪ-c fҕi`†MӨ/"ĥb&mCٶDڶN @ݱK OxK ?X7mËOy"z 3%PLF5l V7(?XC2`~A##r#Ђ@f8QȠ,`0(V xF(? D Dh@3HE4`'LCJ-c 4`?BOz莕Xj:04hlz[ЇHQW24`b!!xIЙۇ[Tm4) -\?hv1*ō9&$)A>$.yTw~"5SϪn&d+^9;Q>>E%堠6RzZij?Ts+ʶ햂vBNz? .JA,ZkQ2Wngw砇.褗n騧ꬷ.n/o'7G/Wogw/o觯/o DZHЀ(! !D@ Ny@ Ā<5@6P%(q@@0" P"P!&C ( qL2p!FH*p !F() [ˆ$I"VF'EF D$@p 2%p cbCAav QA bzAHnD!($EH K*#W!p %֘Kҏ:T-3H I@0)HPhpýyn>,1yM Җԥ.3Mp4Is-9P|%D{^\X9aa$ Q (\$5# d ]"DT;tbC)2Ɛ:Ub>DC,QA+! E@֫\Z'V%L[s m_pH.=kګc"Wz}E襄INBu.{`KW|ϝ +TnqIeQW8Hgͻ-k\3xy$ r{GI" B)t,e6&C NXQkIK1b`CqHcR2~(k1e}L9"Zѭe,»CZ oLݭ*# gxzׂ{;JlKz=1*4V lsS H쌯PAnT0+(C4J9 ':vAϙ85jYeQwœ4: yJo85{ةV9V/9`{NT޷!)9v9N{N Brwo([] uwyn#emEWK-A뮻,g;]<89Mͥгv{݈H5%$/?Xј]s(r[[BZ do<Ɨr2Ua=@WODɄ"8x(*,؂.0284X6x8:<؃>@B8DXFxHJL؄NPR8TXVxXZ\؅^0'$ TM  ` pM  |0M ~p 7Ё @E%R*A$- 1RsMȰ( _, K% poh3rT)A-12r5700q6@ P>0BF&d$4TYHĊ 1 ( i8`AO € d!7N1Џi]] c[&rX`)@X)0I-PQQERx','B(a)7Yb!Z29 Qc2 h@ (͐sRe)IB|Rb #D.ڀK ! 8 ;b2 2p)tٓ%p0 8u(| 7Q> s#$BtPgYBPQ#!YIQ4`/b 9|/A*  -IBCȩi` y>H ȚIf51/) 141-ɗ^L~Hx(Yـ0/`x Aq$I>gIQd6%_5ጄs V)IBr,:$hQr)Ys(١s_+%ښ#g'-P2 І`Fu/_ BɌfQ  QJi$J ԚR\b 01 p}x+'4P@1Z9r+Ұ٩{ @:z 9 ѕ_CxIg? &e#xaqCA5&3@ېEIB*@[:0,*ejH-ͪO HXI;"1 "R *K. =p n'x8+۳ 9/7)Qi/EN[=p<I3@O۵^`b;UQg8C4@dAH`Av{qKO$[AwmAqo #os(ux ч9YT!B7]d4hDxW"v 1D@!u:wVDԆ[SKjѻVnV=X""㊰S(9KçR{Wf<`:ah~$uHk9$ߛ4[+ؑ H9jh)9Ni!  J*7% )|U2+otGSMFMe1DhGPZ\P LDMN9.Zr˾a) \Y!::.7n;Flj5\.}_A[&qn9W4d|]jM66ȋ~T8G0 C] >}ޣ.I`%B3e꧀CҠŨ~#u#++2Mq]PwTovo*oE֐.6Vnp^UTpn8_5tMUt vj#ZI oo:r ޔ?A zǺ7yҫ*4:Q'*Zp bo2+aO1쩠aQTJUq'@gTpWv.ehaeLZ\S`̎kYDUy4dJ*VvK^fj;^s.vT{qovRG{M2z̮OO?0Z{jy~OL* { O߾pPODQć&VEHH)}W'MHBe"W`S #WLsҩ@f$gS^ tTD;N|3T9ethզX1{uղQR6 ̓n\r+9ntŦl9dʖxǘ& |ʖ/dK7"i;}5# ;ܰ僌<$@è3N;|sqG!R!lRQI(9 r%|/L rȅD4s/ g|9-tPA1ˌPGIQF}r4;`&tt$7СSPEtN8uUV7| ZuV(I 5#4uW^{W`vXb5XdUvYfuYhvZj=[Buv[n[pC5\tU8e]xw^zy8w_~]7|x` ~| VxaFta+b?c;|LdSa[vexNfkyYoyg-Uzzh%`<)zituzjnԳzkk{l6lV{mvm{nn{oo|p 7pW|qwq#|r+r3|s;sC}tKI$LNƏ5p325ԡu{J$Uhh߂fv}^^AxQvBkƟBWW##MAy dR?`` ` m%E,T5HF<CF6$\|i=*> )CZPxF$CJ:mr;΀xҎ~?W jo9PN >֣MnH c"H%|5891)G#1O)*~QzH2d6)ۥ:@?>QJA,Hj|RKPOcW"/AXG|B9I`N}xD2iOh!< BK:r8-b+DkhL-3$3ݸhJN9nq D镃&n&v$K(NLg' pɈ&%m-:L5HQ&ɝ7CAB4SNC!7z)eݬK'.Ms 9YPx=J>YWNL2Q- $ٽ:%.#BVv,_wp6?_#>.<%G=|Ӝ^Cù3`%3^c.\4#W42P/zҥ21-g;yHFoE=`O׌fn/wٺݫe1_Ȧltm,?;5Li_W\Ys?x춮 'ޞwټ>aM5cl7 ۽gςMdSh&vukvo7z1ս*:Cv]UC>9]rzSeβ}Nu>[/~>;~%'q^;~Z9qn{mvuǂWp ?= "V|G^jrl?n|u'c>|M莞g}'zƹ^'0`\$h@Gp oOڝW3ܩC7(`R%HG^PO/yԗ*%8Pڔ7- V @)m rWXxL8(L8&؅j xY@ Jҕ: ?8# A#" `@! 0A䛈A(D Ĉ@B /B.LC  0 "BB$ *n@ =)/ u#yA=Y$c*ȇ>+#$ ` Q  xАcʼn(Ÿ1thEť`ź@ʼn(E X 7OĢtDm1ٸ_ jL'ȣ=h9P%FC0 +Ts _u>{$m Iu( 50KMq@`+:}?][ A"S@?h\z Ѽ@@X4A\ b mA7qS FiE8-[yG{|%Gs >qCjNF ozg ({ J MJ`I[RՀ*^֘,uiΛIHILc| M ǁIBc{PcMDxc㊨9NO% ː˻|Vx<,,TK2`AL:L^ALdܿ:0FTPW.*ꄟAdGs((Np)hFeFhHR6*d:&t8֨ ,D䛸cchNr褆Nhg$`o{X8O=\fTjv gxЉЗ 5MuQ{NyN Ui i:Pm( |Ѓrz鉸|/ ¬R<QE)dit.13ŖUӴFS5>x~ 맊1%K!N5ayL=]ӝ cHC9TSh4-UMU}bX}Y0\=@-_vY-Pm\W"1#hm+`VP׍ tEՇY|֗x(L~EnW-PoeY=}Y>?5 ڌP_a3!ciZp p p G^ Zup >ݐ@#c>؈>a%º>PBE\[[[ȥ Q\X8D?ѥ}&_f*-g }RKH ' 2 ˆ@ Pa@ۭA Q4؅<B}]\]8LAX `A Et@"qDs]ڡo}@T2ABD=^½Aes7%"#RQBʜcl'(@^b_MBvw)_eH_>Q^h_;^l=T[NO:}~4M^bLM8f&`h`_'9#;Dala&P)#m\a>_aqiaua=x'y  y4N:XhrnU  8j*HLK>I)1>x=&%SB%>d=f D*ZV=w3lcc'NvtHz=ޘԃd7d=HEnGv} x X. 2d0ϽQPo&P6@̙bD3 $8zY̕}tM`e^eXc[\T~#`FamdVffNg ۜYLi>}_jdpn}|zvr&y_!w[[C2La3P#H] -` ?{~,zle~e…BѢǛ}O?= E4bɿo2K `A;BR+^`ʄ2+TErW- wVP.l0Ċ3n1Ȓ'S,t:X2cQ3XʿN7a*УKI {ΐuM*Q!iO':0r&]8p,H72AahL3ەAU@\o[%TWPpSoAYx!j!zfq#/&CaC4hd7/ʳ. 0N'R%>>ӕ#NB)%2hcJZ?鼧8c&"aVFΔd}9i?IiKݩ6ZQ~^w~ͅU~u}E]%\VX~|8*z*6fu Ccu65uxr$91JP<>乇PV{-z2^8ˬMZZA=uk,AP3+W@e)8i[N+Z ?ͪ1!<2ɎE -Ku 1vrE3 %A=0CF w҉mV/}b^R2i6mk=p ?-7s禲=F8+8zk?Q䍳 D>髿>>?????(< 2| #( R 3 r C(&&"\[6rg&bU "UuX+ي7pe2sC?,?Og'< ] H(ЇB- }O2q&B[IpӱP#OXԞ nIԡ -ޠ#Oi G *C0nrG`*CT2DK=xJU?1\]$OT*pM=Uԡn- 0`5F=j$!p|ŢFzRPBc@P"tp(N(XW>=G`eG|dD{gߡTúz ,&UضA`Hxbԅ7cs,VO /7^P3'VȮD^qNl3z X="+L`;r0%]E;c29ȓ202[:4!T I>_f3r;qa G :J<E 5g&Ja`utnRX]n@[ߊ+[BR#8%##F0t30m Ȉ(kY O`F@I=!'׮2)wqgl3UᠦAq&{d s{qa{2{c*# \ox+y K (E߯ҎIr=s2׈Wr&"bcRwpef<<67l:CІK@lx!XH@,nl̄ڮ mk4{^F Z 8PASYAdMAtKP[TĈ_KYUWY^`.!@W=hYm!Egf)59VW9ɞdta0 !?WBUA7]y z TLԆ%KF,&MDEEFEdRDIDG= TóbS1G~ ^)^VM4[YZ CE]Уh[RM#9YFWyYXY2V6›TQ^X\3օ]d bh<@Gx!!^-Ê *jW!%#2RQ=@P مR*:-!z|b.D%JNv0wwFxIq̔{(GJymHy'ƃ=@JĮxK=3cKxE3%K\KxV5Xe;͍GYE9E:YX <FLzGKEdUb NzhBإ,]Mea_d=]><hbĮ#&jfldF%z&I(ɚ4ɴ`I&dIEp#Do]ȃ:?מC9,˕5HA mcaQ-i'٢\ X d 5HPL`d Q%6\<짧0PA##X8ʤL\ņQ{'^nS!o2IdC?|2CI(/rbݔ:HA"&(L't˃Q19bʣEL4M'V(h0'j:` z(Z90vnEDp鳕D ˴l  #D?@)07ÝdKLc1 KLCfۤQea}P[lY4ɥI*}0 f?J@ND<DMAA ߣEP懛bG/z0Ab責IV6Kvt7Ʒ~k#\>c;JSvO^La6PCfsy[ӗ4:E4~idp&cihvuKySTGk$rf#vĜL>_VXe9aec^*NަC9Q AZYMH憹9I&ӫGLW![zFLs5S'opsȕa/ȏCP8t ɱpw'1qK,%:H='N˒ 'Lۢwꂚ#`g(jJ9EA(zKਣ.4^n _s3Zd<':9g[F{hZu܊+*jKikKl+HsqC,gA@}&p{PoөJ+kpO M*ɿm_ַjD:o̽<FPmKVm&D vF~2* 3Պ ؜lMblWf>ώlwFo {M@>-CM,գX8n.N*tc23.)n??ǿn`/ RE$4xaB 6tbD)V<8-6@AGAL(`Ǐ!5p<ڝ;gN;? *QwhgRYMJ >+T l=Jؖa)TRm܅neH7kƿ](T+x+a=V\ퟪ)!q}se a17=80fcS$ɕ \᫴l]T7X Ԉ/s̓ l|nKKI R@\NѥSd كq?\2ǟ]%WbYE|cQV DHXb1van\fr!5Gn8`OMBg]ZS~v5@ @∂iT+ %,(ҋ+(8dCkӅ/vMmh[d!ZeB9gx QdhCӓG.d'[Xވj / B+fFΚa !%Zʟ;\E͞eGD NǞ̛ aav ͠!XJLr>+ן:5x}><ŏ,BX ?zKSJ:\*niU@6D9X:%nqX4W10yjP1\H' `tC`fD"M>Ź*@ȵ ƪ$ `1'7"wUk! s2G3^dl̐)IBZD&2L2|Y$ ldQ&hQǔ Pʰ (XU$xJaF"LRTM3wD' Rb% [f\+,3DUak'$xSANC`t5BP 44T=UVB>,1,{S:%_䡩F:N01D;KBiW6{KJ_̦I{mҒVKX --KSdԙ,7<_%B UNaQ7%JbaIb8udN9{ %iIk l)g΀^}$ `.x!;{Qw,tlڜ>:uo(-Q!-i!f5yk`ݻe>`s*2;唂d-Jnp\$U@yE!zo[}W{;yE#+PFŘ3!B;X5do`8v/ }xF_l~,ij-y]OՐy*}9/BA_]9R#6OC톀]f?M mEP,EOd+DUT */"$'a" @H*h`.P' cs! ",kFi!l!xJϢD##mpt":0P0OO  q4zop Pp # ǩrp806ʾd~ؐ2 +e*n))c@Gh8"И(taƬp;2 @K#6@z`^UQ gbQvB&wQ"8yQQQ azVr&-`! `"$&lQqv0 'H6aA6\t+ 1!")C38s8⛤E(v"`ppr,"VCr;#"W%[%?@>LEC>Cb)fBbEjoZZjABhdl%+!谴Xnlꃌ '!nm&ndR'X@%Z[&anTR+0so!p,Gx'Gq0sSty8?Tt4)g!xH0O5S舎RÚ'hp dAd& ">4(7 0M5:긨`:<ð86@ ޭ7 J3Pj!S>> r#f~3SS =1+H9 B#TB% ֧@3(-'.@@ \lbB*mBoGqhp /-ݔ.KM֡ph1qj|Ȥ٠ l!rTLt>GYrk` !+O``2M&R4A;̔XHj.+!O~LQ] 5U)@c P S?T h2TWU[. W EP]WsUWWeq3ouWXXYUYYYYZZqTZX[U>9 U\U0\]YrEӕ]ە]U^_H_/` `aal]b#vVb+b'b7cwf³cGd) EXKVeWV&q`YfcVfgfkfogs`EYtggg_V(ih!i]iV\VjZjYVkYkvXVlUlTVmPmGVnBnV:Vo65o0Wp * pw%!,"*---*,;,H-SD]G*oF)~NO+gpew1NwG(SMRMVnQ<<Ioow";4/8!Ф0*.5PP#<326 Ɋ1s)Ч$Ç#p(AjIȱG]10"(S\yJ˗0cr͛8sR1yJCF*] )ӧPr*իXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ Nȓ+_μУKNسkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.U!,$"*&)<-,; ?T1P\O<[TOT$Zw9og=ew6NwG~Y<^^IIgo ~-x o).@S^`BAbc.:߸G24>]cbbbJG]IKTYW[baa@pH,Ryl:s2C1B(Ϩ"2Io2 \5`R]7:s9nI s'09-4 ){-<6<=<&B!8;B vw.nEŻ.ȟD%<1,szԱ E;s(02VS TTO X#!,2$"*&)<-,H-?T,)~QP\f<ew6ZwB=PMR^^I^o*o1~5x o)4@SMX\Aĕь֒И"Ʃ7ƸGƸN˸K24c`bNGITYW_baa@pH6Lk:KuSEu蹑3 4`dCfSYv] |7#Cy{}wx+717)B7"8+36Cvw0 SBBb-+C7!ɽ (,7.'%+/´7`X[  !,M$#+*.)5);;);?--*&S;?I$HA]G*oJ*wQ>wJ@\@+[<@;-OTx^&og"oo.nw9xo2M~LMRMTMTgoo6w.w5~04::4>!@QIP___ba֒֒ےƒ$ƒ)У=߳;(,4H284>J`c`cbbWYDEOZK]aaaaa1.[YEWC/-)'(+0ZZ: MIU; 5ZAZ>!KTYF<7Z9Z8 6QZ?[P%*#@B@Ϡe'GHh"D%{d)XTI=xB A3ҭPRXtqed@C %'Phl0Aѣ'uժ!,h$&+3**&*.*2;.;=-,; H-H<S;,H1wQ*oJ)~Q>wJ=~N@P\@+O;[+o<OIf^+(S=R=MRMT<++<<I^^wo^opx 3@XBCVWFIEICWbbbbc̆dž̆ьь֒թ*У3ڮ2>0A3?V\`bbbbaM@JQLUU\bbaaah"63-7, 7.4cga+$gfgbd(e0DgM5gR #g_?ga8g2 ZbL9h eWa%EgJIQCb*bb&!Ĝq&#n/:|1)f, b^ץ1( A.3`蘲J+rf+gʾ'>1HsrXA+ݺZu.!,$#+)<;?-S;,H-?T,HA]G*oJ)~Q>wJP@+f<OTx^&nw9ZwB=PMRM^o*o1~54:!QMIX\e_̆ь֒И"Ʃ7У=߳;(3ƸGƸN˸KH284>c`c`bbbNI_aaaЀ"0E C6D³%)8D-#D(ɠ C7ّD؞.嬔 D50!MP"'=j59B"?b0 o^(Baa€) Zc !,$"**&;<--+?ISA+]C)~Q=~N@P\@<pg+f<OIN^'[I$fTfg/ew6ZwB=MRdU^^IT^~,I7;>+%@ULM`BEKEaZ̆ƌь֒ڞ!Ʃ7ߣ&ң1'>EƸN˸KڼF2_bc`bNVFIOW[W[babaa311#X4W9W80'$+(  T%IOU7/W=&GWQ),WMԂɹ?GR"FR!X VK*GL4LPE,_@ọG"՘2@ʼnA I@ %@d ⣚!2\ʅJ80q_R~; J},5y0Q :dBN$#M+A][,5' ȖݤkӶX41!,$"+**&)5)9;<-H??I+T,?T,?^0HASA+]C+g@)wJ>wE=~N=~Q@P\@+[<[<gpyf<f<OIOT[I$[T(Zg2Zw~,ITg437;;%@P_L`BYJ`dZbdcdžВڞ!գ3(',>0:3EиCڼI2;>Z_a`baMHNVKPT\baaaaq'?D:9! 9),D<4-ppk7ApSKp8mp5qY2&Ep[ni nhCpP%*;ŮoJpM.pQGpT"ap\0YC78ezq&53tQ0Ȁ/MA( !! Y[K~!H@3X2R Ydʠ`d"AHl0 01G(SUFIJRv>GVtpkv_Jw=+@!,$"+3*&*2)<-,; S;>wJ=~N@P\@+[+OIf^+ew6=RMRMR<^^II^opx o)3@@SBWAIbbb̆ьУ3>2c`bbbbaM@GITYW\baaĀD#&"$( BC@5>A 8@/'C<2C=!%C1ʞ,@?B˸D C-+@<5͍C.*@많C:7`%Gl ɑ4s 2H VC`4%c=uNJ %nRbrʖ.Ylr&M6 q !,$"+;<--+H?+T,?T,?^0HA)~Q=~QP[<gpyf<ZwT4_MEKEbdbdc̆džь֒ВƩ7(,0:3ƸN˸K;?c`bNJPT\baaa΀&$$G'F/F. !!"F3*F G E@E?ķ)F-F2õň F9+BҊ=AE:ш F,F0È18f$G釃Dln"B>l&B!FhlX J5Bx)+9&Oh~Μ!, %#,*)5)9;.;>-,; ?T1HASD+g@)wJ)~S>wE>wOP\@+[<OT[T[T(Zg2Zo6Zw9og=Z~PMRMTvU~_+<Igo)w$~8~-^gw,33.;M@P^^`BYbb̆ьь.(:/ЩJиCڼI244<=Z\c`bbaMHE]JWR[baaaa_( )&38/ * 80OV]G ^^Y,:^UI ;Y$. ]@D'9^F5APY%_5Y#"^<^= ]^?7^-M^H"DP]R+7+J.T@ׯ^R +ٲ΢5vUK!,%$"*&)<-,H-?T,)~QP\f<ew6ZwB=PMR^^I^o*o1~5x o)4@SMX\Aĕь֒И"Ʃ7ƸGƸN˸K24c`bNGITYW_baa@pH6Lk:KuSEu蹑3 4`dCfSYv] |7#Cy{}wx+717)B7"8+36Cvw0 SBBb-+C7!ɽ (,7.'%+/´7`X[  !,@$"**&*.)5)9;)--*&?I?I$HASA+]C*wQ=~N@P\[<@;-f<OI[I$fg/og"oo.xo2M~L=MTTgoo6w.w5~0~,I4:74;>%@LP`BI_`Z_ba֒֒ےƒ$ƒ)ڞ!գ3',>6E2J_`cc`NWYDEOVZK]aaaaaހ_1/*&'5.(^?Z^)_MY@ :^G4^C,NX^I8^F_A<^>[V0;Tǂ2KBȖ ]S$+"b]Er@Ab"x,!0aȄ@x)2膗,6UZtB l&N[p(OB؎QҦ!,["**&)5):;<HA+g@)wJ>wEP\@+[<OT[T(Zg2ew6MTvU^^Io)gx o)3;@@PSBYAиCڼI2=Zc`baMHGITYW]babaaa@pH,{d,*($Q! L,O".)4ϦZ\ڶ{)!Pn+<3"vfC;+5:wx ,j2 n-w.<0!+f8)B oT:6'*i Tj/71PRGwLFDeJA!,m$$+**.)<;>-H<S;HA]G*oJ>wJ=~NP@+O;o<OIOTx^&nw9=MRM<^:3!QIXBFEIC_bc֒թ*У=ڮ2߳;(03AH284>?V\c`cbbbJQUW\baaaՀ" L J8I6!K$ BK HFL=K0+K/#K: L J9I@FK,ًG1眞KD%(&'(7HqL[!."dI fx bI%v $Kndp%ʂT T/8mv SϞ7~ *ϢF!,$+3*&*2-,; S;?T1>wJ=~N@\@+[+OI[TZw9f^+og==RMRMR<I~-^op.3@^`BWIbbb̆ьУ3.;3>`bbbaM@]K[aa@pH,Ryl:s2d1ZWH>iv{:.!p-3949+$;8 <,B";.B(B^ ;)C'9EE;*C&9C;6^ƻDD2;5%1~C!B0z- kTNPTOMU'!,$"**&-,; ?I?T1SA+]C=~N@P\f<OI[T[I$Zw9fg/og==<I~,I7.;%^L`BIaZڞ!գ3.'_a`bN]V[aaa@pH,Ryl:s2D) Q'xZ$ ny66[c>a!8'ugx8(B!~i*TvwB^ 7l4SF .l&VN 8,RC%2+#08)Kx_/r5* LO^vդTIӉNUgA!,%",*;.;?-,H-?T,?^0SD)~R>wO=~Q@P\@<f<OIN^0Zo6xgxw1ZwBZ~P=PMReImY~_<+<<I^Tgo*o1w$w1~8~5^w,43.M^^MX]Wa`Sebdăьь֒И"Ʃ7ڼ:(/ƸGƸN˸KЩJгG44;\Pac`bbbNEIIMW[R\aaaK&gXfPT!9fF;c$+-( .*1*Uc3,.Y^e>fE@f_?c#2 eI )8fD *A,6c" fB fC5`3Q6y19BJD'd̀2F x91Ӂbh,"a>!>+-f4%BM+̄y jg 8h$@.zK@ Ē]K۷j߮+w,ݺU5!,$")<--*+T,P\P!O+@<og/YTdUwO^I~-px w(<->@JUMZLˌ#5߮.024cc`bJEFIU]baaBȤ8k:T VXuzاJd0ѐH0$^u.+3Z2.2$_w!  rZ.1VZ/I&,]QUc\Z^]`[)K[T^ u*(#aZ+U0v"Xj^ EOٞ_VKaA!,$"+3**&*2)<-,; S;?^0>wJ=~N=~Q@P\@+@<[+OIN^0f^+xgew6xw1=RMRMReImY<<<^^IITgo1w1~5^opx o)3.@@S^Wa`BWAISbcbăьУ3ڼ:>гG2Pac`bbbbaM@GIIMTZW\baab L":^$5<3%6>&+M^4,-*`a^/Q\_1BaZT^G=aYNa[27aK +D,ޥC^(]' `߂8aEB^``"W{!AAX^R,! L2A!n\D@J*?8 a($B31wM=~N=~Q@P\@!@<O;gf<o<OIN^0Zg2xgxw1=eImYvZ<<IT^go1w1~5^^43.^XWa`BFEICSdbbbb̆ьВթ*ڮ2ڼ:-0AгG5~,w6I\ggouo)w(w,448.3;(->@@JCPS^KUZ``BdCVWCIEICLT_bb\_bbab̆ɇь֒ՒŒ%5՚"Ʃ7٨*ӥ4ܷ:*)9-3CǸKЩJסXոFH3>YIZKXb`baLXDGXITYU\aaaaØΫұΖӕäأH*!e)ŋ+l'X㱤Ƀ E<ɒ%ǖ0OfIfė hϟTa2`tL*|UOR՗T[~yu؟TϪX6+/*ZpkQV99Y幻P`gsVqVÈ[hF/''W$-(svf;t꘮#2%'s (AhARzHGp>9II7. @p T9*E$hF$:5Υ%,pjOS~^Fgv^%\tUB@]XFP@pRJ$Bvu p`tyGPiȡ@ Qh!p18@`xe(b)*fݐۡc{=[p8He @OFh#E@dc%!7@6ภ &wXAxku|  'P韁*թ\q9V*tuSWsW,b6+aUުN9X a Q]`:<!:ފ)Lk" 9 @+ӪcȮLˊB9:w:.*뱿 @ܾ@ @@ : k{,.տƸ[rBҞZ/40nA T1S宺:u :o v3ނ;3/Z\l±v&|SH6P)B 6(kZ:0YV~xTJn8~A-(#ăSDf:`4 D(,Ԣ"M P x:C(p$^%})<39{~P^{Ճ+O_א,% "c C^{GZ ÜG o!{^"g>Zus;Hg:u^\`@7 | E85{ G?q r'&+G# ʘG/Bٮf{䌮t +R%|Ą\% Dum5چ1 L\ A;QS 2hEE4UA$yn1@D3>hc? }4 []iVBJ9h#Q2ClQVi14ܥ;G]тzf)J,3-~#S4)N$' MgS0p3")1IT5!f9'-ϒ '/IsVܚ@ N8 ᨄ+lѤ%IR"B"4,1%S3G#bf28}Nv:mH  >;>im *X%;T4\URy}2LI H[UѐprT)XW2@W9fd Q٧*tY:uk*Y5bU]E*X!jR{kc<džuHl^)UnT/UkQK! jY{RմeJbz*px jMpp"$p jịf%6 SHэJl)D( A@]kwNofj8{zfMmq*wQ|)LF׼uY]A/-l82 V aW 0GG[\60G.,QS]8 >.MAv;Kdp1 i„*EgzE|Zi{z3Qf/x| RrA0VFl5\a0-W3gsA{x[a%T#\00 U9e 99au1pVXWLPSa8^,a_xC8F8,XTXwMH-!ysX?ф]1PAL脂9Pp7j^--8x+7,QXc+K4?4-qx,(Șʸ-GGh<04J!8(8Xx蘎긎؎8Xx)XyQ 99Y(ّ e[ !0/ynf`T-2@9mg 1=B9TY8lk aP!PٓVYfy(EHq S0-vyx Zɕ tyYy5QEmX`0y4iA,Iyi#Y uY9M@QiٛY9yUYȹٜY։yڹ!, !$..B]g{-B,]*q*{?qNq.@O.MzBP]A.\/pBO@OOO@OOOffp=<LZ.w--AAAONOْ//BBBgg?Pgz'z=zM- ?2;ad,&gegfb*!f1KgMEgT$g^Ig_Dg3 ZgNHgeXd)5g98%gQJf."$f'#fP8CAGL BB  >1Ȉ2҉E#"-dTwf U8i&#Yp F0bXYegO=?9")t4 ҰaM{v#n ߶{.ݺ!Y,!V  '2 '30,'>()+6',FRLYc{h ,P$i)t7z8e:x)7C%8yOR5)S 3F26d+v9NLLvpt3MK/Sm&vF;doJMM MXXXP"D)B8X+W!T6N$-p l!v) p)+PPPQAA-EfmQfB-rnMJKAO\O\OO\\\O\\\N\\\N[kAkzyqNffpfpyyff%' 9<<EIQXBESRnes zs,W&\9i5pAuAy/8|.R*l2vv "%3(- 6Ñ5ˢ3Ⱦ6Ф5޷*$165&(55GnfHNOoo(0/&6/DSBT]+rg8Vkq(z'z=tOypyo* :/6<(@6@3y<ZxZkȒ͓/έ˒KșYҚJҙXסJءXשmxÔύᱼ݈Ѧȸ׸Ҳ±½ұɲɎΎΖӕɧȼأHA:ȰÇ#JHŋ3jȱǏ CIɓ(SNʗ0cʜI͛8sSc~.{ JѣH*]!6 $2@Ė%s!:ah6j`cZi0]˶۷pMС9*+{Q3@t#KL$ Cx=fA߆T.z5 NB}p;QNaz.e_5pSӫ_>}:3|Ktg@J{& 2 -kgU=@.I(,~f|`6soχ`XH& uWDV<|ci;#D>h暒9D5qEP'H!2p1!| dD1&`AZ1F1@ f)b~dgpBk A2# A6䎍#=,9>`$.(iɉ0 02詒,! w0+KRأ*G q7!Ԅi?YXuEBX>$B/d;F7Ds aA8~1O7wXyFWU{heӘ~awl.(:ip&`7evxy(wv=aI84YXI^96!g8`$Y A#6#E(8P'V#mm&0"{;q&I"4Y#72yNub])pgtcٟ%70MCrC5eCb9 4])BE7T.C%14۲`>~z9[eZe%vxxS i5jWdLqs}%}Q@Q|'w'}'f'xbo<}oc[Ԅ|a GpLsy2 [[;빚۸K 1 }$1FH! {ӻMX[R뻭˼ۯvŚ3;G0#TNr0Q۾B(>0K)24[/R8aHcCiPb6!Ij= .4U<$\&|(*/]@w 1[&+$1\ĩ,GAljsid6x#H_N x;j>5hI7C[d8b$P%kMN HJ5J}JKHTs uIx<z\LqLLLI" |қZC(i:<ƞL~[\HMe\kE6|ZEUWgoʌ9X)ѱuu">U ST\+HG}ʌeţ\k6MQEE13p{}|7l6@^NzjL v>LvYȥy$9MyWW m(RFpuЈз}DɾIZ"%-T]>:=3MHfYH1;Y#47X;V6 $EWYT},]/Uh?>L7 Lu\\5]ӟx3 XbO=qŚYzəȕ>^ yD]$؇UYgn<8 HH(Pצ5 1k] 6JʤjjE-eNzL3Ybxճ>`sbc I a|T}m:t8 e=HgM0wޠޓe]Ws%3zf=cZq)npѼѽhщgK뻗L4k$%a!>[0>3@ //<>@B>D&7` H P N1` ` J.G~1UYNGpq lEAf#!253Z56#aa@c37c 3=33>4Es3G#5)C5_L4NK;p Q. ~ *L~ p !  21;. >n!:~!/9|a!:4jGLF2RCF+GobW'Pa   <Z7`눯8`@5%_J0 _m  O %S8 ? Oo?`Ml3MoRo%9$ J!B LNg1QVQQ{S40h vpY]D5nq 4)f) 6Ds&"HHreIǠ9Q 0GdQLK@> HH%PRBj\U2JP kZJ[u̻⥫&ZBcZƌ+U՘ڈ7VhTdT=m鯠#;6UT* f,fГ~#!G?̮VʂUd;Fh׍+4=ϫx+wc%>'H،Hv߫ I\ ?]O3ky|%!?"󳯕yɡHXOc A3("02!$hA`D2?4("P1PQpG&'5yH̓ !v $ ]Z7$K Aڜ: 1$JSD*L*0wb Ȕ3ƋK#SsO0iqBVKk xc\R'M/I!%, ! `Ȏ+#KM%hYIVՑh+QO;l ] cNZ3g(uIzظU_fwTRb 9!̴aԏ4Csl4"l#7Q\D@50IP:NrFO+Et \pG$R'%&ZP%L CP5T:Hp(Kg'zcXbY@J3Ab8hNwSB+ړ_w2K"d,{ڽҩMjR.& +Yq`SXWhfԈ<jf+ƤDܥ&լ!A"uXF; Tݤg7 gd6@<BD;k#VV$m>ZImAyFNME*Ƞ&GDňod,)i.e0Ap':+gԔt(K#B]=/UXR)N$G3B%0+JH42{jY`f[k~%߁u`h*UB8p @IbEa).[7j^_GI}hr@Aj;iˏ{uBal] Tx?Vˣ'IG&92}֜]AAD%9aL\-n̅{75un[ ӚlF\ԃ8G j&t!CXP.:tK)mBw#}.t SFBH: n"-|_}aV骧1 ="ʦfm7Ȝe8-al{&2|+lB^l; ^T'GܻJZ^QqR}WWx5+3oX#̏G$f!z9 Co4=,+?=2g O-q!u#_?aN-~:#@ODo~[ ؿk0k P@h $j 6 Ĉd9J w @A03DA! (! #, A$LB%\B&lB'|B(B)BHHțB-B.B/B0 C1C2,C38C5\C6lC7|C8C9C*eA:C=C>C?C@ DADB,DC]٭Z]-^X]M^]^m^}^^^^^^^^͏bY @MB%b!ߎ&u_ڽ 3&]%( [A_ F²ܯ`}-(\T``q%  kZ^]܂d_ZY=_ _(b~%&6_[ ib9"2Pbш,iaNc<[@b%^@х{ )`@e  6@A^<9N2.w㮅a@c50{IM-.=ZOc S'?.aI&[I*ܕTNQ`aN?%aMn?> MA6%ZaS^T`BfW?Jmi-effv>e6vfdKvf`]{S]hki.g6\NnhaNt&>i|f]wAfnq[N&exF]?d}eecfNzR6c V \f9ۙ\ڹ 6jn 2 fe/~rjFjN f.%Sc5":lc듮k݌xk\AkXmjMUfH;]Fg`dndfе-T|m_]'&㰾M5n>oy]5c3FonYe6oooopM|hLEP4oS)+qēCQL+m5p#pV)f_k$qD wEdĖ`Fr<â\Cf|48B/JE_4_,(f$$ FSP`|^"'1qUrR?kr)=Du$KvDT:F;CʄrI0;8J l4r9',B&A ǗAG~s+O;YaHr;IBn\DFt $Ĝ˝6a O6ẗȎII4H+Ic_TI`7㱯 `Hu,HeHȍHc0qIHKu`uȂTɖT#yVoɳwʹIYuǪtcvg?@h=?[G{1wbZxcdvonw/wZ&-D Ti1T4,aKe;Jp ^߶ԸVqˢ'z+ΐ5JotKi+bw$zr|1zlx?Kwz=G@KԎSiz#rMϻ'‡K\{{{T^uCDj taP͜\g?H}hYR}窤So $Q14֤%<֗js*vjQi JBqL~I H!aJ(7ÉQ"AP$+ Ku1LyX6IgbpX.%CX y&#\&fLE҂ČH6&O!1dMȐKjY U%爓;2?z5QILS~\ Y2|t+k)\E7%nJP)E] 4"B%jFAҐy$@}*T*U NJXu^*XêKn *Ww*ֵn͎N_׫3}+^׽be}P>U3R.eT[5,d#+Ye rUM Bb]$ejMղ$-i`nֵ-nZ6-p=n3u:T2έ"+Rֽ.vr.x+J%݈rKw}M`kWGm s/=U}l`1*8)к Ssy!`0 X7&>qAG,.~1/[o$ą1s6/HN!y0[%3d,)SV2-s^2,1!%-42TrLϠ@vI<䔞-m#6bbyE73+s4JN g|)ms)41Ӵ fs@r6"I#D!}$Ťzխ^ -!kZV>Ik {.v'$`5MJ$k ev8ȇ6`$rh!Fn;!Hu: b -5첊hn uɗ9ISq?KўGp9;:8H\R Kft(xki D>e='$81Q][pJFhs];2:UI:+#Vb'i^"An7{=DcwQ {qRׇXe7I'^y"͙Up"SkmdIZyB#~d og[V5l1ڪw^ͫTp#'>}1zʃQ.Y[WxM9,֐ve)MD ``qtGHDqwj '=d \l4HH ҠUF `@) /u3MژTӘ.a=ӧᓇmM1!V^!fn!DCXJETH!uXSC1}alX3e΁XzSfAH 2fESI!IJ١WH4bNYxRiID4Ara'!#"AbD+*R"b1nTޔPa/v+#b(("~"UTL!0@băcDFRbL<%CT&%3Q>2RWM()Ve̩$dUbUW*%M%)ii! d\¢4,.YUe_RT&WJe["e^Y"#)؇diH%0UbiR$Q6e`)B6SgeEvq&ZaOfb)fFbaor:p#laeBZ 4g+cW'qjk:&#E:U6Zg:FcQdvfdIq'UH_'mf=j!"eV"`TK$(Jb.S'NA;iEҥANgF?2#ie3ctWRb塂jHfOnTć&)>N-(y2hZ1(U FXU23>&׏OviX@Sx'V'c֋h-^T&ȂZ$z>%N~me'&|6i()WJ)%]))%Mauf6*I(fIP)U`M;!*&02S1a'-ғf9BՏ]dm(&&(U"'M=訒j(M(Ji(X)KjeDoV%*FW^9(ݥ>ʀ%(hI+mugZ.9*,P$\iQiHTUtNk!ilVfgX6KDi!ZUhhEj(dre,*ب6jhb~ڹJa"U*QjVY$)ީ^((&Ω:kJWj-.l.m*rmRoff&+֦F-β-^tNkJk^FʢI"/ZjV&"4...ihaJw&Jm市hQvn2^ngBپIdɖ.7Z%BU:en&eSl=Ng-EWL$2jAZM(oJToHx:o+/\M/#>bo>/jR"]MnTr gg;jC JoAA%=B9jI0 T5ecVsvpk= 0 0kaTjv!pv4 ;b ϑ0Eh)ư@]jc<2V$FDؑ.MxnY+/ORfpvw)(6+*&)0+@qZIqI!wK"T{ˮX$VO1p{0-Yc6zdBpN*79 bL~ndB<*d=}MMң=Bv;pFbjd2cZ/H$ NC9b'D$=2(C(cDr5g5D-c3$5_l9{n13,sd43,3#/ {3Cv=߄3N30H#ϨwF%b.bZ-\%..E2M䦙UWbrtbb66TF :E?`\-M.&\JcLH/+G{vHO.IgGR.M/un@SG4.HN*ej*.(pvfs-z"hei o|rj&ufZol(:TVx:U\z>Ww^o'gvE_cuU.vK 2Iͦ5egech1ABmjq E{"dasIjYj),Ҕ^X+z+If1F+3앎&m2*tpo,"g R$ưڨvwI*H"lq7u/VuVqv wR76嬦7r127qXz3VSsvwq, ;m**#j\72!>myxƗYAsF$brDGI0젲x8Wb8E+\w/|y#B,֩j~nwGުTc)R$818.jwKF1.Yn9qTڭPN+l%vow(wcU+Q8ê9D$_(.?yscJr6Gr7bnlnlB&MG3,s[,ިr!Pb;l&,Z,+Slzn,.hעZ{ȮeTw^{bjsW;_ mC*{b+kҔi(qyoˬyݲОZk1 'U,zH̹ВnZE-~-C|I+_;|8ڞo?Ыyil'}ţ{ .S[b,"nMnz5N[V.6$dX*Rg\ڇ}$){/n..."Vn"RUM'1$DU\{IT~f&g7o8Io64*tB/_Ao/Co&JojA/F+##7x$/Cw!𧒤pSrxNUmnC}Q?Ӕ90Ó㖿xW.U 4xAp$HbD6xQ"$H1vdH#IL%'St K3iִyɘ#YPhP ziRK6ujTSVzkV[vlXcɖ5{mZkٶun\sֵ{o^{p` 6|qbŋ7vrdɓ)W|sf͛9wthѣI6}ujիYvvlٳi׶}wnݻyxpÉ7~yr˙7wzt/߰t*ٌa锥R*N~NV7ҀUPhN(v?PE@AKV m/CXC\[bnX=!De;I !J F$A(_(HH&TZDr*HL2ɂ3+P?pL_T+& j`E\G 8eOA I![kp PЃ,LTTQK@O^uK<*u q[WuuU BK` `9ՂU\ѢEeF]ͭpB,/Q y mvzwAS{ d!B}!}X4V%a]) W4TFy YdX<]y J,Y r?KSexk]4-KW_o^eWn9—IvwE/d΁mW5 0[lJcuRH,8­0@CT\ݶPez"F[l@mB+]El&f4K4>ca!? ?Ep;.Q8HD?JKlq<{حjvEeU($zuڡwz#om~Zh!me7hm(Hf8|v.%SV@ ^* !aSU&< R YB1 iXC%) yj) 42@q=Tb RF4FXEpE 8@jIq"[(Fp#"$~"19VD-dm GQ#?ѢH~TsNq<#YIщF|bIO*ǎ@ΘD X HHR QDdTY!%XT B̌2TUMLgji|4$#j^6Mo~18 Ns<:yNrqg9YS'l}5@Q#Pt4EB=P>43D)#Q^4F!cQ~0H#R/&EJRT..L!,i"*---*,;,H-SD]G*oF)~NO+gpew1NwG(SMRMVnQ<<IooL0*.5Bu#<326 1 TBAȰÇLHljm"jȱ㾉qǓ(Sp˗0cJj)͛8ɳJvJhJF*])ӧPJs*իXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ Nȓ+_μУKNسkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀e!,$"**&)<-?ISA+]C=~N@P\P!f<OI[I$fg/=^I~,Ix w(7;%->@JUL`BI`Zڞ!գ3'>E2_acc`bNEVFIU_aaa@pH,!ϡk:hq@9ϧt r lRJ +=@p &xӍ};td[$>*W^>:">.\'>,D^:=?\ =y7B^8aT\#/y)}`]4teC R(5-&3>+Ť[0z;,16ĽceKeԿ\RFDA!,)$#,3*&*2;.;?-,; S;SD)~S>wL=~N@P\@+[+OIZo6f^+Z~P=RMRMR~_+<Igw$~8^opw,33@M^^BWIbbbb̆̆ььУ3(>/ЩJ344;\c`bbbbaM@EJWR\aaa׀S)-(! " PRO$ELQ>SHO8.RL1O' Q9R=3O+OR4 R6̖R52O%R&BR?O#ߑނ0Re : (CF !,D$"*)5)9;<--+HA+g@)wJ)~Q>wEP@+[<OT[T(Zg2ZwBMRMTdUvU^o)g3;@PMBYEEb̆ь֒Ʃ7ƸN˸KиCڼI2=Zc`aMHNI\baaaa@pHFLP(q ((F; L ,"=.xCjkC wJ=~N@P\@+[+OIf^+ZwB=RMRMRdU<I^^op3@MBWIEEbbb̆̆ьь֒Ʃ7У3>ƸN˸K3c``bbbaNM@J\aa€'&&D(C/C.!#  BCA@MPEE_b_băь֒֒ےƒ$ƒ)Ʃ7,6ƸN˸K3J`cc`NWYDEOZJ]aaaaaր,++R.Q4 Q3('$"#Q6AL7 /Q;BK Q>R81Q50HR PG %ւQ2͐MQJS=D!#w)Q$ ኲ; Qt j=~@&1aA'Q:"2ZP!8sn褢F !,$&.**.;=-H=+T,?^0HASD*oJ=~NP\O;gf<o<OIfI =MRmY<I^oE| 43_\XBFEICbccթ*ڮ2%(-0A5;?V\cbbJQLUVYbaaaF%!   BE@"E1+EEF,E.$E6 C>FC:@*E/AE49AE9(D(RT@`DjX` ٶHUh]l,m\3Lh1"nCe6pē1H@.r jP Pt4KB:i*UGVʪX!,&",3***))3):;+;=---+,;-*&,; IT7vH=S; I?I+T,?I$?^0HASB]GF}+]C+g@*oF*oJ)zL*wQ)~Q>wE>wK=~N@P\P!@+O+O;[+[<@;-gpf<f<o<OIOT[I$[T(Zg2Zo6fI f^+ji+xo2NwGM~LZwBZ~Ps(S=R.i==MRMSdUnQmYvU~_25˪6Я5߹%6'+6<<+<^IY^gooo)o6o@@JEM@MPU_\\^LPZ`BWYFIEID_babbZ_bbabc̆̆ьь֒֒՘ےƒ$ƒ)՘(ڞ!Ʃ7թ*ң3ڮ2%(('-,:-6CȸLЩJպF244;>YH\K_`ccc`bbbbaMHNXDEMAHEKVZQFJMTU\baaaaaH"5rpÇ *U A-BƏ;jIR"n$ApIӡ*8q#O:knTCSka*EVnP,XB| MH (EsX HLa(@4Ob1Y #"Ap\蹠' |{vI[q||GlC(l$yqZh8]30C&0,WN-'>э='?q?9#D(ȴ >d00H cC)@Æhog#xb.D/3zx3 SC iRRi%c=H 2pP(K^W&Q?-aA?| c<:tޞi_uq>W=b L1|*L$MrTI?1N;tHcCL!O-4HsC#|S\)ˬ@!7RC,YeFsS(޼,N?='Ks![&b XSp⌶8Oe;;P褛ă:׬o?435 c\^ujw;_#9nGṮܰ.*h2zWĦP8֜Sl+"RN<y!<U D)`JǁS j`@h$c JUNH *Z;ANĢH2V%1T/60x̣> BҐL"rF.|H#J& _`BA&HKzI@Nc, @ G*g t \bI^ޑxb[.if^+wiJgZ3e)yn&'I 29Ώl;Iρ̳'>}Z3 !,!$r.@OBPOOO(ZYAwOp@OO\fxBP]g)=w͓;ȒK͚JҚJҙXl徆ɤÆɎΖɤ@pH,Ry&\e]lSq.Id[@[Dr-93/ C=vIiyE"<C ='=lDC=zC=&xC#=C=MkE=*7Gk3,,-%1=4+8=(fK50J)iGXC[GEMA!,)!$...BPgr?q.@O.@gBPO.\/zz+gAOOOOO\\N\\\=Ym/m.w-[ON\\exɒPPP]ggq(YY͓;͙XҚJҙXʬwܲmlvӟӞ݈رӪȸɆΖӕɣݣd=]^V@ 4V( \)dA?d/d-dF`cHdX d:d,c&ςd9;#慳WPƈ4̘ኆ A76 - IwL2.,d@2Q.Zbd2fDV,8$)d(E]y0̊ABj\@ BMϪ=v[m+W-ݺfE.!,D!$B*{[qez.NgBP]g/q/\BfBfB-@ez<MZA[Ox-ԙ/]?νͽ¼ζΪΪӕäؼ@pHB.j:aAyUT-Kh\vr,:*8A%%&_-/$/fZ{/,\+ U zrgB hrE#('{i]QJD[{A!,_!..BP]g-B*qPA.pBO@OOO@OOOO\Oyff'=<LZKc.wApAOϊBgdסXØΟ׸ܾ±ұɎΖӕ؜äأƀ$ML8I7#,M"&% GHK?M9+0M2 -M<ML;LLBKM ՚M!MF')'(* :.IEr҄HE6hdƉ1p"@J!ѨV(tA&nZ$˕^T)͚n)!,q!..g{,]*{?qNq.@O.MzB]A.\/OOOffpZ--AAAONOْ//BBg?Pgz'z=zMG85 G'G+*G97F FFG*G(4G"F)3F!;>tN=!dZR\EvC"'3)-"6Ð5ױ5/(55[LkjINO\\ppq(0/&6/I]-qi7Vku.uOynyo* :/6<(@6@3y"-<ZxVlw3=C( ]?[HiVޅffvH<8[DJ) X~!kAUC[=݃'VMMXf\zsT5@SK['՗@ges>!!Pr0b& @*NJX奘f! (jVxؙe!EDD6@fY`J!QBb[rj&lHaGZ&hh^އ?wFmF'bsc̺Y"6?1.kk*Gs52jNH6f@Q,5sFs@e~2JZ,w^zS&9qV<؈x8S;2Hqƃ`5ƘS #ëc`-ZmYv>GӬ3tCj5NuHeM;=]U"[XIG.W,:.P-P@Xb瓗n騧ꬷ.n/o'7G/Wogw/o觯/o HL:C6qƄJBR+uS=), ۋFĪTmvѝDU8pDi "ƽO (HWRxmBׄ"9AgWR8؇ }}gz"+}m8~7/;wsU( tD&8TN4PP$I{ O[1zADP'(JGJ%؃,w(aKJ0h{]w.C atf~Dx #m2/ qj .Uh ~} ӴlGYWYrwXx'`y1hXJn+D}G'Pw=g{G0HD1TgHzP 7E3t92BDH g[8He8re ՋDg8 "|#y#- Sc9gFiB/8p S1:'h8KEqTe0$`Z5__x((!N7n ɐVh!X2uC!na_Fvv=D+O$ BC2r8[ؓLJ䓦Tg;Y[hPLIJzDipMFPPo#* `&B65Us5Q=+ 7p4`Y@P;AH |5^y9IAmI5VS!@5Hc i)i҇*K%x rIH|(HX9闵^!IAFm4.u"ev2c HcףdMfuPdOJg[Tq0\ufZVIԝQy$!eCx(-B`.b'H48ovpt'6Itх9ݲ8B0uѡ`]aVK a88w*.f #!t<8Y'CJjy(&$6SZ'DP8}[gjfaiondq1Putcd z!RFe7\mf sfedz$f fZ{|4fYY ';-c A ,":+#g[#ГUsg4׽}ch6%Ufhhf(m!l6-z-Vh*kf g13a/Sҫ)g(EjB,sP>/عg{Sp42`{)N3PyO>xAE=OTaf3Yʻx]"d_w-. .4JJ`OOQ0/|pS?RR@vّΞpg`"s^D,p͚T."2pc.+Xh.V/nX+u(m27Q&0b_x {b}C1e!Buʩ.Sj-x0gB .P;g,Bug2_KXQh -x7>ؠbnf CIy)joqnq p7[Ctb$v$@9v8,3C('c>GJ{&@x%[JI.e4a&R(*`ԩQ}$D)VRP$\ YQ&| EӲg^밁\&M01WJܻ &*=7vʥ9㴙Uٰc(8u]ݚ/ D_ 3V!??֌xevJ#NNgd;vड#`h1 FYN+,+ho4 cj'̙ )gyʩƒ,#k% Cx BKV*b{LxKC=$@3l\9 !C"]42K#=HCKO> Ls?G@ lH]tߌ-9 usG/|A`p)Gli]`fN(\l"%4կH)KmBe\f} A&m< u ҖL<7#{[pτ=E!_!N>gu cN 抓)\8bG'O9I sVflkw;,'uMֻϽ]~Z8@+M\b4<~zĢd-tlno%9Ɲ.U4m& ~452wa7N^7}Lݽ7{cw֧i?0x"8KoȣįW1咂AC:[A&h.ܺ&r*kx'Z٬Hmc-# {jy>3 4@ӦC;L)|/84 b <<467LJ$R8ظě[8H@3G8FT8E,̊i#ʬMaEiX4"l[t61 .2 ({1L -k2.!;$2=>j V I!&2` & B(%fDJ 8kó?D4NT3b.x4}(x,3@B@L~GcGrMd GD"SGfD|4Hȁ$L9 |Eӿjjc:P[3 OOMųCO P =PMP]PmP}PP P P L!( #"MXM0LXEǩO QJ4I_`H@ QQ%#Ƈh!%PQ$#|2"*JR(B҈1".‹/ "ЄO(MpO(SO82U3xS-{2eOXE-`>SdU7EST1@m "8xуyTLEHIMs$l+6V QS^Tm%QX>%CեPmEUT>S฀>%=%嗢đ&.e `U0`?MEݞ=%Vk=ىaW@WBWy'@Ч=(#"ƇC؛ڊd=_e!@V>XVV9R)7+)=> b M10Qᩁ Yq%X֤ٛ5̛]٘]xڦYHڜEMuڇHڴeZ1 SŹ}ZB[5˩`SBB[ژ݁ $03 30w p2@"0lΕ?&#`db!d67YM0G9 d\1]6Pv_C "2[p7ڈ-ݣ؏֡@`EUPT1Y^Uޛ &C')bN,+H^2E bVi^ѡEaDivj [ۥEXq.g!gqaa#vvs[=*\1|Tt6ہ.hU F[quyV]&}i4Ȁ2(5 3(Qcp 8͌AlиfOj(l0}`ȃ[x~^LjjiNWiy}a fL 6I6fӤcd1h[V_AȣUiˇVNT `R~fF6PMMb7W6fӺs{۱ܷlh&ژEkf& Zf^TbE6Vf ETm)f׾mVT4]T_gz>N _V=&m>]Sf6iFF%r%F\Mi xF x} X'oO p ApWcoЁ OZ: ]fgAe:WO B1:кKU5>M b́`ZPE6Y ·k;?\;c SmPm$hmmU3f1?ho6xs2Af<@mavn:w97p5X-.C/@=?sxlG0fi09|!PȸAyv8& Bub ]ospOSx]u]T=]8F"iJH> ,} xR/SVgVT& rc𛦺S(G .=-=`t!t/`>*ÉJKJfltyk`g6/ViFS0g-n@hPert=tola+sIo[E woG}! ` dO(pW6ig}꩖&A}L(h `@vwAH$MaJ+OJI@ Rb(o$)%ESe̓ 2i҄R.%jP&U^yP+VhJK(Vʽ 'f bߚ0K;x#iS ͜#椙ro-iUy$.+U*ض;PsvD4И %4hѤ VHIט 7ѲA>Nmi-q.\8hV1k-+yYiYTڴcvAe[avAGhP4i>???kW"ҏ^p`.< 2|  I5A  r C(&VZD~# 1Á J&2vɩ`9% RPTp a @IKbA>Qǔg'w "D۵:[Ay8*1|&4_(Y%v0h6 y>+-#+ȉsDv;YsL{AVq4cHzs3=(BMf @vs8iAA\qq9(hƞh:5.G HGF_QK C -}yKƄFmD!:ԡD IIZh]b)}][g5o[=HW/,qy@ V2O|G+` nDj]` :eX:. ]lZef9M^ae wE3$g,lc+[bbٻ:2,eU]Ko+:)*{t6PYr èP؋ s .{\ƕ=Lj\"7sUmG]^{.OT tqVk2 YlQE^ (6YgZsSNwpRSJNF"pcNubJ,!UbІnh,--şJe|(/ op `Zƪוnl80,4]Q/ui;8 LE;%GWuі41WfvoɮLԦgA rzc-YӺֶ5s]׾5sD{)!Xl@ 2hGϦ2b0 (G6a1p'MĀxPS#8_O8rKPI!0!I ^ǩ}1 rG@yA~s[ߧy3PǺpR< ߉jX}6ow!%JO 5Ken >7axX?G:ֈn~<_z$@zc|b!'!Y"{>HH/r>1Rs2gH}  KUTf c&#?e8*D 2IYA!G! ! P \ O!Aqm !`ʙ pxĀ  l` @!B2] n`]%!  RA@Va` >R$9GB&)5C0E0B1[A$ dB-$0Ia#%RD\bb"./$ blb4J+E,A]4 ./bIAIA(AV^ԢaB4V#]JI/l|c8FܨUc%dcI\6]ȹ#?^3ZE!E#4J[@>^#E?<dș ؜ lk`@fd%l tс! BFcH4UAAÐMdtdXH k\?dBA?ق^S'x#^ά=h!8 %UHV^Wb<,MeUNT"ݝ b_]*OX eamcDR4 Fp_c0Y #a!hG ҕi0(`M\R6Jn l^f|mbF=M 4AL#P=4bB\>ҟ q# h€ >c[MbA% _A H'!gE'r>'4`Dm {jPVegAyhA S9: Re4@$0R&iHT&EF$ E@kAkہ nJ#l\d,f8&&ei_#ެ)RE͠w&& Bq k.-c9>*ތM_ jImPP9gAX+%r2bpl͉mѾK-IN@8ͥۂsچY0s\y2^+b"(xMLAZn#6NGpYOnA8I\j̊LV"ڄN,L&Dy,)1fR/TTNɚ ޡ(jF>*=oNEB2m~/&XO(Nd(lEH_M:.a)o_EU FL%bYq)DRG4.>H,XDn p a|خ{0n:r*֠Aa%*&U#BrHؒqpR22Oܰ kHz-̬O$At@&6ĽH5'([nFDT,ZT^3JPDS ES  < b\S03=SXEYvQ׶4N?0⽧&r>´ ˴J\CR5"4W4B+0ZSN e(C9tvHlČf8Â`T)FGX8_XeSZ8 x֐Rď{͏8'jM09ml$ۜP^`ypdHp##y/ux=O@йS@_zw%Tae' zܢ?: vG_:go:w:zdl Rϲeڄww%@)x$4zźA7zDǹ㺴>0m8U;ӏCzrM'N;/~A4  ߠ?Z!fuo1A{{|{HL!SBr`Q'; mȁ$1:pkEvFj`ObKDbr6q3 Kđ0<,b_Hȟ|-2q )T9G/4;':B{=Ҡ_I&CY sAԍ `ϝLO)%AqIi~|]41Rl-լtJՅte uu$6U-=p$L TEWWŞV }'O5;C)\:Kh q9*u^U?̱)k+_ [XUbؠe(B沃 d%˾곰9t.e18{ڟd6Gw2[r)͈n{BS69gD(gKhb)4oAZg&˚H扈vު;ni+ݢ%a |ݛV(Ez"YqRrEA%kDHOb`b仵l2̚sRʇKȧZ#ypW̺)/nj$L!0O"YF Bs (0; D d,%Ng8B`JYEPy,_-^r&1yZtB@sW˓<7\M2dbeA$V+D!L2I,)x,vAEn6J{j+cyf5Y}cѳތu8v G"s~2Lw8D r:t{Tp;*yU̓W!eWxL(=A!Җ~Hp!ee7bG8[2jro˝.QzOmkۄsuI"-C7{JA DZyC7=䎿AO̟<~f[EJCdd.LM, /64b>2J%L&+& 0,:N@@D!Gp7bY"C !#bMp. .5p[EPLphBo$J0*P{HN "3 SKNnHP$Bb"7"+brO$QcT* 1G%ǒQa":|9(& cc0OcS 0Ycq}1m k%qRtU"V`1I3TEKD.6#,,02W1-DCr+R.2% '"4Tb"*.%;"$"3:2$u- K1 q$*ņ"P'=&%RŪR+\T{p"1/1)1L N21d#$D*Do'K=Y*F4%=3xB@J @o!BB3,EfEA1FYTCD @E4A֞ OoNyT )N䪞LJ1JIDW4vLBI)7R()yƴyĴQN*RnRBſOA֭9gPi%PP&U \QDHgR/UQ&U14m|eVBU<n@uNU TU_VcUVgVkUTVsl8G) !LusU^u{ِ"vi#vԬZ ) 0"xM͆x,yPx _'fw%Q7l1鐋}$N.0!NPpCWj7v;"@1D3'!#=@SP) _x!"xS)=.vLX?%vъ";؎,c#1%0B1(X'!xpGy1p*Q)%(16-3#'s$"u"+9!p3)+Y=.t3s2#k5o98&磾0@l#@&$K]zEG@DHCc:GkDK⛕QItTC,!49 aNy+" *tWHMJOi#Q%(:86R!Z#b)Vw4?CZGK((v֣=q^lHkr|qij3GwZei.>AJ'\gb暤ɡ{u'KĕT#PX)]bx t AtKZv:l*{[Ki|ֵ;Mƚ~u|4$DXf{g {]U~䐄e|g}ڰ{ MMgbǵ9γg|:p۷INWˤ}gJy})kw56h6THgEƺoHnI|恾{ [8h'ڜ:b9HwBH{B;龱<^Mn{veiWǏ\swdi~zH1añchk%bzAD`z4VcqPfģj{5V~sܟzi In_gR)WXuч)zηᚍHȣΥ\kci% eEoHWʤ&׼F>&w#DȨZJt{Uĥҏߥiz?;(He k{m-UFS X <(B 4 #h7rǂ& D`ʓ WŠMt G:5Ɯ9Ϡ@2yq L:} 5ԩTZ5֜]袢W[h6mU_} 7.ڸtڽ7^!*M^ְbŅ;~ 9dLXFhdB7o|ٳ貝G>:լ[~ ;ٴk۾;ݼ{ <],mi+.5^:*9_{zסGvu3޷z%HX`5U| Ђo5X}8y!QHaaFNWiXUE#qHb`"Oi<#UFczXIN%Fs|ݸf)Gw}5dᩄW^mDBfei›^t}DeU6ge9'QbzCW0墎NUh'9Қ/i&jA҉if1ߨ^򩔪ty\eXv(cTL9RN롱hZCH| B^`uxgqKr$~mDJ8,Tu&{y{'=whBKFV_+m`[zJL O˒uYe#]OQ V{˅RsRwxcbu e6 t,FiV}T`}= r~ym}o}uͽdm{ [USWk_7<e V/=Ml]׷˞="wŐ8}EXcZa>m+`jg%:X>KD]-e5o4nCkz#N m`[$Dfd};7{Rz IU}_OZ6λȯ!xTaŀӃW4FBzh! SWG0n rBz T3O '{߫ ƕ,)^@2ޮ{IWCPU2٘3mN\χIa&JGlUĸzdK *HF 〰\""WوDyTqDl *ܪ$$&sǏ8R]uDăҋ$dExb'==_P$mi\R`$k]\Ջ0X 6#&[& M2VŻq!v Vu o֘uQtm#OH՘HMTNϲy c;Iڗ#QetAh$/t[2w΅h'=ɮHʷ*yOӊ_ z;R"kLt\WzfسT{ߝطv Ŏ!8,WM!BȰ'A05=lzQʁb㻴f ʚŬ+Q$+yLn (KyT,ky\ 0yd.ό4yln 8yt\4_x1y 'q^ݹ_wDvB[&'𕎉@WvH ~zNm'>/.uW߽B&/z[߸qs 2Q{Wnrq{Çzhz7}zrApu!HضAۑlau tbg gnrmRЂGWtH='K&kl焙p&pwmK&v k6Hmu鶀aX~\HpQnЅp?h x\iVHȄ{g **X puF n_x u׈Vllx(nhpFmq|&+EFTqho !z"(tvHGv8p8W(73W*QӨȍ(DXhٲ OWhe8gF.r%g SMXTabg3ۑ8qv)g3PtUl6A&a8nU#f.[Y$f8'J1 f IOm2NECd\CDHaKwHS)fEWY[ɕ]镥a)be fcf\coemIpIS&aYy ewzLƗ)CiVÑ阾ј)iQ陪љ)iQzњ)u!,"*---*,;,H-SD]G*oF)~NO+gpew1NwG(SMRMVnQ<<Ioo";4/8!F0*.5Ph#<326 ˌ1t (@(Hq@?%#JH 8ŏ C :2ɲ˗IMT2oɳ> Jt ТH*ytӧP-6JUySjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ Nȓ+_μУKNسkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.n g!,$"**&*.)5):;=-H<HA+g@*oJ)wJ>wE=~NP\@+O;[<o<OIOT[T(Zg2ew6=MTvU<^^I^o)gx o)33;@@PSXBYDEICbcթ*ڮ20AиCڼI2>V\Zc`baMHGJQITYW\babaaaX1*!,3"-1) RWP$FOTQ'&8W:0W@ DWN(/W?=%2 UͶFP P#U֦ VXQDM Esp 4jظl8k\IEyt"Ԑk"7$-}Y]0 ގJ< A%2P 4ժV)ah+F^V),@!,2$"**.;=--+-*H<*oJ)~Q=~N@P\P!@<O;po<OIZwB=MRdU<^IT^^3>+-@JUMXBYFEIDNbbbc̆ƌь֒Ʃ7թ*ߣ У0ڮ20AƸN˸KڼI?V\ccc`bNGJQFIRW[baaaa&$/-- YJP1X8GPX7HL%"*!G6 TRYXR#'Xȇ4X=)XCGRFSڹVRO14 FlJh6C 8aŋ wJP\@+yf<OTx^&nw9ZwB=PMRdWM<^o*o1~5Tp 4:!%Q\MIX\`e_bd̆ь֒՘ И"Ʃ7У=߳;(-,3ƸGƸN˸KH284;Uc`c`bbbNGJR\aaaa.*)C \[@ ZIP[5WYG0[; [J(+[ #"'\1[% R[о28ƴXTL[> !/[7ץ[9Z듄NV0 %u!`K[~"hRѸB-HAN-6QbeޠQiMElBXl1)B-Wz8q%[-U$Ve&(\[^*,WfbĦ,ٶe 4!,h$"**&)5)9;<--*?IHASA+]C+g@)wJ>wE=~N@P\P!@+@<[<pf<OIOT[I$[T(Zg2fg/=MTvU^ITo)~,Ig37;<+%-@J@PUL`BYYINabZƌڞ!ߣ ң1'>EиCڼI2=Z_bcc`baMHNGVFIPW\baaaaa42 eS[P[":.) 5:,QX3/% `dd*#d^+PdB9dE!-I(wJ=~N@P\@+[+[<@;-OIf^+og"oo.xo2M~LZwB=RMRMSdU<IT^goo6w.w5~0^op4:43>@@MPBWIEE_bb_bab̆̆ьь֒֒ےƒ$ƒ)Ʃ7У3,>6ƸN˸K3J`cc``bbbaNWYDMBOZJ\aaaaa#BAA+tDsN 'sM%:>8 ;9501psn3"PdnT?sm]nQ FsWt˼&sZIn)^msKEn4R8 ^2{0IDč G`W s$"1GƸAA6X$G/s`9i6gliQ5c.xx|a'z8!Q*q5rknՃfb,[MqAǻ-+X—!,$#**.)5)9;);=--*&,; H@^PX`BFEIC_b_bbac֒֒ےƒ$ƒ)թ*ڮ2.,:06A3>?V\J`ccbbWYDEL]ZQKUW[baaaaar761./#<50 <3 "qJ lj)BqeV \kK CqSGqN:qW8Q _k'r]hqU n^j%O;LFqIfWτ  P$ "9@4w7pİbP:2 q8@8f€Ѳ@"qP遥 =n,_xi̛8kP(%A8F"AA D`ÆV!C#D7I)UzU`KcjZC `Nv-!,$",**&;.;?-?ISB+]C)~S>wO=~N@P\f<OI[I$Zo6fg/Z~P=MR~_+<Igw$~8~,I^w,37;%M^L^`BI`bZ̆ььڞ!գ3('>/EЩJ244;\_ac`bbNEVJWR\aaaaЀT.'!  PSS"GLR?-S7&1O% R8T0S:*OS3 S4 QK(S$ES@O#+C6 S=MBOxt D`@F/Lh)A,NQ"*] ,@ '͚ntjM\> *Y !,$"*)<-,H-?T,?^0)~Q=~Q@P\P!@<f<OIN^0xgxw1ZwB=PMReImY<<^I^Tgo*o1w1~5x w(4.->@JU^MX\Wa`Sedăьь֒И"Ʃ7ڼ:ƸGƸN˸KгG24Pacc`bNEIFIM[U\aaA-*XLWFGQ2W>4UIQ %#(#HU)$%!JN,+7W=8WRIU&˲"1W< #9$T'.WEއ/TVyr>DU%$F\ cq!Wt$peGF- cȒ+Mp`)DlaƎQӞ4%PQ " TDjݚuWXUq׮fM{u` !, $$**.;=--+H<*oJ)~Q=~NPO;o<OIZwB=MRdU<^^3MXBFEIDbbc̆ь֒Ʃ7թ*ڮ20AƸN˸K?V\c`bNJQIUWYbaa@pH|: q99O&īK+ (<R `²y*gȝghjB"<(<-=uC;28 zz9v <5Gg <#;4pDR,1<3+&!<7*.'~X0<6p/)r\q܁cXLA!,%$$.**.;=--+H=+T,?^0HASD*oJ)~Q=~NP\O;gf<o<OIfI ZwB=MRdUmY<I^^oE| 43_\MXBFEIDbbcc̆ь֒Ʃ7թ*ڮ2%(-0AƸN˸K5;?V\c`bbNJQKUUYbaaa/--"U0T6 T5 % %+&'T<2T$ QTO! RM3T9*TCȷ1T:RHOݶUAFP P 6oI"D*LX$rBdb/tR̒ o8B'qN| @@PQz dȿk)h'0`ӫKajukUz^v +i,B!,C&#3***+)7;*;=---+-*,;-*&,; IT7vH<S; I?I,H-+T,?I$?T,?T1?^0HASB]GF}+]C*mG)xL)|Q={L=~Q@P\P!B+J;[+[<@;-grj<OIOT[TN^0[I$[T(Zg2Zo6Zw9fI f^+x^&xgli*og=ew6nw9xo2xw1NwGM~LZwBZ~PsAw(S=P.i==MRMSeIeTMmYvU~_25˪6Я5߹%6'+6OOԉ<<+<^^I^T^^hoo)o4w*w3~8~3~,w6IZggopx o)w(w,oE} 443:38.3;=!+%%.=->@@JIDPT]LTY``BXEIEICNS_bbbc[_bbab̆Ȋь֒ ƒ%͓;՚"Ʃ7ק'ը2ܷ:(*6-5ҙXBȸKЩJչGH2844;>YUI\KZacac`baLXDGVFIMSZV[babaaaaɤH𤉁%Z!R ^Dp 48C.l0Đ!!J˗0z)C*Ole$hfQڱ0H+S`1Sf>kjRL@ӧeӪ @+ٱk%rV<4Oɋ@v+ pp%/xcc0=jM#V0bŌ]1k5s&xjÉ]Zlr7c@B *RE <@rC qZt䜠TMPD>ly*fQT )$Qa;^aw}Wxƹd ApR )"yPhax%(|0C*~PxHt'}p8`Rae&m(H@mW %[Y0XU9<TU8RwPZ3@#{{=R!&f-(Neْ`X"iEiP!f峎X8g }EWu@T B&Jj(SK>`+1'Ӈ8D#Bz eÀ"{ ;Tr-Xl>Fkbh`G)PC:ds *eͨpqw0 ;k>`ï2>{!&H!ęr{!%,҂`O;34 #[( 4T&RJW:ԗѨ5iG+Rṫ:XQ>li@70ukF'KmjEŠE@RxH#a@ZWiVS`QM)[β@*eg' s3P=t IJ)P;Q8ޖ&ZFlXVmqbe]Zl5 u7rnwz_RuE*f.è-uMuQ/ʈ&6,Bp/Ƀ#,v,=~2aP!,H(U"x 5ˆ[l6yp DNi,`(ɵ:"qRCR5 .{`~I(3<6ps90< at3>πMBЈNFtMJ[:NG& "N_Ӡ5LgpӓWmh.! /1COָsP.D֦&H!b# C0֨> e b@H-aS> f'vda+nA*/={׽?C6jX+\XA''dyA.K&O9Q򖃛.a.ߚ6Ϲ!, !$...Bgr?q.@O.@gBPO.\/zz+gAOOOOO\\N\\\(=ZYm/m.wO[p@N\\\exfxBPPP]ggg)q(YYwȒK͚J͙XҚJܲmlvӞ݈Ӫȸ徆ÆɆɎΖɤɣݣsZja1Fhi`I <`/#g0>qJp)sf pr*o-po&^sP : GsLHs6@s7As3!sRmrVsc sBsMDs5"r,rP "1':K!oҭ(ݒu+lؑ%ns丈HmJӆM\SF:j L97a- sܜpXฉ@9d@fsTa#'X.@-0Db0pC#ۜ(P"waÅ+&\vc/N,qʖ!,;!$.BP*{[qez.NgBP]g/q/\BfBfB-@ez<MZA[Ox--Oϙ/]?͓;ҙXʬwΟӥؽͽ¼ζΪΪΖӕӕäؼ@pH,%l6!lj)4F]\TpsqJ?tvxD"M+rwB-SS1&i=$?/?pLCБ2Z]^Ԣ^ r9@D$l8UMU {]_`(U}hje"o!sa _%P! JUfVFk)kGBkA!,h!$..BPBP]gqpA@)cm-n\x.AB]+q(ɊK͒KȒYצbت·ΝΖӕӝ@pH,R9LD|FrK`-o@K fpp$J5{}wx8j1 -8rfgjK"rxj548Bk 62 hzT8Z,{ 81]B 38.B*/ 8C80Յfo#xGI2hF'[ɳ&p"b-!,!$..P]g{,]*{?qNq.@O.MzB]A.\/OOOO\Offpyff'<ZKc.w--ApAAONOْ//BBg?Pgz'z=zM) ?.:=<9Bc$cacb_'b-^c"c\Hc]Cc/YcJFTcOA2c65#Ib*aRa̸"b%B1aL cf *2ų,;  >1pD̙'CT9EY0&#JZĨF,cQ-V1bp5ZR_MDxP(J]+H-[nj+7ݺ%T2!,!$....BP]-B,]*qBP]pBfB-AOOO@OOO@OOO\O\fpy=<LY.c.w-\AOfيBgg?Pxn͓;ҙXסXܬmØɟȸײ׸ܾ±½ɎӕΪ513"];(]'+0. -0/$ W[!X#]>]B8]H9]@, Ʒ\P[ Ү:]G]]Y%]U14bȨ`"68JT,SVI%xFf У!1F']$!(DdG85 G'G+*G97F FFG*G(4G"F)3F!;>tN=!dZR\EvC"%3(- 6Ñ5֯/(55@C[ohINO\\expxo(0/&6/I]+]?rg9Vkg)q(x'z=uNypyo* :/6<(@6@3y"-<ZxYjw3UʦM N8T&M?GwRkkT_Gr [\.hL NӷtB 0"#@ " 0 @$Y,xBAͧ`0\ЃN@x 0(㌾!GeH!A2P~9:@;.xs{2_}f~YNxa3A@C^i."1'PjfPkY9dvv&j衈& oFDM |L'b@r: Yfp:*:\6˔3j⪫B>u1 a1!0^6Đ @Ë=du7zJ+x ŧ qEPc7%C2I3\6_3u˝- r|F-TG@@ |! g 9$n@|q-1bg7< gJrA\]C\g:W6j#RB d3\CVF?hW-褗nđ}÷u8bV?5s^dZ\jSfU.wy7?G[xA (\2OX=G98r/*95&$9cwƒPO Yi@T5V%Vw!K Y=}Fuc|І:hE`SͨF7юz HGJҒ(MJWҖ0LgJӚ8ͩNwӞ@ PJԢHMRԦ:PTJժZXͪVծz` XJֲhMZֶp\J׺xͫ^jP$ q@{]@ ]+0% KXBa"YZlfשЊHd@Zt5j)jA@L;Z8@]P⢂ < 08nL, PgI"B*Zp00/yU"2D* D !Ӕ_(W!+׿d!0~[gwp0H+a bUxؽQ0'…TX 'b&C„v?^b_Jނ.J/D[`w}qc,myA`w ,2&\/F)[ vZ,:w@* w (Q@Dy:I‹6J3Cf)+d! @ Z@ִ@\K7XgpT`8@+0׮5<d>vBkXKV(@.jg/FB,[ J6A<>ozO63-.b.kp/{ LΖpw!!GlBB/)o4`P& 8;7*n@D_%t )FRzAs!Sջ^u')6[kDZ;񇵇'4oOPF0O9ƃ/< ̊ -`/tqݴ7OH,%v)'ʙ>;P 5S.O#$F&W hGmdb? 8Ybtoԁހ&{mʶ}}VwkZp'nnX~8Fh%gd( @ntj~e |-v`W}т/8y yG4X[ yAHzug3g:Qz1{t(u)G}V}'g@]wb/xi!ff s7WlSl]Adwr`y8hQle^fGHVRoxGGh;} 1}}t^^'w(`DVG =1a/fe xusNy صi1s@X}|`狚{Q!G](Vk)G2&xFh60.ce1]3] h1uAdV~ +Fvo%gXpu A _tgr(Wi'tTraFwŏUfYOsH!A3Wj dw{4e8y q_8a&1Etx$isF ]y}|Hirsx+sZZife9 )Sdu)F v)yiIb&Ft#Ɩn ryg0'eaY%{yyٕrI]wipƕWs"X;cM ~eqWL{7ga@&8Ydw9uIͶn AbLy;^v7Ix :o ~1\ɠ᠚* |x7lZJH`ǡ`YX1zEZYXKp"ȡz+FXqpc%t y'I //]eF`$YZKgfJHGa? 7֘GGyja}>Z rn:hoٝe] oI`:hbzQaEdЦ*6nx:ਐz#fߗ~^ c mWc|\J_{ x]Kx(_*p@`:ei明p]Aw*ErO֎rE_Oz`RƬƨVtwu܉i IPbf{}uc~ ~J AvYpƦoʯ{-{^ wa=Ob^X'k!-f/y140dP2;l9³2+D I+`y&MP/aiPsQY[_˴Xf`;h{T wm[qKsv{IPww۷9?'~;+HH۸~W:[Y QwpU5 K( `S!aB :5YzYa[Za[Z'jծۅ[@_) nC 70!& @ .1nS(Pkw3pQaP$ LpY`&6`|`q4G}}A %$k% VjVU6 a7 k𛿄}!(K\(BPD|c}5'ƿ%XegeуqQ6plqZl(pfxe ]Xu|v+4 Ȯܳhh%iyiijV [O5hLI|PMʞʊ OLʊ\|CŜˮ<@K,֌ڳ B; 9'|~G0ddc0aPP0W "!d|3 aBu R mBO X'2 r iA"^07&M!e!ҷ "SQq7ap' 7ppjȪWO_jpI`?ׅgH; =\0ß@J T\*`rssi@8h6/f `!D|خ/~}ãlÒkÄ؍- ْؒ>Tk|l؂ؒm%ِ A!KlڲC(7C7/p@6%!P'9''(´''tދ1mѽjÕ_לrxGxyKpyyߝk|z zcלI,k+P)m{7}'p| '^V|r|9,ا=ذk˄ 7㚭4,̥[-3Cl&ՂP$+/.[#Ý5Yl^3{5p/GO 4!vS;1O)PI2*sE29sc @w3m%r!%1<Ac7X"*8skȃO?x턙v>^ױ5Ѫ96lV򿊰%O?x8OVVavZ-Oʝ??% on@~CC!8],_Tl*^ ۸/@ʽǑ#t5Ys5^se\0ԁAL ' JBPEQ1DL gFª( ( $FC@P N:y'H>ZQRR@x'?wBS]~Yo]W1rE +W46p^: (Ag@ @'I4'!qqEIIJEj+-bqE/ͽ-8TEV|5m9b w(VT]ac$n;k~={pW/G7i]\lÀYmE1⨢8ʰ2ވ#*zx:^iadCb2Hy'd^Bz1fsb8Ë`Fcreh4b"0LC`G*(X‮@<‡)s'0 `-J( %`ϝ` #4K@ML2Ls+.#jβR53-r#ϢLc%>mē5+PsV8d`cVU3Vi-ZػZE/vi{ 7VrAH] 8Ӎq@ !tŠp`4gOkF|^wF眊Pqh@c .8Z2"_Hؠ~)P3S'ϴ(,1Yh(g^i0?z3hܩ'z +*>OQB$5>6OSML 螉O"˞&~hҐb4Pꢉ/V*ׯ>Űi'(8|IɄM|bUy@ Czˁ.+Z;pT |jAV2a "Knr@u"V.䕢^XMuFXssx۰),pXf.3oQ|5qG)E I<5GMt4Yb(R`J9v#פ|jTZ@= @c;܅"h nY9U3zҼ΁k[ &|pK5/’}nt6@v(`|Y$;|҈{]v*k07}~ߔf_+g.~v:يx=u\b`KךV7J<圎].Qf%o0XJL;(x~']Klț9i(7 aNWԹ< G̫f Ϲ-Y.h?UIt]CDL yrYӵ|wxwNU|uY^+b7HZ_{=/f3e v|g}#T:ل.+('9jYr}NRzY`S^Wu ~]lܻIFziÓ|q`T5O2<~w ,(T*~#hr*Չ@ @*Ҳ,,5 @ A?cͺAl2-2,,XAAAAA B!B",B#9D@DD>1>*rDABDM R$(A(EKȸT,ŌTK(DA\҄K0Q ^,\LF*FcŊH^["#9a"K%b ːJ Ch˼Ȭ 9 4| 1$7yq%Z!!X؂EGՄBŞ|hHg؎=լh$0䣫 %JىGh٬HUHJxi(KSRMXbS@@N5%۴p&IhH'J NM(@8ˢ}5f,ԝYuRքTctB]ɋM[[}I-O%ڭB)ij 38#xW]iWU&]ʼni% I` 'Tw J@pɆ Hj : ؍%F`p]=¦{ 8tw4I(ډ~=$-ze׋%$J3ʼn$KyY|%2҃^ۏuJl Y8ߤJ GJRȻZHHaqԤuB,VID@`Xڋ FZMTe`D FDO+ &ގ~a `\M=@ǵ(\7x`X^`HbMu=Jq `Jt%g؈b.b0^7^8^y5'@'YQZG0<>F>WĒX *XmQ(@JOnRܜZCYYZ,G.ʅJe!(٠CM geSK`8Թh^f ƈkXg^a\Zf"O羕 crU'i3!荺p@1f \iHO~Xhϵ)D, @`y~TQ鏙 ڊ2"*zʟFE$eM@a\eĉ ʼn#\˩ 玼EY94grY`V%jTSL`BdBDkH{^wޓsgz.l\`kf¦zql*w,8h &lj)%vhN푎!''imв,Q)`E Eܦm4 ŗvCQ(E19n? A',ꊈRzng >ؚ8 ǦTa#~FD복eVSMkvgknoH,m FTa>g)-\nNo^ _l ڌ$lͶbƈh8q.h^^(]??6m0YaASi IF|'"D-=9%Y "/q(ךrnUBH$ʔ -T%̘2gҬi&Μ:wa&MbdRBbiȗ25tɢXa^I)&K ʰ^ײm-ܸrUYTKST5@PN"t%Ѵu챬ѭV53ТG.]xxE|_ "l CDŽQ+ν`c f|:j{t nm:jծ &Ͻ<㴫?_)Hj2cŦ?uUfQd a T^A P'8Ҁ :(Y"UW`TXRHihA9wЂXmBA I*$McoҘpX'Up0P*&T%YVe<%peTEQSGxYfyP#fu(Mj)zՂh}eV-GJaR&J*( R&'Ad6@Z[Vz+ lڞBkB~-;.~fI e b 0Rf&EQpn-)_lX ,ٻiFo[Ѣ{E6x7K.{g IYgoƻ1j0elTaRaƺhAihh `;gY|0W(5U[}52[]gݫN R8l~D"ĮPn-Ys65ܚ cv+ \n֑K>9Y!Pq}4z?gi}a%LfPdDhQ暷~XdUi9ykaX{V]`cZF]^ʕk=N)X|JT&!UD5QdՎožQ-~T!qe0A ?;E>1(|L8MH}hW&YJ| C=@?)BP & &ǜD3aO ۥ&!(!1H̀38F9OF)RVtƜI%li(1Oj O83 U)YZd6&O#V %kɳ5=.i*' FE Nɨtdk=Jң]n iKu-=zޖu\7"E.~AYE&Ӝun\Gֺ/cox.ײdS%Q6s3P=d [2&puapSUX7WzKIfh*T3'x7UF\Nl2-/Y\ =f-E$ظM~OMs1; {W!Sg=ŀ& )mlqIa8SZ'MujzMT?su tQ}Zt'W}+[JŶh!5g {_fkZ|ь*${-7*I tnLLm…4DqP.5܈82>? Iy~#E8IBGӷ.w3s8C.n!)T&"\ۂ$39llΑ=)KTy{<@`A24eSܒ(qQRuQ-&eYO+2aZܮJASݽN-O{Jྙ%dW0SsbDŸ DL󲗇]&EA{O: 8W J)4~ p^{&1O04tHPsKG2YxCC|fG\?S맀#@Pl#ဟX3F )OϿ#?!ԉ kF䝆`y4~Gt PB  }ޝD_ql_ FE `q,kPX t@R HӭQPR,aU1O@et<ΐRlHLa, S ESń^ZTPHDdŤ!E@)d! < Q UOp~HP؝\di!fX ZPebT@a!bb׭'z(D*vK!!>b$$!=Wˣ HAp 16 TǹT z Lx435Bc0jI6~bXBlԊ P cxAD7MZ,cKʠ9F;r:ʜ1^5 $Ɉ2/|У$:#4ML$DҢEbQ\c dʤ0,BE 2Ο}hL$~ʴxKNM^dXC@YDIЭG\KEl ~tMN r AMbXRJT@o C%B\ld X:LW^BwGe__$afb:%%VJ] J4L.ɺKYf2H`zaĀjVc4ka%TRZUNlPVl@Fa ҈_bHpnԈ1쨋ufLG& Mxgi֕'dsQ'snfn uFO~ f4Bp2yL(_rg$􏃖c|ʈea ˜E|\(tYNh gvmD\hD6č&D6h9͉ƍ "\e'}F]؄u Zi]aNviaMT EM@a#nDo&eQߘ͛rMŜ {J N1fGK䩏 蘒Dji Qd4tIM$d(Q܍HtAΨ0$K0fP5[:K*\ppu&Mx M d8Tד<$g&9&%5"oMt{: iш)u coL|u?ua`#аLP6 f pvI {dUu\6V4z ^6&x*Y|9}!~K2QHT~M~[}D56\} 뻐=\xY?1I֤8u|[;Y=~G)YqD EA(bD)JXcF9vdH#A $"I"h0̇'4 :*L &A6Ó\*p'O4{v$4f(qyTk:!֥[ՆaҥJ*-V뚝"єu~pӰk&V(T+?>|sf͛9o4Ub$_)X,Ugx8ͅ !v(Dn~zbRa Yagrlw QĠWɛ䈁:Yٷm}[Fn6seG̢nr-L['"c<:@+Ь 쩩< |=n"*l[, ː[X3^εN"~+q)/XV9?&JYH-=nemuޙ}蠅袍>/T,-eZc&@߃~ꀑ;7:lGVQ*funN1lP$E.86H2^lWI1CN6#sN:-W"b}|-ݼWݼdlDMzٙk, Jǜ?F].m. I{Z#9ߛ䩺SZAo_ڪu?rz20+CAzCN!PbY'deK=/$(x'>X/:+ڣ,!>" yLu3K(iċ8:~~ᄉSFBDog&*crJKtUeOcLCq#&'; l_92E+b#队xk_OM怕$M9ISr4Kz&!YfudGX\Y<,"TM%.2x 2Q nx0aF 㦿 2-M xicv` ;K,99הR>݌,G/R'($&|~!Nd\ҩMkb8gradG-6\zf_WQ-++EטLknI9)KiC処X9N7`j̦'( UHL'g,=SR?;(&e"bҫ4Y(sP# vJ۫6f]Ւt:5]Y1'ya[z#I55}ucJUʨCee:U4R}c gaa=0 +!SjX\u(PEk5h=MTؼ risk [V/$Ҧ2fW%6>[Z1-R%i#ڬK;\V=ԯlp;Oh44ݬ3Y{ɊQ#`cʌ%mX"vWūC5(KLY)W/llej⭊i@[4^DJR'$Y>ɉ#qٹ)h­CABT'T/q|%⎨Bu"%!~7[v@Kc,sC+ ? :+=%kL"]3ZE#"XDL#aӉW7W{YSN|2+9RJ}KX)ҸQy|*Ke-$.;Ʌճ|:gLƜt+epz-v2C# F;PQk b'z' PN" )bwS-Q(F1ǰDQ QSp {',Q"FQ  !C &"1"mq5v0qq"5A !" R1*,R&)X2"j*Op1&yPo 9'(IL1"&-S0r"rq&^+Sq#/#1,A /!-(r 2-R/b)+11a's'2&%%!,a)-3P#<O3r)/O4#2//=,&}1w^rW|3FFfW(4# P"d73P>2 +S:b3)A0 ';e,<ד==>S>s;>܆X?6H*-Z@gy(@Bn=B`#4B3T$";4/8!F0*.5Ph#<326 ˌ1t (@(Hq@?%#JH 8ŏ C :2ɲ˗IMT2oɳ> Jt ТH*ytӧP-6JUySjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ Nȓ+_μУKNسkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n'7G.WngNt!,$"**.;=--*,; H<+T,?T1*oJ=~NPO+@<O;o<OIZw9og/og==YTdUwO<<I^~-p.3<@^MZX`BFEICLbbcˌ#5թ*߮.ڮ2.:0A4>?V\cc`bbJJ]QIUW[bbaaU &%! !,#,$)TT?2TK@ QO TP7(6'<HP4T:*TAUDP";+SGOEM P3dCT PA0Z!tJA @$1(gPTh!08HcYIBɍP( @BОB"M:i)SGN*ժ[!,2$&**.)5)9;=-HwE=~N=~Q@P\@+@<O;[<o<OIOTN^0[T(Zg2xgxw1=MTeImYvU<<IT^go)o1w1~5g33;.@P^XWa`BYFEICSdbbьթ*ڮ2ڼ:0AгGиCڼI2>V\ZPa`baMHIQMU[W[baaaah$U';b(6=2.Vb5/0,"=3#ggb1D^ ca+N->gP .F!/ FgI9gQ h fԂ8eXa' W0 X.1rf 3]~DsD g+Ås< 3` Q2!@3_D2&tiP]-lQ[pЈ nHP観̢=o-[n %+.]D!,M$"--*+T,P\O+O<@<OT$og/ew6NwGYTdUwO~Ygo ~-p<@MZLcˌ#5߮.0߸G24]cc`bbbJIK]baa@pH,Ryl:s2 ƒ^zV T/{6' |'.n*$evN'0Ev4(DoMf'3*3Nj-)"3-&jVS1k!B2j#,RT D DTBTOMUGA!,h$"+3**&*2-,; S;?I?^0SA+]C>wJ=~N=~Q@P\@+@<[+f<OIN^0[I$f^+xgfg/xw1=R=MRMReImY<<<ITgo1w1~5~,I^op73;%.@^LW``BWIISacZbăьڞ!ң3ڼ:'>EгG2P_a``bbbaNM@IVKM[\aaai%T'>e)"@70-Ve9./,:@6fhh1Fcge3>hM5 -I .\eMAhbiEhP;$hSHe*ha8TF #ehpG]L(4K)#c H(/ R9GDr͓AАBZxEeBa4]eR 0АҐ  )`ӲMh yLi-[In +wٺp!,$".)9;.;<H-,H1wQ*oH)~Q>oH=~LPy(S=RMRMV<++<<II^^woz ^OZCVWădžƌ̆ь֒֒0=UbLMVZZNR\abaaaaÀ@!5621?9?##"/&?-?=; ?.?7%?8$? ?*ţ' ?,+ ՗99?ݭ <9Аɒ&Li%F._"'Q̚!,$#+:*)9;>--+,; H=?I,H)>g7@\@+[+pf<OIYTdSwO+Igoo$ogo;^Q\`MFOJ`b[džь˩7ƸIиI2<^Q\RWcc`bbBNTDEOQQ^PT[aaa׀N868'68+M.%M/&JMF J:I#M@1"LF)9A0NȡJ ϠG4؄ -M4LB >ƅLC L34#taKL `=F%!hBu #T5{TpHLbܩs'> (QD e!,$"+3*&*2--+-*,; S;+T,)~Q>wJ=~N@P\@+O+@<[+OIf^+og/ZwB=RMRMRYTdUwO<I^~-^op3<@@MMZBWIEELbbb̆̆ˌьь֒#5Ʃ7߮.У3>0ƸN˸K34cc``abbaJNM@I\baa322#Z5Y=Y< +)$*/(.HXV&V?->PVB0YUĶIV'YG7V"ٵZJUY96Yv aDmeQhC*xb%ĠYp RM$˔MȒ,R9O+ZD "RpaBuǞJ%dtԪV;a:i+WC^Re!,$"+3**&*2-,; S;?I?T1SA+]C>wJ=~N@P\@+[+f<OI[T[I$Zw9f^+fg/og==R=MRMR<I~,I^op7.3;%@^L`BWIIabZb̆ьڞ!ң3.'=E2>_a``bbbaNM@]VK\aaaW/3, % 3+  3-%UVS(7VPVDTV&WLS>4VR0AKS$2V>*W"VC:V?2AV;8S)S# bYBзVx 1>k("0W<)U?v+Nj$!9q ,@+g.M5%a@IJ$ִ귪Mbu^ [[ !,$"+3*&*2--*,; S;+T,>wJ=~N@P\@+O+@<[+OIf^+og/=RMRMRYTdUwO<I~-^op3<@@MZBWILbbb̆ˌь#5߮.У3>034cc`abbaJM@I\baaĀK '% &*$)JJ; IG"JG5(4BG7+JFKTp%#BH?~˖^,$s&J6! !, $"+3*&*2--+,; S;?T1)~Q>wJ=~N@P\@+[+OI[TZw9f^+og=ZwB=RMRMRdU<I^~-^op.3@^M`BWIEEbbb̆̆ьь֒Ʃ7У3.<ƸN˸K3>c``bbbaNM@]J[aa/.. O0N7N6'+& !+% MNL#J?FL9,NK(;ELOͽN>2N:*N41L$ *([Fo`0я)8H$xâpRqŐs& 'H0JK P $؎PD4o$qӢNB:j*LMbͥ@!,%$"**&)<--*?I+T,SA+]C=~N@P\P!O+@<f<OI[I$fg/og/=YTdUwO^I~,Ipx w(7<;%->@JULMZ`BIL`Zˌ#5ڞ!߮.գ3'>0E24_acc``bJNEVFIU^abaa+(UHNDN1& *%EK*) QTT /TADP"0T;$TP8.7TO#,T@4T=P!DOSU SL'E@k=s +,>DrPWـ'`9]j(!4J2㈏c:Q8j_PzA/ǖL8J@&|**LVRi+WI^Nm!,@$&**.;.;=-H-H<,H1wQ*oJ)~Q=~NPO;o<OI(S=R=MRMV<++<<^^wox 3XBCVFEICWbc̆džь֒թ*ڮ20A?V\bJQNUV[bbaaaF%# &&! AE?EDE@BEF.E4$E7E=,'E"FC:?/ E21@@@E15(Ŋ*VH>ʪ׮n:,!,[$"*&)5;<+g@>wM@P\@<pg+N^'fTew6~[<^^IT>+8@UZMaadžƌߣ&У03ڼFQccbEFIOT[W[baba@pH,Ryl:s2@B`*B;^5Z'Apl/d(2{}Br, BrynB 2!T 4. 46+Or2&36#mBx Srj60$a6%)- Dj/-ɖ'Ѹ*EUbOVM{A!,v$"*&)<;9-,H-?T,]G)~Q@P\@&[+pf<ew6nw6ZwB=PMRwH++^^I^o*o1~5x o)24@SMX\AY]e`̆ь֒И"Ʃ71ƸGƸN˸K52<4`cc`bNGLFIOSYW]abaa7& QBP=G+P4?G ! %',%/P3JNL"0PHí*P2?PI#(P;G.PEQKOE-]+&!Aa;ϩ0(<z(h RfA%H#!8j8> 4bSƂ:Ed"BzP *ÀVd5+ծSu*V!,$".*2)9;>*oH)~Q>oH=~L@Py<II^{ ^OZaƌ̆֒ռ>ڼ>0=TSQSQUbLMVZIZR\aaaa@pH,Ryl.NcuuV:8q ^Y| E0vc._) _D 0+ XqM.,Vo1 B0C1"{!~ /DE-]#'(&CÐ,YMHNܭocA!,& "+3***))5;.;=---+-*,;,; IT7vH-H=S; I?I,H+,H1+T,?T,?X0>g7HAUCF}wQ+]C*mG)zL)~Q>oH={L=~Q@P\@&P!F+O<E;[+[<grg+j<OIOT[TNY%N^0[I$[T(Zg2Zw9fTf^+xgkg/og=fw6xw1MzHZwBs(S=Q.i==MRYTeFeIePdTwNmZ|Y235˪6Я5߹%6'+6+<<+<^^II[^iwgoo&o2w1~5o$~,w6I^igoto)w({ 237.3<;<*-99@@JEFPT]MXZZQXWZ``BCMVWEIEICOKU]babbZ`bab̆Ɉьь֒֒֒՘–#5כ"ǩ7۩*Ԧ2ع:.'6+3EǸKշF@<4>X^GQR\QSKRY_`accc`baKMUZPDHUFIM^SZU\aaH*\ȰÇ#J ,WP"F! $AȓL0 (c.نD419Z&ɝ=}, v,fǭ):CP[z5\XgEXc]c8IF2^b&i"XV :G=TMK \C.װ`3TtI%.c_Xe TW$YI &bE^ 퀄&S H]A".ڂ:AF .U:S?ܒ D*/KjG 65)!8 Qȏ?SEWzԧFP:%pb, b֞duәIM_0:Ғ-\M4J<jrG^eEh*-eďgA c ԁUQe&!T[}!fgZXMЏUeUqK$b` #X1,Hhւ|hOaoBmXw\&$} h)W o;b F cl2^C'Lw * u7 qoM0Lko Pp@ R"B!xv|HP AlDk 5f>@Bj܎Kj0ri@?fZ;4 Ԑ7DBͫ% 3^4@d8j|e0/d8.cD/p4P30},EN+9P8%Ր=P; = ryLi{&?|TF!Ys!ifcVڑEQ7p{E 5Ѫ@F/ۚ f09*`P,ÖpHK7Tst wVlp<&;p~ m 9D^J9?VqI:-s,Bwxb#|ˈgX,rz"$2Fڈ 3nj#4@j $ vk?Hڭ& پd;{N ^ {A7y׻'xX!| _'#w G& w?oV3O;"'$)PϾDOOo8 fqǀX{M`f!w "$Pf #؂.Qd`c0:`a@8B8Hb@6DL(``7MXV(h^W`h~Haxhx~^l؆طnr|p8vxQx|z؇Xfx(!,!$r.@OBPOOO(ZYAwOp@OO\fxBP]g)=w͓;ȒK͚JҚJҙXl徆ɤÆɎΖɤ@pH,Ry&\e]lSq.Id[@[Dr-93/ C=vIiyE"<C ='=lDC=zC=&xC#=C=MkE=*7Gk3,,-%1=4+8=(fK50J)iGXC[GEMA!,)!...Bgr?q.@O.@gBPO.\/zz+gAOOOOO\\N\\\=Ym/m.w[N\\exɒPPP]ggq(YY͙XҚJܲmlvӞ݈ӪȸɆɣݣـR5KLE8 .E%J&P RI PQ!CR: , 6R97R)R<NQ>RG R3R(Q#R24 "-AQRQ$1R*0ŎDA_< ߼[9$  JU/>!2@6('Ϟ~-$t!F"MzW !,;!$..BP,]+g.?q-A-B]A.\/AAAOOO\fffgNfffLLK.w-AOOyɟx͓;͒K’YҙXҠXʬwv楼Οӥؼ¦ΖӕدE)526!'?@:+7,B> E*E. % E= E"ȿEλп ֪ذ/ܝECEE(49E<3&;1A""`zR G3 C PRadž^„%s&]!,V!$r.@OBPOOO(ZYAwOp@OO\fxBP]g)=w͓;ȒK͚JҚJҙXl徆ɤÆɎΖɤ@pH,R)\l0P)`|$Iq^7.\K s.J =C!=xzDBI"<C ='gDB'=C=E=&<&#=C=CB=*7E1=4+8=(By3,,-%[0J)͉K5ICwĈ@ *\p" J(!Ŋ /b<"*!,q!$..BPr{*{-AA-OOBP]gqOO@OOOpA@=<Mcm\xAw.AAʃB]+q>q(ɊK͒KסXצbؤҸ·ΪΪɖΝӕӝΰݩU(>:=-$CNNGBT)RSU"AJ 'U2SK U3OH ÉLDU#EUP%8::;. U1UT,OI Q&B#`d)0C0aO?iP͐"a uPI TظR;??@6 RO#+RK RNI O"Dhw(CzQ" @'oP\ت! P N4(=^+1ZV`@EF17yeЄFJӦEB]*uSj!,!$.......P-B-[qPA.O.\BAAAO\O\\fppy)(=K-n\o--@\OO\fyxؑg?q(z'ypx͓;͙XҙXסX¦mΛɘȫ¦ȸ྇ȶΎӕ؜201 S6(S',/* +-$ R!5?S<#8S>R94)ŷȻ QDS"ǹɈGEMۉHSK.3FCtaJDAd)& @#)L !CENzd#R<%y2(v$@蜨"]jt)SNE5**UK!,!$..BP-[q-[zBP]\/qB]PP\BfB'=c.dyypyAOԃ//PPP+g*ϠJ:) 4S<(PNSR8zd" ad G 8Qc,p0a/ L6C;HDT&Sv : /W 䔄(SDIJAӐ#s#ŴҦPQJ׳Tbuzu+^^ !,!$..BPBP]gqfBpP,pA@)cm-n\x.Ayyɒ/BB]+Pq(ɊK͒KȒYܡX¦mȦmצbتŸ·ΎΝΖӕӝQE;@!0?;>5/6CP.PBI-Q9Q:Q4%&& BJ DQ"ɬ,ҋ7ڟ'#$ N)MQQPIOK ZU!X[@F0rnF"QjQ WO(I Z G HIArtDK.I( usҦNyBʴ(U!,!$..BPr*{BPgqzpA@(=<cm.w\xAw-@BPP]+g*q(<<ɊK͒KșYפbΐت·ΪΪΎΝӕӝө߀O'958+$HJ?L;C&O0&2)O"O1.D =3556,%O ˬ/IBOE ;K#ǂMOO@hRD9tb?֡fk7ZlĉB? HR 9b$ȅ:P)1O~)Ѣ"=tiN !,!$.{*q.@O-[q-[zBP]g\BfBO\OLY.dyyOfAANOffoPPP+q)z=yZÃ<Ί;ɒKסXܡXȠnvݘ݁汼ݽ·½ÖɎÝɣɰدOBJD!L$OOCKOE/O;MNƃO%O#5׉ӦO2O>AOF3O"", 0O<+ O?4@6| A75| "-Tx# 4A$H$io ɑI@&NA t :djDCU":nWD]kآfM{j-C!,.!$..BP.-ABP]\/qB]PPAAA)==c-nApy//BPg?P]xɊKȒYșYl؁ͥҲÏӝΖݩ$%'M@F=D>B #(" < 1MG=MJ)MD,ME MJ^41h*&Qp"!ppBi ( ኽ}&Sn$"%G0<)(U6@!,d!$....BP.-ABP]qPPOBAAAO\\=-O\fOfٙPg?g?P]qMz[x͓;șYҙXסXlؘɂͥȸҲӕ؜ȼ$%)'(L?F -!;EL d1Z 9&ƂIq@ԜrNA$DIP =u*զVnʪ5׮F!,!$..BP]g-B*qPA.pBO@OOO@OOOO\Oyff'=<LZKc.wApAOϊBgdסXØΟ׸ܾ±ұɎΖӕ؜äأӀ$ML8I7#,M"&% GHK?M9+0M2 -M<ML;LLBKҖM ܞ!MF')'(* trqLB"Sd`H"A'zKS&hIc @RA o~fΞ~]sh$i!,!..g{,]*{?qNq.@O.MzB]A.\/OOOffpZ--AAAONOْ//BBg?Pgz'z=zMG85 G'G+*G97F FFG*G(4G"F)3F!;>tN=!dZRg I:A6Ouez5KW;UcABSQJ2I/ F;-mz8j/QMNwtKtdz+gU@TF/iBcW;jf5OQNI\c\a\Vfed[IgfTgie501MKZDQKY\i1Q#\.d/oIOloy!v"_y#A[UsKxnz.i|{-2-5Ӱ0*6\LshfwuIKNO[\igzu{o+/%"5Jj!J#z#V'qHW-gg*g?g*g?q>Wgr,wQyp%6(K+j2u#&'*)Ϩ-ҡ0x-.6<5:ܹ|q6O@6Dv9t20vu5ONR5]7haXɱB!w8|)#;,!xfѡl_dM]`>~ î߼Pkf 3CGl>KʼУC?ϔesX${vBf GeBy7n}5cuk`zC0z%t:O79=Ua`Bqفß )w!bv!ԟ ͈P64aD ,'ݐDi U@h?|@h9 ANh`Y0+D9e*YP0Ӡ 1%:ٕJ.$_P,Jce -hc_@D( 5!r63pp`+:ꌊ2څvBKg1@BB.(Orz@;P6i+JZ d'"+)lW8@zquicA@s? uAOl,r@scBO XY9r^I]g'@ٕ rS Pb:a@T3j2]X=G]?~Y0p vepDf4B;'@Wϕ)bg[pEC(ʪ@ZSf.>Ћ8dBI\}NE;ze?ڀY|ip`? nȟ#3J0 €Bx Ì6ΈG^1W"j5Կ-+ț^AX1"z!trl=bASi” Hx0yՃƬ,\{V;A_4{ 0\N qftN XFvݕ.:e@(-ы#N8\U&ɘw4$FUPjX| 9C{`aD n ?!IRE@AX8Vf*Y RizhXcI,E2NT$(y qGf I&iI'ȅ$a2SKMrғeqO|Lh;*D:9PU뼐 b ,#Ctr;>h)oTdY4zFG"ر2C`*+s4p;:DiUѢSP?.#CԌq,QĔYi&p=#u9HBU$Z gzU񡩖)MU >-IXb$Ęa`>W@ \_'!UerheA4:d$bԈ dolك4P$ 4UJrGYlp"x"^)Ud,GVօXx @"!DPX5M L%sbBegͼgK]Log~ˤUjN09Hޕ" 8LJѠr*8"yGd&iT3,fuI%: 4 s2sD> 0DTcc; JPxD#Qƶ&CVX&sY͑pGyG70UZMs,&ُ҆mxHr,9L;DxA7N ;h0x̯ȫ3iu(OyNĤGQ2;8i9brex(8QTS.{!lBI ѓީPœ<{pCv1NAqN"5!@bI,Ry:M҂p*jӼ1g9~ǂ3curPjBDGC^P\9!$;>h1mPW7kgO#NH]{ L H:(pC{ ]m IN$0q[WR~DAkO'zA~g.lh]p  ؀E X0Ep WQ[ }1@&x40"*4,284X6x8:<؃>@B8DXFxHJL؄NPR8TXVxXZ\؅^`b8dXfxhjl؆npr8tXvxxz|؇~8Xx؈8XxT{ @~G0ɧ{,7vQC!(B|3!8H:X˜:'0͘{P3Ќ:{0'g @9p.0&E!0$f CҎB3PCr2a(H(~#&"%*y&8)h9')8ٓ334$, 3  a5IS,!AZE`9$cTh T(a eqmi‘ZҔH*@C)|yL9`"E9ّ.nُ9ؑ&)ّ)Б䒔viҔ%40hXNJ| p|Iה%(F.ICaHћ3)i.)!ѝ)ĸYٗiIiyӹk):әGQ _`.P/М มY3@I:)Y7ʝiI.Izآɑ0J%ivI)~XjYgəُ9Hn] iB)\+*|юK W9s5{~X QA@$ T:@ُK' I&%c"Y4iiX)@y4 ٫PIت ɕFm y Zrk  ZY j񪼚ڑ) Z뺩9 "ӌ i%Z)[^jjd:J 谩ڔ98 &ni%MF "u%|۹0P b3;ʬ)șɟ/xzYT+309ó>'Y [ +|%{hۥm*jgyS[+.ȩ_ 4 ᭿zߺ K:a+9|9"%ugwAںO)Dk? d;4k˚ y+»kȫʛzkƫsH.K%IP,ˬM &os:ٌ M혫yiֻy ~5k<7z8[GoY:'<.aKZWzY.z:йifԹ%EL좟R&~ؔ/qI8vyGRY*'Ȝ%̩ۘg|*[LJjy<%Q Ǹ Ȑ L\ǁ(ؑ9P\,ے ",܎ Ш#HeK~|vyp<2R8Q\˴LL˶ar*Qv̨ Dziŷ,̼,{GR`6 ` l/(IW9} Szꚴh0)ф<°̬HF) ,n){Mɑ")JˑIxz*Д7󬙰KCF/Yʺ!ܜ<ӑԭ9O)7l[R Wl >m/S-?=Ռy{(4D"Κ[Ύ ۪ ==՟۔7M ɶf |^ ˬ+|W٤!H̥o-k˕x\kv Iۉ,ù}w*ֲ<qRɭ,[j$Y8|~ ұ ]؛ڍ h 1}M\Rc| |-o}Φ,+e^MMo \[4*NRK0ά.!/8\2PVz㴈:xBN A0[=٨/y(.9 |](.LF 9ۯ;9CN AZ:.Jص`^QH|.m5aЋѠJs>ޡ;0pM<+j*cQ쭱~9k[*͛:DΕNԒn案抮:oqە-k?ykRIpk[Јu 䞯^͛ã ~%ࠊK{(H渊ώՎ- Ě[{y;vQ4dj},jւM!, }'9.j Sk*OJo Ih> ֓u!DmӵD06:kw0`G2K*W,!"tSW=b ; lkv\csXws~xw. 17y裗~z꫷z~{{|!=`M]}Öd8bEF~w|9E"~NDIItBG %vbHE$`hJD@0F0E%LhdjF0DǒI1T,5LRE==ʏ hg)elj\[AvHDJpk F%\cnN̡#I$[Fq$ꇐ0jyL$+% bL̊&$ G4\N,qfN v:ɞ1 8hR.g0u%=`H'Z`BDr݀y@_Nb|ՈG1/*Q!%*`@ N ˱Ilb2ESYX1@cp@6OmhLq/ 5{b05n)!ygKvQ= `?({ 4imN༛Lw[CJp{fQ8_? =TXi0N#WK:W,Nd"p.c7GZޕoshc#DJlbw ވDX} q7 -J wǍC`V~6C l!c 6ƿny"x|LS ZЄ"ĴIC?y8oT;ȝ?i*%@ay_]z.tcdpy>Yݔ0@Ypߘ:|]fBwRsy.?k"@*hE%e xp?poZd!h"仈#?;Q#i3faDJGOQPz445~ %10> qM雯MKLu3[XZb+)ҪD"r$+J*\rT(\):&k#)zܯ+I+ܶzc\ʫ2= xs\X}41f S/s1EۯIzE(Rކ^2 ^6VᜢQ +^=Xr o[X6jRk&fR}râsKM=Kiե= 8趸ʇ΃EdmѼ_W+zMCͣ;h7NFCU+<% =jOY%__Sb@œDb;ۘ]\ua2S%Z$Bu" ,UDc7"¹47G%Dx6b7ψA5N=nfT-cH3vdEv5F8):EcJOWc,zM*%f;ETn)L)O9<&R3:el)h}HfF^^1ʭJ˜Df%IlԴelEϼCeU6Aed,O^%mN_ib%["8j_ caaiSBJ`utmNm^mnk2Q!R׮m~: mN ,Q MhNn-1\A0X]n nnob) $oVo5*[oVo&0!owm WC_p.U@MpW p p pppqq/q?q( Xq:uȌP!LqYm`!2'[QMR,ᔥ:rLq]>A N 5Ir5O#/Q(N v9+7.11Ny' ؒ xqJo , Q)HCO4:n6St*G;mFx/Di#uBHn4Ǔ$7ȖRV_o `U9u*p]ua͔I*n 3eiJ v0)Q!vP9w/puDS}s`0Au0 nqD>NT ȏ]u0)i:Gx(/OwX wVwJF* ]yFd0ôyLQcn=yF=KxWQsnuwWN:`?zuzQC$?{FPTp-d'&O5؀ y'Mք9?\|w lj*g?UWwQñoD"]uᷤ Dd79oI~e U- 1}ƒw 9o?q?0Rė#Cؗ?p<4h` 3l@4>h"ƌ7r#Ȑ"G,i$ʔ*Wl R H&a4ßs>2B4Bᇆ rH&֬Zr+ذbǒ-kc.\HէĤt۳z/vՃ Qwc) Sl2̚7snPzٳ3ԪWn5زgӮm6ܺw7‡/nҤ{NGi&!1IRȕ30}yk.d>A&,>۩o:vgW??keA걧EGt&z4t@$.XsZXg'<AH@XƒsfҟG>]E*R02jU(bP;DG6n,vbHUW3.YPjÃE>xd*YY8'_%'VFcx1¡c86v!DĚTä:4dЁ(8ݡu` T>x9#dxXJ+_E7鲖"zIZnX)<%p.EXI!|DfY[-I @ 0g,r dCi$i)s~V-"P<툧qӛLI?cy%a,I@e ]To2&ky'vk:dp\PIht&b#ԕʡAH@ B-L S t&b:SJ#Lj!tC#mRTkWLݷ%^hO ,iXJў ⧡4:)Vi!y=XxʲNHMZIfwV],#>?z-M(w/Xa792s<~7>r/5 E 8#S /;ܝՙ V%5zG$ȋ4`P9rٺ]=du3;):0Bw$|Ks|oQxS^Ick(loy 勞/}i3pȡLpF^}=mfp-0nktϼ5$8 y+5Po|G6O~O_s>/??ӯ1 `?/W$l %@LSП ~U [&JS@FN qD @BЀ fNbP `fE"$ . $"`%…D F'~ơH !("*T$F*+ #"-֢-".."//"00#11#/ڟD 0#2F4"FTT#^L6njX bbr#:` `OO:#=< ֣?X9$B&dMtaCHZȣBFDZRDfF~FPdnHh[\"b"$Kn$JKLdK֤MxM$OO$PP%QQ%R&R.%S6ejX@eG8\FTSnHIWxUqXEI q[DxE\՟\I^ U_͸˘Mdd$Ĉ hX` &Xa6BbRA0&< HfF ˸ΰ'I#i@jB%l]Z\A̦զQʡn2DYc-C0gҩ\lFEHRIe%`eU|AR+mg) ujuz%#}؅rN%tgg+AE" #TONU ((D (4yF:9I Jv'*hI"(M(x((hEUy2(t`LAď~|)qkŨVՓ؂wWOdYDsAߑJg)1)jBe)gB>W9i؏ĵ% >I,)RMZI*m ©Z)ɑr.'mj0Z[fHqB*lRjvB"Ӫ((ЌҪn\*)Uȡ[PaBt<윫V+KlDf!UPQ]zAL鹦C`@Xr^M8_mi5W.,6>,F.VD>CFZDDET ؟LfFBl,`Jnɺ,\6B@#DdZ#alCɮmE d ɒZ>*-HEtFLBTa:b#f`?F'A)*"B8Fd`^- `BXmEڪD^D@|_92<\`i-`Dzg;b$RѪE$*E6Dj `Z.fƅGzT銠T&@2,6o/ޮD0B~nEo.b鮮vj DJ//w/ZLD/咠B\n= aD|cLIFRocz!>7S D fDaRLd x$>.`0ƀ X C! q*q7 C]TdZPT\4*ELpf'cKAq[A mq_ E\H )*D3:c0ʅnnծ,L."Uho\X"3>ǣZ0m z- m*c2bmDz'wr?N3:d\o>22ߖ f%gE+sEC&^ "!JB\ _s-+$3Dr Σ$JAEʾs)n. nЎr#1SL0 4A/1N"+#C28ED0ZdhDZؠ<3CG=+tb?#a $cDKpR Efゆ4s64Ms\'t(s!scB$sa$85n8KD HRO3 C$N[5F C XWd,&"<„F8@0D>WSRL[@ L"[Z_Bu b~a^XLa]gtEX#"6dNd{<wf.!Wo9sTET#C;6VV-LC`;W{avm'E,LޣhDP0N._76UL"ccD,qpsn@!,NaJpcctsCn? #rl!5t >s&j?o6sEG1:cN\$P_S@0L?U &B&BCb!PT#o#opINl,^O*m _V4 8^LbwsO7ł7ĂpcN6K8=[xjo@dm"#.'yR܄&$?Jm:1f;6@{.fsmBN!KRaq9_5Ԟ,kg)8twa빚GNc"+c6zc"F0SqS!n 'Ww(zUr/ɮxalwc"'# c: 80_ck׮: fb[󱑃LXKw;,Si7{pz%~'EqL#;r?-yCq c6"cc$ӻcO ~?x/w1G8e7O8|PdF@ Ww{|7 P|,ďDDm?V7dFPᏣuןGNwOljLZp3_VsѫcFg`c(|cgwFiFه=۷ۿ=ǽF^D_Z̪[D݃b FRH>kD{w>c*#om05++p`{~I-՚w旄j{E<0EQsD^c+sϦT-2m3Ѣ SQH34zSEU6OISՊ~U(XF]JIREW1e)U]i@s' vZ\TPBMv6@Y`sL %s$Tp" }x˰< ]oAp"})&s+>&HĮeZNDKRrYw^hu(וQ 4Rm\>W U ܸ(ӕtx:s.Rٟ'nZ0ȁ&kO dbudH(3Ls]p^3L\#I^vw/&s ^{L%@!@^ xHCdyd= "EzLW6'anF-"F b!"O4k7X;pk`@@$ 8dG+jx8X.-faH.5*qHR,e&mEѤ 3$Ңh" wi6LPq]1HZ 蛁2A{q*DJ4ח/.ɏ CiJrAHPR<3إvgˊf-2y& w{t$ UqyHGhћ\\ЙOC‰IwJ(GA&v M+z6;Jas:ә]eOuJq!k4ߔEešH2YU5ibqjR7Ut-Q (xBv{*laqPxTO:UZ䘙v'R+SWmT%SzEa3+wb"yGh^mu֯iAɓ">X-:X-}i?b6A6eb"َMsI+\l&;[MSX->U]^wy.@k6޸̕az(bΤWql"*a&ظ*[U/~i ,߂!5ph"#Ax¬$ra8eE51 Y1bR S20uco2A]jAƘ;1lu.Q: )gW{c|B&[2TJ2fpfKf:ȩق#<`3 ]hCщVhG?ґ)]iK_ә9iOԡI]jSթVYjWֱi]k[׹yk_]lcVlg?і]mk_mo]nsVnw]o{ I{M&p-! AЉE SWv" oB0C{oRqL*N( 'Wj 8&q6yQs<'A>s0>I, 5'n(q:4?څ=CoJ$Nh!%ط\& !$΁kߝ:Ox{K!PwLH`񒚃-g1'`(̓O<c8~ 0}WAx;]uN&8 KΏ9ʁNM~'0k!/o68`n8nurO@:A\/N6Ԙ1|n熯܏O< B@o o /07A7'mPq$,1 [U.Qn +~G`%NN;1Aln0vP8 gn )Q>$9H!F$ $;" 4% & $?%ffCR(ro.()f /e )+ׄNLD1,,,-R-ג-X0R.%%.a#q4G/MG$F±1 T"s e@B22-|ex`¨*3mLʃ+$H:3S3 }r&~/w pT6 qh6(@„6sFS*nF8s1PL4B9fhLs:P:s .$&L&;sKeN=#6>M>S???@T@@@ TA AtAA!BMBB3.@5CCCGPBDOtLEWTE_4\FgdFolGwTtG|HӄHtҌIєI4ќJФJ!,i"*---*,;,H-SD]G*oF)~NO+gpew1NwG(SMRMVnQ<<Ioo";4/8!L0*.5Pi#<326 ˌ1t 8@(Hq@?%#JH 8ŏ C :2ɲ˗IT2oɳ'> J ТH*ytӧP?6JySjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCMӨS^ͺװc˞M۸sͻ Nȓ+_μУKNسkνËOӫ_Ͼ˟OϿ(h& 6F(Vhfv ($h(,0(4h8<@)DiH&L6PF)TViXf\v`)dihlp)tix|矀*蠄j衈&袌6裐F*餔Vj饘f馜v駠*ꨤjꩨꪬ꫰*무j뭸뮼+k&6F+Vkfv+k覫+k,l' 7G,Wlgw ,$l(,0,4l8<@-DmH'L7PG-TWmXg\w`-dmhlp-tmx|߀.n!,$"**&;+.@U^Wa`MSadbƌьߣ&У0ڼ:гGܺF24]PbcbbbJIFIMW[W[babaaT@/N+( $#%AN*&'CKQS6J D>4SBSM),SI I C=%5&TN"!طۂ-H3NB0Z0}AJ0EɃ[8L aʍd u5+ )LvБ\cLr e"8vDM A#:%CZuT [. +Y΢!,2$"**.;<-H<]G*oJ=~N@P\@&O;[+po<OInw6=wH+<+^034XBFEICY]`bcթ*ڮ210A55D1 D:"%F(1p!(\X ֺɀ"-N ㅈ+$ӧCpPF<"EI}13O *Ѣ"%-!,M$"+**&;<-H??I+T,?T,?^0HASA+]C=~N=~Q@P\[<gpyf<f<OI[I$Zw~,IT47;%_L`BJ`dZbdcdžВڞ!գ3(',>0:3E2;?_a`bNVKPT]baaaـW + +"2-'/V@8V*TVV(WUPUO1V= ,7V:#V>4VAWVG9R%UN.LQ&UH0I<̖$v`H?IvYAMXbE4@I-)A(\d )) P^\fL"dn5h qi)!,kSFG&JJT !,h$"+3*&*2)<-,; S;>wJ=~N@P\@+[+OIf^+ew6=RMRMR<^^II^opx o)3@@SBWAIbbb̆ьУ3>2c`bbbbaM@GITYW\baaD#&"$( BC@5>A 8@/'C<2C=!%C1Ȟ,@?BɎD C-+@<5؍C.*@C:7@իtj!9Rh6@e(jdwA $@ɓNLҔɖ%,qf[!,$",**&*.)<;.;>-H<SD*oJ)~S>wO=~NP\O;o<OIZo6ew6Z~P=MR~_<+<^^II^gw$~8^x o)w,33@MS^^XBDEICbbc̆ььթ*ڮ2(0/AЩJ244;?V\\cbbbFJQIUYU[bbaaa_ .5!4-& '%OW[^^Y) Z^X$PU ]GN^V*0^F;^@3^J 9Y , ]A_X"\ \X1Y^<^=O"ҕ/+!ɐ?'^=sJ 6nK.ʚd0"@n׋YU&YʈX(^"Eâ5`2PȻd>28J,X@*VulWf϶J[G!,$"*&)<--+,H-?T,)~QP\f<ew6ZwB=PMRdU^^I^^o*o1~5x o)4@SMX\AEEc̆ь֒И"Ʃ7ƸGƸN˸K24c`bNGITYW_baa@4YȤcUI:T (񮨧@{=0DxoCT$Dd0F2А :"HpqsiIVXI[7:W9a=IN tH0<6<.N8;r5 2_0H <&_[p-1<3,* ȦpW<04cn_M |I !,$&**.)5;=-H<+g@*oJ>wM=~N@P\O;o<OI=~[<^38ZXBFEICbacdžթ*ڮ203A?V\QbEJQISW\baaa@pH,Ryl:s2 6̄-G]U`3E69M'89`YPv d95v: 91  vx0]F"5$T!93)+%C79/S,'D92vCsC9(N d3ON -`NiVG߁`A!,#**&*.;=-H0AE2?V\_a`bNJVQUW\baaaJ% % GII FDJ$I0-I1#I8*I3H>D HA!Eճ";. IB&)'()ք7@+?6PH"@I0,Rxπo4RD@AT8j$FN:2˖%It)sfLJ!,$*?^0=~Q@P\@<OIN^0xgxw1eImY<<ITgo1w1~5.^Wa`Sdaьڼ:гGPaIM[\a@pH,R)lǨ:\Z$znV2:]* 0.ӀK.^˓f  k)BZkE_BX'DY`rB'CaB(D(&! v$B qќQHޡaA!,$#**.;.;=-H-H<,H-,H1?T,wQ*oJ)~Q=~NPO;f<o<OIZwB(S=Q=MRMV<++<<^^^woo*o1~5x 43MX\XBCVFEICWebc̆džь֒֒И"Ʃ7թ*ڮ20AƸGƸN˸K4?V\c`bNJQKUU\bbaaaG"]P\J/\A )(+ % 2$2&1,9\@\[\WY X\V#] '.\>\T83\*;\D0\Kӂ\<\?>ZV pC+0`Ьٕj`ElLq obEi -<O^@*Fh0M' Iȉ" 4iX(PX .`^ U$OfZJSĶk!,$&+3*#)3)<;>-,; H?S;?I$>wJ=~N@\@+O;[+OI[T[T#Ng:No=f^+ZoH=RMRMRmW<T II^wop<3;@RBWINbbb̆ьےУ3>/3ƸG˼N28`bbbbaM@HBK[aaaaЀ0<;!ONN6AJ% DH +-)M>LJ&1#J7.NIO*,NG(**N=3J"שL9N42J'LN5PB"_}qpb!J@̴By1d,QK8 |. jlIs婚4'̤s'> Y !,7$*)5)9;.;<-,; H-,H1?T1HAwQ+g@)wJ)~Q>wE@+[<OT[T[T(Zg2Zw9og=(S=RMRMUvU++<<I^woo)~-gx 3.;@P^`BCVYWb̆džь֒.:иCڼI2>=Z`baMH]NR[babaaaaT (2, % 3$3&.2+7SISASQSLO!)0=EL#SJ6SK4S*>'5S@S<18 S;: RTL>l`Bx 'Vg8#SxL 'B=8HB)a Cj"LDBaGtH ylt*IV:ʪ׮t,!,R$*)5?^0+g@>wM=~Q@P\@<OIN^0xgxw1eImY~[<<ITgo1w1~5.8^ZWa`Sdaadžьڼ:3гGQPaEIIMR[\aa@pH,R)(qIjvH]:2Gl]%ngdWȘ#.O =X|hsV5S"5}]B7(F%5'gs8B74+#) B67/ZB m0 C71pB D7*Gl3P[R,~RԉאUKA!,m$#**&*.;=--+H0AEƸN˸K2?V\_ac`bNJVQIUW\baaa0..!Y1X7 X6,%,&" UXS VX#Y4X<*XE+X;$ʸͼWLSX>ǔT WO'˘r(-aQH(W*,5sJ="5H1d &Br 0 - @F /L i{Q^8rG$xp".`KD`DMj:o֬^ +j,Kf. !,$"**&--*?I+T,SA+]C=~N@P\O+@<f<OI[I$fg/og/=YTdUwO~,Ip7<;%@LMZ`BIL`Zˌ#5ڞ!߮.գ3'>0E24_acc``JNVI]abaaF& ! BEE$E6F%E0EA-#,)E29A D? :@ ӵ"7.Ȅ E59E+*>4';E1z1%8XmR!^` > ` E?Q Ii$G&O6J.-!,$"+3**&*2)<-,; S;?^0>wJ=~N=~Q@P\@+@<[+OIN^0f^+xgew6xw1=RMRMReImY<<<^^IITgo1w1~5^opx o)3.@@S^Wa`BWAISbcbăьУ3ڼ:>гG2Pac`bbbbaM@GIIMTZW\baab L":^$5<3%6>&+M^4,-*`a^/Q\_1BaZT^G=aYNa[27aK +D,ޥC^(]' `߂8aEB^``"W{!AAX^R,! L2A!n\D@J*?8 a($B31wM=~N=~Q@P\@!@<O;gf<o<OIN^0Zg2xgxw1=eImYvZ<<IT^go1w1~5^^43.^XWa`BFEICSdbbbb̆ьВթ*ڮ2ڼ:-0AгG5~,w6I\ggwouo)w,367.3<;<+=84@@IFPS]LVX``BCVWDIEICMT]babcZabab̆ɇь֒֒В՘ے#Ǖ8֛"Ʃ7ר*֨2ڼ:*(7-3ҙXBƸGƸN˸KЩJӵF53>YGUKV`accc`bbaLEGSFIMTZV\aaɤH& i‡#JH Zd1ڞ CH@jeː3n|ḮN0!nM\щH@?*5+bfСJu)NU-dӧcǖ=!.{qӓT=;Dc/f0Ue~O+qAÈ@,p⟚ߍ@׼120;Bm#5J=N NH@/K(( +L|c JDJ!zkء`Vx>z͟G"@2BP7P{ǜsН]w _[pěo 'V'P~l  FPcA700+$X[R ]8#wdqJ&0PG{bH!j@~AVhXpvuPQ0R3RC.p:'qz@/#=O4$S<¦8g=BEꔩ5 }5S $Agvꨚn Hi~h",~`ch>jBT2}V+*MV7 x"< V!:P [,X*dغz"&HC(R;C&n:iNQZU oM rz1pK> y@Sp8c++P\>@s?=t r B>@R-v@ Mt>F3SWl<3'5ߜ4,P{/ɟ6/XkQH4I3)l\,s咋~xO v2H ogJ9䖋>xc:#?:`;wGG|ȶ fp} Hԁ  6To @(<0$`A@uܰuBͥ QC&;* M@`1K BP+ %kÂ";Ah r:y85a CFwEBb.˓B8WuH `*@J(xpS .LIe&u:''Fq1З04$0K82$t)cvA{ԡ ֤`Y-$Dd*Si&5#N&U %X(KyJTCV$Jam&V `'s.d^ɱGZrZ(-IrLE,02 ZT찇!S)AVg@HG*`ڰ=Q`.nK)UvJR.NS DۂV»`EdjOmD()sIb*ô1?UdԁT@JYnUq-`<´yؠ( 77$|N1A6E(WLkmA/Q8šXa0 A{ t"ݡt Bڣ>i/ ׵1+AnkݎF"o5 -u;j mv 5N򬽻-Z2X`TSsnﱍYةk7"OcxF2XJ<5`  ixk❔";xwRe|)EϸRr7P3xg; \9p2d'3ي"0ۓlb!uN e1WmF|f4lT~GLGL<9XA.Zƅns< قSQt8ы>r)KPŮZzNȟ+G; vIrB bMbvʋ(jܧՒ rwj!A˦n%# ۯ[ Ӿi/ ۮNHHpJ7Xml! wJk}\Y.vX!m06h:l BD{g^%+Ǜqq$ qn~g/_>u6MZvl1@r`l=mTZ r }"f a@ p;'$#IK.x]wm(dGYÛO)bzԯwQ|>eICLO^O }⧞E@$;ЏO[Ͼ{O׿~NP x}eV0oHX|Rn`H~8$X7mg0H&2841lk 4@ !),<8!8B؄N88 OZXhpUfx؁XtX䷀W,0vx~X7~"׈8X|Xw؉X!, !$...Bgr?q.@O.@gBPO.\/zz+gAOOOOO\\N\\\(=ZYm/m.wO[p@N\\\exfxBPPP]ggg)q(YYwȒK͚J͙XҚJܲmlvӞ݈Ӫȸ徆ÆɆɎΖɤɣݣsZja1Fhi`I <`/#g0>qJp)sf pr*o-po&^sP : GsLHs6@s7As3!sRmrVsc sBsMDs5"r,rP "1':K!oҭ(ݒu+lؑ%ns丈HmJӆM\SF:j L97a- sܜpXฉ@9d@fsTa#'X.@-0Db0pC#ۜ(P"waÅ+&\vc/N,qʖ!,;!$.BP*{[qez.NgBP]g/q/\BfBfB-@ez<MZA[Ox--Oϙ/]?͓;ҙXʬwΟӥؽͽ¼ζΪΪΖӕӕäؼ@pH,%l6!lj)4F]\TpsqJ?tvxD"M+rwB-SS1&i=$?/?pLCdA?d/d-dF`cHdX d:d,c&ςd9;#慳WPƈ4̘ኆ A76 - IwL2.,d@2Q.Zbd2fDV,8$)d(E]y0̊ABj\@ BMϪ=v[m+W-ݺfE.!,!%..r,].@OB]OOOO\\\\\\fffgNfff(ZKYOp@\ofxBBPP+P]g)zZxwȒK͚JҚJܡXȦmlͷ徆ÆˎΖɤ׀MB=>'?FC"48/K62LJI0M(1M$ LM8Mċ&ѾM)2M5,-.M7L3M#M%񞽅~ HHu, &=H4@m1*V\"A8VLB,hg7qV $QDCz!,!$..BP{*{BP]gqz/gBpA@=<KcmP<\xAw.N@OO\\gfeޒ.,BP]+P]]q(z'z'x<͒KךJҙXɊbצblvθΈتͲ·ΣÆˎΝΖӕӛ˷j;OMNB$VCQX";YAUi(ji&%cj_ T]8jH3>jf#,jI[hgj-f5jGӽ^Wj17fPiRf6j/Lb(0EFaf%x&@5*Uq ӄ\蠦uH@ / 0ha0A[TS Z gdFM~h(;1DKSMW)(%h =ķ拓~#,] Mx1㾎!,!$.BP,]*{BP]qg/AAANfff]@=xʒKșYҙXvرȈҲΪΪͼ@pH,R)yOH.kRSjH S~q0r ݋)P+,&2=; =6|~CxK4;1<Bb]5B$;JB#*.P-'2598 re<(!x{o=\̉I<%nosF7 DBVCu7_D H^G !,!$..B]-B*q.@OBP]AA-pBO@OOO@OOO\\NA[z@ezOezyqN=<L.wpo[yfAAoBBBPgP]qMyxҚJװ׸ܾ±徆Σ½Ɏɣ^R ;]")1.-1/ (O]0+,'=^YKW[$>V 8JQ]#B^D 9^L(A+^F%\P[6:]!Q=h0x"5DJ U2e^T\\t @h)"ɐAtAd^@XȀEIL]KD%K Y#״ZJR Z);Z+td!q/mZTڠ\ 1#yp! 4Fp@D $@#!,0yd$CB &<ӧB}*u*V'ajh+ר!,I!$..BPg{*q*{.@OBP]A.gzA@OOOOO\O(<LKYm.wO\fAAANOffoBBP]q)z=ZÃ<Ί;ȒKȠnҦcvɁ潽±ݟȲ½ÖΪΪÏɎɰدݣi2]e^;PbT+7ih_A#f.S\a[ d)"iX ad(gF igh'‰HJJK> hJgi0i-6*iaRE3iBOiY5Ұxi@4c$! Hq.޼l̬^A$M1C" L!cF*r@+4 4Zxȋ'(RB'zpr %mh Lv-ۧn 6+׺s!,d!$.B-B*{BP]AA-OOO@ezOezyqN)<-nAyfAoBBP]qMyȒYҚJ׷ΪΣΪ½ΖA8%@ 7@'< * 0223+A"?:ě$@ϖ&@ˋ)AA165-ñ >A9A@.(,Bj $@D="Q 6.L%r##;p%T!,!.P]{*q.@OBP]BBgBO\OLYc.wOfAANOffoyPq)q(z=O\ZÃ<Ί;ȒKȠnҲvvӁ汼ݟพ½ÖɤÆɎɰدԀO;J? '>1L#F =KOA25C&4Hbd#4y-y䉉Br@`$߭AX2T$͛l⤩sgMd>y %QB!,!$....BP]{*q.@O.NgBP]A.gg/fBAOOOO@OOOO\OLY.[AeOfAANOfffyyo/Pq)z=Pq)q>z=LZÃ<Ί;ȒKȠnv汼ݟӐ«½ÖɎɰدݩjVe\0%YOP)#g3@6Xf,!j_ ?i+TjLjGhi(i'jSjKj2>.=jZM8Ӄ79jHRja:j1(JR /'jY! d,FM-/a@3 d<($B .S8w8R%8L6AEF KE L8B$Pp@֡];,[n z+ݺ|!,!$.Pr{*q.@OBP]gOO@O\OLKYOfAANOffoPq)z=ZÃ<Ί;ȒKɢmv汼ݟ½ÖɎɰد@pH,Ry$F^8 ئ%?]j `h5ۍ(3J2y{}vIZ=$JI=Z"=+.=4#=ZJ,=IM=< B%B&B;6 76 ;='=5(7=!0zD-J)CWB G FvlBkAe*,P ÆAR)!,!$.....BP{*q.@O-[qBP]O.gAAAO\Oppy)LY-nAOfAANO\ffyoBPq)z'z=xZÃ<Ί;ȒKȒY͙X¦mȠnvɁ汼ݚȷ¦྇½ÖˎΖ؜ɰد]JXM(Z+KY$]O 12' ]@[\#7B]]*&\<4.5]CG]Q6])H]%D !]IP]]\/8[SpeAtta1[fE+]` `:$bʭxQ5(4P@IX   %% Xu Ef$բU25ꬮ!,!$..BPg{-B,]*{.@OBP]A.\/AA-OOO@ezOezyqNffp'ZAfyfAAAONoBBBPPg*g?P]gz'z=qMyoy<͒KҚJӈץҲΣ½ӕΪaU"A`$6:8'7;(0O`945._`-S^\1DZ TaIFaPa]/=aL0H4 ڥG`)^%\ۂ>a2,Y  {>1h8H)yDTp` -5(9C0K(Y, R5Y   DppЁAʕܭ\$vlf)Kg !,!$..BP]-B*q.NqBP]gBPAA-fBpBO@OOO@OOO@ezOezyqN)=<Lc.w\oAyfAAoxBBPg]ggqMy͒KҚJҠXװ׸ܾ±Σ½ÆɎӝݩf!Y&@e'586 4-3.Ue723`c)fe,+B_ GfI>fQ%f\ Wf1.F 2fdXcEO="DŽ?ePK9t C1*)qP a*3_ "a@J̈QC i(dȒ 53ZHaBh(* 9/U@U`$vfM[h-[!,!$.{*q*{.@OBP]gO\O<LYOfAANOffoPq)z=ZÃ<Ί;ȒKȠnv汼ݟ½ÖΪΪɎɰدA4<6>5=A7A)?@A,../'A" ; A*3A8!Aʠ+AAA@#ٖ-10( ?: ;: jD%} L`@n" Xh#ņ7 ɰɉOQ@!,3!$..BP]g-B*q?qNq.MzPA.pBO@OOO@OOOO\Oyff'=<LZKc.w--ApAAOOْ//BBBgg?zM(),5(,EQLXI k,O$i)u8g;u8e=t)5K%\EvC"(3)-"6Ð5ױ5/(55[KmfpKhoexpxq(0/&6/I[-qi7Wku/O\tNyozZyo* :/6<(@6@3yx"-<ZxLZYmw3dsE ?|8'!mڠ3{{.}Z E.z4mkWzcqԬGLe2f>~]{10'I<& =߸ S/hzv{^s/jTyh1|1c{# @ ٤?DBTs]:xŷ@Vb%^)&f]&!Au՘e9Lgn)P[ DB AB#]”j#Br1c  @$CB BB2L̬@E`&Q+ qZ*ΉP%O]^ zPƊ췤1n-.A*P+Dn@QU{@mn@ j̪oŷ{*0@ƪ pWDy!ѥLϷHA|u ASY:e?8DWx=I 3x@'j#Ubv2&?5鵷O9uZB26z5fX8|SKBbw`cX~fn@Yrǘ Q菄stv.6Akc4 S2 =w겏B9NS}?Sn9#d| Q!w|c ܑ}=su#a@1f@$^{&_wI]Gs[} /_@C`?7QHׅ"8%f/ +ᯧYv"s~LVK>O0v|V5Q%OR5Œ)0]Uf0QoAMe ]S= D )<,tR M4LkөɎPt|7dc)/rU d_1IW1B? |ZMB "ozE LlO߻tr{tzcO.GPc6]ZHGճp]^;ĞS}̣ oxlҊ sLBUhf9IIOyyZk2C45ᜨ6АCEѦ'H=Ɓ|{gt vVW|Ugrշަ/~y>RIKVDb ~B9Q|zJR<4pƕI԰M8r=t\#_"WV2tlCyg# }lj5t0|yIsFQ2RPEA;%iTUAd#E38 s{8?ES0ĄVXKrӅttH_^BUx!L&|rMBQ6| 9sT8g<6uOskNr#b?0Q")c@@`?B!=M,"-Q?Ӌ tAH-@Q0H|XθH׈|h ኪ! Qx@ +h2+eáǁ3#y: ِ9[!"qz>nOّ)&y( EВ.YEB0NE):<ٓ>@B9DYFyHJLٔNPR9TYVyXZ\ٕ^`b9dYfyhjlٖnpr9tYvyxz|ٗ~9Yy٘9Yyٙ9YyٚN吆$!ᚶ>ON0ALNO ٜ2)ĩ$Qp "yWQ^tiHP  MU0 ihUOYU.[0&g(e3"9QVA'1"%]١IvXT`9 q!=&)6"ʛ J}>Za5%p`A -2*,1ȷ,,2* ")s+XH3gY2b*)Ǡ Lꡌy/=!JO7ʠHQIɛ:06F$騗*hX[ Er<,"2ccU1Q-$R_gha,7V e5rP/99ɟx *JʟZZ7z!UyUY[_rh 3z2 6l fP뺲ۺ*x.A [U0}kK@8:]kc3l$ uÏhVfuYVi K/n6,d5[hBImА˘Jz2>/?8zȷQ $* +^F/+=BXE75se27V"1|tF65 -?&9J<[CAI&J K Z\[knNzxyE2y!{[4҆ {a'tZk}n&]x Fܘ 0ڸ飗7r;iNpB"ZVt/!{8+<~X4'<݁˔UɎ@|܉,<`*эH )zjZc Ó܎a V AvaM} =~h$Qd 7m' D!M$-*,.0/l@¢e<%)B] 3r0G8I= 2 ^v|CQr!{hM7un= "|"pkiP 2b,Ȣ,̒Aa,c*1ihM#1SX ^ 1d!, Ӌ:ޕn"o Q8Y1y1&`;9e"ѪP>m5&γ |x`P3>{STEW$p׫ hLl+Zr:}dLsHEL!!=%2wtL7~ rQQȗrIUR&bW#&!5R+܁kUFXAohԻCDNW] VE182yqM>\&e5S^t+GR[V`"=`5EG>I~Kk|ieZ{R-^Uve{TK/f?H^n}3W=h`%`n, &71P&NnmEgIgGU@+ d.l~:Wq 3%'c9w<@&sLusD>&VL#X|RH$ҜNV]#ڇnr]1H*+ |H=8Ә)R6 "! (t~BVyqB?L/Nr!M_VXZ\^'Adɹ )POM  2aA`Ϟv+i6}L۟ʩ3 ZM @p :%z)z-Z X7木)>CK^Ff47ք{)$d@ƩHɯ/ ~%S:3RNj-R|{ }*lz'U XР'U8ФGL Cݢ(_-O0!a@x`šBV!A0@…4asN!G͟#W$=UR*(U+:Hi`Z%M[u-KqΥ[]y_3D0CXdIς? 5HDE07B\`:lL-ȑ!WԍF7! K&t&($<24͋č. S9"Ik:+EHKUV. DU#[?p@ 4@T LH &RA" ("H('n j;m-ykLBH cN (G&W6GD#O2@6ILJsA4TsM6ts¬ 2l\(Bj kBA1J CE6ajK/& ri(s( `lSPZg(] rSŪ**-~\) `}XdUvYfS,6IA M  X$D<ҀRaF(>h:SAdDb( PCcE(Ѕ64.>D`PJO~a$fMmVA:A<ࡧj6:5 *P P):$DC^)meXH%LU ՖSk)fZ `fEZW+57%laS<kN8x n>PNXf|X4T J`>YƆCd=g%+=A@ZVy5=4W\6j?2q4qבB<0qI=n{;VæW,i%zцLQ) NVѬoDDd5yO``~UԖ=) pC\K(Z@QVo}Dwl7R (a qzU IiVujzw\j+竄4Dp`/O0o!\"B#,]cYZQT*rB\ǹ7쀳PXnjHr^N5ėNG?.G=`#4i/oz"`A 9VKgZsWIg# _u@PNɁqKn l]/BYxƅm*d墹u)mrඩm+>_r6G &n[[ ͆2sxtWP q`, _^6a; v8 -c!S߭HNs:'OrzYԄGhłW"׹Q.[txXߜ*|xՅS6(1$u\._ū!- .bH3V^=)z$0V<-/|@V~^v8gz8sL ׳v9bD }}{_'~|'_g~|G_/i-6ܙ~19$K|!ΰ9h~(XG+@$ y/@+(: o 40=k,PD3t$ hc@ G!AXjHH% ä)K*"4$:̩ڢ PWCl3.#% BC,->۲,◮jBxhHZWcC7<8l3*B=L:*4`6̸- 4QD("CK,>:<+A a/ChR+Q􈹹+KE?NԵMpŖ~-lPd Ty8 I$MY P包hSXNU8MZ[̀\E΂2XNN ,\ N[uUbMVVb5Vg-V[e ^]Ui}U/VXmSb KqUbl-VSȌHi (Pi9 xͫԔ(IT/`UK=Ӏx%u=ie,OY VU/-̈́REQ`/*5S, `N٘%W/ؠR$EYeé܁Ҩ=4eYN/گ-O S&:Yw] ݬ'А~e EE yHNIU}۬ ja]YСpUYRROTUPe$k5<mSڵ[]U5Y](m׃M]MU^^u]mWu[4[ݻ}WQ;T%Э>iM@Y(=EEP1]% Ȍi9!qMjY8UĈS%alSZ3hj N`T`Y۳LhM^ڵT ^ UԭamMa]N .V<_xlq( &+q!XEHLY_P`.(ѝ%-^[mU/AݽڃFZ`r NCv ^D`]-5I]fdOR.@%f❹))\me..!XcXUUNa9ce\h(ñ7%Nh 0.=cGfZt^%ES@gffX1%-y>YU]=~&Z~nYf^JY$ٛmN!qq1䐋.(0JL_5d6c31ֹ0TP0 q>&W@mRhjuUR.hj>fd̾gkAkVP:񌅮fN ^6lY2GGlT5 l AOb N(2;ՀilH(eGu̹`M&^nV\Pn/agNLոNF/jY@^^&F9 N>[fn̅NJ 'p"s؀p!^D o^? 'g'7`gq Lj 7/ge nY`޻Wh"OUr'r(r)r*LZVH5H0Sst6.g斐˸<m6s/0GKS(tS (tځCWN BS /MZF' 4!u@OoJx͸k^Mju@u TGuMtM'LGy*]_u [tHtQlOmLtOАO[ّf].L^t]LtitP P PAc QOG(2_Ѝ7iwHkgxxH@xHySy/Pg^G8 tBz/s/ـXxzv_e=fO*SƕA}_x7TҵsB ?Y*vuK Hv~loxPԈQP%5 FT|[u`'}Txo_ ӷ_ |M_}|Ї}I}avΟO}ؗ}o} ~_~~p}WFxyu | 8@ rW_ l0|T@uKx]xkX T!I*4†*`I-6|Ɛ!;ؚ$"9Dٲu@ʗ0iQ2dJS=~آygKG<} =XBg͖r@R%K0jKhO,M`IVPnT3-ۓ۵q-ڵW+$@&7u$f3ТG.m&ULUfW-fg,2raޭC;T 7+EkS]BŸHG`]@u]11jHD' +"[ɄO TzYI ΁#"Eф[q矃 ҔYWOf)H"g!Xa.ȒI6Iy Q%]y$I*diQgyEAgUB !D9T$В-vl1_"ӴI+4tyI M @'a TeqwNi49nb_dʍ!睟Ԭg5ɿTX 9c=$h7=<ڸ"E]lgG[%o4k&e`)t3/}3 q1Fb]pRZZI -䟱??(`OL@A?U0g $0XIpNlALHۤXȟ~-5bTae 4fVCJHxQJZ@?8!$^,\ D=`6ZJct%@Zxp^kT ta\V2y'l*CCM(᮴RIİAc$CB(őwX(UɔǒCՎZIQ998)qHaKI%''1Hie2HOMhF'3L`s{Tpy,4<w~%$v3 =]TcJ9MxJ;͉R(F3QMģO@% (JSҕ.L)R1+)P*@&F:@z~N}*T*թRV*Vխr^*X*ֱBKlP W,`jUd+^R$AK?h!*$v'` kXRa-aY84-mH:^}4AIҐ 82 A 52"A>DXtC #A*HHL@0aBE?! ay]oHc%|黽.wύ.l7yxmWaT(:xA>!bv"Esb"0?(x8Ɠűul$XĒ@M"&F1,)'k"~@ih`,oypgJ"4+Ö`s\"`{LH6 V:"-is6Fr@D/h X:n?Ͼ9sfc-͙-*· qۙ%C9BqWGT@vlَN#:Þ6F˳34t$ dVTkf`-U.h^c7ՀdCFDL\Xg3SD3BBn;dx)#"?U@]XA؆M&۰be $^,dPHK<$CvF%IE+HHjJ.b@"1ߣDV[_db ELLTMRJLNKdNe%df`Q d-JvXڿ]yƁ$$ffB0 h Nd& jݥbfVe ^itdeNTp HxgDoԥ0'ͅK|LJzL$m^'VpcD^M'ouNrjjΉxNy2J'DMT)Dl ,b'U _f-`̓\gNBcTOQrrg6ЄBEpJQ )&V|$4d$Q(LP! y"\8`xN%ɮr 'Z& )|RH$Y(]*eҝ'vW%>Ti@E@Q1DәbNtzXHVXN>NKNe$M)4!!R&*V^*fn*v 4\$#@ 4&4ZDjjDv<8 |8LjgD@,kوѱg&Tk*$najPik'l#@H$'&@E|'8 *2 n'+EkZRIm I*#IEՀHl8k&x'(EǒlPzl+^2 kӄ~B̞fϊDl FTDZ 4mg[nQ.|`-]I4'֫٢r m۾h@}F|5ކgm', B%B# Bh̀҆ Bvf Ā2BO. ,鴀" D^g@"$"6)zB'""BngoEnz\D|SOH0lJFADͱU-/TH- ¯,T0BMjK؆jLq G/A/]@z,ayF.bȶFk'k.ʦJmzlfp6[D @ ZpϢJH +N. {bj,,mF0Qq؆H`pFtIz 41VA'0"m @,1DGmqDdlTDqW1jB b/lB#rO'.r#'0@掭@Ȓj 0Z &B ~%O+#4 3#&s2r 'l-1+2o*'*oql[ފhk1*l/3s[&+gij>}FLMh9>[ICZJsۚ*mNr̶k'.&/J*t.lB4grHBDc2EcF`45WF 5.nADȾDDL0MM4[46ʖp pA tmDjITs2)'4"4XOH 5yuZv"DPB$N3҅^]+g/0 ;3 _4N3tH 3eIPcvgPP/ s*44dKj59ך 6a4IW'I,Lp- k|P0qgh,,$C0_ldf6dOnuo4hvc_k^vwFNPw`oNw6=nh7iO.wy*pW*۠o@q>dlGỲI7fhg8f'2:moĈE^E46+7\reJvK^W􌓵,D4"p-swHlM_3g8Gv?57r,wu[y'Lj|lMyGf3v o+ ϘOH+t O4bkxVpVy"۲*yKfC:&\!ky[̪w zzֲO9.{륣[+GQ[c;ZzlhQFQ:mTD݇S5;~9<_v#gd˵Wji؄Dƻ2:Z:kֲȾD{g׫(q0y&&`wfŽ#mK<ū,&sisŷtcʳz*]8<B5}HPg>1Ӄt?Ko}ҎJn'o:ٯ=J=h(Cǽ===R5C9T2=+nm5M˥H~m@l>? ?1agDݷmD(5ZٗzyUu1uW;W|W}SC;!W}BPua YADR_:  c.>AڸP<"1*g$FJcbdA%R3̔7DWT%.y4gTSVzkV[vlXcɖ555$F%wlxwn] NX$$.IG}rQ]Ŝ)IfrhyPFDߚ4s zPFV|r"0xpÉ7~9#n=pwK7zF0nAiPr,haȎPGEFQԔw#ӌ<{! L6pS)>ZzK - 5%0(xD; =b0&(fh&rp$Aڊ4oB|(J<,2,Q |4fTp Ii.*1͜I\08;F1<D]Q!0#$4(&Z6!?it 2L^~垛ޛ ?qahoa7$oF:źM?=8O>īD>y]X}DH߄гuR\+5M8WMb_OGr}z={f>{'6r*>)u3<|Λ?Q2 F |iA+H:4WO BA ZЄ(!"P!| B*d ,T\XAP0)aAlgnv8_4>Xt7>-P~ AWW $d^N-hAEF3y \(Cwhc׻/F]p!c w1b>DO##WJ7kAMĀwFT W<X2{-%:PuT&,eI"z&L0e9xEWd.E1*>Eߢ:a s#3SjCѥk?;[ˬ^Y .lwFNmNVDu>_ e{>wfrBuQ/7˫^FOH]^w *E67 v/Ϲ힘o;Aڨw 7!޵{wcVdƽ[֭!0~ۉ-/D)M Ydd&?9B5 H0+y,2Yp>>ٜ_9,):MC@/D`fh)b [!HKZq9i )ٺdr@]өVuqHi_.N߯J:9]2qy6MNOKz͊e{*P1_HCw\s޹a/}yVCwUnmy,Wqx>>WvoOg|N7BՁ _xD 4x ?uߕHpr! (kP]8A31@\@ n$A6 (//Dxbk~gO:O̟WK$-3_*B-f/IrĔ$IF(s-6B윜 !vl" / wP*)4gyϲt2p%8!.I*O2&pȸBN2t6  -j0n0#?x:pIϼ'*PzT@Pd|pѐIʗ80n)$+݈P vѶpfl j/磌h_I Miuhu04A08M,1Q&i'gp8RV-ԩ@ܑIln(o ʔ걠JKk؉K' QI2:)!ΓJvJ*D QN$߇$-8(r iR"!R+dm' wK=~N@P\@!@+[+[<@;-gf<OIZg2f^+og"oo.xo2M~L=RMRMSvZ<ITgoo6w.w5~2^^op44:43>@@PBWI_bb_bbab̆ь֒Ӓےƒ$ƒ)У3-,>63 A?;45:0#5!qto8(tRto76eoU$Dtn_oS ItY,tk`tQu+tZMo.`nMtNHo9TL *gATy2H/Kp9(Ȃd޴0 -2ZC'M1ls ѱ@ - xkv5 sO "8 we:Py=$MB#h^pA{dP3Jx;ጭ@!,;$#+)<;?-S;,H-?T,HA]G*oJ)~Q>wJP@+f<OTx^&nw9ZwB=PMRM^o*o1~54:!QMIX\e_̆ь֒И"Ʃ7У=߳;(3ƸGƸN˸KH284>c`c`bbbNI_aaaˀ0"EE#D(8D- C7قثD. D' D50qX!d #  2#G>E# Y B>P20_|&s65̩h'O!,V$&**!*.)5):;=-H=?I$HA+g@*oJ)wJ>wE=~NP@+O;[+[<o<OIOT[T[T#[T(Ng:No=Zg2ZoH=MTmWvU<T ^o)Igw3<3;;@PRXBYFEICNcbcےթ*ڮ20/3AƸG˼NиCڼI28>V\Z`baMHHBJQUWZbaaaaEгG2P_a`NIVM[\aaaÀJ=+F-%" ?F' !GII#1DI6$3 0I9( HC&֘Fڝ)>5,F敄 I<I42A:\Iڂ$Ev?jZ4p(h  "Lii%F._"&&͚3a!,+3*&*2-,; S;>wJ=~N@\@+[+OIf^+=RMRMR<I^op3@BWIbbb̆ьУ3>3`bbbaM@K\aa@pH,cd,*(4C:"lHȂ5p`-FJU0!C.~^0"C.T0,).O(0+'wgh&c0$ ^C \]NDtTBtA!,$#**#)5):;=-H??I?I$HASA+]C+g@)wJ>wE=~N@P\@+O;[+[<f<OIOT[T[I$[T#[T(Ng:No=Zg2fg/ZoH=MTmWvUT o)~,Igw3<7;;%@PLR`BYINaZےڞ!գ3'>/3EƸG˼NиCڼI28=Z_a`baMHNHBV\baaaa#?KJ+c)bbBU]0 V[ $7<1'<4-&aO (b]/_.@ʕL,!=bN;bD%3Ө"4:bZ244 aFY2|PbC1ʊ,5pxT JCq "_qф)Hb&Q(}$KLE E**]mJ]TXC6+,fLv-Rnbz!,$*)5?^0+g@>wM=~Q@P\@<OIN^0xgxw1eImY~[<<ITgo1w1~5.8^ZWa`Sdaadžьڼ:3гGQPaEIIMR[\aa@pH,R)(qIjvH]:2Gl]%ngdWȘ#.O =X|hsV5S"5}]B7(F%5'gs8B74+#) B67/ZB m0 C71pB D7*Gl3P[R,~RԉאUKA!,$"**&)5):;<HA+g@)wJ>wEP\@+O<[<OTOT$[T(Zg2ew6NwGMTvU~Y^^Igo o)gx o)3;@@PSBYAcиC߸GڼI24=]Zc`bbbaMIGIKTYW]babaaaK&,'*$8@928BGJJD"D!6? 16JA#)J . +CH՛ IK˯ 7v(Q>o8iGFfZpi욗LV?H[+zxeƣH;c&@4*t(F!Mh)J'65!, $$+3*&*2)<;?-,; S;?T1HA]G*oJ>wJ=~N@\@+[+OIOT[TZw9f^+x^&og=nw9=RMRMRM<I~-^op:.3!@Q^I`BWIbb_b̆ь֒У3У=߳;+<3H284>c`c`bbbaM@]K\aaa/+V TDSB(-U,1* $ 1) LUSR&4UPE FU=!MR;2UQ.?LR#VTE 7U>0U:DcP )'!HfhH)ޥf g㗇*Ol 0߈D,H/ dVq2C <0VE $$C u"zk׏]~*+ٲMvms!,%$"+**&*.)<;>-H<S;HA]G*oJ>wJ=~NP\@+O;o<OIOTx^&ew6nw9=MRM<^^I^x o):3!@QSIXBDEIC_bc֒թ*У=ڮ2߳;(03AH284>?V\c`cbbbGJQITYW]bbaaa,(Z XBW@ )/!.'&*YJRVYYT$ UYS# LĵGYQ%+5Y9-YD Y:̷S" WSXC͘PzQ! AlOɧY# w Cxs   ?Nj"7X^=::Ҥ',!_8( @ @P9-U *6,ٲ΢vn } !,@$#,3;=-,;H9,I?I>oF=~N=~Q@P\@+gyp+OIN^'Zo=wNK<Ig2^Y_֒Щ34ƳJƼRռM@:\KNQZSca`bbbbYFGN_KWR\aaaàC.,*-66+BB> :AB!2@9 C/8Âŧ5B<Ϸ0>"ܧ)# @;ٳ4=԰!ARN GGf]sM7"y+717)G36W8GQ+0 RVsG7!-K(,7.'% XvХ/b`HrZ齁A!,$"+3*&*2;<-,; S;?T1>wJ=~N@P\@+@<[+pg+OI[TN^'Zw9fTf^+og=ew6=RMRMR<^^IT~-^op.3>+@@U^`BWIMabbƌ̆ьߣ&У1.<ڼF3>cc`bbbbaM@]FJOW[W[babaa\#0-$ ' 4+ /4,ISY[;8[O[D ZV)F[U.1[Q2AKV%LV?5\V&E[@3![C:P"  l1(8W@@l1 < ʼnD$"ƕ->؉D@ɖ&6#V.*?ɘ9h]A6&ba%B .HSa%r!p2lI`ϖuv@!,$"+)<;?--*S;+T,HA]G*oJ>wJP\@+O+O<@<OTOT$x^&og/ew6nw9NwGMRYTdUwOM~Ygo ~-p:]c`c`bbbbJIK]baaa+(Q O>N<&*P#" )'$ HPEKF,PAP6 JEPL3+2 O?ֿAL%QP1ACѻq/~Y hV_i`[FBv $@ve+I "8ā Cm El>4ECf"( `aB% 穪"V *֮u"y!,$"+3**&*2-,; S;,H-?T,?^0)~Q>wJ=~N=~Q@P\@+@<[+f<OIN^0f^+xgxw1ZwB=QMRMReImY<<<I^Tgo*o1w1~5^op43.@^MX\Wa`BWISccbă̆ьь֒И"Ʃ7У3ڼ:>ƸGƸN˸KгG34Pac``bbbbaNM@IJM[\aaP)j#V%\iU4CieBJhg1j-E. ,9iI_gM?idj7 ߃"iTDg(!EHsdА32qFſ"$ $LT A$P %13% pHɒL& tIȖz~ c  FZ=!.*@A =%mY_eώ ۶$-!,&#3***&)3);;);=---+-*,;-*&,; IT7vH<S; I,I?I,H-+T,?I$?T,?Z0HAXEF}+]B*lF)xK)|Q>oF=zK=~Q@S@!A+O<F;[+[<@;-gsg+h<p+y+OIOT[TNX%N^0[I$[T&Nk;Zh4Zw9fTf^+x^&xgkh,og=gw6xo2xw1MxHZoHZwBs(S=Q.i=MQMSYTeInHmOdUdZnQmWwOwNLmYyX~^25˪6Я5߹%6'+6<<<[^IX^gko&o2w.w1~4~,w6I\ggwoso)x 44:3<9.3;)*5@@ECPSZ^\^KTY``BXCIEIDMS_bbbb]_bbab̆ʈць֒Ӓ՘ےē%5Ԛ"Ʃ7ۦ&Ҥ5ܷ:**9-3çCóLƸGƸN˹KƼRָFF28<4=>ZJGNQXSZSK_PY_b`baKTYYEFX`ITZV\aaaaH'TcÇفؐ@(Ji% ڜ *dɓ7v˗-bR&͛ Hɓ͞uN[P審/ e~U3zi4KN b9ز8r,ԞW"rv!0@q}30 x* $!n@-rPJuͺ/F*%|oC1-zY81 Y(U_!\4Z5AR.f۹__M3lShh5Sk ƺNk-+=LUV"I -$ ,@Bq"ls@,@;4@PBhb#26N8PC:@D?9Eh 1X@GM In7戝s *t 4$Jy@ Di@&(g#Ti 3Rh3Q?ieagfih9ɠg. d'6":ۇ8Y$,na>Xy*qՙC<>\c@M4O0%X'"x XށA;=wMY <850U;ؓTE+, .Mڋou{pu 3\(Ie0î>oS tn=rLÕ6 He2).W2W$N$Hu D.)D~W=;$=?6732[M&՚x̕UKW @&:H+ >q ,0O3K<-/q(C?F10MrL65zNG.B2H@C  7;W @zz|)6<%ߒ=pҽn楟>3u,D;7ԭux=H躇%T<}|K R_M!]ؾVDs ?^gDmA>Pw+_>23ywyNW-ݛ" =Rt:~#AILVpUp>N A Re$QY4ot>zIp8|F>}Yl(F٘gסNy<@uXcGrFNғ q{.9)) { E.Z&"Q ]) w(k RLAJ;t4yE Ezxm`(k>1\ln VrG}Qig, %X̬)ޅ!1|0f, $0DSQR% n1@d;l.WJ-T U)č,äɠ2ċp|Hv*I:7ifQA5 rQ;<U3t[ `OcyPvP2ݢ* Vt(Y?1 :|"JW h{ Bٽ b .:VV@:KZ+mcz*cR VAmLEU ( JQX<>q܆L*}XCv`kwjp#u˹Uو]5J 2ߌtlu׆ lدYh&*-:d^I<86Q tM[a\xEu'J/R}'@pvTN/)00V a,6ZT)cF?g(@V)we%ɞodJv@}@:C@(> D~]B@d=#p~&QV~!8}&!`~'}sg6~&/Ҁn" hq K `^(28'!P4:1aU0@B4j$ڦ \ڠH(X0@ 'Q"ǎ>t$r䡒& L IV !,h!B-BBP]AA-OOO@ezOezyqNyfAoBBP]qMyҚJ׽Σ½g@p8DG! "B | cL֣j* h(gafZ 7H*${P(HB ('"!g(BG%DBDIEqA!h,!.........BQgv,M+g*t>q/P.,Y.?q I-A-@ZFkez-@N.Ng.Mu-[qBTB.\/qm/FPB?qXBAA,iBhJ,NPOG[rHfxhU@spTfffffpfpffpyyffpvx('=<MLZNcms.[.d-i/m.v.P=A[RoNwts.i-2-5˪6Я5߹%6'+6[@G\\fxplHNN\\jlq/BPBPZ-gl7WP?gg)q(v=x'z=O\qMz[zMynzXyoywA3@@@PDl> 6$M%pg hDXȖD9&3)eՋpf馜vzAdC{zlO<y@Ry(u42R `pk"g%:fͩL*$^,?2ڎË=`hCڎPNӋ4${W`Y4i͜TnVa9Dˏ6.CfƏ3՗RgFl(%  '`,_C' ]52 )-DcvsH'ǹ)PG-S-BTg\w`-dmhlp-tmx|߀.n'7G.Wngw砇.褗n騧ꬷ.{_CO BuFϻ?Q|!  Q Rzԃn#At,(CW(r!& A !D@hhÊL`aAA"C4Q F(4L?'Pc8s]0!@ϘFmU.2dScF> ae5KIj %-eVهM~SOr`,Rz 鐗tG5MMM$C=PpԣF M::$O b GR:XI](FR{PFIjT 3% >*ׂ pX@'P@u|Me?RkhQK|P@\A-2K% \ ZBZVes;E.t^Y.Ʋe;^"%/+^ɱcCb (T!=m( )0!.YFc`r*I7b zVZ?Mpď4eqpAzTԆ@XpI&*>&,"(&YltARr\14gj,J6=wN`A2+l2 `8` 1%W&stPL4)>J-G{&M,gɭyMl*ScVۀ ""35DX_c IdFh~9T9x[9@լ1-ȗ 9/mTYCbD 4ԆfwC@йhhz{FLv+8 BnpDlwmnZnTa Mh3 `&D| :VîdwNM;D$ 0N`ˁ̓A!<D=q|!dՙv>e[w,Ho{k!:Ϳs@1']6\  kx;wDG|VwGp/wц7yDx5 ⤃w8Iw^ g|1/?d IjȌ0!K} 6`UZ'. O~126YSH췐4tЂx"'"v}w|78# E &*'A+B$5,zp!P$ fr #XX(Jf5~zqgS8sE0?ȁ6TKxKO?{kQ*&.)tRt$ MQZF32p7PJj#83G%f%K[xhw7n<.TGo$sJ}Dk3sg:Q&g"[fu+qhj"!ab!'{2CԃxxC'h7mmփы'qRQGjH8TZ`!w&83h @'~ E1+"ЎܒtthsPLF5fM$8%)0)%İo1,df CV8w!Δ\sl8<0T!0F+ɉ79j4O2+߸OS:46i3Ii7EcaZ2ǔ@&xVwe$#L'byRe91R e2.bI{|YEdti~qge9$+tyG.gi2Sl"3*U+"<7+,Q/i9B0Hjh ' dk  ɛ " Yܱ)֜yhb&'YNrHISIARFr9xbQH `& v5fF`q 2tzwyj  `&@-v-r⨟ւ-T%}f:yj-2.j /f1ʣJ-1-ƐZb`/h<h//&iUc:"SekAPe!&'nZqtxvQJ$po{ `  &Z|7enW-9*owg42v\7-A2JjWb衐(:1Ł0 #u0`ɚZQ0#1A1۠_liؙb譤KcG笤`: Ж32!A3 3-33';/s@{[4x1Q!)!̩PJ&k)K /0aEѲ2=3M'ѳ[K+CiG 4{盾.##;JYJH3YG;GGHtlF\4\ @Lf_FV ܚi%|+̡v±v$|" j;=MݤNO#OɈA<CE|, 7 pt>#!d%^%YErcV ZQ@sK2ԽLvk]Նk|vՈ6֔Fe|ziX/J\V}hR}ԥQjoNm3;bÝIjwMj]mfk|Bfh gRhU#DSgs1&֊&3t ]1iQH32jFa]د$y]?}hntPj ׇHIufj2daJfڰApԍ MQw1dYtM#qM}wN' Lj 6v*sa(r /F|hzs\uuuu_t[qWgX1us(ƾIIFP%wr#4nrPs'mҲ_7^@_@u+4EP3NrN^~)FH| "m\e.~")"An~%nx )X#w=g 'AvWqԚ|L6ވ%2=L!?Rt |HdHftxw(3Y[Vi R*Owyyǭ[i+O%UOa?^φSO'u/`C씤 $\2%UeyLf(wwu5yQcY}?w&~DxKLua'Q:`_MqM +%`Ɍl,瘎xӯ-O}G۟V'ec{ Al _%\( FιȦEG fǓ  ג_<c"%s ?F=/#@}ld Ξ"!_8@DjԑT{ḫ]WMۖY=qkun]=+ױS ~{֠ߥ-z4)3m QJ 51B5ovmɩN_#e PpKb&QtdֈK;7Q"|D ^j֭ /;fð: {O<ǖCƱ9rLpS|>ORX2(%~B;$N=j Pui h^)B~I%>k pE fnzaXEF cgeR'l|$Jr&.TŠ$L!I'LKEH4ZiLk̈<dgRP>30ѳ? $l'̴y' :@vJpRM-/QK=5U4m8QGgB<}GdiM%5pίl(VS5Ո8 @Z*H|B-->0K9)('dJ SHe[g&fR&^v)]":1vicX{yHĵm14n ҺkHۚ%گZ&&sB0gMn[Vj)r ;p+fsg+9[f]>l_BvNnGGZttqer~,gH:ҍK 4'_oKUn-?|ދH{#H ~ 1*_]\!ClAfaNN@m9!T &>(*Y( B/ N FE! {8#6d}c"X%#IpEKN/j@cF8Qkݧ <aqGR $K42狄Ji=R#IAf2L!/HMƱsB ) >EmZOY>,JZ)VF$.몓@*II" 8̹N[@I8E .s)/oye~#^ C+": 2t"„M[n}%!?4},=Ͱ&%ґxr߼Иll{Ћ7fH ѷQT9l&7QPx@"D)2!d@KTxsT|%L~ԣ4sDl"ˤ 0o pX@'Pѹp3CP+(DL;B3C'CY[5?[ڈʛ"Ώ9oR"rkQ.`u-qy@%x'ߒʷ[<Ȩ>j-q ӓgp#N|2 "zpc;a  ?\ Kq b>L)<٠%)=s2%.pʳJ /h h Q| Iyh 2@7!">0IJq;HxM0 !$BY?` ?xH5;mH i`c<,>@I EA%!ÞA)=C;#L !Ãp虳":DT̜cB'"YdTTEċ- :Pڶ|؇7 ܍GlQW}81qNRkjfXFx9: OܠK? D\B4DDi} '_DCD ]H  {G.)~D~Hb<"?D6H!ȕI=B0cԴ20pm ?,CLC!HHKKx :26*e{s TPOP-t mzb SL,10ʯ0 )DJ`o;RxЄ;IWķjƛ|LK - PȘlPQͮ_`Ɩ :Ь0}PK16R~S1-؂«MP -ڋPȁhρثW*T4ੋP@ #m$&@'K?튋0Ȇ1{R$R]SJ3ZR-QTRaQxaN?=0[Т9X :Z̲ku@Һ2dW*-0nlm%qvRh$=ƽd/|(}$U VV1;G1Srp<10}XmբAtTtqMH B jmѤ{X=Wv؁嬚 z@XRL42[Bڌ*|ڃZQ?}wEYXxeۄ-ό]؎̀6~ i>Eܽ- YA)8ZA|h cz[U[Z_:۠>-+1$88]mU!a<,m|Љ( ])%w+5e%ݞ0]i-蠇X5iՍ.=ŌZȊ]\Y0ਠg% 0Rqٞs9?* "IVמ%YzAŖYj-8d߃q9>;a f57YX>ayhZtXEg1&~ѐC114.A =žШݝda`^D qd'V6I?<`AmatyE稸lFyR%> vꚡy%""*"$ k" ۟*rfʋ(¿+MU2 jQ9Nfӎp*̥FVO՞Ɇ^ֆnl̖!mT͆!cmƠ'^naFԠDrɶAor NF&'ҫeVحoE=Qd voek/ oWu ' $  O(x' xB8w& Pz]#q r#?r$Or%_r&or'r(r)r*r+r,?%B)QҤ(Tx,Ap4(- B*(r}Rs sQk=):ُJ8BACw6@wtڥE%sEq٥a\x0sܢb-ע+dhqHu]8. Ft9֪*,Y7UO \pP˲϶*YB샬whPv77E*vu]w$ޞ P(O,{oK-i՘_Sb1 _JowmU ،k bx /0o8"72@aym wt Pry4Ryi(3.Ic)Po{ Q0 õs5NB. x:3>qXF#9YzK83e#zJ37+MٺR? |b|{zЀx6{Rw3˪7A:;9K93:*4 5SC5U|WC37zZ9?+˲Ae7q O{%O~o~''G~88BTSp`N2U4B=!9~Vp!Hsv Vc:z^` $I$РB)T ˕ut$I+JH.=x+Mqhp>ŏDb +TG\q\j>~$} :%&rQ/c}W*ՠYjWaǖ=K/fB8?@+?h$'WN^op'=XO^`lN LՄ1˄ITKawz+wJyчcaTeJ,IV Ǐ|-^R1蘈͖7/>Yb%M;:"HM/1v[vI5JpPWf s+)I@.m >t^ɜU8蠧T_ &3Qkⶒ6I]}%dCǑA0`CA h (?JXD1$j_`9fY)Vb%qY'~ϔAm-P5>K$*DPqǏwLOKVE=% eJwMA)TB[-l®ڀʴQ `F:ᾚJFwUu0~ڥ̖Vd>l*мB)-с̏$s@ \5kV 3]K v@Fqx-MG ?hR )0I(@^uC:,%] )$֊%@ـOa6?~?޲+RPp׉G8i{G>C&Ђ6;A4hy6l㶯pS~!88~N.V_$ ^;P { ߹:qi_s b=fI;ꆓ*} @luV-Or~n֓95phBB^'eANh@fx W.r&B50}zNBkE$P8.(-<Ʊjw#C\,I?؁] CȍqNʁYT$Dq_QWl#3I.klcPHF90\_R>Y @97i)0t J=IOa KI.AR"'OX^5Iٷ\= .D*(>)wl:)Cv~3vin眚&?IxrAɪ\Wa#F |REe|u)I#gfT~s#>i (P {}.-dx%Hҭ?j'KJP5)W-J[?5 jH(P=ɡ&5󾫈GLWTmŰM= `LU]Il-(=IY:49gǒЍD]ZV2=skQ¢5(+إv#f[ee:ZrTL>Q&/U'h;L4L%;?JK伦Y#J7S+cY[:Ee_؛_*DGN2]%fT\]wu D,VLW~ e;d3rkNYtHp$P4 (ɒ#*b]1PDC] Zp/}8T~(\`2,z_02uKIKɚe:_zM3 0%.cLVPp]r͛~10ICBJIE.p|E畎D$ !R E")R_ С \AVZMv!I!!B RUlGO!b$ֆ!nP@#fb_#%I,J,b]*!a/BI#W.2J(k' !0%f13MbU~%VSWX [U%]Y&Z]D^֥]e_`B^VKR b.f@ 0#c !@+bdVeFf_dI`5f_gzfZfRj_fgb¦l֦m&nn&oo&pp'qq'r&r.'s6s>'tFtNo"(DvuuI8/'ug_Q8D: h)fP~'?C{ JU}xFbvw֥y'|dw>ސiQIjh|A= Ct%`fO~< I⦬?ԃ}*;`((:<B,9):v"+C>P\KdvP_Ш_ihr4A|R8:[;|=!Û:IF $š#G88HCm%00 p`ni"j#1LsF~E_GEQ䎘hUmAL.DbfE/f|m( . Gf'BD*vbϖƒ./ljnGz&W8To2D*/m)D%iFLqTp喨eD$DNO`#sTtu[Xpp] ohcdR0?q JG 0p00 KH^$ Oi$y%DutA\rDjhxLN/q.rU#3aآ4 ̰L,yˡX墨TL%@Vſ/L0KА2l dMeɳDP ŀ͚ˠp9 |Lps#sHEϖ B0112@^,J$W)-P|8I" /Ҩ|2ז<ȌI kEfi(I0q88s99A:K e;.KDQXѤ YJIGNF؄ (UN]܊4X5 H%9dʔHu$305\^NA\9l3pUdTUOqX &λ^ Qud kcR6 u 1|BpAħlCF5_ GZRr77Ź:)P\ ް-uJ 0BWϓ%w@ZGӕ`1e"\"؅wcض u kj6쑀'x́M y|]D]6dSiowdLxwMޠWNSi=тt)@A8A&98fk99u,C))'Gv*2 TBk#ytyԭmg<;uJ4.|S h::P`G\Wq2Plkp5_uz=DD?c^TXtR;ZB c}14-AYUxRPc'츆eQTI;I"k>pQ! I6? ]qo(Y2l{i^c мpylkƃ]qp!WH9[LeR mbb;h)+£H3Oy4ӐVU G4Q}pJ(e G_I{GmM eZqur0U?;5ķU_|"fpNHoS7[,+QgWN.9m?K-]D, O>n;ġ')}~aP=X OÎ9ٿi/!CY~c_X\XNA[8H4 ZNuP|P ٖt˧>\P:r S >AW qIpp>p&ܼ lAĉ/V`Ȍ@f|(79 y_E2t ?D"##ȐC+4iRHqsN+fS\(s3 oPĥO2 񓗪Äի@sڶop6-ҳV?! 3ݭibb)+ޥ0MJ|1YW-2'Liڇ~)䇳.5:c'z勶L~6+8mUDj,$-Wf8S|5uko͖zߡV'<\~ҝ]wyVox߃F*%vMaY smۃBRSumpub;&M].eEk̶zٕ:!6!?:I BR0C Sׇ<]CeOߑp' w!R?5r/^^qO*cJhxts/{J:/SrAkL"eщD&)ҫ=r2'!V BP"/ N!$є4YMk^6Mo~8YNsu c R2SG8M AC9;@P•g@B4&ʊj!uhѨ xPt* <8ǖTFe~ǏEҋYxS C!1;<ǞF \x0:5?bRSMFU|)(&7T%} })QZ:Ʈ"H~9hMʠ.sJCΚAb-u:l(G [.u6LZ44)hhZ>v(~$EJ4Bʺ%^wG帜<&J Lm!A!pnսnH ٵn('ʎ$(E=0 zx:6S.KF8,(vUIV7.)a0:W/0 #: 2` 88|IԛJTb}J b0x|pC PX\  nR,?"@'DA 6 E>QP @\!qw*3n|ѫ{eU.C)pgXYnc^wq%xW"!:y0%xJ_30D0A[,;p)(:NC BKޮh1]D/px_iI7ldz>fՠɎ܎[.tnrqFTFXMy!MpxOLT0 ёB,l8An8⽊&YebU$,Yŝ{eߑj̸@j]KSa ^Yz[Mat/]GP[n8Wn <&(x{%v۴nd^#䪭וHJ b*ֱ{b ( %%B.B6zBw{Q=6~x{;_[)%4 KIKWp{4.houڇ!X3H5]_W;?_MjhGio/HS]A C,.+I@0aon:F *a"*f)H6ASIo6WO?bb*0'"'$-ЉolozL "7*87ou&pUOX !fAh"~xCpP bB Nnc0),ND.Sސ 0?BP 9&m".v  P`h OI+o )F<&I#&{ML2bDI {^a4ր <1&(_&n ÎBA!: aTeQ)Ka h"NRo/Bbjcr(qQe%F ρ1Dq(^%ܮz"o|c'B :7QQ!W%18 u94RQPW&~)|ҷ`e,) )"Z!"%28#EP*2%&%K:1)t)K'* ]+hf ? Hy\tičDy EE=ta`"5g}2&02R,1!DViL2$2C24c4'4# x# rQD0 3# )~"((1qS7b0ns(Z`L2U+.s0rs7L'#S[&1?:6i6Kfj38:{sB8G9:FsDܓ:c":;Ҍ) 50s+JI<2s=n*|qe,7d: 2P2JF,(7KD;Aܮ$ozkt`TF3F;%HLh3saxÎ(+\b 4I[tKJ86h^;Ց\LC4&J%GMyKm4;sON&v0kH4KtJ RN{T$0Nq sU$UA`S4$RG-U37e8BO%DTIWLpHBt".tF5?RNA"O.(o=5L{#HG%N17"0$92)6 JFIVeF>% b !^7_J,4]Cb,$ۈ)S*b;-\c7c"as5$J1y$8^XDsؔkhcEX^BXY\yAEie"ӊxG9kf]ё?'8_XdrH h~Hh%N@2&8S+<*$0hC+Gn zι3hGzzx RT)Nv_ (hY)Y ڔY)&:?ZA "P+Ǥ ;vz DZv:(yu,(|ږr ֍*sb>cZ)%fHhQ.諕".)?czZvl%]'Ȯzɐā\&鯑ۯ]I몱-F,*(&>鲍iB{(`HZi2_iV;{۷[۸[۹ˏDJvI)$F][)In(CL*$䉞iu0JWbd);6+ @ )je' <)@ār^j(( !\3<)rJbZ%+2)jcr" *@j/,āCqX|*c_ǭBrlA0%!dM yhEuJVu~ hh3!gܛ')t&,p/Pt׌gۨMȔٜm2.,MRT%m(]ܿ6*Yse>-lKת^~]U&ؒ>eв~޽.+" ў:3LMS~]uU@#tᅌ5f~[ÂELMlي |,: xрTUd?ٛO)?iXPBTp{C:% 7 LHUxqa\G_ta0!2?4YRYRH;Sšf ?i aU뎝GHBcKMu@Pqmo1 uUU"#O(knjoz.k~4wܝ7ciΗ*aߌ[wj`e-i^,(fKL; uiDj;J?"5U.=NqT#g~>44Bp pЈ臣AmϏ&Agۼbyaʢ8'*.}kheaƁjjUʨb-0c%." 40e20MvBGh 9 CХ]B8 pW'FGK SD#^/[|u`'¡_pƏXF1%R1h!uDP`z,ZWb tIPe<$$D0-3|>'(Η5dy\K_)hd>d0y0(d,]ŀeT1N#`#IH]#\".lI?c2pآrЇhhC[Ϩln p<:;g9E-hAèE .*FK0j'&'$HRfĞK2r>pifѨ h{JНNe#ӊ7Ꙕy.SC*zQE;tx`˒IKBHa aŅIx'(KGL ,ObQA6cX@ ^uW}sU ?ƚn)IRr ~>޸U9O8</]z}'y2ppԇ'&mHN'TRaCpEUAI?aC %2'tDpb@'mQWIAQ!#,%؁$CIтRJx9I"RуL.KUMD;{ÁQD dSpӃI86cȃ'0j:(A?gsȃ{Cf3xw#NGXb؈aY$*UQ@=ȇLL2QaFH3UȆ0>? Acx|<ȊFX@ cd(PE8%$8 儍:*!i؍RHpS0&؎X@ȏh. hd9@ pX v+a˘ 7 9`($h+96<*05Ҙ9-ɓ y1@+CY?KɔMO Q)SIUiWY[ɕ]_ a)cIeigRpJm%Z 4* SaxIoɓ~ ZPtrI.Ö.i fRfqy)%7 ~96@_Ѹ %y cR@Țal$Uxf@i=ˈRQ9s=GSX"_Xs `?Qk CXbXE9)&2iP|Ȝ6vIH ocxyYiϩ:Y1uhzw`&2 DN rB!K*hzB.#ʌ% ,CEW7<5Eh$>( =ƴHǃD8#8L' ͟M4K#sS'F1MS^$}+C4>K}+S;Z^6WVX+!4[m4pJУ9|l=.95GQ:-p..'wX^Z//.s)RR1$,0@4`8@Ӹ11z 0m2(2,A%3wk83<34Icv5Wn5qxsD}IJD/MKAdFTٔIНC;*ҭJVݲ46vKHtCݾs]J~HkM<~RCMqB-Bg3JެTdPLLW*\GWQ.C| $@ ֖>X:cnoqsLJG. cN@Jߺ$B&BB&d')t!B~ዪ*EFߍ]#O8[zg] ݁fGhfdc[1.VqaWs mW"vջ*OWL疎KT^w~6VhEnMXrSQMıc "amgn@!Wc Z#ML¥,DnE*~RTMVLN,؁TqNODOPP|.NG*" %2)$4F.Ad';& FeqEa%1 b. rH&aD6b\-fG[.:n(6/NADbNma)_sLcO^7jߤ{6*shJAYUy]Kxjʓ6 "|jT>@eb" !DRBs$'X3q CG>cȑ2)C6Y-x1C#Ox1Ǝ9Ԧ?DO:S8ȸN|O䙘=cYoS"K{} 簋n5~pb@p΋;k=;G=$);..31CH|ꀋ.C,o3J[m$ b['CrJ/MX<()"7k$Dņ0!1Si6FjHhz170!G9}BbxԨ .01{5&{Q~ZkLOx #mzSAʧzU3J-T1G2 N@$NlN K֧N0 mRH 2+qw0pE6[qϝul({w>ѝ7`)Ⴕ}b! $P*5ldGV`~e@W\~'^,~UY=秦k|WgU^l3 qAޖ>;?q@eԕ'$\m8o;o כqj Nfrp/]-˯sэ?YaQW]\G=vgWP*=m?w;׆xEumXw驯{c?!BV{W(}ه1~Ov)y1?ЀD`@6Ё`%8A VЂ`5AvЃaEҌe q/ #BpПZ H^pzأ@"B4`6#-aBg0B(Vx,n|]G'Fq%q!f{bB*xu%t2hB# ut,f#0ÔjDҘ!q1@2 ɇK4T ONQ 1vE:G2|HEꮕKn]҉DKT21f~i9bjlf9$1'a^Ь>2( ᠓f >m!7r'c%AHlPw: 5E„]"R)ͲJ;S"=+ʻ65bĊ^?IB Ew}/Ld 2` 88|0:QL )DWFQJa$GD uR3P t:&`JVUV),u)WtݞЅK4kUH .Uh;T/H*LPթd-YcYX,T~5x0Gš є@CUttT S&'e=\DׄG,g=WҋO*?ZUpH;2ճi(v:B7ɵlK13 tBZ}V^(8mjZk^`ԵSw%QJ#+aZ}kyϋާX"*N٫JLYˬ."PY)YPO} d ;S+gny b:6|H2䈧T#^30<3vuYiAqȼJ;L!E 8Km*ZȦlrH>2ĸƐB}A3Z-du4V'xy"L$\@0ϓU$ؗvwjZqfq&ʆV!9c$F:H,mG]v}<۽>ϯu;'Q6vٮj$V&%%a&J1?9" 2ZP+nG C4Z%E*b(JA%bPQ[qBH2NMDGvhrʜ %C"LLI W9ѓMORC: oCz$`#"AzERd0~5tP8yVFq{[WDNrz\r{j6u'NOl%񅃼;% C/sy3AWNW=xS2=33!ߣU F_cLW!owֻSeO{~~QQ<˸KSۧC ӱ @!H@S{ )"A# WM І+P|  cI}8?PA$s9}Pe < B'"0A(cjHs-k IK4Y*4.2 $ Bo ?=T L zC(BA 7iGLĉC1D@/L#5LCCP 5\=Cҧ?1R$5NzoM+9ƒlCG~`H„  d )G2hLxhGOt=1-%ҥOPh &NMTLSUe(VST-&P /ҴRTӂ{Uu 5Y=OQݓaU&53TR - ei?9G4q Ӱ;--g]ʘ{(-N*kahf@ ~jDN^Њ:ax-Ë, X% E Áv}` WM}YqqH xdu@wdydL1H3F)rM䌙;AXdZ6 4*ڬ ȑ"TʜGZ+=2`fٜU~8LS/ȄZ`YaDZcktIn-swfy w{^ѷggYF:a!ٷq h҆iftR̐2a&3>!h񟑾 >iNi&D I&`fAfi & F?qꧦꪶ&63RS- #~9Bk!`yk5hsNT0A՘N K > dž?Y&vNfOl.#ꆷ> ֧})Iwq'X6( !8:o ?I4+rp| p<_(/%(WDG3!M#\˃@ c{sR 4Ѐd8O@T5%N)۹䗊uP սSmwH צ奄ʧD!1jLBDbCJȨfoIA<'/ؿ8ʌft7c5 A1##dnB%^d&EbXJ0hH|:^^#}?&YҖHaeu\ lKn,[L#$? I͏`iH(IńSٜ՘<{{w(kfVID`k%)T)1&,KuΒaԋB!W5K2)GS h 1EIh9fϏ 4Xh/ѕⱘliPXƙ5EMρx` q @[I݄E=azt#"^JaSYF*Ƒ0I.ĪXV.~L(LJ!.G*CCnV]kܬ d)k٦U(;8of;xFNh"mQ V@M$d5g*2-o:o\)LC͉%vo|dۭhzWk]fuAb;NJ#UqI0Yrv[ڢJnQ +E`O a6@P:"> Lz5Moa 0m1{6ci׻qf@ZyeEDx ?#'CZ\v. %ۆ: YDQrPIM詤'kHǏ5v8ىq"o+ [Nvu$@]*bzΧ]2{.κ^*l.7xX\ݮƧ# NeQ= 궟:=?O@y" ?|FL{O΀VckþE?Q@~]偿|??|?qF_^Ԁ:9D8Ԝ`.*ߩ5R` *`@  M I 2 p R "a_*a:BaJRaZbajrazaaazDOD BNa U})! !&"!!_#f! TbB" n"NI,mb/C48=F 9 r$UB.[@y$-$F Д$$I\52y^0T!h X-P^A)Bb@%%LLčB%TC& %E%eR^\eV.S2\ pVmU d)4&!`ZtB)dU e&Vv_@%)e>tp,@' cFfZ@ &R%i*g [\%C,_VAp-EEP.U'Z~kfa6&e(q]eWe'!rr&,eS>oNeU><gZnyg)|"^hvj5 ¦\ҥ]Bl'&`'o& Hep pg%'Cpg^~~Df\C g'YrYxŸ́ hZ:v_ ށCe6؄>bMD+D4AM)4MȚmGwP4ih^D ,鱐<D8鐲ř0)lA>FmȒaIh ۖ2iBiW`)ioB )T4s]-j=)z$Fm`*d"9iNhƒ,oTF-XlEC PI-rD j>BBM6_UPHqXF,m>X n=gA *,0,Eei B_Ĥ2*y-"hYP d 0G 3I]pF˭JiCގ^~Ϣ :Hŗp`J,{H M4o^ouԊ .to@8Kf/WޅNl .TNp DlNЊ,@L>/H :rvwS0'ǣo|ʝ/yhBAdh XDńNH1D6\dq2I\N#hM#MرP˰PVP yX;c؏q̍8`%"+rMHV7AѪH+7N#[%r<2Ѝ$(Ur}Nō. {wդ>HCq?AκOEi9Ϗ q-c,+Hv\66Fs~A S@TJ=@s>;L+7MF+Jǔ9B@2iI4`1OQG/CD>LPW宕uJ,PtVh6J)J`·MJ'M?\/fY?Ş#Mb5]kэ6CIE]#M R[ FH"B 1O&u/WS1O?vSv eoXDGv7Әq`66Cu=MGDA Ea5TB 1j6ah;MiTPjvr[CD!M7osCG$]{T^tRR!6Vbط88H~ؓ-ٗiy}\Uq_:7ߕjYPȔKC;0C* %փV)x4YcKAHtx=xG8;x_8#8C@Ǹ:auP69-Z֍cjqsOr]dPxY-GIqYjÈ=/DsO+9g9u8@whGWyImU緑VXXY[h1tWEtlqaGHǵ,qAƉ\^DEGDu٧%گOS܁YZD2cā=6=`ٽ,3{l|/CUNh{uT5"\N`?hSWky盺\{d;-iMpXD;[Bܾ;ͼ3C|óuq|GƔ9;;sYEx͓C!ܝZ|)r%]=^aу3&~_>k55F QO_dZc)8B?y'o?_*@40Ǐ AI&TaC! ,hbE1fPăAXcH'QTeK/AheҴi?Y3h̙D3iSKjUWfպkW_;lYgѦUm[oƕ;n]wՒ/d ^⢹Qh y#|))[x@d8޾o!Kk:_/e/Ԅu <5 T!r'm]rr+WMtܹk{ zxv7Ib`a ' F"Bo"7J>lqJ B~$(X 0D> 6Y~XH ~rQ!0&*( Z"2 g L"$Q&#!G:@K/ }HHuC!&dhbI8gYylq}h/IԑG#j6/NTI'N+EHS!ɺ!SMF="2TؤPB%V5Mh~WEI@`DIJSnI naXCI`SR$(TE!.~BH,C A$w"0; ЃLq(!a;](+|0C>i12t'<%J^23'AvZɏWr0̌P 3&^IUH/;r$=eB*KOQ KhB,Yʏ4Ԗ:'Ezӕ¼Cؐ&%U37{:p ҩ2)ۑLijSt>$P+XV\wW@>qjH *QD\O@ל~[$Ix$"| 8cHe0YB1hI>΅HJB*"R@( &A`U~Hxhr\Jo˨??.T؅V I  nDZf;YKy@Zs\ x X{:ndC{vi컞v],,8Oڌ$40ρ`CrQ]|mY4R0|NCx@ $(7d`-+7qdؿ4mw7NJy3K $R7^Ys2fe!,0 %VK7 TJ2p^A` gwL3ĜH?2xw!V5{]SK ̅nHZU3o>6 | MueêÝ dxqLQKNLd. :ϙzF?:c<6'"eOh]߽#KJnܶmpllMP0ԍgz"/?p8!v4Io(eAO$h=s"+G G>D:2R>*P .G<#;Y)K!'B'uvo}C[j~EnT?AVP''Hmw}3BI.ÓJ!uxt{!e~2u#==)VW9ύ"at[+@ͷ${} }eH| fΟ0v&^lj8 ]?&5"|j$mR}(eWuyN ܪl0j~ B$BBN!xfˆC,$Hb.H, PgN|'꺘o!$L›/g|DozO;0Ooӯep0EE€4! poGj b̰" @/ ؐnAa'lzAH!9 ~ARy=B;!!!*䤔$CbqHšP'p+D!n!qm Tn!g?a;1!1!OVPw'c$1 K/Q=Q"!Mm1PLXqwB"q4R` $jrq$Q";2#r#-#G" i!>F`G)y%)r*ܪh"ɘl )xDґa"$&]6%/rP'6% <❄ !$qҲ]#-^ Lɞ[1!)G"6-2/&=/SS! H-yhAd-q ".RyH 8 /\3gS!(4!s )SQG-d s:s+>' 6%0@< =;r=rA^ؠ@*Jc|";!LBA8 8_(=R?$CW*g#0PTz"G6%7$D .N@!l$FBz"b" (t!L~BG]t!H>4KWNJbIUBGKhNuXK_TJKeFFG.JHBHCOQH5OeF tMw"ȴ*5b%(#w77{_{/"dd{kBsB|_|/}Qo\|} $K{'$w+yp {+#F%'{(7%\M"dcHc8c~Nnbv wZ$tVIMXo:sBgtfGuF@hWi_lV !f8!fu.TMT^8!4D4sX[Ĝp&dƢBcchϷKAn8Fs<tDljioXigiJf_؈XdE\K`p qLM8Yj؎q@NiQ JZʸ*ghsuYmC{{hl;BDC{w\{e{ T4>4呴Ja[Z;&ʞ5mL3ѱ-Z|I9=ɖ ~:0q9 4]וӋ:n!xxk|Z,!l t+#|x=ף})Cޮ{W {ۄMƑ5߲LMA.j]i@w߽r!*l p"..!M ?+ g]J=[}u57@l2~V~uslQ?a޶%I>>ငHc;Ԡ꫄ju~n.]"=}A !r]^^2q2Y#񁞩°è$r]"N/ !6_ -i)a5 OqQw\/ GpampXi廵{dfnjS_W~Z!j葟b. ;!&CuwJ_W a:0*_qΕs  G_<k.~sJPAF-G($"f!/D0Rر uؑjy=XSb)}(I2I "YՉ eU Em;qH {6ZB6w:/ Mz$jK.3 )1#݉|dx,ԨYCʤȹa俁):ᇈ"bn=qpK7hGCVaNyeeܯ+ul%V8"iYGw<ǯխ'X`|4]^W)qE;?".*ΧX61ƨɏ<0VӨ:Ë=ԘI*S&|(4RSm58mR`yd\jꚹxwD@4ď6A5Pp ha+xC-h>EۨSHT}:9n.X].9 a3;c/zA֔J^}S1Pvn|t/׹0:A0=B?Y`NBw;@!{Q>C0Hxh41` 2""$9 B<Asls5y #'8A(8ZvZCx;2z, #JI57n!!%r9H$QRH=.LdF pR($*9F<%&D*Q(9IIKB$0er"D1KLCN3y$-/Lձte+%K^ g8S Tw4%:%,xl&>xʌ xT-(1K"P$҄TJBSA7Q'˗|JcX0 }X 0 =QC @- =!i}P: :IUxAbh2@8/ '09.:ڐ8'1` &()ьxPИdz@!Ԩ%̗ogO$^Xsm)苖؈(HpX؉H_!hO.!'ghRl$Fܨ;oA@e82ɒH )i59dD ɎȑVRc`d% A7F=7v  @  AA!Ti^isn p{ٗE+#6c_weٔ_!A[cdWYya0Dj j"iU8 9eyi֖o@fhx!dĄOz4Qy Sf@ٙ])WEIɔɗH1J锯ȞG7@`;=Dq1qjC#I(# "0VFssf!'q)BDwNpd2G5ڝzI1dN T|AI1vxj&rJRk(*z:~QZѥa$e*yP$2=7*F(17;Fɠ%+q76zFQbP*q} P*|<,1Á_E QQ3*I>rPUwV ЊAHvpbZʫFJRPqի I$"SEzDQkB K25+|k;SU qEq {>u۞64a10*G3b48A2q2AbAJE!b c/S4S&F/8!..E2z'~Hc"D5{#.=2k뺫/,b`2k2X1q6ĻN˼Qk=қ7vG+zã'ћ=ۋBZ{K7M(C5|"#|]NN0` p{tN\^vb8g{r;tƇ|Azwsgρ烞Hxy{!P|v^LnwrGwlkon戮lpqNOu_镐G9{ꓞ"pp &P5"( >mWuvxA~6hOvFpxX#dwq7Ksĵt;=0}e@?Ȯ앐p @+^dyÇuz'zvpWdȅ";~X4f!ɽ㓳V*AHg؊6e}w8n戭Ӹs8GaU?#HOy͖bO?q|1V9P2`㉿O O}}oTOfa ryR~U,zĀm@`׶bBY %T%/ІS/ D'ÒڿqA$h?.Ju@_p4ŏ$`$ 8<' 0~6?GS"oTJ+4+~4øSƚ7XtC~%hPY _q#5TYQH* ȍ=7\é)*bQѮ)VM9)Qr䙡!8FXd_3z14"R6rF&j`Z&;Q0X 䁹jeZQ9;FI?89uѬaP}@Q^IA1xz-xhUD < |ĪdFϿhgz.*..\I&**d @L(~nH} g…8NLq=!$HG6g$"VKK(6$j걺#HR0*(Qj8r12 k'nh'<}r<0sӨ.9G $8 DiN- ''J++N6rU[2h:;!G뼵:~<SIQڡhʁ'XtՈTSGT_$[2Zڳ?ÒN.">Q" ^NUAbi8],*| f߁DzEխ݈O=|L']u\_͕=;I`6h梌4J H&ZTZp \yb1BP7.giZgN쁴GKm]St'%JUԯQhmKiںiꝰ6JeKm6G+SQj?Cr _p ԅg<% i\Tn_лx~ 1>{S͗Cp( ^ǃ}"@)nF9/_#ѧW y=Rq `n%X)UTl |CPy4%E9 BK5_s FfC~Trs!A% EZۧFÁh%❌h)5l89P*1,x*,hdL^V*M!EzYE1VBٻTD$_G-# #_fv)F=$;^QFGR/D뎅* 2ʹntއGEIfQhN(J'R3f:###(@hBNaM1_OQt - Ih?O"CaEA'dEbʝB92u[O]X7ZR۵;AXN< LCyJhG7V?xB]<,@WXKDo\5CC"5j[?(^n"WxVR+Yie֕h3Rk򥍌4 aAHSgIC#؀E6 Qb uL+P֓YwaWr(AAP=W(f4ȴ#3^;_l&6F(k[':nl>ejzGRB[=dk^PwqֱRokF uuߴn[K,s!5}G~4ަUU䷾ģmCA 5rcz ܤtmgC[Vnm$3>YT8؆q,减]/0S1br<_9GNg ^xYdTeQ` < Zx6_vY~ E9yh>}GS'Sz TGU#K'|z?zݟX?B7 _|~?|G_߾4/lAėga?,2 ;ȳ#TA1 V`y(%B,djå,-4.4 C3\1l21M(Pm9N(LUMj oYU8XN@xzKM̄J# \}@fNN8҈$B`:LM@B +MAOρAS8> .؃\Q|:3PߔPMOjNDQ P-P~?9PQ ӀNBhP .X' T uJNDPeP͚ 'RFeu΢R!m4}QM4( <H~!wۇ:2 `~_өZ?M΁`!=?';) =JX'-]}N$U(uϢSkU.JU`M泙BضHj0mۊ+,o O-851GKfV Z&f ʗ}xӇ|v 8oz[ʗnj)jщ1S9WaWzp؈Vлafzbŗ՗e`{}0ׂ m}5~K|%ו͗_BŶ8mmyTo6:~!Pё}님5deWS|qر䀮ٮd}Y5WUȷ5(d{=@3P %%d Ў0M p<ƚ\_].ڰP8HY"] @ Lk i MXީ^޷߀%ڵ]=eX]e*ՠ i @ ֭ ތx]M_~!Pۋ:H aLc`P1 ޥО NΕJɥ͐ X (\yy>thщ,GA8RxЄR NmpމIn#*0KI2"bOa!sp!W9n$N#58b0qX6Fn9dSc6)07;NWo)30CAQ6!VAcDy|Fb!Ɋ2XfB\|XbTb&Vdb6L.bRj/W:8FiZe_JXa$KT;;3?);yQ1 sVחQ~.Yw0OiAo4#4(&!"I>ƴv>""h`)iuynyٞǏ.1Q! iiѸg}v}#{DikUZ9jZG"[.;3n#*%cfҟlrJK I =lFg:z`#7:!xk9h8!$@^6fFؖd:^m5 ,sl MCk+N,VR 6@f}e%ˣv%ɐkQcS^"P&Jl,n$aŪ3(J-r~ ,?Չw- on(~Bo2U.iܺ2O&cvp*²x˸)jp(?d8wnZO(06bOpÅ)6ਵQ+PC,ȣr Jh;z,ra;sR۬*+VJo I,WQ12a2H28QPt6ޖC2[1Ji#34:2{Z zr-w-R2N 3 ;0 1RtΈmc?3K 0Zq<=/I{v]l"NQs.,su(s7 i>dvgߎN/v4c0rոK4}38Tu3 >@10:;-H_uK9M0r 5Ct0#tS,c:SV3;p9bHkoH:8, 77);&kcU˗Vci?55|;O+9gy60Pyz̮OY0; :99Η{`˗o%>ix|1+G~ztíە|J1 3}wo{;׷^?;_S3 G/~T?;@㫾=3V+/yK[<HQ~>:3_@#',h ': pÏZA]"TP"Ń .8qDÔjP2 6ʗDg#gvnzyG;x'bZ 1t}|wo>*ӗ>=~X x * : J8!Zx!j!z!!\'bV8<)7 )U(܇ \ y#"Ģ A3XM~Wd^Εpa ?՜Zl#V`\R僧uzZS;ni*<(Uꩩ)? Ó2}QO2͑igr6ShTr]N'VS]rr;)2:ALUEd$o.܋廯DĸZې x)5bdAً϶1A}̱dT9?$ r=d pt>dyY[vJUtCZAJ+B%\R[\@'Pd` AI)PRS]XkmPƝ;t7?lR )`z& p)θ ]Uv&T2\HZn烛k⡨GPgNSakjBNpC h5d+CU''N8d *'Ԅ*r8PZ>.X(0,\ ,L(Ŗ2UϴLLaJtFveqh")8j׈i# XjWZVf=,=+J/ҔevgE*U_ #x{׸@n@b-?^~Xo{/]vOղ7-Rɏcm>Q*7P.[BW{+XWv'yXBKo W"dď-Ma+h( (S!C7G,#}zlg岃(mxYUc&D= zy#N2=T#2q' [ J%Hg+Bb"}-WocRlBɡd1,4-AְlDM? iZ FMl/akHZ+N1hw^=9'mRf2V]:ӛFsLPg,٨eJU"ʆ|:_qvٜnm{%CȰ}Yk&qpfJnū]mnhƴ [}b)}M qْ̖OH L:E_?'_Jpjti P=1 ׼'[^ClAHifsnns.͸tNY)kg7d%we`) m}fXja~gQֳګs5-Y$#5lsrB"x(9@oΏ4iz׻˺M<=Ð%O@$2m }<,aW^8kLOy7{]?Hwy)J6l#O{'~ t&/ mْe|_%?>ٺl.5EݭA]9q`D9ꁞݞF؞39A]9L1_J `)dy`ATL6EKY唴=ռ(BPC*\RDNauTݠ F<8 z[C aRl!&ШJ[OH!q֔!Z)~ #T!f!An`"J!"$#IL"![JUv?"BdeTQrhtR50rYh)6!Lz͠I7>b!YoF́%^(Ƞ8VEL7.J"%PA%Rc?\#<">P%"%VKPiEi©J!.fA_AԥbS5^L AѡC*\03d'?P28$"wz'x']FQXVHp MC/\J=8{Vg>'D?C*􌉅cA((:hʄ"~gLPAwΝ{$)phEFə'f^ q&?`eD y'zLpg*(?hW}/1=X0Qw~hxš\|;J|iC.Dy.REbLAF =3A6@FS8A+@*nl+B૷ꆿ6<λk) f+fQ~, Űf+lCʆΡtl5Vql*85C%puTzƴЎLCm̄t@Al9"IΉ)kt$+B,k*'lF&FHmRPmeFbk\`Yِh I𘄍Ԅp!ʄEFD Je{d0HTD:OnCHnV&ÝJEInW.R]nO,MT^RLBKHЄ2rO8 JDN/j0 k~1O/.2-Fj/Zp|gDj]ēf\Tdo2brd(000ʯүɲ<a$-(`X3.k`np7tk[ #TpWt K 0}%Ā0G}$G K;F?/GW1w11111VT V0)ЈnH,<1 waC\ĒE:2#7#?2 MU!jAA&o2'wr}JstGy*2+^@1.\Ad+2/+#a B/1s#;@T((;2G4O/B؂R37w7O0֣ʄQȃL7:󃰢8m], ;3=׳lj.3??3sC?Ac V0 "C?4D7nF4FgFg%} o4HtD/ H4JJ4KK4LǴL4M33FMN?MN4PqOCPQPR/'5S?5TSG5UW5LUgVKVoW5t5X5YX5Z5pZ[c[\V5]5^]5_^5`_6a`6ba'6cgb76dCu@!,Dڋ޼H扦ʶnLlL*̦)*Ԫj\  9:(8HWt)9IIX y *9jzT K[k{ ;,<ܩK|L -=M]m} .>N^n~/?O_o0 <0… :|1ĉ+Z1ƍ;z2ȑ$K<2ʕ,[| 3̙4kڼ3Ν<{ 4СD=4ҥL:} 5ԩTZ5֭\z 6رd˚=6ڵlۺ} 7ܹtڽ7޽| 8 >8Ō;~ 9ɔ+[9͜;{ :ѤK>:լ[~ ;ٴk۾;ݼ{ <ċ?<̛;=ԫ[=ܻ{>˛?>ۻ?ۿ?`H`` .`>aNHa^ana~b"Hb&b*b.c2Hc6ވc:c>dBIdFdJ.dN> eRNIeV^eZne^~ fbIfffjfn grIgvމgzg~ hJhh.h> iNJi^ini~ jJjjj kJkފkk lKllʋ.l> mNKm^mnm~ nKn枋nn oKoދoo pLpp /p? qOLq_qoq r"Lr&r*r. s2Ls6Li;logxi-1/v1/000077500000000000000000000000001300440512700126605ustar00rootroot00000000000000logxi-1/v1/bench/000077500000000000000000000000001300440512700137375ustar00rootroot00000000000000logxi-1/v1/bench/bench_test.go000066400000000000000000000115011300440512700164020ustar00rootroot00000000000000package bench import ( "encoding/json" L "log" "os" "testing" "github.com/Sirupsen/logrus" "github.com/mgutz/logxi/v1" "gopkg.in/inconshreveable/log15.v2" ) type M map[string]interface{} var testObject = M{ "foo": "bar", "bah": M{ "int": 1, "float": -100.23, "date": "06-01-01T15:04:05-0700", "bool": true, "nullable": nil, }, } var pid = os.Getpid() func toJSON(m map[string]interface{}) string { b, _ := json.Marshal(m) return string(b) } // These tests write out all log levels with concurrency turned on and // equivalent fields. func BenchmarkLog(b *testing.B) { //fmt.Println("") l := L.New(os.Stdout, "bench ", L.LstdFlags) b.ResetTimer() for i := 0; i < b.N; i++ { debug := map[string]interface{}{"l": "debug", "key1": 1, "key2": "string", "key3": false} l.Printf(toJSON(debug)) info := map[string]interface{}{"l": "info", "key1": 1, "key2": "string", "key3": false} l.Printf(toJSON(info)) warn := map[string]interface{}{"l": "warn", "key1": 1, "key2": "string", "key3": false} l.Printf(toJSON(warn)) err := map[string]interface{}{"l": "error", "key1": 1, "key2": "string", "key3": false} l.Printf(toJSON(err)) } b.StopTimer() } func BenchmarkLogComplex(b *testing.B) { //fmt.Println("") l := L.New(os.Stdout, "bench ", L.LstdFlags) b.ResetTimer() for i := 0; i < b.N; i++ { debug := map[string]interface{}{"l": "debug", "key1": 1, "obj": testObject} l.Printf(toJSON(debug)) info := map[string]interface{}{"l": "info", "key1": 1, "obj": testObject} l.Printf(toJSON(info)) warn := map[string]interface{}{"l": "warn", "key1": 1, "obj": testObject} l.Printf(toJSON(warn)) err := map[string]interface{}{"l": "error", "key1": 1, "obj": testObject} l.Printf(toJSON(err)) } b.StopTimer() } func BenchmarkLogxi(b *testing.B) { //fmt.Println("") stdout := log.NewConcurrentWriter(os.Stdout) l := log.NewLogger3(stdout, "bench", log.NewJSONFormatter("bench")) l.SetLevel(log.LevelDebug) b.ResetTimer() for i := 0; i < b.N; i++ { l.Debug("debug", "key", 1, "key2", "string", "key3", false) l.Info("info", "key", 1, "key2", "string", "key3", false) l.Warn("warn", "key", 1, "key2", "string", "key3", false) l.Error("error", "key", 1, "key2", "string", "key3", false) } b.StopTimer() } func BenchmarkLogxiComplex(b *testing.B) { //fmt.Println("") stdout := log.NewConcurrentWriter(os.Stdout) l := log.NewLogger3(stdout, "bench", log.NewJSONFormatter("bench")) l.SetLevel(log.LevelDebug) b.ResetTimer() for i := 0; i < b.N; i++ { l.Debug("debug", "key", 1, "obj", testObject) l.Info("info", "key", 1, "obj", testObject) l.Warn("warn", "key", 1, "obj", testObject) l.Error("error", "key", 1, "obj", testObject) } b.StopTimer() } func BenchmarkLogrus(b *testing.B) { //fmt.Println("") l := logrus.New() l.Formatter = &logrus.JSONFormatter{} b.ResetTimer() for i := 0; i < b.N; i++ { l.WithFields(logrus.Fields{"_n": "bench", "_p": pid, "key": 1, "key2": "string", "key3": false}).Debug("debug") l.WithFields(logrus.Fields{"_n": "bench", "_p": pid, "key": 1, "key2": "string", "key3": false}).Info("info") l.WithFields(logrus.Fields{"_n": "bench", "_p": pid, "key": 1, "key2": "string", "key3": false}).Warn("warn") l.WithFields(logrus.Fields{"_n": "bench", "_p": pid, "key": 1, "key2": "string", "key3": false}).Error("error") } b.StopTimer() } func BenchmarkLogrusComplex(b *testing.B) { //fmt.Println("") l := logrus.New() l.Formatter = &logrus.JSONFormatter{} b.ResetTimer() for i := 0; i < b.N; i++ { l.WithFields(logrus.Fields{"_n": "bench", "_p": pid, "key": 1, "obj": testObject}).Debug("debug") l.WithFields(logrus.Fields{"_n": "bench", "_p": pid, "key": 1, "obj": testObject}).Info("info") l.WithFields(logrus.Fields{"_n": "bench", "_p": pid, "key": 1, "obj": testObject}).Warn("warn") l.WithFields(logrus.Fields{"_n": "bench", "_p": pid, "key": 1, "obj": testObject}).Error("error") } b.StopTimer() } func BenchmarkLog15(b *testing.B) { //fmt.Println("") l := log15.New(log15.Ctx{"_n": "bench", "_p": pid}) l.SetHandler(log15.SyncHandler(log15.StreamHandler(os.Stdout, log15.JsonFormat()))) b.ResetTimer() for i := 0; i < b.N; i++ { l.Debug("debug", "key", 1, "key2", "string", "key3", false) l.Info("info", "key", 1, "key2", "string", "key3", false) l.Warn("warn", "key", 1, "key2", "string", "key3", false) l.Error("error", "key", 1, "key2", "string", "key3", false) } b.StopTimer() } func BenchmarkLog15Complex(b *testing.B) { //fmt.Println("") l := log15.New(log15.Ctx{"_n": "bench", "_p": pid}) l.SetHandler(log15.SyncHandler(log15.StreamHandler(os.Stdout, log15.JsonFormat()))) b.ResetTimer() for i := 0; i < b.N; i++ { l.Debug("debug", "key", 1, "obj", testObject) l.Info("info", "key", 1, "obj", testObject) l.Warn("warn", "key", 1, "obj", testObject) l.Error("error", "key", 1, "obj", testObject) } b.StopTimer() } logxi-1/v1/callstack.go000066400000000000000000000156571300440512700151660ustar00rootroot00000000000000package log import ( "bufio" "fmt" "os" "path/filepath" "strconv" "strings" "github.com/mgutz/ansi" ) type sourceLine struct { lineno int line string } type frameInfo struct { filename string lineno int method string context []*sourceLine contextLines int } func (ci *frameInfo) readSource(contextLines int) error { if ci.lineno == 0 || disableCallstack { return nil } start := maxInt(1, ci.lineno-contextLines) end := ci.lineno + contextLines f, err := os.Open(ci.filename) if err != nil { // if we can't read a file, it means user is running this in production disableCallstack = true return err } defer f.Close() lineno := 1 scanner := bufio.NewScanner(f) for scanner.Scan() { if start <= lineno && lineno <= end { line := scanner.Text() line = expandTabs(line, 4) ci.context = append(ci.context, &sourceLine{lineno: lineno, line: line}) } lineno++ } if err := scanner.Err(); err != nil { InternalLog.Warn("scanner error", "file", ci.filename, "err", err) } return nil } func (ci *frameInfo) String(color string, sourceColor string) string { buf := pool.Get() defer pool.Put(buf) if disableCallstack { buf.WriteString(color) buf.WriteString(Separator) buf.WriteString(indent) buf.WriteString(ci.filename) buf.WriteRune(':') buf.WriteString(strconv.Itoa(ci.lineno)) return buf.String() } // skip anything in the logxi package if isLogxiCode(ci.filename) { return "" } // make path relative to current working directory or home tildeFilename, err := filepath.Rel(wd, ci.filename) if err != nil { InternalLog.Warn("Could not make path relative", "path", ci.filename) return "" } // ../../../ is too complex. Make path relative to home if strings.HasPrefix(tildeFilename, strings.Repeat(".."+string(os.PathSeparator), 3)) { tildeFilename = strings.Replace(tildeFilename, home, "~", 1) } buf.WriteString(color) buf.WriteString(Separator) buf.WriteString(indent) buf.WriteString("in ") buf.WriteString(ci.method) buf.WriteString("(") buf.WriteString(tildeFilename) buf.WriteRune(':') buf.WriteString(strconv.Itoa(ci.lineno)) buf.WriteString(")") if ci.contextLines == -1 { return buf.String() } buf.WriteString("\n") // the width of the printed line number var linenoWidth int // trim spaces at start of source code based on common spaces var skipSpaces = 1000 // calculate width of lineno and number of leading spaces that can be // removed for _, li := range ci.context { linenoWidth = maxInt(linenoWidth, len(fmt.Sprintf("%d", li.lineno))) index := indexOfNonSpace(li.line) if index > -1 && index < skipSpaces { skipSpaces = index } } for _, li := range ci.context { var format string format = fmt.Sprintf("%%s%%%dd: %%s\n", linenoWidth) if li.lineno == ci.lineno { buf.WriteString(color) if ci.contextLines > 2 { format = fmt.Sprintf("%%s=> %%%dd: %%s\n", linenoWidth) } } else { buf.WriteString(sourceColor) if ci.contextLines > 2 { // account for "=> " format = fmt.Sprintf("%%s%%%dd: %%s\n", linenoWidth+3) } } // trim spaces at start idx := minInt(len(li.line), skipSpaces) buf.WriteString(fmt.Sprintf(format, Separator+indent+indent, li.lineno, li.line[idx:])) } // get rid of last \n buf.Truncate(buf.Len() - 1) if !disableColors { buf.WriteString(ansi.Reset) } return buf.String() } // parseDebugStack parases a stack created by debug.Stack() // // This is what the string looks like // /Users/mgutz/go/src/github.com/mgutz/logxi/v1/jsonFormatter.go:45 (0x5fa70) // (*JSONFormatter).writeError: jf.writeString(buf, err.Error()+"\n"+string(debug.Stack())) // /Users/mgutz/go/src/github.com/mgutz/logxi/v1/jsonFormatter.go:82 (0x5fdc3) // (*JSONFormatter).appendValue: jf.writeError(buf, err) // /Users/mgutz/go/src/github.com/mgutz/logxi/v1/jsonFormatter.go:109 (0x605ca) // (*JSONFormatter).set: jf.appendValue(buf, val) // ... // /Users/mgutz/goroot/src/runtime/asm_amd64.s:2232 (0x38bf1) // goexit: func parseDebugStack(stack string, skip int, ignoreRuntime bool) []*frameInfo { frames := []*frameInfo{} // BUG temporarily disable since there is a bug with embedded newlines if true { return frames } lines := strings.Split(stack, "\n") for i := skip * 2; i < len(lines); i += 2 { ci := &frameInfo{} sourceLine := lines[i] if sourceLine == "" { break } if ignoreRuntime && strings.Contains(sourceLine, filepath.Join("src", "runtime")) { break } colon := strings.Index(sourceLine, ":") slash := strings.Index(sourceLine, "/") if colon < slash { // must be on Windows where paths look like c:/foo/bar.go:lineno colon = strings.Index(sourceLine[slash:], ":") + slash } space := strings.Index(sourceLine, " ") ci.filename = sourceLine[0:colon] // BUG with callstack where the error message has embedded newlines // if colon > space { // fmt.Println("lines", lines) // } // fmt.Println("SOURCELINE", sourceLine, "len", len(sourceLine), "COLON", colon, "SPACE", space) numstr := sourceLine[colon+1 : space] lineno, err := strconv.Atoi(numstr) if err != nil { InternalLog.Warn("Could not parse line number", "sourceLine", sourceLine, "numstr", numstr) continue } ci.lineno = lineno methodLine := lines[i+1] colon = strings.Index(methodLine, ":") ci.method = strings.Trim(methodLine[0:colon], "\t ") frames = append(frames, ci) } return frames } // parseDebugStack parases a stack created by debug.Stack() // // This is what the string looks like // /Users/mgutz/go/src/github.com/mgutz/logxi/v1/jsonFormatter.go:45 (0x5fa70) // (*JSONFormatter).writeError: jf.writeString(buf, err.Error()+"\n"+string(debug.Stack())) // /Users/mgutz/go/src/github.com/mgutz/logxi/v1/jsonFormatter.go:82 (0x5fdc3) // (*JSONFormatter).appendValue: jf.writeError(buf, err) // /Users/mgutz/go/src/github.com/mgutz/logxi/v1/jsonFormatter.go:109 (0x605ca) // (*JSONFormatter).set: jf.appendValue(buf, val) // ... // /Users/mgutz/goroot/src/runtime/asm_amd64.s:2232 (0x38bf1) // goexit: func trimDebugStack(stack string) string { buf := pool.Get() defer pool.Put(buf) lines := strings.Split(stack, "\n") for i := 0; i < len(lines); i += 2 { sourceLine := lines[i] if sourceLine == "" { break } colon := strings.Index(sourceLine, ":") slash := strings.Index(sourceLine, "/") if colon < slash { // must be on Windows where paths look like c:/foo/bar.go:lineno colon = strings.Index(sourceLine[slash:], ":") + slash } filename := sourceLine[0:colon] // skip anything in the logxi package if isLogxiCode(filename) { continue } buf.WriteString(sourceLine) buf.WriteRune('\n') buf.WriteString(lines[i+1]) buf.WriteRune('\n') } return buf.String() } func parseLogxiStack(entry map[string]interface{}, skip int, ignoreRuntime bool) []*frameInfo { kv := entry[KeyMap.CallStack] if kv == nil { return nil } var frames []*frameInfo if stack, ok := kv.(string); ok { frames = parseDebugStack(stack, skip, ignoreRuntime) } return frames } logxi-1/v1/cmd/000077500000000000000000000000001300440512700134235ustar00rootroot00000000000000logxi-1/v1/cmd/demo/000077500000000000000000000000001300440512700143475ustar00rootroot00000000000000logxi-1/v1/cmd/demo/main.ansi000066400000000000000000000041221300440512700161460ustar00rootroot00000000000000import  "github.com/mgutz/logxi/v1" func loadConfig() {  logger.Error("Could not read config file", "err", errConfig) } func main() {  // create loggers  log.Trace("creating loggers")  logger = log.New("server")  modelsLogger := log.New("models")  logger.Debug("Process", "hostname", hostname, "pid", os.Getpid())  modelsLogger.Info("Connecting to database...")  modelsLogger.Warn("Could not connect, retrying ...", "dsn", dsn)  loadConfig() } logxi-1/v1/cmd/demo/main.go000066400000000000000000000012361300440512700156240ustar00rootroot00000000000000package main import ( "fmt" "os" "github.com/mgutz/logxi/v1" ) var errConfig = fmt.Errorf("file not found") var dsn = "dbname=testdb" var logger log.Logger var hostname string var configFile = "config.json" func init() { hostname, _ = os.Hostname() } func loadConfig() { logger.Error("Could not read config file", "err", errConfig) } func main() { // create loggers log.Trace("creating loggers") logger = log.New("server") modelsLogger := log.New("models") logger.Debug("Process", "hostname", hostname, "pid", os.Getpid()) modelsLogger.Info("Connecting to database...") modelsLogger.Warn("Could not connect, retrying ...", "dsn", dsn) loadConfig() } logxi-1/v1/cmd/filter/000077500000000000000000000000001300440512700147105ustar00rootroot00000000000000logxi-1/v1/cmd/filter/README.md000066400000000000000000000002541300440512700161700ustar00rootroot00000000000000# filter Filter is an example of a how to process JSON log entries using pipes in your shell. ```sh yourapp | filter ``` You can try see it in action with `godo filter` logxi-1/v1/cmd/filter/main.go000066400000000000000000000012571300440512700161700ustar00rootroot00000000000000package main import ( "bufio" "encoding/json" "fmt" "io" "os" "github.com/mgutz/logxi/v1" ) func sendExternal(obj map[string]interface{}) { // normally you would send this to an external service like InfluxDB // or some logging framework. Let's filter out some data. fmt.Printf("Time: %s Level: %s Message: %s\n", obj[log.KeyMap.Time], obj[log.KeyMap.Level], obj[log.KeyMap.Message], ) } func main() { r := bufio.NewReader(os.Stdin) dec := json.NewDecoder(r) for { var obj map[string]interface{} if err := dec.Decode(&obj); err == io.EOF { break } else if err != nil { log.InternalLog.Fatal("Could not decode", "err", err) } sendExternal(obj) } } logxi-1/v1/cmd/reldir/000077500000000000000000000000001300440512700147045ustar00rootroot00000000000000logxi-1/v1/cmd/reldir/README.md000066400000000000000000000000741300440512700161640ustar00rootroot00000000000000# reldir Used to test relative paths when logging context. logxi-1/v1/cmd/reldir/foo.go000066400000000000000000000001561300440512700160200ustar00rootroot00000000000000package reldir import "github.com/mgutz/logxi/v1" // Foo returns error func Foo() { log.Error("Oh bar!") } logxi-1/v1/concurrentWriter.go000066400000000000000000000011341300440512700165650ustar00rootroot00000000000000package log import ( "io" "sync" ) // ConcurrentWriter is a concurrent safe wrapper around io.Writer type ConcurrentWriter struct { writer io.Writer sync.Mutex } // NewConcurrentWriter crates a new concurrent writer wrapper around existing writer. func NewConcurrentWriter(writer io.Writer) io.Writer { return &ConcurrentWriter{writer: writer} } func (cw *ConcurrentWriter) Write(p []byte) (n int, err error) { cw.Lock() defer cw.Unlock() // This is basically the same logic as in go's log.Output() which // doesn't look at the returned number of bytes returned return cw.writer.Write(p) } logxi-1/v1/defaultLogger.go000066400000000000000000000070511300440512700157760ustar00rootroot00000000000000package log import ( "fmt" "io" ) // DefaultLogger is the default logger for this package. type DefaultLogger struct { writer io.Writer name string level int formatter Formatter } // NewLogger creates a new default logger. If writer is not concurrent // safe, wrap it with NewConcurrentWriter. func NewLogger(writer io.Writer, name string) Logger { formatter, err := createFormatter(name, logxiFormat) if err != nil { panic("Could not create formatter") } return NewLogger3(writer, name, formatter) } // NewLogger3 creates a new logger with a writer, name and formatter. If writer is not concurrent // safe, wrap it with NewConcurrentWriter. func NewLogger3(writer io.Writer, name string, formatter Formatter) Logger { var level int if name != "__logxi" { // if err is returned, then it means the log is disabled level = getLogLevel(name) if level == LevelOff { return NullLog } } log := &DefaultLogger{ formatter: formatter, writer: writer, name: name, level: level, } // TODO loggers will be used when watching changes to configuration such // as in consul, etcd loggers.Lock() loggers.loggers[name] = log loggers.Unlock() return log } // New creates a colorable default logger. func New(name string) Logger { return NewLogger(colorableStdout, name) } // Trace logs a debug entry. func (l *DefaultLogger) Trace(msg string, args ...interface{}) { l.Log(LevelTrace, msg, args) } // Debug logs a debug entry. func (l *DefaultLogger) Debug(msg string, args ...interface{}) { l.Log(LevelDebug, msg, args) } // Info logs an info entry. func (l *DefaultLogger) Info(msg string, args ...interface{}) { l.Log(LevelInfo, msg, args) } // Warn logs a warn entry. func (l *DefaultLogger) Warn(msg string, args ...interface{}) error { if l.IsWarn() { defer l.Log(LevelWarn, msg, args) for _, arg := range args { if err, ok := arg.(error); ok { return err } } return nil } return nil } func (l *DefaultLogger) extractLogError(level int, msg string, args []interface{}) error { defer l.Log(level, msg, args) for _, arg := range args { if err, ok := arg.(error); ok { return err } } return fmt.Errorf(msg) } // Error logs an error entry. func (l *DefaultLogger) Error(msg string, args ...interface{}) error { return l.extractLogError(LevelError, msg, args) } // Fatal logs a fatal entry then panics. func (l *DefaultLogger) Fatal(msg string, args ...interface{}) { l.extractLogError(LevelFatal, msg, args) defer panic("Exit due to fatal error: ") } // Log logs a leveled entry. func (l *DefaultLogger) Log(level int, msg string, args []interface{}) { // log if the log level (warn=4) >= level of message (err=3) if l.level < level || silent { return } l.formatter.Format(l.writer, level, msg, args) } // IsTrace determines if this logger logs a debug statement. func (l *DefaultLogger) IsTrace() bool { // DEBUG(7) >= TRACE(10) return l.level >= LevelTrace } // IsDebug determines if this logger logs a debug statement. func (l *DefaultLogger) IsDebug() bool { return l.level >= LevelDebug } // IsInfo determines if this logger logs an info statement. func (l *DefaultLogger) IsInfo() bool { return l.level >= LevelInfo } // IsWarn determines if this logger logs a warning statement. func (l *DefaultLogger) IsWarn() bool { return l.level >= LevelWarn } // SetLevel sets the level of this logger. func (l *DefaultLogger) SetLevel(level int) { l.level = level } // SetFormatter set the formatter for this logger. func (l *DefaultLogger) SetFormatter(formatter Formatter) { l.formatter = formatter } logxi-1/v1/env.go000066400000000000000000000071061300440512700140030ustar00rootroot00000000000000package log import ( "os" "strconv" "strings" ) var contextLines int // Configuration comes from environment or external services like // consul, etcd. type Configuration struct { Format string `json:"format"` Colors string `json:"colors"` Levels string `json:"levels"` } func readFromEnviron() *Configuration { conf := &Configuration{} var envOrDefault = func(name, val string) string { result := os.Getenv(name) if result == "" { result = val } return result } conf.Levels = envOrDefault("LOGXI", defaultLogxiEnv) conf.Format = envOrDefault("LOGXI_FORMAT", defaultLogxiFormatEnv) conf.Colors = envOrDefault("LOGXI_COLORS", defaultLogxiColorsEnv) return conf } // ProcessEnv (re)processes environment. func ProcessEnv(env *Configuration) { // TODO: allow reading from etcd ProcessLogxiEnv(env.Levels) ProcessLogxiColorsEnv(env.Colors) ProcessLogxiFormatEnv(env.Format) } // ProcessLogxiFormatEnv parses LOGXI_FORMAT func ProcessLogxiFormatEnv(env string) { logxiFormat = env m := parseKVList(logxiFormat, ",") formatterFormat := "" tFormat := "" for key, value := range m { switch key { default: formatterFormat = key case "t": tFormat = value case "pretty": isPretty = value != "false" && value != "0" case "maxcol": col, err := strconv.Atoi(value) if err == nil { maxCol = col } else { maxCol = defaultMaxCol } case "context": lines, err := strconv.Atoi(value) if err == nil { contextLines = lines } else { contextLines = defaultContextLines } case "LTSV": formatterFormat = "text" AssignmentChar = ltsvAssignmentChar Separator = ltsvSeparator } } if formatterFormat == "" || formatterCreators[formatterFormat] == nil { formatterFormat = defaultFormat } logxiFormat = formatterFormat if tFormat == "" { tFormat = defaultTimeFormat } timeFormat = tFormat } // ProcessLogxiEnv parses LOGXI variable func ProcessLogxiEnv(env string) { logxiEnable := env if logxiEnable == "" { logxiEnable = defaultLogxiEnv } logxiNameLevelMap = map[string]int{} m := parseKVList(logxiEnable, ",") if m == nil { logxiNameLevelMap["*"] = defaultLevel } for key, value := range m { if strings.HasPrefix(key, "-") { // LOGXI=*,-foo => disable foo logxiNameLevelMap[key[1:]] = LevelOff } else if value == "" { // LOGXI=* => default to all logxiNameLevelMap[key] = LevelAll } else { // LOGXI=*=ERR => use user-specified level level := LevelAtoi[value] if level == 0 { InternalLog.Error("Unknown level in LOGXI environment variable", "key", key, "value", value, "LOGXI", env) level = defaultLevel } logxiNameLevelMap[key] = level } } // must always have global default, otherwise errs may get eaten up if _, ok := logxiNameLevelMap["*"]; !ok { logxiNameLevelMap["*"] = LevelError } } func getLogLevel(name string) int { var wildcardLevel int var result int for k, v := range logxiNameLevelMap { if k == name { result = v } else if k == "*" { wildcardLevel = v } else if strings.HasPrefix(k, "*") && strings.HasSuffix(name, k[1:]) { result = v } else if strings.HasSuffix(k, "*") && strings.HasPrefix(name, k[:len(k)-1]) { result = v } } if result == LevelOff { return LevelOff } if result > 0 { return result } if wildcardLevel > 0 { return wildcardLevel } return LevelOff } // ProcessLogxiColorsEnv parases LOGXI_COLORS func ProcessLogxiColorsEnv(env string) { colors := env if colors == "" { colors = defaultLogxiColorsEnv } else if colors == "*=off" { // disable all colors disableColors = true } theme = parseTheme(colors) } logxi-1/v1/formatter.go000066400000000000000000000027201300440512700152130ustar00rootroot00000000000000package log var formatterCreators = map[string]CreateFormatterFunc{} // CreateFormatterFunc is a function which creates a new instance // of a Formatter. type CreateFormatterFunc func(name, kind string) (Formatter, error) // createFormatter creates formatters. It accepts a kind in {"text", "JSON"} // which correspond to TextFormatter and JSONFormatter, and the name of the // logger. func createFormatter(name string, kind string) (Formatter, error) { if kind == FormatEnv { kind = logxiFormat } if kind == "" { kind = FormatText } fn := formatterCreators[kind] if fn == nil { fn = formatterCreators[FormatText] } formatter, err := fn(name, kind) if err != nil { return nil, err } // custom formatter may have not returned a formatter if formatter == nil { formatter, err = formatFactory(name, FormatText) } return formatter, err } func formatFactory(name string, kind string) (Formatter, error) { var formatter Formatter var err error switch kind { default: formatter = NewTextFormatter(name) case FormatHappy: formatter = NewHappyDevFormatter(name) case FormatText: formatter = NewTextFormatter(name) case FormatJSON: formatter = NewJSONFormatter(name) } return formatter, err } // RegisterFormatFactory registers a format factory function. func RegisterFormatFactory(kind string, fn CreateFormatterFunc) { if kind == "" { panic("kind is empty string") } if fn == nil { panic("creator is nil") } formatterCreators[kind] = fn } logxi-1/v1/happyDevFormatter.go000066400000000000000000000214271300440512700166610ustar00rootroot00000000000000package log import ( "encoding/json" "fmt" "io" "runtime/debug" "strings" "github.com/mgutz/ansi" ) // colorScheme defines a color theme for HappyDevFormatter type colorScheme struct { Key string Message string Value string Misc string Source string Trace string Debug string Info string Warn string Error string } var indent = " " var maxCol = defaultMaxCol var theme *colorScheme func parseKVList(s, separator string) map[string]string { pairs := strings.Split(s, separator) if len(pairs) == 0 { return nil } m := map[string]string{} for _, pair := range pairs { if pair == "" { continue } parts := strings.Split(pair, "=") switch len(parts) { case 1: m[parts[0]] = "" case 2: m[parts[0]] = parts[1] } } return m } func parseTheme(theme string) *colorScheme { m := parseKVList(theme, ",") cs := &colorScheme{} var wildcard string var color = func(key string) string { if disableColors { return "" } style := m[key] c := ansi.ColorCode(style) if c == "" { c = wildcard } //fmt.Printf("plain=%b [%s] %s=%q\n", ansi.DefaultFG, key, style, c) return c } wildcard = color("*") if wildcard != ansi.Reset { cs.Key = wildcard cs.Value = wildcard cs.Misc = wildcard cs.Source = wildcard cs.Message = wildcard cs.Trace = wildcard cs.Debug = wildcard cs.Warn = wildcard cs.Info = wildcard cs.Error = wildcard } cs.Key = color("key") cs.Value = color("value") cs.Misc = color("misc") cs.Source = color("source") cs.Message = color("message") cs.Trace = color("TRC") cs.Debug = color("DBG") cs.Warn = color("WRN") cs.Info = color("INF") cs.Error = color("ERR") return cs } // HappyDevFormatter is the formatter used for terminals. It is // colorful, dev friendly and provides meaningful logs when // warnings and errors occur. // // HappyDevFormatter does not worry about performance. It's at least 3-4X // slower than JSONFormatter since it delegates to JSONFormatter to marshal // then unmarshal JSON. Then it does other stuff like read source files, sort // keys all to give a developer more information. // // SHOULD NOT be used in production for extended period of time. However, it // works fine in SSH terminals and binary deployments. type HappyDevFormatter struct { name string col int // always use the production formatter jsonFormatter *JSONFormatter } // NewHappyDevFormatter returns a new instance of HappyDevFormatter. func NewHappyDevFormatter(name string) *HappyDevFormatter { jf := NewJSONFormatter(name) return &HappyDevFormatter{ name: name, jsonFormatter: jf, } } func (hd *HappyDevFormatter) writeKey(buf bufferWriter, key string) { // assumes this is not the first key hd.writeString(buf, Separator) if key == "" { return } buf.WriteString(theme.Key) hd.writeString(buf, key) hd.writeString(buf, AssignmentChar) if !disableColors { buf.WriteString(ansi.Reset) } } func (hd *HappyDevFormatter) set(buf bufferWriter, key string, value interface{}, color string) { var str string if s, ok := value.(string); ok { str = s } else if s, ok := value.(fmt.Stringer); ok { str = s.String() } else { str = fmt.Sprintf("%v", value) } val := strings.Trim(str, "\n ") if (isPretty && key != "") || hd.col+len(key)+2+len(val) >= maxCol { buf.WriteString("\n") hd.col = 0 hd.writeString(buf, indent) } hd.writeKey(buf, key) if color != "" { buf.WriteString(color) } hd.writeString(buf, val) if color != "" && !disableColors { buf.WriteString(ansi.Reset) } } // Write a string and tracks the position of the string so we can break lines // cleanly. Do not send ANSI escape sequences, just raw strings func (hd *HappyDevFormatter) writeString(buf bufferWriter, s string) { buf.WriteString(s) hd.col += len(s) } func (hd *HappyDevFormatter) getContext(color string) string { if disableCallstack { return "" } frames := parseDebugStack(string(debug.Stack()), 5, true) if len(frames) == 0 { return "" } for _, frame := range frames { context := frame.String(color, theme.Source) if context != "" { return context } } return "" } func (hd *HappyDevFormatter) getLevelContext(level int, entry map[string]interface{}) (message string, context string, color string) { switch level { case LevelTrace: color = theme.Trace context = hd.getContext(color) context += "\n" case LevelDebug: color = theme.Debug case LevelInfo: color = theme.Info // case LevelWarn: // color = theme.Warn // context = hd.getContext(color) // context += "\n" case LevelWarn, LevelError, LevelFatal: // warnings return an error but if it does not have an error // then print line info only if level == LevelWarn { color = theme.Warn kv := entry[KeyMap.CallStack] if kv == nil { context = hd.getContext(color) context += "\n" break } } else { color = theme.Error } if disableCallstack || contextLines == -1 { context = trimDebugStack(string(debug.Stack())) break } frames := parseLogxiStack(entry, 4, true) if frames == nil { frames = parseDebugStack(string(debug.Stack()), 4, true) } if len(frames) == 0 { break } errbuf := pool.Get() defer pool.Put(errbuf) lines := 0 for _, frame := range frames { err := frame.readSource(contextLines) if err != nil { // by setting to empty, the original stack is used errbuf.Reset() break } ctx := frame.String(color, theme.Source) if ctx == "" { continue } errbuf.WriteString(ctx) errbuf.WriteRune('\n') lines++ } context = errbuf.String() default: panic("should never get here") } return message, context, color } // Format a log entry. func (hd *HappyDevFormatter) Format(writer io.Writer, level int, msg string, args []interface{}) { buf := pool.Get() defer pool.Put(buf) if len(args) == 1 { args = append(args, 0) copy(args[1:], args[0:]) args[0] = singleArgKey } // warn about reserved, bad and complex keys for i := 0; i < len(args); i += 2 { isReserved, err := isReservedKey(args[i]) if err != nil { InternalLog.Error("Key is not a string.", "err", fmt.Errorf("args[%d]=%v", i, args[i])) } else if isReserved { InternalLog.Fatal("Key conflicts with reserved key. Avoiding using single rune keys.", "key", args[i].(string)) } else { // Ensure keys are simple strings. The JSONFormatter doesn't escape // keys as a performance tradeoff. This panics if the JSON key // value has a different value than a simple quoted string. key := args[i].(string) b, err := json.Marshal(key) if err != nil { panic("Key is invalid. " + err.Error()) } if string(b) != `"`+key+`"` { panic("Key is complex. Use simpler key for: " + fmt.Sprintf("%q", key)) } } } // use the production JSON formatter to format the log first. This // ensures JSON will marshal/unmarshal correctly in production. entry := hd.jsonFormatter.LogEntry(level, msg, args) // reset the column tracker used for fancy formatting hd.col = 0 // timestamp buf.WriteString(theme.Misc) hd.writeString(buf, entry[KeyMap.Time].(string)) if !disableColors { buf.WriteString(ansi.Reset) } // emphasize warnings and errors message, context, color := hd.getLevelContext(level, entry) if message == "" { message = entry[KeyMap.Message].(string) } // DBG, INF ... hd.set(buf, "", entry[KeyMap.Level].(string), color) // logger name hd.set(buf, "", entry[KeyMap.Name], theme.Misc) // message from user hd.set(buf, "", message, theme.Message) // Preserve key order in the sequencethey were added by developer.This // makes it easier for developers to follow the log. order := []string{} lenArgs := len(args) for i := 0; i < len(args); i += 2 { if i+1 >= lenArgs { continue } if key, ok := args[i].(string); ok { order = append(order, key) } else { order = append(order, badKeyAtIndex(i)) } } for _, key := range order { // skip reserved keys which were already added to buffer above isReserved, err := isReservedKey(key) if err != nil { panic("key is invalid. Should never get here. " + err.Error()) } else if isReserved { continue } hd.set(buf, key, entry[key], theme.Value) } addLF := true hasCallStack := entry[KeyMap.CallStack] != nil // WRN,ERR file, line number context if context != "" { // warnings and traces are single line, space can be optimized if level == LevelTrace || (level == LevelWarn && !hasCallStack) { // gets rid of "in " idx := strings.IndexRune(context, 'n') hd.set(buf, "in", context[idx+2:], color) } else { buf.WriteRune('\n') if !disableColors { buf.WriteString(color) } addLF = context[len(context)-1:len(context)] != "\n" buf.WriteString(context) if !disableColors { buf.WriteString(ansi.Reset) } } } else if hasCallStack { hd.set(buf, "", entry[KeyMap.CallStack], color) } if addLF { buf.WriteRune('\n') } buf.WriteTo(writer) } logxi-1/v1/init.go000066400000000000000000000114141300440512700141530ustar00rootroot00000000000000package log import ( "fmt" "io" "os" "runtime" "strconv" "sync" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" ) // scream so user fixes it const warnImbalancedKey = "FIX_IMBALANCED_PAIRS" const warnImbalancedPairs = warnImbalancedKey + " => " const singleArgKey = "_" func badKeyAtIndex(i int) string { return "BAD_KEY_AT_INDEX_" + strconv.Itoa(i) } // DefaultLogLog is the default log for this package. var DefaultLog Logger // Suppress supresses logging and is useful to supress output in // in unit tests. // // Example // log.Suppress(true) // defer log.suppress(false) func Suppress(quiet bool) { silent = quiet } var silent bool // internalLog is the logger used by logxi itself var InternalLog Logger type loggerMap struct { sync.Mutex loggers map[string]Logger } var loggers = &loggerMap{ loggers: map[string]Logger{}, } func (lm *loggerMap) set(name string, logger Logger) { lm.loggers[name] = logger } // The assignment character between key-value pairs var AssignmentChar = ": " // Separator is the separator to use between key value pairs //var Separator = "{~}" var Separator = " " const ltsvAssignmentChar = ":" const ltsvSeparator = "\t" // logxiEnabledMap maps log name patterns to levels var logxiNameLevelMap map[string]int // logxiFormat is the formatter kind to create var logxiFormat string var colorableStdout io.Writer var defaultContextLines = 2 var defaultFormat string var defaultLevel int var defaultLogxiEnv string var defaultLogxiFormatEnv string var defaultMaxCol = 80 var defaultPretty = false var defaultLogxiColorsEnv string var defaultTimeFormat string var disableCallstack bool var disableCheckKeys bool var disableColors bool var home string var isPretty bool var isTerminal bool var isWindows = runtime.GOOS == "windows" var pkgMutex sync.Mutex var pool = NewBufferPool() var timeFormat string var wd string var pid = os.Getpid() var pidStr = strconv.Itoa(os.Getpid()) // KeyMapping is the key map used to print built-in log entry fields. type KeyMapping struct { Level string Message string Name string PID string Time string CallStack string } // KeyMap is the key map to use when printing log statements. var KeyMap = &KeyMapping{ Level: "_l", Message: "_m", Name: "_n", PID: "_p", Time: "_t", CallStack: "_c", } var logxiKeys []string func setDefaults(isTerminal bool) { var err error contextLines = defaultContextLines wd, err = os.Getwd() if err != nil { InternalLog.Error("Could not get working directory") } logxiKeys = []string{KeyMap.Level, KeyMap.Message, KeyMap.Name, KeyMap.Time, KeyMap.CallStack, KeyMap.PID} if isTerminal { defaultLogxiEnv = "*=WRN" defaultLogxiFormatEnv = "happy,fit,maxcol=80,t=15:04:05.000000,context=-1" defaultFormat = FormatHappy defaultLevel = LevelWarn defaultTimeFormat = "15:04:05.000000" } else { defaultLogxiEnv = "*=ERR" defaultLogxiFormatEnv = "JSON,t=2006-01-02T15:04:05-0700" defaultFormat = FormatJSON defaultLevel = LevelError defaultTimeFormat = "2006-01-02T15:04:05-0700" disableColors = true } if isWindows { home = os.Getenv("HOMEPATH") if os.Getenv("ConEmuANSI") == "ON" { defaultLogxiColorsEnv = "key=cyan+h,value,misc=blue+h,source=yellow,TRC,DBG,WRN=yellow+h,INF=green+h,ERR=red+h" } else { colorableStdout = NewConcurrentWriter(colorable.NewColorableStdout()) defaultLogxiColorsEnv = "ERR=red,misc=cyan,key=cyan" } // DefaultScheme is a color scheme optimized for dark background // but works well with light backgrounds } else { home = os.Getenv("HOME") term := os.Getenv("TERM") if term == "xterm-256color" { defaultLogxiColorsEnv = "key=cyan+h,value,misc=blue,source=88,TRC,DBG,WRN=yellow,INF=green+h,ERR=red+h,message=magenta+h" } else { defaultLogxiColorsEnv = "key=cyan+h,value,misc=blue,source=magenta,TRC,DBG,WRN=yellow,INF=green,ERR=red+h" } } } func isReservedKey(k interface{}) (bool, error) { key, ok := k.(string) if !ok { return false, fmt.Errorf("Key is not a string") } // check if reserved for _, key2 := range logxiKeys { if key == key2 { return true, nil } } return false, nil } func init() { colorableStdout = NewConcurrentWriter(os.Stdout) isTerminal = isatty.IsTerminal(os.Stdout.Fd()) // the internal logger to report errors if isTerminal { InternalLog = NewLogger3(NewConcurrentWriter(os.Stdout), "__logxi", NewTextFormatter("__logxi")) } else { InternalLog = NewLogger3(NewConcurrentWriter(os.Stdout), "__logxi", NewJSONFormatter("__logxi")) } InternalLog.SetLevel(LevelError) setDefaults(isTerminal) RegisterFormatFactory(FormatHappy, formatFactory) RegisterFormatFactory(FormatText, formatFactory) RegisterFormatFactory(FormatJSON, formatFactory) ProcessEnv(readFromEnviron()) // package logger for users DefaultLog = New("~") } logxi-1/v1/init_test.go000066400000000000000000000007431300440512700152150ustar00rootroot00000000000000package log import ( "bytes" "os" "testing" "github.com/stretchr/testify/assert" ) var testBuf bytes.Buffer var testInternalLog Logger func init() { testInternalLog = NewLogger3(&testBuf, "__logxi", NewTextFormatter("__logxi")) testInternalLog.SetLevel(LevelError) } func TestUnknownLevel(t *testing.T) { testResetEnv() os.Setenv("LOGXI", "*=oy") processEnv() buffer := testBuf.String() assert.Contains(t, buffer, "Unknown level", "should error on unknown level") } logxi-1/v1/jsonFormatter.go000066400000000000000000000122361300440512700160500ustar00rootroot00000000000000package log import ( "encoding/json" "fmt" "io" "reflect" "runtime/debug" "strconv" "time" ) type bufferWriter interface { Write(p []byte) (nn int, err error) WriteRune(r rune) (n int, err error) WriteString(s string) (n int, err error) } // JSONFormatter is a fast, efficient JSON formatter optimized for logging. // // * log entry keys are not escaped // Who uses complex keys when coding? Checked by HappyDevFormatter in case user does. // Nested object keys are escaped by json.Marshal(). // * Primitive types uses strconv // * Logger reserved key values (time, log name, level) require no conversion // * sync.Pool buffer for bytes.Buffer type JSONFormatter struct { name string } // NewJSONFormatter creates a new instance of JSONFormatter. func NewJSONFormatter(name string) *JSONFormatter { return &JSONFormatter{name: name} } func (jf *JSONFormatter) writeString(buf bufferWriter, s string) { b, err := json.Marshal(s) if err != nil { InternalLog.Error("Could not json.Marshal string.", "str", s) buf.WriteString(`"Could not marshal this key's string"`) return } buf.Write(b) } func (jf *JSONFormatter) writeError(buf bufferWriter, err error) { jf.writeString(buf, err.Error()) jf.set(buf, KeyMap.CallStack, string(debug.Stack())) return } func (jf *JSONFormatter) appendValue(buf bufferWriter, val interface{}) { if val == nil { buf.WriteString("null") return } // always show error stack even at cost of some performance. there's // nothing worse than looking at production logs without a clue if err, ok := val.(error); ok { jf.writeError(buf, err) return } value := reflect.ValueOf(val) kind := value.Kind() if kind == reflect.Ptr { if value.IsNil() { buf.WriteString("null") return } value = value.Elem() kind = value.Kind() } switch kind { case reflect.Bool: if value.Bool() { buf.WriteString("true") } else { buf.WriteString("false") } case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: buf.WriteString(strconv.FormatInt(value.Int(), 10)) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: buf.WriteString(strconv.FormatUint(value.Uint(), 10)) case reflect.Float32: buf.WriteString(strconv.FormatFloat(value.Float(), 'g', -1, 32)) case reflect.Float64: buf.WriteString(strconv.FormatFloat(value.Float(), 'g', -1, 64)) default: var err error var b []byte if stringer, ok := val.(fmt.Stringer); ok { b, err = json.Marshal(stringer.String()) } else { b, err = json.Marshal(val) } if err != nil { InternalLog.Error("Could not json.Marshal value: ", "formatter", "JSONFormatter", "err", err.Error()) if s, ok := val.(string); ok { b, err = json.Marshal(s) } else if s, ok := val.(fmt.Stringer); ok { b, err = json.Marshal(s.String()) } else { b, err = json.Marshal(fmt.Sprintf("%#v", val)) } if err != nil { // should never get here, but JSONFormatter should never panic msg := "Could not Sprintf value" InternalLog.Error(msg) buf.WriteString(`"` + msg + `"`) return } } buf.Write(b) } } func (jf *JSONFormatter) set(buf bufferWriter, key string, val interface{}) { // WARNING: assumes this is not first key buf.WriteString(`, "`) buf.WriteString(key) buf.WriteString(`":`) jf.appendValue(buf, val) } // Format formats log entry as JSON. func (jf *JSONFormatter) Format(writer io.Writer, level int, msg string, args []interface{}) { buf := pool.Get() defer pool.Put(buf) const lead = `", "` const colon = `":"` buf.WriteString(`{"`) buf.WriteString(KeyMap.Time) buf.WriteString(`":"`) buf.WriteString(time.Now().Format(timeFormat)) buf.WriteString(`", "`) buf.WriteString(KeyMap.PID) buf.WriteString(`":"`) buf.WriteString(pidStr) buf.WriteString(`", "`) buf.WriteString(KeyMap.Level) buf.WriteString(`":"`) buf.WriteString(LevelMap[level]) buf.WriteString(`", "`) buf.WriteString(KeyMap.Name) buf.WriteString(`":"`) buf.WriteString(jf.name) buf.WriteString(`", "`) buf.WriteString(KeyMap.Message) buf.WriteString(`":`) jf.appendValue(buf, msg) var lenArgs = len(args) if lenArgs > 0 { if lenArgs == 1 { jf.set(buf, singleArgKey, args[0]) } else if lenArgs%2 == 0 { for i := 0; i < lenArgs; i += 2 { if key, ok := args[i].(string); ok { if key == "" { // show key is invalid jf.set(buf, badKeyAtIndex(i), args[i+1]) } else { jf.set(buf, key, args[i+1]) } } else { // show key is invalid jf.set(buf, badKeyAtIndex(i), args[i+1]) } } } else { jf.set(buf, warnImbalancedKey, args) } } buf.WriteString("}\n") buf.WriteTo(writer) } // LogEntry returns the JSON log entry object built by Format(). Used by // HappyDevFormatter to ensure any data logged while developing properly // logs in production. func (jf *JSONFormatter) LogEntry(level int, msg string, args []interface{}) map[string]interface{} { buf := pool.Get() defer pool.Put(buf) jf.Format(buf, level, msg, args) var entry map[string]interface{} err := json.Unmarshal(buf.Bytes(), &entry) if err != nil { panic("Unable to unmarhsal entry from JSONFormatter: " + err.Error() + " \"" + string(buf.Bytes()) + "\"") } return entry } logxi-1/v1/logger.go000066400000000000000000000076711300440512700145010ustar00rootroot00000000000000package log /* http://en.wikipedia.org/wiki/Syslog Code Severity Keyword 0 Emergency emerg (panic) System is unusable. A "panic" condition usually affecting multiple apps/servers/sites. At this level it would usually notify all tech staff on call. 1 Alert alert Action must be taken immediately. Should be corrected immediately, therefore notify staff who can fix the problem. An example would be the loss of a primary ISP connection. 2 Critical crit Critical conditions. Should be corrected immediately, but indicates failure in a secondary system, an example is a loss of a backup ISP connection. 3 Error err (error) Error conditions. Non-urgent failures, these should be relayed to developers or admins; each item must be resolved within a given time. 4 Warning warning (warn) Warning conditions. Warning messages, not an error, but indication that an error will occur if action is not taken, e.g. file system 85% full - each item must be resolved within a given time. 5 Notice notice Normal but significant condition. Events that are unusual but not error conditions - might be summarized in an email to developers or admins to spot potential problems - no immediate action required. 6 Informational info Informational messages. Normal operational messages - may be harvested for reporting, measuring throughput, etc. - no action required. 7 Debug debug Debug-level messages. Info useful to developers for debugging the application, not useful during operations. */ const ( // LevelEnv chooses level from LOGXI environment variable or defaults // to LevelInfo LevelEnv = -10000 // LevelOff means logging is disabled for logger. This should always // be first LevelOff = -1000 // LevelEmergency is usually 0 but that is also the "zero" value // for Go, which means whenever we do any lookup in string -> int // map 0 is returned (not good). LevelEmergency = -1 // LevelAlert means action must be taken immediately. LevelAlert = 1 // LevelFatal means it should be corrected immediately, eg cannot connect to database. LevelFatal = 2 // LevelCritical is alias for LevelFatal LevelCritical = 2 // LevelError is a non-urgen failure to notify devlopers or admins LevelError = 3 // LevelWarn indiates an error will occur if action is not taken, eg file system 85% full LevelWarn = 4 // LevelNotice is normal but significant condition. LevelNotice = 5 // LevelInfo is info level LevelInfo = 6 // LevelDebug is debug level LevelDebug = 7 // LevelTrace is trace level and displays file and line in terminal LevelTrace = 10 // LevelAll is all levels LevelAll = 1000 ) // FormatHappy uses HappyDevFormatter const FormatHappy = "happy" // FormatText uses TextFormatter const FormatText = "text" // FormatJSON uses JSONFormatter const FormatJSON = "JSON" // FormatEnv selects formatter based on LOGXI_FORMAT environment variable const FormatEnv = "" // LevelMap maps int enums to string level. var LevelMap = map[int]string{ LevelFatal: "FTL", LevelError: "ERR", LevelWarn: "WRN", LevelInfo: "INF", LevelDebug: "DBG", LevelTrace: "TRC", } // LevelMap maps int enums to string level. var LevelAtoi = map[string]int{ "OFF": LevelOff, "FTL": LevelFatal, "ERR": LevelError, "WRN": LevelWarn, "INF": LevelInfo, "DBG": LevelDebug, "TRC": LevelTrace, "ALL": LevelAll, "off": LevelOff, "fatal": LevelFatal, "error": LevelError, "warn": LevelWarn, "info": LevelInfo, "debug": LevelDebug, "trace": LevelTrace, "all": LevelAll, } // Logger is the interface for logging. type Logger interface { Trace(msg string, args ...interface{}) Debug(msg string, args ...interface{}) Info(msg string, args ...interface{}) Warn(msg string, args ...interface{}) error Error(msg string, args ...interface{}) error Fatal(msg string, args ...interface{}) Log(level int, msg string, args []interface{}) SetLevel(int) IsTrace() bool IsDebug() bool IsInfo() bool IsWarn() bool // Error, Fatal not needed, those SHOULD always be logged } logxi-1/v1/logger_test.go000066400000000000000000000215411300440512700155300ustar00rootroot00000000000000package log import ( "bytes" "encoding/json" "errors" "os" "regexp" "strings" "testing" "github.com/stretchr/testify/assert" ) func processEnv() { ProcessEnv(readFromEnviron()) } func testResetEnv() { disableColors = false testBuf.Reset() os.Clearenv() processEnv() InternalLog = testInternalLog } func TestEnvLOGXI(t *testing.T) { assert := assert.New(t) os.Setenv("LOGXI", "") processEnv() assert.Equal(LevelWarn, logxiNameLevelMap["*"], "Unset LOGXI defaults to *:WRN with TTY") // default all to ERR os.Setenv("LOGXI", "*=ERR") processEnv() level := getLogLevel("mylog") assert.Equal(LevelError, level) level = getLogLevel("mylog2") assert.Equal(LevelError, level) // unrecognized defaults to LevelDebug on TTY os.Setenv("LOGXI", "mylog=badlevel") processEnv() level = getLogLevel("mylog") assert.Equal(LevelWarn, level) // wildcard should not override exact match os.Setenv("LOGXI", "*=WRN,mylog=ERR,other=OFF") processEnv() level = getLogLevel("mylog") assert.Equal(LevelError, level) level = getLogLevel("other") assert.Equal(LevelOff, level) // wildcard pattern should match os.Setenv("LOGXI", "*log=ERR") processEnv() level = getLogLevel("mylog") assert.Equal(LevelError, level, "wildcat prefix should match") os.Setenv("LOGXI", "myx*=ERR") processEnv() level = getLogLevel("mylog") assert.Equal(LevelError, level, "no match should return LevelError") os.Setenv("LOGXI", "myl*,-foo") processEnv() level = getLogLevel("mylog") assert.Equal(LevelAll, level) level = getLogLevel("foo") assert.Equal(LevelOff, level) } func TestEnvLOGXI_FORMAT(t *testing.T) { assert := assert.New(t) oldIsTerminal := isTerminal os.Setenv("LOGXI_FORMAT", "") setDefaults(true) processEnv() assert.Equal(FormatHappy, logxiFormat, "terminal defaults to FormatHappy") setDefaults(false) processEnv() assert.Equal(FormatJSON, logxiFormat, "non terminal defaults to FormatJSON") os.Setenv("LOGXI_FORMAT", "JSON") processEnv() assert.Equal(FormatJSON, logxiFormat) os.Setenv("LOGXI_FORMAT", "json") setDefaults(true) processEnv() assert.Equal(FormatHappy, logxiFormat, "Mismatches defaults to FormatHappy") setDefaults(false) processEnv() assert.Equal(FormatJSON, logxiFormat, "Mismatches defaults to FormatJSON non terminal") isTerminal = oldIsTerminal setDefaults(isTerminal) } func TestEnvLOGXI_COLORS(t *testing.T) { oldIsTerminal := isTerminal os.Setenv("LOGXI_COLORS", "*=off") setDefaults(true) processEnv() var buf bytes.Buffer l := NewLogger3(&buf, "telc", NewHappyDevFormatter("logxi-colors")) l.SetLevel(LevelDebug) l.Info("info") r := regexp.MustCompile(`^\d{2}:\d{2}:\d{2}\.\d{6} INF logxi-colors info`) assert.True(t, r.Match(buf.Bytes())) setDefaults(true) isTerminal = oldIsTerminal setDefaults(isTerminal) } func TestComplexKeys(t *testing.T) { testResetEnv() var buf bytes.Buffer l := NewLogger(&buf, "bench") assert.Panics(t, func() { l.Error("complex", "foo\n", 1) }) assert.Panics(t, func() { l.Error("complex", "foo\"s", 1) }) l.Error("apos is ok", "foo's", 1) } func TestJSON(t *testing.T) { testResetEnv() var buf bytes.Buffer l := NewLogger3(&buf, "bench", NewJSONFormatter("bench")) l.SetLevel(LevelDebug) l.Error("hello", "foo", "bar") var obj map[string]interface{} err := json.Unmarshal(buf.Bytes(), &obj) assert.NoError(t, err) assert.Equal(t, "bar", obj["foo"].(string)) assert.Equal(t, "hello", obj[KeyMap.Message].(string)) } func TestJSONImbalanced(t *testing.T) { testResetEnv() var buf bytes.Buffer l := NewLogger3(&buf, "bench", NewJSONFormatter("bench")) l.SetLevel(LevelDebug) l.Error("hello", "foo", "bar", "bah") var obj map[string]interface{} err := json.Unmarshal(buf.Bytes(), &obj) assert.NoError(t, err) assert.Exactly(t, []interface{}{"foo", "bar", "bah"}, obj[warnImbalancedKey]) assert.Equal(t, "hello", obj[KeyMap.Message].(string)) } func TestJSONNoArgs(t *testing.T) { testResetEnv() var buf bytes.Buffer l := NewLogger3(&buf, "bench", NewJSONFormatter("bench")) l.SetLevel(LevelDebug) l.Error("hello") var obj map[string]interface{} err := json.Unmarshal(buf.Bytes(), &obj) assert.NoError(t, err) assert.Equal(t, "hello", obj[KeyMap.Message].(string)) } func TestJSONNested(t *testing.T) { testResetEnv() var buf bytes.Buffer l := NewLogger3(&buf, "bench", NewJSONFormatter("bench")) l.SetLevel(LevelDebug) l.Error("hello", "obj", map[string]string{"fruit": "apple"}) var obj map[string]interface{} err := json.Unmarshal(buf.Bytes(), &obj) assert.NoError(t, err) assert.Equal(t, "hello", obj[KeyMap.Message].(string)) o := obj["obj"] assert.Equal(t, "apple", o.(map[string]interface{})["fruit"].(string)) } func TestJSONEscapeSequences(t *testing.T) { testResetEnv() var buf bytes.Buffer l := NewLogger3(&buf, "bench", NewJSONFormatter("bench")) l.SetLevel(LevelDebug) esc := "I said, \"a's \\ \\\b\f\n\r\t\x1a\"你好'; DELETE FROM people" var obj map[string]interface{} // test as message l.Error(esc) err := json.Unmarshal(buf.Bytes(), &obj) assert.NoError(t, err) assert.Equal(t, esc, obj[KeyMap.Message].(string)) // test as key buf.Reset() key := "你好" l.Error("as key", key, "esc") err = json.Unmarshal(buf.Bytes(), &obj) assert.NoError(t, err) assert.Equal(t, "as key", obj[KeyMap.Message].(string)) assert.Equal(t, "esc", obj[key].(string)) } func TestKeyNotString(t *testing.T) { testResetEnv() var buf bytes.Buffer l := NewLogger3(&buf, "badkey", NewHappyDevFormatter("badkey")) l.SetLevel(LevelDebug) l.Debug("foo", 1) assert.Panics(t, func() { l.Debug("reserved key", "_t", "trying to use time") }) } func TestWarningErrorContext(t *testing.T) { testResetEnv() var buf bytes.Buffer l := NewLogger3(&buf, "wrnerr", NewHappyDevFormatter("wrnerr")) l.Warn("no keys") l.Warn("has eys", "key1", 2) l.Error("no keys") l.Error("has keys", "key1", 2) } func TestLevels(t *testing.T) { var buf bytes.Buffer l := NewLogger3(&buf, "bench", NewJSONFormatter("bench")) l.SetLevel(LevelFatal) assert.False(t, l.IsWarn()) assert.False(t, l.IsInfo()) assert.False(t, l.IsTrace()) assert.False(t, l.IsDebug()) l.SetLevel(LevelError) assert.False(t, l.IsWarn()) l.SetLevel(LevelWarn) assert.True(t, l.IsWarn()) assert.False(t, l.IsDebug()) l.SetLevel(LevelInfo) assert.True(t, l.IsInfo()) assert.True(t, l.IsWarn()) assert.False(t, l.IsDebug()) l.SetLevel(LevelDebug) assert.True(t, l.IsDebug()) assert.True(t, l.IsInfo()) assert.False(t, l.IsTrace()) l.SetLevel(LevelTrace) assert.True(t, l.IsTrace()) assert.True(t, l.IsDebug()) } func TestAllowSingleParam(t *testing.T) { var buf bytes.Buffer l := NewLogger3(&buf, "wrnerr", NewTextFormatter("wrnerr")) l.SetLevel(LevelDebug) l.Info("info", 1) assert.True(t, strings.HasSuffix(buf.String(), singleArgKey+": 1\n")) buf.Reset() l = NewLogger3(&buf, "wrnerr", NewHappyDevFormatter("wrnerr")) l.SetLevel(LevelDebug) l.Info("info", 1) assert.True(t, strings.HasSuffix(buf.String(), "_: \x1b[0m1\n")) var obj map[string]interface{} buf.Reset() l = NewLogger3(&buf, "wrnerr", NewJSONFormatter("wrnerr")) l.SetLevel(LevelDebug) l.Info("info", 1) err := json.Unmarshal(buf.Bytes(), &obj) assert.NoError(t, err) assert.Equal(t, float64(1), obj["_"]) } func TestErrorOnWarn(t *testing.T) { testResetEnv() // os.Setenv("LOGXI_FORMAT", "context=2") // processEnv() var buf bytes.Buffer l := NewLogger3(&buf, "wrnerr", NewHappyDevFormatter("wrnerr")) l.SetLevel(LevelWarn) ErrorDummy := errors.New("dummy error") err := l.Warn("warn with error", "err", ErrorDummy) assert.Error(t, err) assert.Equal(t, "dummy error", err.Error()) err = l.Warn("warn with no error", "one", 1) assert.NoError(t, err) //l.Error("error with err", "err", ErrorDummy) } type CheckStringer struct { s string } func (cs CheckStringer) String() string { return "bbb" } func TestStringer(t *testing.T) { f := CheckStringer{s: "aaa"} var buf bytes.Buffer l := NewLogger3(&buf, "cs1", NewTextFormatter("stringer-text")) l.SetLevel(LevelDebug) l.Info("info", "f", f) assert.True(t, strings.Contains(buf.String(), "bbb")) buf.Reset() l = NewLogger3(&buf, "cs2", NewHappyDevFormatter("stringer-happy")) l.SetLevel(LevelDebug) l.Info("info", "f", f) assert.True(t, strings.Contains(buf.String(), "bbb")) var obj map[string]interface{} buf.Reset() l = NewLogger3(&buf, "cs3", NewJSONFormatter("stringer-json")) l.SetLevel(LevelDebug) l.Info("info", "f", f) err := json.Unmarshal(buf.Bytes(), &obj) assert.NoError(t, err) assert.Equal(t, "bbb", obj["f"]) } // When log functions cast pointers to interface{}. // Say p is a pointer set to nil: // // interface{}(p) == nil // this is false // // Casting it to interface{} makes it trickier to test whether its nil. func TestStringerNullPointers(t *testing.T) { var f *CheckStringer var buf bytes.Buffer l := NewLogger3(&buf, "cs1", NewJSONFormatter("stringer-json")) l.SetLevel(LevelDebug) l.Info("info", "f", f) assert.Contains(t, buf.String(), "null") }logxi-1/v1/methods.go000066400000000000000000000023451300440512700146560ustar00rootroot00000000000000package log // Trace logs a trace statement. On terminals file and line number are logged. func Trace(msg string, args ...interface{}) { DefaultLog.Trace(msg, args...) } // Debug logs a debug statement. func Debug(msg string, args ...interface{}) { DefaultLog.Debug(msg, args...) } // Info logs an info statement. func Info(msg string, args ...interface{}) { DefaultLog.Info(msg, args...) } // Warn logs a warning statement. On terminals it logs file and line number. func Warn(msg string, args ...interface{}) { DefaultLog.Warn(msg, args...) } // Error logs an error statement with callstack. func Error(msg string, args ...interface{}) { DefaultLog.Error(msg, args...) } // Fatal logs a fatal statement. func Fatal(msg string, args ...interface{}) { DefaultLog.Fatal(msg, args...) } // IsTrace determines if this logger logs a trace statement. func IsTrace() bool { return DefaultLog.IsTrace() } // IsDebug determines if this logger logs a debug statement. func IsDebug() bool { return DefaultLog.IsDebug() } // IsInfo determines if this logger logs an info statement. func IsInfo() bool { return DefaultLog.IsInfo() } // IsWarn determines if this logger logs a warning statement. func IsWarn() bool { return DefaultLog.IsWarn() } logxi-1/v1/nullLogger.go000066400000000000000000000030561300440512700153250ustar00rootroot00000000000000package log // NullLog is a noop logger. Think of it as /dev/null. var NullLog = &NullLogger{} // NullLogger is the default logger for this package. type NullLogger struct{} // Trace logs a debug entry. func (l *NullLogger) Trace(msg string, args ...interface{}) { } // Debug logs a debug entry. func (l *NullLogger) Debug(msg string, args ...interface{}) { } // Info logs an info entry. func (l *NullLogger) Info(msg string, args ...interface{}) { } // Warn logs a warn entry. func (l *NullLogger) Warn(msg string, args ...interface{}) error { return nil } // Error logs an error entry. func (l *NullLogger) Error(msg string, args ...interface{}) error { return nil } // Fatal logs a fatal entry then panics. func (l *NullLogger) Fatal(msg string, args ...interface{}) { panic("exit due to fatal error") } // Log logs a leveled entry. func (l *NullLogger) Log(level int, msg string, args []interface{}) { } // IsTrace determines if this logger logs a trace statement. func (l *NullLogger) IsTrace() bool { return false } // IsDebug determines if this logger logs a debug statement. func (l *NullLogger) IsDebug() bool { return false } // IsInfo determines if this logger logs an info statement. func (l *NullLogger) IsInfo() bool { return false } // IsWarn determines if this logger logs a warning statement. func (l *NullLogger) IsWarn() bool { return false } // SetLevel sets the level of this logger. func (l *NullLogger) SetLevel(level int) { } // SetFormatter set the formatter for this logger. func (l *NullLogger) SetFormatter(formatter Formatter) { } logxi-1/v1/pool.go000066400000000000000000000006441300440512700141640ustar00rootroot00000000000000package log import ( "bytes" "sync" ) type BufferPool struct { sync.Pool } func NewBufferPool() *BufferPool { return &BufferPool{ Pool: sync.Pool{New: func() interface{} { b := bytes.NewBuffer(make([]byte, 128)) b.Reset() return b }}, } } func (bp *BufferPool) Get() *bytes.Buffer { return bp.Pool.Get().(*bytes.Buffer) } func (bp *BufferPool) Put(b *bytes.Buffer) { b.Reset() bp.Pool.Put(b) } logxi-1/v1/textFormatter.go000066400000000000000000000053401300440512700160610ustar00rootroot00000000000000package log import ( "fmt" "io" "runtime/debug" "time" ) // Formatter records log entries. type Formatter interface { Format(writer io.Writer, level int, msg string, args []interface{}) } // TextFormatter is the default recorder used if one is unspecified when // creating a new Logger. type TextFormatter struct { name string itoaLevelMap map[int]string timeLabel string } // NewTextFormatter returns a new instance of TextFormatter. SetName // must be called befored using it. func NewTextFormatter(name string) *TextFormatter { timeLabel := KeyMap.Time + AssignmentChar levelLabel := Separator + KeyMap.Level + AssignmentChar messageLabel := Separator + KeyMap.Message + AssignmentChar nameLabel := Separator + KeyMap.Name + AssignmentChar pidLabel := Separator + KeyMap.PID + AssignmentChar var buildKV = func(level string) string { buf := pool.Get() defer pool.Put(buf) buf.WriteString(pidLabel) buf.WriteString(pidStr) //buf.WriteString(Separator) buf.WriteString(nameLabel) buf.WriteString(name) //buf.WriteString(Separator) buf.WriteString(levelLabel) buf.WriteString(level) //buf.WriteString(Separator) buf.WriteString(messageLabel) return buf.String() } itoaLevelMap := map[int]string{ LevelDebug: buildKV(LevelMap[LevelDebug]), LevelWarn: buildKV(LevelMap[LevelWarn]), LevelInfo: buildKV(LevelMap[LevelInfo]), LevelError: buildKV(LevelMap[LevelError]), LevelFatal: buildKV(LevelMap[LevelFatal]), } return &TextFormatter{itoaLevelMap: itoaLevelMap, name: name, timeLabel: timeLabel} } func (tf *TextFormatter) set(buf bufferWriter, key string, val interface{}) { buf.WriteString(Separator) buf.WriteString(key) buf.WriteString(AssignmentChar) if err, ok := val.(error); ok { buf.WriteString(err.Error()) buf.WriteRune('\n') buf.WriteString(string(debug.Stack())) return } buf.WriteString(fmt.Sprintf("%v", val)) } // Format records a log entry. func (tf *TextFormatter) Format(writer io.Writer, level int, msg string, args []interface{}) { buf := pool.Get() defer pool.Put(buf) buf.WriteString(tf.timeLabel) buf.WriteString(time.Now().Format(timeFormat)) buf.WriteString(tf.itoaLevelMap[level]) buf.WriteString(msg) var lenArgs = len(args) if lenArgs > 0 { if lenArgs == 1 { tf.set(buf, singleArgKey, args[0]) } else if lenArgs%2 == 0 { for i := 0; i < lenArgs; i += 2 { if key, ok := args[i].(string); ok { if key == "" { // show key is invalid tf.set(buf, badKeyAtIndex(i), args[i+1]) } else { tf.set(buf, key, args[i+1]) } } else { // show key is invalid tf.set(buf, badKeyAtIndex(i), args[i+1]) } } } else { tf.set(buf, warnImbalancedKey, args) } } buf.WriteRune('\n') buf.WriteTo(writer) } logxi-1/v1/util.go000066400000000000000000000015701300440512700141670ustar00rootroot00000000000000package log import ( "path/filepath" "strings" ) func expandTabs(s string, tabLen int) string { if s == "" { return s } parts := strings.Split(s, "\t") buf := pool.Get() defer pool.Put(buf) for _, part := range parts { buf.WriteString(part) buf.WriteString(strings.Repeat(" ", tabLen-len(part)%tabLen)) } return buf.String() } func maxInt(a, b int) int { if a > b { return a } return b } func minInt(a, b int) int { if a < b { return a } return b } func indexOfNonSpace(s string) int { if s == "" { return -1 } for i, r := range s { if r != ' ' { return i } } return -1 } var inLogxiPath = filepath.Join("mgutz", "logxi", "v"+strings.Split(Version, ".")[0]) func isLogxiCode(filename string) bool { // need to see errors in tests return strings.HasSuffix(filepath.Dir(filename), inLogxiPath) && !strings.HasSuffix(filename, "_test.go") } logxi-1/v1/version.go000066400000000000000000000001231300440512700146700ustar00rootroot00000000000000package log // Version is the version of this package const Version = "1.0.0-pre"