pax_global_header00006660000000000000000000000064140217244310014510gustar00rootroot0000000000000052 comment=f0d72b655eaaae461099187aaaa3d81381c969a6 mxj-2.5.5/000077500000000000000000000000001402172443100123175ustar00rootroot00000000000000mxj-2.5.5/.travis.yml000066400000000000000000000000271402172443100144270ustar00rootroot00000000000000language: go go: - 1.xmxj-2.5.5/LICENSE000066400000000000000000000021551402172443100133270ustar00rootroot00000000000000Copyright (c) 2012-2021 Charles Banning . All rights reserved. The MIT License (MIT) 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. mxj-2.5.5/anyxml.go000066400000000000000000000103741402172443100141630ustar00rootroot00000000000000package mxj import ( "bytes" "encoding/xml" "reflect" ) const ( DefaultElementTag = "element" ) // Encode arbitrary value as XML. // // Note: unmarshaling the resultant // XML may not return the original value, since tag labels may have been injected // to create the XML representation of the value. /* Encode an arbitrary JSON object. package main import ( "encoding/json" "fmt" "github.com/clbanning/mxj" ) func main() { jsondata := []byte(`[ { "somekey":"somevalue" }, "string", 3.14159265, true ]`) var i interface{} err := json.Unmarshal(jsondata, &i) if err != nil { // do something } x, err := mxj.AnyXmlIndent(i, "", " ", "mydoc") if err != nil { // do something else } fmt.Println(string(x)) } output: somevalue string 3.14159265 true An extreme example is available in examples/goofy_map.go. */ // Alternative values for DefaultRootTag and DefaultElementTag can be set as: // AnyXml( v, myRootTag, myElementTag). func AnyXml(v interface{}, tags ...string) ([]byte, error) { var rt, et string if len(tags) == 1 || len(tags) == 2 { rt = tags[0] } else { rt = DefaultRootTag } if len(tags) == 2 { et = tags[1] } else { et = DefaultElementTag } if v == nil { if useGoXmlEmptyElemSyntax { return []byte("<" + rt + ">"), nil } return []byte("<" + rt + "/>"), nil } if reflect.TypeOf(v).Kind() == reflect.Struct { return xml.Marshal(v) } var err error s := new(bytes.Buffer) p := new(pretty) var b []byte switch v.(type) { case []interface{}: if _, err = s.WriteString("<" + rt + ">"); err != nil { return nil, err } for _, vv := range v.([]interface{}) { switch vv.(type) { case map[string]interface{}: m := vv.(map[string]interface{}) if len(m) == 1 { for tag, val := range m { err = marshalMapToXmlIndent(false, s, tag, val, p) } } else { err = marshalMapToXmlIndent(false, s, et, vv, p) } default: err = marshalMapToXmlIndent(false, s, et, vv, p) } if err != nil { break } } if _, err = s.WriteString(""); err != nil { return nil, err } b = s.Bytes() case map[string]interface{}: m := Map(v.(map[string]interface{})) b, err = m.Xml(rt) default: err = marshalMapToXmlIndent(false, s, rt, v, p) b = s.Bytes() } return b, err } // Encode an arbitrary value as a pretty XML string. // Alternative values for DefaultRootTag and DefaultElementTag can be set as: // AnyXmlIndent( v, "", " ", myRootTag, myElementTag). func AnyXmlIndent(v interface{}, prefix, indent string, tags ...string) ([]byte, error) { var rt, et string if len(tags) == 1 || len(tags) == 2 { rt = tags[0] } else { rt = DefaultRootTag } if len(tags) == 2 { et = tags[1] } else { et = DefaultElementTag } if v == nil { if useGoXmlEmptyElemSyntax { return []byte(prefix + "<" + rt + ">"), nil } return []byte(prefix + "<" + rt + "/>"), nil } if reflect.TypeOf(v).Kind() == reflect.Struct { return xml.MarshalIndent(v, prefix, indent) } var err error s := new(bytes.Buffer) p := new(pretty) p.indent = indent p.padding = prefix var b []byte switch v.(type) { case []interface{}: if _, err = s.WriteString("<" + rt + ">\n"); err != nil { return nil, err } p.Indent() for _, vv := range v.([]interface{}) { switch vv.(type) { case map[string]interface{}: m := vv.(map[string]interface{}) if len(m) == 1 { for tag, val := range m { err = marshalMapToXmlIndent(true, s, tag, val, p) } } else { p.start = 1 // we 1 tag in err = marshalMapToXmlIndent(true, s, et, vv, p) // *s += "\n" if _, err = s.WriteString("\n"); err != nil { return nil, err } } default: p.start = 0 // in case trailing p.start = 1 err = marshalMapToXmlIndent(true, s, et, vv, p) } if err != nil { break } } if _, err = s.WriteString(``); err != nil { return nil, err } b = s.Bytes() case map[string]interface{}: m := Map(v.(map[string]interface{})) b, err = m.XmlIndent(prefix, indent, rt) default: err = marshalMapToXmlIndent(true, s, rt, v, p) b = s.Bytes() } return b, err } mxj-2.5.5/anyxml_test.go000066400000000000000000000077101402172443100152220ustar00rootroot00000000000000package mxj import ( "encoding/json" "fmt" "testing" ) func TestAnyXmlHeader(t *testing.T) { fmt.Println("\n---------------- anyxml_test.go ...") } var anydata = []byte(`[ { "somekey": "somevalue" }, { "somekey": "somevalue" }, { "somekey": "somevalue", "someotherkey": "someothervalue" }, "string", 3.14159265, true ]`) type MyStruct struct { Somekey string `xml:"somekey"` B float32 `xml:"floatval"` } func TestAnyXml(t *testing.T) { var i interface{} err := json.Unmarshal(anydata, &i) if err != nil { t.Fatal(err) } x, err := AnyXml(i) if err != nil { t.Fatal(err) } fmt.Println("[]->x:", string(x)) a := []interface{}{"try", "this", 3.14159265, true} x, err = AnyXml(a) if err != nil { t.Fatal(err) } fmt.Println("a->x:", string(x)) x, err = AnyXml(a, "myRootTag", "myElementTag") if err != nil { t.Fatal(err) } fmt.Println("a->x:", string(x)) x, err = AnyXml(3.14159625) if err != nil { t.Fatal(err) } fmt.Println("f->x:", string(x)) s := MyStruct{"somevalue", 3.14159625} x, err = AnyXml(s) if err != nil { t.Fatal(err) } fmt.Println("s->x:", string(x)) } func TestAnyXmlIndent(t *testing.T) { var i interface{} err := json.Unmarshal(anydata, &i) if err != nil { t.Fatal(err) } x, err := AnyXmlIndent(i, "", " ") if err != nil { t.Fatal(err) } fmt.Println("[]->x:\n", string(x)) a := []interface{}{"try", "this", 3.14159265, true} x, err = AnyXmlIndent(a, "", " ") if err != nil { t.Fatal(err) } fmt.Println("a->x:\n", string(x)) x, err = AnyXmlIndent(3.14159625, "", " ") if err != nil { t.Fatal(err) } fmt.Println("f->x:\n", string(x)) x, err = AnyXmlIndent(3.14159625, "", " ", "myRootTag", "myElementTag") if err != nil { t.Fatal(err) } fmt.Println("f->x:\n", string(x)) s := MyStruct{"somevalue", 3.14159625} x, err = AnyXmlIndent(s, "", " ") if err != nil { t.Fatal(err) } fmt.Println("s->x:\n", string(x)) } func TestNilMap(t *testing.T) { XmlDefaultEmptyElemSyntax() checkval := "" xmlout, err := AnyXml(nil, "root") if err != nil { t.Fatal(err) } if string(xmlout) != checkval { fmt.Println(string(xmlout), "!=", checkval) t.Fatal() } checkval = " " xmlout, err = AnyXmlIndent(nil, " ", " ", "root") if err != nil { t.Fatal(err) } if string(xmlout) != checkval { fmt.Println(string(xmlout), "!=", checkval) t.Fatal() } // use Go XML marshal syntax for empty element" XmlGoEmptyElemSyntax() checkval = "" xmlout, err = AnyXml(nil, "root") if err != nil { t.Fatal(err) } if string(xmlout) != checkval { fmt.Println(string(xmlout), "!=", checkval) t.Fatal() } checkval = ` ` xmlout, err = AnyXmlIndent(nil, " ", " ", "root") if err != nil { t.Fatal(err) } if string(xmlout) != checkval { fmt.Println(string(xmlout), "!=", checkval) t.Fatal() } XmlDefaultEmptyElemSyntax() } func TestNilValue(t *testing.T) { val := map[string]interface{}{"toplevel": nil} checkval := "" XmlDefaultEmptyElemSyntax() xmlout, err := AnyXml(val, "root") if err != nil { t.Fatal(err) } if string(xmlout) != checkval { fmt.Println(string(xmlout), "!=", checkval) t.Fatal() } checkval = ` ` xmlout, err = AnyXmlIndent(val, " ", " ", "root") if err != nil { t.Fatal(err) } if string(xmlout) != checkval { fmt.Println(string(xmlout), "!=", checkval) t.Fatal() } XmlGoEmptyElemSyntax() checkval = "" xmlout, err = AnyXml(val, "root") if err != nil { t.Fatal(err) } if string(xmlout) != checkval { fmt.Println(string(xmlout), "!=", checkval) t.Fatal() } checkval = ` ` xmlout, err = AnyXmlIndent(val, " ", " ", "root") if err != nil { t.Fatal(err) } if string(xmlout) != checkval { fmt.Println(string(xmlout), "!=", checkval) t.Fatal() } XmlDefaultEmptyElemSyntax() } mxj-2.5.5/atomFeedString.xml000066400000000000000000000056531402172443100157650ustar00rootroot00000000000000 Code Review - My issueshttp://codereview.appspot.com/rietveld<>rietveld: an attempt at pubsubhubbub 2009-10-04T01:35:58+00:00email-address-removedurn:md5:134d9179c41f806be79b3a5f7877d19a An attempt at adding pubsubhubbub support to Rietveld. http://code.google.com/p/pubsubhubbub http://code.google.com/p/rietveld/issues/detail?id=155 The server side of the protocol is trivial: 1. add a &lt;link rel=&quot;hub&quot; href=&quot;hub-server&quot;&gt; tag to all feeds that will be pubsubhubbubbed. 2. every time one of those feeds changes, tell the hub with a simple POST request. I have tested this by adding debug prints to a local hub server and checking that the server got the right publish requests. I can&#39;t quite get the server to work, but I think the bug is not in my code. I think that the server expects to be able to grab the feed and see the feed&#39;s actual URL in the link rel=&quot;self&quot;, but the default value for that drops the :port from the URL, and I cannot for the life of me figure out how to get the Atom generator deep inside django not to do that, or even where it is doing that, or even what code is running to generate the Atom feed. (I thought I knew but I added some assert False statements and it kept running!) Ignoring that particular problem, I would appreciate feedback on the right way to get the two values at the top of feeds.py marked NOTE(rsc). rietveld: correct tab handling 2009-10-03T23:02:17+00:00email-address-removedurn:md5:0a2a4f19bb815101f0ba2904aed7c35a This fixes the buggy tab rendering that can be seen at http://codereview.appspot.com/116075/diff/1/2 The fundamental problem was that the tab code was not being told what column the text began in, so it didn&#39;t know where to put the tab stops. Another problem was that some of the code assumed that string byte offsets were the same as column offsets, which is only true if there are no tabs. In the process of fixing this, I cleaned up the arguments to Fold and ExpandTabs and renamed them Break and _ExpandTabs so that I could be sure that I found all the call sites. I also wanted to verify that ExpandTabs was not being used from outside intra_region_diff.py. ` mxj-2.5.5/attrprefix_test.go000066400000000000000000000057701402172443100161060ustar00rootroot00000000000000// attrprefix_test.go - change attrPrefix var package mxj import ( "fmt" "testing" ) var data = []byte(` a test a test `) func TestPrefixDefault(t *testing.T) { fmt.Println("----------------- TestPrefixDefault ...") m, err := NewMapXml(data) if err != nil { t.Fatal(err) } vals, err := m.ValuesForKey("-attr1") if err != nil { t.Fatal(err) } if len(vals) != 2 { t.Fatal("didn't get 2 -attr1 vals", len(vals)) } vals, err = m.ValuesForKey("-attr2") if err != nil { t.Fatal(err) } if len(vals) != 2 { t.Fatal("didn't get 2 -attr2 vals", len(vals)) } } func TestPrefixNoHyphen(t *testing.T) { fmt.Println("----------------- TestPrefixNoHyphen ...") PrependAttrWithHyphen(false) m, err := NewMapXml(data) if err != nil { t.Fatal(err) } vals, err := m.ValuesForKey("attr1") if err != nil { t.Fatal(err) } if len(vals) != 2 { t.Fatal("didn't get 2 attr1 vals", len(vals)) } vals, err = m.ValuesForKey("attr2") if err != nil { t.Fatal(err) } if len(vals) != 2 { t.Fatal("didn't get 2 attr2 vals", len(vals)) } } func TestPrefixUnderscore(t *testing.T) { fmt.Println("----------------- TestPrefixUnderscore ...") SetAttrPrefix("_") m, err := NewMapXml(data) if err != nil { t.Fatal(err) } vals, err := m.ValuesForKey("_attr1") if err != nil { t.Fatal(err) } if len(vals) != 2 { t.Fatal("didn't get 2 _attr1 vals", len(vals)) } vals, err = m.ValuesForKey("_attr2") if err != nil { t.Fatal(err) } if len(vals) != 2 { t.Fatal("didn't get 2 _attr2 vals", len(vals)) } } func TestPrefixAt(t *testing.T) { fmt.Println("----------------- TestPrefixAt ...") SetAttrPrefix("@") m, err := NewMapXml(data) if err != nil { t.Fatal(err) } vals, err := m.ValuesForKey("@attr1") if err != nil { t.Fatal(err) } if len(vals) != 2 { t.Fatal("didn't get 2 @attr1 vals", len(vals)) } vals, err = m.ValuesForKey("@attr2") if err != nil { t.Fatal(err) } if len(vals) != 2 { t.Fatal("didn't get 2 @attr2 vals", len(vals)) } } func TestMarshalPrefixDefault(t *testing.T) { fmt.Println("----------------- TestMarshalPrefixDefault ...") m, err := NewMapXml(data) if err != nil { t.Fatal(err) } x, err := m.XmlIndent("", " ") if err != nil { t.Fatal(err) } fmt.Println(string(x)) } func TestMarshalPrefixNoHyphen(t *testing.T) { fmt.Println("----------------- TestMarshalPrefixNoHyphen ...") // 2021.03.09 - per issue #90, no produces a complex element PrependAttrWithHyphen(false) m, err := NewMapXml(data) if err != nil { t.Fatal(err) } x, err := m.XmlIndent("", " ") if err != nil { t.Fatal("error not reported for invalid key label") } fmt.Println("x:", string(x)) } func TestMarshalPrefixUnderscore(t *testing.T) { fmt.Println("----------------- TestMarshalPrefixUnderscore ...") SetAttrPrefix("_") m, err := NewMapXml(data) if err != nil { t.Fatal(err) } x, err := m.XmlIndent("", " ") if err != nil { t.Fatal(err) } fmt.Println(string(x)) } mxj-2.5.5/badxml_test.go000066400000000000000000000025661402172443100151650ustar00rootroot00000000000000// trying to recreate a panic package mxj import ( "bytes" "fmt" "testing" ) var baddata = []byte(` something strange http://www.something.com Some description goes here. `) func TestBadXml(t *testing.T) { fmt.Println("\n---------------- badxml_test.go") fmt.Println("TestBadXml ...") m, err := NewMapXml(baddata) if err != nil { t.Fatalf("err: didn't find xml.StartElement") } fmt.Printf("m: %v\n", m) j, _ := m.Xml() fmt.Println("m:", string(j)) } func TestBadXmlSeq(t *testing.T) { fmt.Println("TestBadXmlSeq ...") m, err := NewMapXmlSeq(baddata) if err != nil { t.Fatalf("err: didn't find xmlStartElement") } fmt.Printf("m: %v\n", m) j, _ := m.Xml() fmt.Println("m:", string(j)) } func TestBadXmlReader(t *testing.T) { fmt.Println("TestBadXmlReader ...") r := bytes.NewReader(baddata) m, err := NewMapXmlReader(r) if err != nil { t.Fatalf("err: didn't find xml.StartElement") } fmt.Printf("m: %v\n", m) j, _ := m.Xml() fmt.Println("m:", string(j)) } func TestBadXmlSeqReader(t *testing.T) { fmt.Println("TestBadXmlSeqReader ...") r := bytes.NewReader(baddata) m, err := NewMapXmlSeqReader(r) if err != nil { t.Fatalf("err: didn't find xmlStartElement") } fmt.Printf("m: %v\n", m) j, _ := m.Xml() fmt.Println("m:", string(j)) } mxj-2.5.5/bom_test.go000066400000000000000000000036201402172443100144630ustar00rootroot00000000000000// bomxml.go - test handling Byte-Order-Mark headers package mxj import ( "bytes" "fmt" "io" "testing" ) // Check for Byte-Order-Mark header. var boms = [][]byte{ {'\xef', '\xbb', '\xbf'}, {'\xfe', '\xff'}, {'\xff', '\xfe'}, {'\x00', '\x00', '\xfe', '\xff'}, {'\xff', '\xfe', '\x00', '\x00'}, } func TestBom(t *testing.T) { fmt.Println("\n--------------- bom_test.go") fmt.Println("TestBom ...") // use just UTF-8 BOM ... no alternative CharSetReader if _, err := NewMapXml(boms[0]); err != io.EOF { t.Fatalf("NewMapXml err; %v\n", err) } if _, err := NewMapXmlSeq(boms[0]); err != io.EOF { t.Fatalf("NewMapXmlSeq err: %v\n", err) } } var bomdata = append(boms[0], []byte(` http://www.something.com Some description goes here. `)...) func TestBomData(t *testing.T) { fmt.Println("TestBomData ...") m, err := NewMapXml(bomdata) if err != nil { t.Fatalf("err: didn't find xml.StartElement") } fmt.Printf("m: %v\n", m) j, _ := m.Xml() fmt.Println("m:", string(j)) } func TestBomDataSeq(t *testing.T) { fmt.Println("TestBomDataSeq ...") m, err := NewMapXmlSeq(bomdata) if err != nil { t.Fatalf("err: didn't find xml.StartElement") } fmt.Printf("m: %v\n", m) j, _ := m.Xml() fmt.Println("m:", string(j)) } func TestBomDataReader(t *testing.T) { fmt.Println("TestBomDataReader ...") r := bytes.NewReader(bomdata) m, err := NewMapXmlReader(r) if err != nil { t.Fatalf("err: didn't find xml.StartElement") } fmt.Printf("m: %v\n", m) j, _ := m.Xml() fmt.Println("m:", string(j)) } func TestBomDataSeqReader(t *testing.T) { fmt.Println("TestBomDataSeqReader ...") r := bytes.NewReader(bomdata) m, err := NewMapXmlSeqReader(r) if err != nil { t.Fatalf("err: didn't find xml.StartElement") } fmt.Printf("m: %v\n", m) j, _ := m.Xml() fmt.Println("m:", string(j)) } mxj-2.5.5/bulk_test.go000066400000000000000000000046441402172443100146520ustar00rootroot00000000000000// bulk_test.go - uses Handler and Writer functions to process some streams as a demo. package mxj import ( "bytes" "fmt" "testing" ) func TestBulkHeader(t *testing.T) { fmt.Println("\n---------------- bulk_test.go ...") } var jsonWriter = new(bytes.Buffer) var xmlWriter = new(bytes.Buffer) var jsonErrLog = new(bytes.Buffer) var xmlErrLog = new(bytes.Buffer) func TestXmlReader(t *testing.T) { // create Reader for xmldata xmlReader := bytes.NewReader(xmldata) // read XML from Readerand pass Map value with the raw XML to handler err := HandleXmlReader(xmlReader, bxmaphandler, bxerrhandler) if err != nil { t.Fatal("err:", err.Error()) } // get the JSON j := make([]byte, jsonWriter.Len()) _, _ = jsonWriter.Read(j) // get the errors e := make([]byte, xmlErrLog.Len()) _, _ = xmlErrLog.Read(e) // print the input fmt.Println("XmlReader, xmldata:\n", string(xmldata)) // print the result fmt.Println("XmlReader, result :\n", string(j)) // print the errors fmt.Println("XmlReader, errors :\n", string(e)) } func bxmaphandler(m Map) bool { j, err := m.JsonIndent("", " ", true) if err != nil { return false } _, _ = jsonWriter.Write(j) // put in a NL to pretty up printing the Writer _, _ = jsonWriter.Write([]byte("\n")) return true } func bxerrhandler(err error) bool { // write errors to file _, _ = xmlErrLog.Write([]byte(err.Error())) _, _ = xmlErrLog.Write([]byte("\n")) // pretty up return true } func TestJsonReader(t *testing.T) { jsonReader := bytes.NewReader(jsondata) // read all the JSON err := HandleJsonReader(jsonReader, bjmaphandler, bjerrhandler) if err != nil { t.Fatal("err:", err.Error()) } // get the XML x := make([]byte, xmlWriter.Len()) _, _ = xmlWriter.Read(x) // get the errors e := make([]byte, jsonErrLog.Len()) _, _ = jsonErrLog.Read(e) // print the input fmt.Println("JsonReader, jsondata:\n", string(jsondata)) // print the result fmt.Println("JsonReader, result :\n", string(x)) // print the errors fmt.Println("JsonReader, errors :\n", string(e)) } func bjmaphandler(m Map) bool { x, err := m.XmlIndent(" ", " ") if err != nil { return false } _, _ = xmlWriter.Write(x) // put in a NL to pretty up printing the Writer _, _ = xmlWriter.Write([]byte("\n")) return true } func bjerrhandler(err error) bool { // write errors to file _, _ = jsonErrLog.Write([]byte(err.Error())) _, _ = jsonErrLog.Write([]byte("\n")) // pretty up return true } mxj-2.5.5/bulkraw_test.go000066400000000000000000000054731402172443100153650ustar00rootroot00000000000000// bulk_test.go - uses Handler and Writer functions to process some streams as a demo. package mxj import ( "bytes" "fmt" "testing" ) func TestBulkRawHeader(t *testing.T) { fmt.Println("\n---------------- bulkraw_test.go ...") } // use data from bulk_test.go var jsonWriterRaw = new(bytes.Buffer) var xmlWriterRaw = new(bytes.Buffer) var jsonErrLogRaw = new(bytes.Buffer) var xmlErrLogRaw = new(bytes.Buffer) func TestXmlReaderRaw(t *testing.T) { // create Reader for xmldata xmlReader := bytes.NewReader(xmldata) // read XML from Reader and pass Map value with the raw XML to handler err := HandleXmlReaderRaw(xmlReader, bxmaphandlerRaw, bxerrhandlerRaw) if err != nil { t.Fatal("err:", err.Error()) } // get the JSON j := make([]byte, jsonWriterRaw.Len()) _, _ = jsonWriterRaw.Read(j) // get the errors e := make([]byte, xmlErrLogRaw.Len()) _, _ = xmlErrLogRaw.Read(e) // print the input fmt.Println("XmlReaderRaw, xmldata:\n", string(xmldata)) // print the result fmt.Println("XmlReaderRaw, result :\n", string(j)) // print the errors fmt.Println("XmlReaderRaw, errors :\n", string(e)) } func bxmaphandlerRaw(m Map, raw []byte) bool { j, err := m.JsonIndent("", " ", true) if err != nil { return false } _, _ = jsonWriterRaw.Write(j) // put in a NL to pretty up printing the Writer _, _ = jsonWriterRaw.Write([]byte("\n")) return true } func bxerrhandlerRaw(err error, raw []byte) bool { // write errors to file _, _ = xmlErrLogRaw.Write([]byte(err.Error())) _, _ = xmlErrLogRaw.Write([]byte("\n")) // pretty up _, _ = xmlErrLogRaw.Write(raw) _, _ = xmlErrLogRaw.Write([]byte("\n")) // pretty up return true } func TestJsonReaderRaw(t *testing.T) { jsonReader := bytes.NewReader(jsondata) // read all the JSON err := HandleJsonReaderRaw(jsonReader, bjmaphandlerRaw, bjerrhandlerRaw) if err != nil { t.Fatal("err:", err.Error()) } // get the XML x := make([]byte, xmlWriterRaw.Len()) _, _ = xmlWriterRaw.Read(x) // get the errors e := make([]byte, jsonErrLogRaw.Len()) _, _ = jsonErrLogRaw.Read(e) // print the input fmt.Println("JsonReaderRaw, jsondata:\n", string(jsondata)) // print the result fmt.Println("JsonReaderRaw, result :\n", string(x)) // print the errors fmt.Println("JsonReaderRaw, errors :\n", string(e)) } func bjmaphandlerRaw(m Map, raw []byte) bool { x, err := m.XmlIndent(" ", " ") if err != nil { return false } _, _ = xmlWriterRaw.Write(x) // put in a NL to pretty up printing the Writer _, _ = xmlWriterRaw.Write([]byte("\n")) return true } func bjerrhandlerRaw(err error, raw []byte) bool { // write errors to file _, _ = jsonErrLogRaw.Write([]byte(err.Error())) _, _ = jsonErrLogRaw.Write([]byte("\n")) // pretty up, Error() from json.Unmarshal !NL _, _ = jsonErrLogRaw.Write(raw) _, _ = jsonErrLogRaw.Write([]byte("\n")) // pretty up return true } mxj-2.5.5/cast_test.go000066400000000000000000000030361402172443100146410ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) var castdata = []byte(` string 3.14159625 2019 true FALSE T f `) func TestHeader(t *testing.T) { fmt.Println("\ncast_test.go ----------") } func TestCastDefault(t *testing.T) { fmt.Println("------------ TestCastDefault ...") m, err := NewMapXml(castdata) if err != nil { t.Fatal(err.Error()) } fmt.Printf("%#v\n", m) } func TestCastTrue(t *testing.T) { fmt.Println("------------ TestCastTrue ...") m, _ := NewMapXml(castdata, true) fmt.Printf("%#v\n", m) } func TestSetCheckTagToSkipFunc(t *testing.T) { fmt.Println("------------ TestSetCheckTagToSkipFunc ...") fn := func(tag string) bool { list := []string{"int","false"} for _, v := range list { if v == tag { return true } } return false } SetCheckTagToSkipFunc(fn) m, err := NewMapXml(castdata, true) if err != nil { t.Fatal(err.Error()) } fmt.Printf("%#v\n", m) } func TestCastValuesToFloat(t *testing.T) { fmt.Println("------------ TestCastValuesToFloat(false) ...") CastValuesToFloat(false) defer CastValuesToFloat(true) m, err := NewMapXml(castdata, true) if err != nil { t.Fatal(err.Error()) } fmt.Printf("%#v\n", m) } func TestCastValuesToBool(t *testing.T) { fmt.Println("------------ TestCastValuesToBool(false) ...") CastValuesToBool(false) defer CastValuesToBool(true) m, err := NewMapXml(castdata, true) if err != nil { t.Fatal(err.Error()) } fmt.Printf("%#v\n", m) } mxj-2.5.5/data_test.go000066400000000000000000000025641402172443100146250ustar00rootroot00000000000000package mxj var xmldata = []byte(` William H. Gaddis The Recognitions One of the seminal American novels of the 20th century. William H. Gaddis JR Won the National Book Award. Austin Tappan Wright Islandia An example of earlier 20th century American utopian fiction. John Hawkes The Beetle Leg A lyrical novel about the construction of Ft. Peck Dam in Montana. T.E. Porter King's Day A magical novella. `) var jsondata = []byte(` {"book":{"author":"William H. Gaddis","review":"One of the great seminal American novels of the 20th century.","title":"The Recognitions"}} {"book":{"author":"Austin Tappan Wright","review":"An example of earlier 20th century American utopian fiction.","title":"Islandia"}} {"book":{"author":"John Hawkes","review":"A lyrical novel about the construction of Ft. Peck Dam in Montana.","title":"The Beetle Leg"}} {"book":{"author":{"first_name":"T.E.","last_name":"Porter"},"review":"A magical novella.","title":"King's Day"}} { "here":"we", "put":"in", "an":error }`) mxj-2.5.5/deprecate/000077500000000000000000000000001402172443100142535ustar00rootroot00000000000000mxj-2.5.5/deprecate/stuff.go000066400000000000000000000021341402172443100157310ustar00rootroot00000000000000 // ======================== newMapToXmlIndent func (mv Map) MarshalXml(rootTag ...string) ([]byte, error) { m := map[string]interface{}(mv) var err error // s := new(string) // b := new(strings.Builder) b := new(bytes.Buffer) p := new(pretty) // just a stub if len(m) == 1 && len(rootTag) == 0 { for key, value := range m { // if it an array, see if all values are map[string]interface{} // we force a new root tag if we'll end up with no key:value in the list // so: key:[string_val, bool:true] --> string_valtrue switch value.(type) { case []interface{}: for _, v := range value.([]interface{}) { switch v.(type) { case map[string]interface{}: // noop default: // anything else err = marshalMapToXmlIndent(false, b, DefaultRootTag, m, p) goto done } } } err = marshalMapToXmlIndent(false, b, key, value, p) } } else if len(rootTag) == 1 { err = marshalMapToXmlIndent(false, b, rootTag[0], m, p) } else { err = marshalMapToXmlIndent(false, b, DefaultRootTag, m, p) } done: return b.Bytes(), err } mxj-2.5.5/doc.go000066400000000000000000000175221402172443100134220ustar00rootroot00000000000000// mxj - A collection of map[string]interface{} and associated XML and JSON utilities. // Copyright 2012-2019, Charles Banning. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file /* Marshal/Unmarshal XML to/from map[string]interface{} values (and JSON); extract/modify values from maps by key or key-path, including wildcards. mxj supplants the legacy x2j and j2x packages. The subpackage x2j-wrapper is provided to facilitate migrating from the x2j package. The x2j and j2x subpackages provide similar functionality of the old packages but are not function-name compatible with them. Note: this library was designed for processing ad hoc anonymous messages. Bulk processing large data sets may be much more efficiently performed using the encoding/xml or encoding/json packages from Go's standard library directly. Related Packages: checkxml: github.com/clbanning/checkxml provides functions for validating XML data. Notes: 2020.05.01: v2.2 - optimize map to XML encoding for large XML docs. 2019.07.04: v2.0 - remove unnecessary methods - mv.XmlWriterRaw, mv.XmlIndentWriterRaw - for Map and MapSeq. 2019.07.04: Add MapSeq type and move associated functions and methods from Map to MapSeq. 2019.01.21: DecodeSimpleValuesAsMap - decode to map[:map["#text":]] rather than map[:]. 2018.04.18: mv.Xml/mv.XmlIndent encodes non-map[string]interface{} map values - map[string]string, map[int]uint, etc. 2018.03.29: mv.Gob/NewMapGob support gob encoding/decoding of Maps. 2018.03.26: Added mxj/x2j-wrapper sub-package for migrating from legacy x2j package. 2017.02.22: LeafNode paths can use ".N" syntax rather than "[N]" for list member indexing. 2017.02.21: github.com/clbanning/checkxml provides functions for validating XML data. 2017.02.10: SetFieldSeparator changes field separator for args in UpdateValuesForPath, ValuesFor... methods. 2017.02.06: Support XMPP stream processing - HandleXMPPStreamTag(). 2016.11.07: Preserve name space prefix syntax in XmlSeq parser - NewMapXmlSeq(), etc. 2016.06.25: Support overriding default XML attribute prefix, "-", in Map keys - SetAttrPrefix(). 2016.05.26: Support customization of xml.Decoder by exposing CustomDecoder variable. 2016.03.19: Escape invalid chars when encoding XML attribute and element values - XMLEscapeChars(). 2016.03.02: By default decoding XML with float64 and bool value casting will not cast "NaN", "Inf", and "-Inf". To cast them to float64, first set flag with CastNanInf(true). 2016.02.22: New mv.Root(), mv.Elements(), mv.Attributes methods let you examine XML document structure. 2016.02.16: Add CoerceKeysToLower() option to handle tags with mixed capitalization. 2016.02.12: Seek for first xml.StartElement token; only return error if io.EOF is reached first (handles BOM). 2015-12-02: NewMapXmlSeq() with mv.XmlSeq() & co. will try to preserve structure of XML doc when re-encoding. 2014-08-02: AnyXml() and AnyXmlIndent() will try to marshal arbitrary values to XML. SUMMARY type Map map[string]interface{} Create a Map value, 'mv', from any map[string]interface{} value, 'v': mv := Map(v) Unmarshal / marshal XML as a Map value, 'mv': mv, err := NewMapXml(xmlValue) // unmarshal xmlValue, err := mv.Xml() // marshal Unmarshal XML from an io.Reader as a Map value, 'mv': mv, err := NewMapXmlReader(xmlReader) // repeated calls, as with an os.File Reader, will process stream mv, raw, err := NewMapXmlReaderRaw(xmlReader) // 'raw' is the raw XML that was decoded Marshal Map value, 'mv', to an XML Writer (io.Writer): err := mv.XmlWriter(xmlWriter) raw, err := mv.XmlWriterRaw(xmlWriter) // 'raw' is the raw XML that was written on xmlWriter Also, for prettified output: xmlValue, err := mv.XmlIndent(prefix, indent, ...) err := mv.XmlIndentWriter(xmlWriter, prefix, indent, ...) raw, err := mv.XmlIndentWriterRaw(xmlWriter, prefix, indent, ...) Bulk process XML with error handling (note: handlers must return a boolean value): err := HandleXmlReader(xmlReader, mapHandler(Map), errHandler(error)) err := HandleXmlReaderRaw(xmlReader, mapHandler(Map, []byte), errHandler(error, []byte)) Converting XML to JSON: see Examples for NewMapXml and HandleXmlReader. There are comparable functions and methods for JSON processing. Arbitrary structure values can be decoded to / encoded from Map values: mv, err := NewMapStruct(structVal) err := mv.Struct(structPointer) To work with XML tag values, JSON or Map key values or structure field values, decode the XML, JSON or structure to a Map value, 'mv', or cast a map[string]interface{} value to a Map value, 'mv', then: paths := mv.PathsForKey(key) path := mv.PathForKeyShortest(key) values, err := mv.ValuesForKey(key, subkeys) values, err := mv.ValuesForPath(path, subkeys) // 'path' can be dot-notation with wildcards and indexed arrays. count, err := mv.UpdateValuesForPath(newVal, path, subkeys) Get everything at once, irrespective of path depth: leafnodes := mv.LeafNodes() leafvalues := mv.LeafValues() A new Map with whatever keys are desired can be created from the current Map and then encoded in XML or JSON. (Note: keys can use dot-notation. 'oldKey' can also use wildcards and indexed arrays.) newMap, err := mv.NewMap("oldKey_1:newKey_1", "oldKey_2:newKey_2", ..., "oldKey_N:newKey_N") newMap, err := mv.NewMap("oldKey1", "oldKey3", "oldKey5") // a subset of 'mv'; see "examples/partial.go" newXml, err := newMap.Xml() // for example newJson, err := newMap.Json() // ditto XML PARSING CONVENTIONS Using NewMapXml() - Attributes are parsed to `map[string]interface{}` values by prefixing a hyphen, `-`, to the attribute label. (Unless overridden by `PrependAttrWithHyphen(false)` or `SetAttrPrefix()`.) - If the element is a simple element and has attributes, the element value is given the key `#text` for its `map[string]interface{}` representation. (See the 'atomFeedString.xml' test data, below.) - XML comments, directives, and process instructions are ignored. - If CoerceKeysToLower() has been called, then the resultant keys will be lower case. Using NewMapXmlSeq() - Attributes are parsed to `map["#attr"]map[]map[string]interface{}`values where the `` value has "#text" and "#seq" keys - the "#text" key holds the value for ``. - All elements, except for the root, have a "#seq" key. - Comments, directives, and process instructions are unmarshalled into the Map using the keys "#comment", "#directive", and "#procinst", respectively. (See documentation for more specifics.) - Name space syntax is preserved: - something parses to map["ns:key"]interface{}{"something"} - xmlns:ns="http://myns.com/ns" parses to map["xmlns:ns"]interface{}{"http://myns.com/ns"} Both - By default, "Nan", "Inf", and "-Inf" values are not cast to float64. If you want them to be cast, set a flag to cast them using CastNanInf(true). XML ENCODING CONVENTIONS - 'nil' Map values, which may represent 'null' JSON values, are encoded as "". NOTE: the operation is not symmetric as "" elements are decoded as 'tag:""' Map values, which, then, encode in JSON as '"tag":""' values.. - ALSO: there is no guarantee that the encoded XML doc will be the same as the decoded one. (Go randomizes the walk through map[string]interface{} values.) If you plan to re-encode the Map value to XML and want the same sequencing of elements look at NewMapXmlSeq() and mv.XmlSeq() - these try to preserve the element sequencing but with added complexity when working with the Map representation. */ package mxj mxj-2.5.5/escapechars.go000066400000000000000000000050631402172443100151330ustar00rootroot00000000000000// Copyright 2016 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file package mxj import ( "bytes" ) var xmlEscapeChars bool // XMLEscapeChars(true) forces escaping invalid characters in attribute and element values. // NOTE: this is brute force with NO interrogation of '&' being escaped already; if it is // then '&' will be re-escaped as '&amp;'. // /* The values are: " " ' ' < < > > & & */ // // Note: if XMLEscapeCharsDecoder(true) has been called - or the default, 'false,' value // has been toggled to 'true' - then XMLEscapeChars(true) is ignored. If XMLEscapeChars(true) // has already been called before XMLEscapeCharsDecoder(true), XMLEscapeChars(false) is called // to turn escape encoding on mv.Xml, etc., to prevent double escaping ampersands, '&'. func XMLEscapeChars(b ...bool) { var bb bool if len(b) == 0 { bb = !xmlEscapeChars } else { bb = b[0] } if bb == true && xmlEscapeCharsDecoder == false { xmlEscapeChars = true } else { xmlEscapeChars = false } } // Scan for '&' first, since 's' may contain "&" that is parsed to "&amp;" // - or "<" that is parsed to "&lt;". var escapechars = [][2][]byte{ {[]byte(`&`), []byte(`&`)}, {[]byte(`<`), []byte(`<`)}, {[]byte(`>`), []byte(`>`)}, {[]byte(`"`), []byte(`"`)}, {[]byte(`'`), []byte(`'`)}, } func escapeChars(s string) string { if len(s) == 0 { return s } b := []byte(s) for _, v := range escapechars { n := bytes.Count(b, v[0]) if n == 0 { continue } b = bytes.Replace(b, v[0], v[1], n) } return string(b) } // per issue #84, escape CharData values from xml.Decoder var xmlEscapeCharsDecoder bool // XMLEscapeCharsDecoder(b ...bool) escapes XML characters in xml.CharData values // returned by Decoder.Token. Thus, the internal Map values will contain escaped // values, and you do not need to set XMLEscapeChars for proper encoding. // // By default, the Map values have the non-escaped values returned by Decoder.Token. // XMLEscapeCharsDecoder(true) - or, XMLEscapeCharsDecoder() - will toggle escape // encoding 'on.' // // Note: if XMLEscapeCharDecoder(true) is call then XMLEscapeChars(false) is // called to prevent re-escaping the values on encoding using mv.Xml, etc. func XMLEscapeCharsDecoder(b ...bool) { if len(b) == 0 { xmlEscapeCharsDecoder = !xmlEscapeCharsDecoder } else { xmlEscapeCharsDecoder = b[0] } if xmlEscapeCharsDecoder == true && xmlEscapeChars == true { xmlEscapeChars = false } } mxj-2.5.5/escapechars_test.go000066400000000000000000000042231402172443100161670ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) var s = `"'<>&` func TestEscapeChars(t *testing.T) { fmt.Println("\n================== TestEscapeChars") ss := escapeChars(s) if ss != `"'<>&` { t.Fatal(s, ":", ss) } fmt.Println(" s:", s) fmt.Println("ss:", ss) } func TestXMLEscapeChars(t *testing.T) { fmt.Println("================== TestXMLEscapeChars") XMLEscapeChars(true) defer XMLEscapeChars(false) m := map[string]interface{}{"mychars":s} x, err := AnyXmlIndent(s, "", " ") if err != nil { t.Fatal(err) } fmt.Println("s:", string(x)) x, err = AnyXmlIndent(m, "", " ") if err != nil { t.Fatal(err) } fmt.Println("m:", string(x)) } func TestXMLEscapeChars2(t *testing.T) { fmt.Println("================== TestXMLEscapeChars2") XMLEscapeChars(true) defer XMLEscapeChars(false) ss := []byte(`"'<>&`) fmt.Println(string(ss)) mv, err := NewMapXml(ss) if err != nil { t.Fatal(err) } fmt.Printf("%v\n", mv) x, err := mv.XmlIndent("", " ") if err != nil { t.Fatal(err) } fmt.Println("mv:", string(x)) } func TestXMLSeqEscapeChars(t *testing.T) { fmt.Println("================== TestXMLSeqEscapeChars") data := []byte(` >0-2y `) fmt.Println("data:", string(data)) m, err := NewMapXmlSeq(data) if err != nil { t.Fatal(err) } fmt.Printf("m: %v\n", m) XMLEscapeChars(true) defer XMLEscapeChars(false) x, err := m.XmlIndent("", " ") if err != nil { t.Fatal(err) } fmt.Println("m:", string(x)) } func TestXMLSeqEscapeChars2(t *testing.T) { fmt.Println("================== TestXMLSeqEscapeChars2") data := []byte(` >0-2y <10-15 `) fmt.Println("data:", string(data)) m, err := NewMapXmlSeq(data) if err != nil { t.Fatal(err) } fmt.Printf("m: %v\n", m) XMLEscapeChars(true) defer XMLEscapeChars(false) x, err := m.XmlIndent("", " ") if err != nil { t.Fatal(err) } fmt.Println("m:", string(x)) } mxj-2.5.5/example_test.go000066400000000000000000000241771402172443100153530ustar00rootroot00000000000000// +test OMIT // note - "// Output:" is a key for "go test" to match function ouput with the lines that follow. // It is also use by "godoc" to build the Output block of the function / method documentation. // To skip processing Example* functions, use: go test -run "Test*" // or make sure example function output matches // Output: documentation EXACTLY. package mxj_test import ( /* "bytes" "fmt" "github.com/clbanning/mxj" "io" */ ) func ExampleHandleXmlReader() { /* Bulk processing XML to JSON seems to be a common requirement. See: bulk_test.go for working example. Run "go test" in package directory then scroll back to find output. The logic is as follows. // need somewhere to write the JSON. var jsonWriter io.Writer // probably want to log any errors in reading the XML stream var xmlErrLogger io.Writer // func to handle Map value from XML Reader func maphandler(m mxj.Map) bool { // marshal Map as JSON jsonVal, err := m.Json() if err != nil { // log error return false // stops further processing of XML Reader } // write JSON somewhere _, err = jsonWriter.Write(jsonVal) if err != nil { // log error return false // stops further processing of XML Reader } // continue - get next XML from Reader return true } // func to handle error from unmarshaling XML Reader func errhandler(errVal error) bool { // log error somewhere _, err := xmlErrLogger.Write([]byte(errVal.Error())) if err != nil { // log error return false // stops further processing of XML Reader } // continue processing return true } // func that starts bulk processing of the XML ... // set up io.Reader for XML data - perhaps an os.File ... err := mxj.HandleXmlReader(xmlReader, maphandler, errhandler) if err != nil { // handle error } ... */ } func ExampleHandleXmlReaderRaw() { /* See: bulkraw_test.go for working example. Run "go test" in package directory then scroll back to find output. Basic logic for bulk XML to JSON processing is in HandleXmlReader example; the only major difference is in handler function signatures so they are passed the raw XML. (Read documentation on NewXmlReader regarding performance.) */ } func ExampleHandleJsonReader() { /* See: bulk_test.go for working example. Run "go test" in package directory then scroll back to find output. Basic logic for bulk JSON to XML processing is similar to that for bulk XML to JSON processing as outlined in the HandleXmlReader example. The test case is also a good example. */ } func ExampleHandleJsonReaderRaw() { /* See: bulkraw_test.go for working example. Run "go test" in package directory then scroll back to find output. Basic logic for bulk JSON to XML processing is similar to that for bulk XML to JSON processing as outlined in the HandleXmlReader example. The test case is also a good example. */ } /* func ExampleNewMapXmlReaderRaw() { // in an http.Handler mapVal, raw, err := mxj.NewMapXmlReader(req.Body) if err != nil { // handle error } logger.Print(string(*raw)) // do something with mapVal } */ /* func ExampleNewMapStruct() { type str struct { IntVal int `structs:"int"` StrVal string `structs:"str"` FloatVal float64 `structs:"float"` BoolVal bool `structs:"bool"` private string } strVal := str{IntVal: 4, StrVal: "now's the time", FloatVal: 3.14159, BoolVal: true, private: "Skies are blue"} mapVal, merr := mxj.NewMapStruct(strVal) if merr != nil { // handle error } fmt.Printf("strVal: %#v\n", strVal) fmt.Printf("mapVal: %#v\n", mapVal) // Note: example output is conformed to pass "go test". "mxj_test" is example_test.go package name. // NoFail output: // strVal: mxj_test.str{IntVal:4, StrVal:"now's the time", FloatVal:3.14159, BoolVal:true, private:"Skies are blue"} // mapVal: mxj.Map{"float":3.14159, "bool":true, "int":4, "str":"now's the time"} } */ func ExampleMap_Struct() { /* type str struct { IntVal int `json:"int"` StrVal string `json:"str"` FloatVal float64 `json:"float"` BoolVal bool `json:"bool"` private string } mapVal := mxj.Map{"int": 4, "str": "now's the time", "float": 3.14159, "bool": true, "private": "Somewhere over the rainbow"} var strVal str mverr := mapVal.Struct(&strVal) if mverr != nil { // handle error } fmt.Printf("mapVal: %#v\n", mapVal) fmt.Printf("strVal: %#v\n", strVal) // Unordered output for above: // mapVal: mxj.Map{"int":4, "str":"now's the time", "float":3.14159, "bool":true, "private":"Somewhere over the rainbow"} // strVal: mxj_test.str{IntVal:4, StrVal:"now's the time", FloatVal:3.14159, BoolVal:true, private:""} */ } func ExampleMap_ValuesForPath() { /* // a snippet from examples/gonuts1.go // How to compensate for irregular tag labels in data. // Need to extract from an XML stream the values for "netid" and "idnet". // Solution: use a wildcard path "data.*" to anonymize the "netid" and "idnet" tags. var msg1 = []byte(` no default:text default:word `) var msg2 = []byte(` yes default:text default:word `) // let's create a message stream buf := new(bytes.Buffer) // load a couple of messages into it _, _ = buf.Write(msg1) _, _ = buf.Write(msg2) n := 0 for { n++ // Read the stream as Map values - quit on io.EOF. // Get the raw XML as well as the Map value. m, merr := mxj.NewMapXmlReader(buf) if merr != nil && merr != io.EOF { // handle error - for demo we just print it and continue fmt.Printf("msg: %d - merr: %s\n", n, merr.Error()) continue } else if merr == io.EOF { break } // get the values for "netid" or "idnet" key using path == "data.*" values, _ := m.ValuesForPath("data.*") fmt.Println("\nmsg:", n, "> path == data.* - got array of values, len:", len(values)) for i, val := range values { fmt.Println("ValuesForPath result array member -", i, ":", val) fmt.Println(" k:v pairs for array member:", i) for key, val := range val.(map[string]interface{}) { // You'd probably want to process the value, as appropriate. // Here we just print it out. fmt.Println("\t\t", key, ":", val) } } } // NoFail output: // msg: 1 > path == data.* - got array of values, len: 1 // ValuesForPath result array member - 0 : map[disable:no text1:default:text word1:default:word] // k:v pairs for array member: 0 // disable : no // text1 : default:text // word1 : default:word // // msg: 2 > path == data.* - got array of values, len: 1 // ValuesForPath result array member - 0 : map[disable:yes text1:default:text word1:default:word] // k:v pairs for array member: 0 // disable : yes // text1 : default:text // word1 : default:word */ } func ExampleMap_UpdateValuesForPath() { /* var biblioDoc = []byte(` William Gaddis The Recognitions 1955 A novel that changed the face of American literature. JR 1975 Winner of National Book Award for Fiction. `) ... m, merr := mxj.NewMapXml(biblioDoc) if merr != nil { // handle error } // change 'review' for a book count, err := m.UpdateValuesForPath("review:National Book Award winner." "*.*.*.*", "title:JR") if err != nil { // handle error } ... // change 'date' value from string type to float64 type // Note: the following is equivalent to m, merr := NewMapXml(biblioDoc, mxj.Cast). path := m.PathForKeyShortest("date") v, err := m.ValuesForPath(path) if err != nil { // handle error } var total int for _, vv := range v { oldVal := "date:" + vv.(string) newVal := "date:" + vv.(string) + ":num" n, err := m.UpdateValuesForPath(newVal, path, oldVal) if err != nil { // handle error } total += n } ... */ } func ExampleMap_Copy() { /* // Hand-crafted Map values that include structures do NOT Copy() as expected, // since to simulate a deep copy the original Map value is JSON encoded then decoded. type str struct { IntVal int `json:"int"` StrVal string `json:"str"` FloatVal float64 `json:"float"` BoolVal bool `json:"bool"` private string } s := str{IntVal: 4, StrVal: "now's the time", FloatVal: 3.14159, BoolVal: true, private: "Skies are blue"} m := make(map[string]interface{}, 0) m["struct"] = interface{}(s) m["struct_ptr"] = interface{}(&s) m["misc"] = interface{}(`Now is the time`) mv := mxj.Map(m) cp, _ := mv.Copy() fmt.Printf("mv:\n%s\n", mv.StringIndent(2)) fmt.Printf("cp:\n%s\n", cp.StringIndent(2)) // NoFail output: // mv: // misc : [string] Now is the time // struct : [mxj_test.str] {IntVal:4 StrVal:now's the time FloatVal:3.14159 BoolVal:true private:Skies are blue} // struct_ptr : [*mxj_test.str] &{IntVal:4 StrVal:now's the time FloatVal:3.14159 BoolVal:true private:Skies are blue} // cp: // misc : [string] Now is the time // struct : // bool : [bool] true // float : [float64] 3.14159 // int : [float64] 4 // str : [string] now's the time // struct_ptr : // bool : [bool] true // float : [float64] 3.14159 // int : [float64] 4 // str : [string] now's the time // */ } mxj-2.5.5/examples/000077500000000000000000000000001402172443100141355ustar00rootroot00000000000000mxj-2.5.5/examples/README000066400000000000000000000114371402172443100150230ustar00rootroot00000000000000Recent additions from gonuts issues: - append.go illustrates turning a sub-element into a list (or appending to a list) - order.go illustrates working with a list of mixed tags and preserving their sequence Examples of using ValuesFromTagPath(). A number of interesting examples have shown up in the gonuts discussion group that could be handled - after a fashion - using the ValuesFromTagPath() function. gonuts1.go - Here we see that the message stream has a problem with multiple tag spellings, though the message structure remains constant. In this example we 'anonymize' the tag for the variant spellings. values := m.ValuesForPath("data.*) where '*' is any possible spelling - "netid" or "idnet" and the result is a list with 1 member of map[string]interface{} type. Once we've retrieved the Map, we can parse it using the known keys - "disable", "text1" and "word1". gonuts1a.go - (03-mar-14) Here we just permute the tag labels using m.NewMap() to make all the messages consistent. Then they can be decoded into a single structure definition. gonuts2.go - This is an interesting case where there was a need to handle messages with lists of "ClaimStatusCodeRecord" entries as well as messages with NONE. (Here we see some of the vagaries of dealing with mixed messages that are verging on becoming anonymous.) msg1 - the message with two ClaimStatusCodeRecord entries msg2 - the message with one ClaimStatusCodeRecord entry msg3 - the message with NO ClaimStatusCodeRecord entries ValuesForPath options: path == "Envelope.Body.GetClaimStatusCodesResponse.GetClaimStatusCodesResult.ClaimStatusCodeRecord" for msg == msg1: returns: a list - []interface{} - with two values of map[string]interface{} type for msg == msg2: returns: a list - []interface{} - with one map[string]interface{} type for msg == msg3: returns 'nil' - no values path == "*.*.*.*.*" for msg == msg1: returns: a list - []interface{} - with two values of map[string]interface{} type path == "*.*.*.*.*.Description for msg == msg1: returns: a list - []interface{} - with two values of string type, the individual values from parsing the two map[string]interface{} values where key=="Description" path == "*.*.*.*.*.*" for msg == msg1: returns: a list - []interface{} - with six values of string type, the individual values from parsing all keys in the two map[string]interface{} values Think of the wildcard character "*" as anonymizing the tag in the position of the path where it occurs. The books.go example has a range of use cases. gonuts3.go - Uses the ValuesForKey method to extract a list of image "src" file names that are encoded as attribute values. gonuts4.go - Here we use the ValuesForPath to extract attribute values for country names. The attribute is included in the 'path' argument by prepending it with a hyphen: ""doc.some_tag.geoInfo.country.-name". gonuts5.go (10-mar-14) - Extract a node of values using ValuesForPath based on name="list3-1-1-1". Then get the values for the 'int' entries based on attribute 'name' values - mv.ValuesForKey("int", "-name:"+n). gonuts5a.go (10-mar-14) - Extract a node of values using ValuesForPath based on name="list3-1-1-1". Then get the values for the 'int' entries based on attribute 'name' values - mv.ValuesForKey("*", "-name:"+n). (Same as gonuts5.go but with wildcarded key value, since we're matching elements on subkey.) EAT YOUR OWN DOG FOOD ... I needed to convert a large (14.9 MB) XML data set from an Eclipse metrics report on an application that had 355,100 lines of code in 211 packages into CSV data sets. The report included application-, package-, class- and method-level metrics reported in an element, "Value", with varying attributes. In addition, the metrics were reported with two different "Metric" compound elements: ... ... ... Using the mxj package seemed a more straightforward approach than using Go vernacular and the standard xml package. I wrote the program getmetrics.go to do this. Here are three version to illustrate using getmetrics1.go - pass os.File handle for metrics_data.xml to NewMapXmlReader. getmetrics2.go - load metrics_data.xml into an in-memory buffer, then pass it to NewMapXml. getmetrics3.go - demonstrates overhead of extracting the raw XML while decoding with NewMapXmlReaderRaw. To run example getmetrics1.go, extract a 120,000+ row data set from metrics_data.zip. Then: go run getmetrics1.go -file=metrics_data.xml mxj-2.5.5/examples/append.go000066400000000000000000000025061402172443100157360ustar00rootroot00000000000000// Per https://github.com/clbanning/mxj/issues/34 package main import ( "fmt" "strconv" "github.com/clbanning/mxj" ) var data = []byte(` 1 `) func main() { m, err := mxj.NewMapXml(data) if err != nil { fmt.Println("new err:", err) return } b, err := m.ValueForPath("a.b") if err != nil { fmt.Println("value err:", err) return } b, err = appendElement(b, 2) if err != nil { fmt.Println("append err:", err) return } // Create the new value for 'b' as a map // and update 'm'. // We should probably have an UpdateValueForPath // method just as there is ValueForPath/ValuesForPath // methods. val := map[string]interface{}{"b": b} n, err := m.UpdateValuesForPath(val, "a.b") if err != nil { fmt.Println("update err:", err) return } if n == 0 { fmt.Println("err: a.b not updated, n =", n) return } x, err := m.XmlIndent("", " ") if err != nil { fmt.Println("XmlIndent err:", err) return } fmt.Println(string(x)) } func appendElement(v interface{}, n int) (interface{}, error) { switch v.(type) { case string: v = []interface{}{v.(string), strconv.Itoa(n)} case []interface{}: v = append(v.([]interface{}), interface{}(strconv.Itoa(n))) default: // capture map[string]interface{} value, simple element, etc. return v, fmt.Errorf("invalid type") } return v, nil } mxj-2.5.5/examples/bom.go000066400000000000000000000022031402172443100152360ustar00rootroot00000000000000// from: https://www.reddit.com/r/golang/comments/99lnxd/help_needed_encodingxml_parsing_malformed_xml/ // package main import ( "encoding/xml" "fmt" "github.com/clbanning/mxj" ) func main() { type decodedXml struct { XMLName xml.Name `xml:"tag" binding:"required"` SomeAttr string `xml:"someattr,attr"` } data := []byte(` -==sddsfdqsdqsdsqd A BUNCH OF INVALID DATA IN THE XML FILE HAHAH --SEPARATERUFCIFHEIR Content-Type: text/plain --SEPARATERUFCIFHEIR-- {"hello": "world"} `) // don't prepend attributes with '-' mxj.SetAttrPrefix("") // parse the data as a map[string]interface{} value m, err := mxj.NewMapXml(data) if err != nil { fmt.Println("err:", err) return } // check that we got a 'tag' tagged doc if _, ok := m["tag"]; !ok { fmt.Println("no tag doc ...") return } fmt.Printf("%v\n", m) // extract the attribute value attrval, err := m.ValueForPath("tag.someattr") if err != nil { fmt.Println("err:", err) return } // create decodeXml value val := decodedXml{ XMLName: xml.Name{"", "tag"}, SomeAttr: attrval.(string)} fmt.Printf("%v\n", val) } mxj-2.5.5/examples/books.go000066400000000000000000000033501402172443100156020ustar00rootroot00000000000000// Note: this illustrates ValuesForKey() and ValuesForPath() methods package main import ( "fmt" "github.com/clbanning/mxj" "log" ) var xmldata = []byte(` William H. Gaddis The Recognitions One of the great seminal American novels of the 20th century. Austin Tappan Wright Islandia An example of earlier 20th century American utopian fiction. John Hawkes The Beetle Leg A lyrical novel about the construction of Ft. Peck Dam in Montana. T.E. Porter King's Day A magical novella. `) func main() { fmt.Println(string(xmldata)) m, err := mxj.NewMapXml(xmldata) if err != nil { log.Fatal("err:", err.Error()) } v, _ := m.ValuesForKey("books") fmt.Println("path: books; len(v):", len(v)) fmt.Printf("\t%+v\n", v) v, _ = m.ValuesForPath("books.book") fmt.Println("path: books.book; len(v):", len(v)) for _, vv := range v { fmt.Printf("\t%+v\n", vv) } v, _ = m.ValuesForPath("books.*") fmt.Println("path: books.*; len(v):", len(v)) for _, vv := range v { fmt.Printf("\t%+v\n", vv) } v, _ = m.ValuesForPath("books.*.title") fmt.Println("path: books.*.title len(v):", len(v)) for _, vv := range v { fmt.Printf("\t%+v\n", vv) } v, _ = m.ValuesForPath("books.*.*") fmt.Println("path: books.*.*; len(v):", len(v)) for _, vv := range v { fmt.Printf("\t%+v\n", vv) } } mxj-2.5.5/examples/getmetrics1.go000066400000000000000000000116501402172443100167160ustar00rootroot00000000000000// getmetrics1.go - transform Eclipse Metrics (v3) XML report into CSV files for each metric // Uses NewMapXmlReader on os.File without copying the raw XML into a buffer while decoding.. // Shows no significant overhead for not first buffering large XML file as in getmetrics2.go. /* I needed to convert a large (14.9 MB) XML data set from an Eclipse metrics report on an application that had 355,100 lines of code in 211 packages into CSV data sets. The report included application-, package-, class- and method-level metrics reported in an element, "Value", with varying attributes. In addition, the metrics were reported with two different "Metric" compound elements: ... ... ... To run this example, extract the metrics_data.xml file from metrics_data.zip, then: > go run getmetrics1 -file=metrics_data.xml The output will be a set of "csv" files. */ package main import ( "flag" "fmt" "github.com/clbanning/mxj" "log" "os" "sort" "time" ) func main() { var file string flag.StringVar(&file, "file", "", "file to process") flag.Parse() fh, fherr := os.Open(file) if fherr != nil { fmt.Println("fherr:", fherr.Error()) return } defer fh.Close() fmt.Println(time.Now().String(), "... File Opened:", file) /* // Get the XML data set from the file. fs, _ := fh.Stat() xmldata := make([]byte, fs.Size()) n, frerr := fh.Read(xmldata) if frerr != nil { fmt.Println("frerr:", frerr.Error()) return } if int64(n) != fs.Size() { fmt.Println("n:", n, "fs.Size():", fs.Size()) return } fmt.Println(time.Now().String(), "... File Read - size:", fs.Size()) // load XML into a Map value m, merr := mxj.NewMapXml(xmldata) */ // Consume the file using os.File Reader. // Note: there is a single record with root tag of "Metrics". m, merr := mxj.NewMapXmlReader(fh) if merr != nil { log.Fatal("merr:", merr.Error()) } fmt.Println(time.Now().String(), "... XML Unmarshaled - len:", len(m)) // Get just the key values of interest. // Could also use m.ValuesForKey("Metric"), // since there's just the one path. metricVals, err := m.ValuesForPath("Metrics.Metric") if err != nil { log.Fatal("err:", err.Error()) } fmt.Println(time.Now().String(), "... ValuesFromKeyPath - len:", len(metricVals)) // now just manipulate Map entries returned as []interface{} array. for _, v := range metricVals { aMetricVal := v.(map[string]interface{}) // create file to hold csv data sets id := aMetricVal["-id"].(string) desc := aMetricVal["-description"].(string) mf, mferr := os.OpenFile(id+".csv", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666) if mferr != nil { fmt.Println("mferr:", mferr.Error()) return } fmt.Print(time.Now().String(), " id: ", id, " desc: ", desc) mf.WriteString(id + "," + desc + "\n") // rescan looking for keys with data: Values or Value for key, val := range aMetricVal { switch key { case "Values": // extract the list of "Value" from map values := val.(map[string]interface{})["Value"].([]interface{}) fmt.Println(" len(Values):", len(values)) // first line in file is the metric label values (keys) var gotKeys bool for _, vval := range values { valueEntry := vval.(map[string]interface{}) // no guarantee that range on map will follow any sequence lv := len(valueEntry) list := make([][2]string, lv) var i int for k, v := range valueEntry { list[i][0] = k list[i][1] = v.(string) i++ } sort.Sort(mylist(list)) // extract keys as column header on first pass if !gotKeys { // print out the keys var gotFirstKey bool // for kk, _ := range valueEntry { for i := 0; i < lv; i++ { if gotFirstKey { mf.WriteString(",") } else { gotFirstKey = true } // strip prepended hyphen mf.WriteString((list[i][0])[1:]) } mf.WriteString("\n") gotKeys = true } // print out values var gotFirstVal bool // for _, vv := range valueEntry { for i := 0; i < lv; i++ { if gotFirstVal { mf.WriteString(",") } else { gotFirstVal = true } mf.WriteString(list[i][1]) } // terminate row of data mf.WriteString("\n") } case "Value": vv := val.(map[string]interface{}) fmt.Println(" len(Value):", len(vv)) mf.WriteString("value\n" + vv["-value"].(string) + "\n") } } mf.Close() } } type mylist [][2]string func (m mylist) Len() int { return len(m) } func (m mylist) Less(i, j int) bool { if m[i][0] > m[j][0] { return false } return true } func (m mylist) Swap(i, j int) { m[i], m[j] = m[j], m[i] } mxj-2.5.5/examples/getmetrics2.go000066400000000000000000000115421402172443100167170ustar00rootroot00000000000000// getmetrics2.go - transform Eclipse Metrics (v3) XML report into CSV files for each metric // Uses an in-memory buffer for the XML data and direct XML decoding of the buffer into a Map. // Not significantly faster than getmetrics1.go that uses an io.Reader (os.File) to directly // decode the XML from the file. /* I needed to convert a large (14.9 MB) XML data set from an Eclipse metrics report on an application that had 355,100 lines of code in 211 packages into CSV data sets. The report included application-, package-, class- and method-level metrics reported in an element, "Value", with varying attributes. In addition, the metrics were reported with two different "Metric" compound elements: ... ... ... To run this example, extract the metrics_data.xml file from metrics_data.zip, then: > go run getmetrics -file=metrics_data.xml The output will be a set of "csv" files. */ package main import ( "flag" "fmt" "github.com/clbanning/mxj" "log" "os" "sort" "time" ) func main() { var file string flag.StringVar(&file, "file", "", "file to process") flag.Parse() fh, fherr := os.Open(file) if fherr != nil { fmt.Println("fherr:", fherr.Error()) return } defer fh.Close() fmt.Println(time.Now().String(), "... File Opened:", file) // Get the XML data set from the file. fs, _ := fh.Stat() xmldata := make([]byte, fs.Size()) n, frerr := fh.Read(xmldata) if frerr != nil { fmt.Println("frerr:", frerr.Error()) return } if int64(n) != fs.Size() { fmt.Println("n:", n, "fs.Size():", fs.Size()) return } fmt.Println(time.Now().String(), "... File Read - size:", fs.Size()) // load XML into a Map value // Note: there is a single record with root tag of "Metrics". m, merr := mxj.NewMapXml(xmldata) if merr != nil { log.Fatal("merr:", merr.Error()) } fmt.Println(time.Now().String(), "... XML Unmarshaled - len:", len(m)) // Get just the key values of interest. // Could also use m.ValuesForKey("Metric"), // since there's just the one path. metricVals, err := m.ValuesForPath("Metrics.Metric") if err != nil { log.Fatal("err:", err.Error()) } fmt.Println(time.Now().String(), "... ValuesFromKeyPath - len:", len(metricVals)) // now just manipulate Map entries returned as []interface{} array. for _, v := range metricVals { aMetricVal := v.(map[string]interface{}) // create file to hold csv data sets id := aMetricVal["-id"].(string) desc := aMetricVal["-description"].(string) mf, mferr := os.OpenFile(id+".csv", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666) if mferr != nil { fmt.Println("mferr:", mferr.Error()) return } fmt.Print(time.Now().String(), " id: ", id, " desc: ", desc) mf.WriteString(id + "," + desc + "\n") // rescan looking for keys with data: Values or Value for key, val := range aMetricVal { switch key { case "Values": // extract the list of "Value" from map values := val.(map[string]interface{})["Value"].([]interface{}) fmt.Println(" len(Values):", len(values)) // first line in file is the metric label values (keys) var gotKeys bool for _, vval := range values { valueEntry := vval.(map[string]interface{}) // no guarantee that range on map will follow any sequence lv := len(valueEntry) list := make([][2]string, lv) var i int for k, v := range valueEntry { list[i][0] = k list[i][1] = v.(string) i++ } sort.Sort(mylist(list)) // extract keys as column header on first pass if !gotKeys { // print out the keys var gotFirstKey bool // for kk, _ := range valueEntry { for i := 0; i < lv; i++ { if gotFirstKey { mf.WriteString(",") } else { gotFirstKey = true } // strip prepended hyphen mf.WriteString((list[i][0])[1:]) } mf.WriteString("\n") gotKeys = true } // print out values var gotFirstVal bool // for _, vv := range valueEntry { for i := 0; i < lv; i++ { if gotFirstVal { mf.WriteString(",") } else { gotFirstVal = true } mf.WriteString(list[i][1]) } // terminate row of data mf.WriteString("\n") } case "Value": vv := val.(map[string]interface{}) fmt.Println(" len(Value):", len(vv)) mf.WriteString("value\n" + vv["-value"].(string) + "\n") } } mf.Close() } } type mylist [][2]string func (m mylist) Len() int { return len(m) } func (m mylist) Less(i, j int) bool { if m[i][0] > m[j][0] { return false } return true } func (m mylist) Swap(i, j int) { m[i], m[j] = m[j], m[i] } mxj-2.5.5/examples/getmetrics3.go000066400000000000000000000124301402172443100167150ustar00rootroot00000000000000// getmetrics3.go - transform Eclipse Metrics (v3) XML report into CSV files for each metric // Uses NewMapXmlReaderRaw that requires loading raw XML into a []byte buffer using a ByteReader. // Show's performance impact of copying the raw XML while simultaneously decoding it from on os.File // Reader. (vs. getmetrics1.go) If you're processing a file and need a copy of the raw XML and SPEED, // should buffer the file in memory and decode using mxj.NewMapXmlReaderRaw as in getmetrics4.go. /* I needed to convert a large (14.9 MB) XML data set from an Eclipse metrics report on an application that had 355,100 lines of code in 211 packages into CSV data sets. The report included application-, package-, class- and method-level metrics reported in an element, "Value", with varying attributes. In addition, the metrics were reported with two different "Metric" compound elements: ... ... ... To run this example, extract the metrics_data.xml file from metrics_data.zip, then: > go run getmetrics3 -file=metrics_data.xml The output will be a set of "csv" files. */ package main import ( "flag" "fmt" "github.com/clbanning/mxj" "log" "os" "sort" "time" ) func main() { var file string flag.StringVar(&file, "file", "", "file to process") flag.Parse() fh, fherr := os.Open(file) if fherr != nil { fmt.Println("fherr:", fherr.Error()) return } defer fh.Close() fmt.Println(time.Now().String(), "... File Opened:", file) /* // Get the XML data set from the file. fs, _ := fh.Stat() xmldata := make([]byte, fs.Size()) n, frerr := fh.Read(xmldata) if frerr != nil { fmt.Println("frerr:", frerr.Error()) return } if int64(n) != fs.Size() { fmt.Println("n:", n, "fs.Size():", fs.Size()) return } fmt.Println(time.Now().String(), "... File Read - size:", fs.Size()) // load XML into a Map value m, merr := mxj.NewMapXml(xmldata) */ // Consume the file using os.File Reader. // Note: there is a single record with root tag of "Metrics". // Also: this is MUCH slower than using buffer or not loading raw XML. m, raw, merr := mxj.NewMapXmlReaderRaw(fh) if merr != nil { log.Fatal("merr:", merr.Error()) } fmt.Println(time.Now().String(), "... XML Unmarshaled - len:", len(m)) fmt.Println("raw XML buffer size (should be same as File size):", len(raw)) // Get just the key values of interest. // Could also use m.ValuesForKey("Metric"), // since there's just the one path. metricVals, err := m.ValuesForPath("Metrics.Metric") if err != nil { log.Fatal("err:", err.Error()) } fmt.Println(time.Now().String(), "... ValuesFromKeyPath - len:", len(metricVals)) // now just manipulate Map entries returned as []interface{} array. for _, v := range metricVals { aMetricVal := v.(map[string]interface{}) // create file to hold csv data sets id := aMetricVal["-id"].(string) desc := aMetricVal["-description"].(string) mf, mferr := os.OpenFile(id+".csv", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666) if mferr != nil { fmt.Println("mferr:", mferr.Error()) return } fmt.Print(time.Now().String(), " id: ", id, " desc: ", desc) mf.WriteString(id + "," + desc + "\n") // rescan looking for keys with data: Values or Value for key, val := range aMetricVal { switch key { case "Values": // extract the list of "Value" from map values := val.(map[string]interface{})["Value"].([]interface{}) fmt.Println(" len(Values):", len(values)) // first line in file is the metric label values (keys) var gotKeys bool for _, vval := range values { valueEntry := vval.(map[string]interface{}) // no guarantee that range on map will follow any sequence lv := len(valueEntry) list := make([][2]string, lv) var i int for k, v := range valueEntry { list[i][0] = k list[i][1] = v.(string) i++ } sort.Sort(mylist(list)) // extract keys as column header on first pass if !gotKeys { // print out the keys var gotFirstKey bool // for kk, _ := range valueEntry { for i := 0; i < lv; i++ { if gotFirstKey { mf.WriteString(",") } else { gotFirstKey = true } // strip prepended hyphen mf.WriteString((list[i][0])[1:]) } mf.WriteString("\n") gotKeys = true } // print out values var gotFirstVal bool // for _, vv := range valueEntry { for i := 0; i < lv; i++ { if gotFirstVal { mf.WriteString(",") } else { gotFirstVal = true } mf.WriteString(list[i][1]) } // terminate row of data mf.WriteString("\n") } case "Value": vv := val.(map[string]interface{}) fmt.Println(" len(Value):", len(vv)) mf.WriteString("value\n" + vv["-value"].(string) + "\n") } } mf.Close() } } type mylist [][2]string func (m mylist) Len() int { return len(m) } func (m mylist) Less(i, j int) bool { if m[i][0] > m[j][0] { return false } return true } func (m mylist) Swap(i, j int) { m[i], m[j] = m[j], m[i] } mxj-2.5.5/examples/getmetrics4.go000066400000000000000000000122671402172443100167260ustar00rootroot00000000000000// getmetrics2.go - transform Eclipse Metrics (v3) XML report into CSV files for each metric // Uses an in-memory buffer for the XML data and direct XML decoding of the buffer into a Map. // Then XML buffer is decoded into a Map while the raw XML is copied using NewMapXmlReaderRaw() // to illustrate processing overhead relative to getmetrics2.go. Not a practical example, // but confirms the getmetrics1.go vs. getmetrics3.go use case. /* I needed to convert a large (14.9 MB) XML data set from an Eclipse metrics report on an application that had 355,100 lines of code in 211 packages into CSV data sets. The report included application-, package-, class- and method-level metrics reported in an element, "Value", with varying attributes. In addition, the metrics were reported with two different "Metric" compound elements: ... ... ... To run this example, extract the metrics_data.xml file from metrics_data.zip, then: > go run getmetrics -file=metrics_data.xml The output will be a set of "csv" files. */ package main import ( "bytes" "flag" "fmt" "github.com/clbanning/mxj" "log" "os" "sort" "time" ) func main() { var file string flag.StringVar(&file, "file", "", "file to process") flag.Parse() fh, fherr := os.Open(file) if fherr != nil { fmt.Println("fherr:", fherr.Error()) return } defer fh.Close() fmt.Println(time.Now().String(), "... File Opened:", file) // Get the XML data set from the file. fs, _ := fh.Stat() xmldata := make([]byte, fs.Size()) n, frerr := fh.Read(xmldata) if frerr != nil { fmt.Println("frerr:", frerr.Error()) return } if int64(n) != fs.Size() { fmt.Println("n:", n, "fs.Size():", fs.Size()) return } fmt.Println(time.Now().String(), "... File Read - size:", fs.Size()) // wrap the buffer in an io.Reader xmlReader := bytes.NewBuffer(xmldata) // load XML into a Map value // Note: there is a single record with root tag of "Metrics". m, raw, merr := mxj.NewMapXmlReaderRaw(xmlReader) // don't catch the pointer to raw XML if merr != nil { log.Fatal("merr:", merr.Error()) } fmt.Println(time.Now().String(), "... XML Unmarshaled - len:", len(m)) fmt.Println("raw XML buffer size (should be same as File size):", len(raw)) // Get just the key values of interest. // Could also use m.ValuesForKey("Metric"), // since there's just the one path. metricVals, err := m.ValuesForPath("Metrics.Metric") if err != nil { log.Fatal("err:", err.Error()) } fmt.Println(time.Now().String(), "... ValuesFromKeyPath - len:", len(metricVals)) // now just manipulate Map entries returned as []interface{} array. for _, v := range metricVals { aMetricVal := v.(map[string]interface{}) // create file to hold csv data sets id := aMetricVal["-id"].(string) desc := aMetricVal["-description"].(string) mf, mferr := os.OpenFile(id+".csv", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666) if mferr != nil { fmt.Println("mferr:", mferr.Error()) return } fmt.Print(time.Now().String(), " id: ", id, " desc: ", desc) mf.WriteString(id + "," + desc + "\n") // rescan looking for keys with data: Values or Value for key, val := range aMetricVal { switch key { case "Values": // extract the list of "Value" from map values := val.(map[string]interface{})["Value"].([]interface{}) fmt.Println(" len(Values):", len(values)) // first line in file is the metric label values (keys) var gotKeys bool for _, vval := range values { valueEntry := vval.(map[string]interface{}) // no guarantee that range on map will follow any sequence lv := len(valueEntry) list := make([][2]string, lv) var i int for k, v := range valueEntry { list[i][0] = k list[i][1] = v.(string) i++ } sort.Sort(mylist(list)) // extract keys as column header on first pass if !gotKeys { // print out the keys var gotFirstKey bool // for kk, _ := range valueEntry { for i := 0; i < lv; i++ { if gotFirstKey { mf.WriteString(",") } else { gotFirstKey = true } // strip prepended hyphen mf.WriteString((list[i][0])[1:]) } mf.WriteString("\n") gotKeys = true } // print out values var gotFirstVal bool // for _, vv := range valueEntry { for i := 0; i < lv; i++ { if gotFirstVal { mf.WriteString(",") } else { gotFirstVal = true } mf.WriteString(list[i][1]) } // terminate row of data mf.WriteString("\n") } case "Value": vv := val.(map[string]interface{}) fmt.Println(" len(Value):", len(vv)) mf.WriteString("value\n" + vv["-value"].(string) + "\n") } } mf.Close() } } type mylist [][2]string func (m mylist) Len() int { return len(m) } func (m mylist) Less(i, j int) bool { if m[i][0] > m[j][0] { return false } return true } func (m mylist) Swap(i, j int) { m[i], m[j] = m[j], m[i] } mxj-2.5.5/examples/gitissue1.go000066400000000000000000000011111402172443100163730ustar00rootroot00000000000000// https://github.com/clbanning/mxj/issues/17 package main import ( "bytes" "fmt" "github.com/clbanning/mxj" "io" ) var data = []byte(` just something to demo `) func main() { r := bytes.NewReader(data) m := make(map[string]interface{}) var v map[string]interface{} var err error for { v, err = mxj.NewMapXmlSeqReader(r) if err != nil { if err == io.EOF { break } if err != mxj.NoRoot { // handle error } } for key, val := range v { m[key] = val } } fmt.Printf("%v\n", m) } mxj-2.5.5/examples/gitissue2.dat000066400000000000000000000001341402172443100165430ustar00rootroot00000000000000 QQ mxj-2.5.5/examples/gitissue2.go000066400000000000000000000011541402172443100164030ustar00rootroot00000000000000// https://github.com/clbanning/mxj/issues/17 package main import ( "bytes" "fmt" "github.com/clbanning/mxj" "io" "io/ioutil" ) func main() { b, err := ioutil.ReadFile("gitissue2.dat") if err != nil { fmt.Println("err:", err) return } r := bytes.NewReader(b) m := make(map[string]interface{}) for { v, err := mxj.NewMapXmlSeqReader(r) // v, raw, err := mxj.NewMapXmlSeqReaderRaw(r) if err != nil { if err == io.EOF { break } if err != mxj.NoRoot { // handle error } } for key, val := range v { m[key] = val } // fmt.Println(string(raw)) } fmt.Printf("%v\n", m) } mxj-2.5.5/examples/gitissue2_2.go000066400000000000000000000010141402172443100166170ustar00rootroot00000000000000// https://github.com/clbanning/mxj/issues/17 package main import ( "fmt" "github.com/clbanning/mxj" "io" "os" ) func main() { fh, err := os.Open("gitissue2.dat") if err != nil { fmt.Println("err:", err) return } m := make(map[string]interface{}) for { v, err := mxj.NewMapXmlSeqReader(fh) if err != nil { if err == io.EOF { break } if err != mxj.NoRoot { // handle error } } for key, val := range v { m[key] = val } // fmt.Println(string(raw)) } fmt.Printf("%v\n", m) } mxj-2.5.5/examples/gonuts1.go000066400000000000000000000046111402172443100160660ustar00rootroot00000000000000// https://groups.google.com/forum/#!searchin/golang-nuts/idnet$20netid/golang-nuts/guM3ZHHqSF0/K1pBpMqQSSwJ // http://play.golang.org/p/BFFDxphKYK package main import ( "bytes" "fmt" "github.com/clbanning/mxj" "io" ) // Demo how to compensate for irregular tag labels in data. // Need to extract from an XML stream the values for "netid" and "idnet". // Solution: use a wildcard path "data.*" to anonymize the "netid" and "idnet" tags. var msg1 = []byte(` no default:text default:word `) var msg2 = []byte(` yes default:text default:word `) func main() { // let's create a message stream buf := new(bytes.Buffer) // load a couple of messages into it _, _ = buf.Write(msg1) _, _ = buf.Write(msg2) n := 0 for { n++ // read the stream as Map values - quit on io.EOF m, raw, merr := mxj.NewMapXmlReaderRaw(buf) if merr != nil && merr != io.EOF { // handle error - for demo we just print it and continue fmt.Printf("msg: %d - merr: %s\n", n, merr.Error()) continue } else if merr == io.EOF { break } fmt.Println("\nMessage to parse:", string(raw)) fmt.Println("Map value for XML message:", m.StringIndent()) // get the values for "netid" or "idnet" key using path == "data.*" values, _ := m.ValuesForPath("data.*") fmt.Println("\nmsg:", n, "> path == data.* - got array of values, len:", len(values)) for i, val := range values { fmt.Println("ValuesForPath result array member -", i, ":", val) fmt.Println(" k:v pairs for array member:", i) for key, val := range val.(map[string]interface{}) { // You'd probably want to process the value, as appropriate. // Here we just print it out. fmt.Println("\t\t", key, ":", val) } } // This shows what happens if you wildcard the value keys for "idnet" and "netid" values, _ = m.ValuesForPath("data.*.*") fmt.Println("\npath == data.*.* - got an array of values, len(v):", len(values)) fmt.Println("(Note: values returned by ValuesForPath are at maximum depth of the tree. So just have values.)") for i, val := range values { fmt.Println("ValuesForPath array member -", i, ":", val) } } } mxj-2.5.5/examples/gonuts10.go000066400000000000000000000051441402172443100161500ustar00rootroot00000000000000/* gonuts10.go - https://groups.google.com/forum/?fromgroups#!topic/golang-nuts/tf4aDQ1Hn_c change: Sam Kevin Smith to: Sam Kevin Smith Kevin Smith NOTE: sequence of elements NOT guaranteed due to use of map[string]interface{}. Here we build the "full-name" element value from other values in the doc by selecting the "first-name" value with the latest dates. */ package main import ( "fmt" "github.com/clbanning/mxj" ) var data = []byte(` Sam Kevin Smith `) func main() { m, err := mxj.NewMapXml(data) if err != nil { fmt.Println("NewMapXml err:", err) return } // vals, err := m.ValuesForPath("author.first-name") // full-path option vals, err := m.ValuesForKey("first-name") // key-only alternatively if err != nil { fmt.Println("ValuesForPath err:", err) return } else if len(vals) == 0 { fmt.Println("no first-name vals") return } var fname, date string for _, v := range vals { vm, ok := v.(map[string]interface{}) if !ok { fmt.Println("assertion failed") return } fn, ok := vm["#text"].(string) if !ok { fmt.Println("no #text tag") return } dt, ok := vm["-effect_range"].(string) if !ok { fmt.Println("no -effect_range attr") return } if dt > date { date = dt fname = fn } } /* // alternatively: //(however, this requires knowing what latest "effect_range" attribute value is) vals, err := m.ValuesForKey("first-name", "-effect_range:2012-") if len(vals) == 0 { fmt.Println("no #text vals") return } fname := vals[0].(map[string]interface{})["#text"].(string) */ // vals, err = m.ValuesForKey("last-name") // key-only option vals, err = m.ValuesForPath("author.last-name") // full-path option if err != nil { fmt.Println("ValuesForPath err:", err) return } else if len(vals) == 0 { fmt.Println("no last-name vals") return } lname := vals[0].(string) if err = m.SetValueForPath(fname+" "+lname, "author.full-name"); err != nil { fmt.Println("SetValueForPath err:", err) return } b, err := m.XmlIndent("", " ") if err != nil { fmt.Println("XmlIndent err:", err) return } fmt.Println(string(b)) } mxj-2.5.5/examples/gonuts10seq.go000066400000000000000000000047441402172443100166660ustar00rootroot00000000000000/* gonuts10.go - https://groups.google.com/forum/?fromgroups#!topic/golang-nuts/tf4aDQ1Hn_c change: Sam Kevin Smith to: Sam Kevin Smith Kevin Smith NOTE: use NewMapXmlSeq() and mv.XmlSeqIndent() to preserve structure. Here we build the "full-name" element value from other values in the doc by selecting the "first-name" value with the latest dates. */ package main import ( "fmt" "github.com/clbanning/mxj" "strings" ) var data = []byte(` Sam Kevin Smith `) func main() { fmt.Println(string(data)) m, err := mxj.NewMapXmlSeq(data) if err != nil { fmt.Println("NewMapXml err:", err) return } vals, err := m.ValuesForPath("author.first-name") // full-path option if err != nil { fmt.Println("ValuesForPath err:", err) return } else if len(vals) == 0 { fmt.Println("no first-name vals") return } var fname, date string var index int for _, v := range vals { vm, ok := v.(map[string]interface{}) if !ok { fmt.Println("assertion failed") return } fn, ok := vm["#text"].(string) if !ok { fmt.Println("no #text tag") return } // extract the associated date dt, _ := mxj.Map(vm).ValueForPathString("#attr.effect_range.#text") if dt == "" { fmt.Println("no effect_range attr") return } dts := strings.Split(dt, "-") if len(dts) > 1 && dts[len(dts)-1] == "" { index = len(dts) - 2 } else if len(dts) > 0 { index = len(dts) - 1 } if len(dts) > 0 && dts[index] > date { date = dts[index] fname = fn } } vals, err = m.ValuesForPath("author.last-name.#text") // full-path option if err != nil { fmt.Println("ValuesForPath err:", err) return } else if len(vals) == 0 { fmt.Println("no last-name vals") return } lname := vals[0].(string) if err = m.SetValueForPath(fname+" "+lname, "author.full-name.#text"); err != nil { fmt.Println("SetValueForPath err:", err) return } b, err := m.XmlSeqIndent("", " ") if err != nil { fmt.Println("XmlIndent err:", err) return } fmt.Println(string(b)) } mxj-2.5.5/examples/gonuts11seq.go000066400000000000000000001047411402172443100166650ustar00rootroot00000000000000/* gonuts10seqB.go - https://groups.google.com/forum/?fromgroups#!topic/golang-nuts/tf4aDQ1Hn_c Objective: assign Comment.CommentText attribute value to Request.ReportingName attribute that immediately follows Comment. NOTE: use NewMapXmlSeq() and mv.XmlSeqIndent() to preserve structure. See data value at EOF - from: https://gist.github.com/suntong/e4dcdc6c85dcf769eec4 */ package main import ( "bytes" "fmt" "github.com/clbanning/mxj" "io" ) func main() { // fmt.Println(string(data)) rdr := bytes.NewReader(data) var m mxj.Map var err error // We read processing docs sequentially. // Un-rooted ProcInst or Comments are processed AND just reencoded. (XmlSeqIndent() knows how, now.) for m, err = mxj.NewMapXmlSeqReader(rdr); m != nil || err != io.EOF; m, err = mxj.NewMapXmlSeqReader(rdr) { if err != nil { if err != mxj.NO_ROOT { fmt.Println("NewMapXmlSeq err:", err) fmt.Println("m:", m) } else if m != nil { x, _ := m.XmlSeqIndent("", " ") fmt.Println(string(x)) } continue } // fmt.Println(m.StringIndent()) // We have Two different arrays of Items in the XML doc, one nested in the other. if err = copyCmts(m, "WebTest.Items"); err != nil { fmt.Println("err:", err) } if err = copyCmts(m, "WebTest.Items.TransactionTimer.Items"); err != nil { fmt.Println("err:", err) } // re-encode the map with the Items.Comment[#seq==n].#attr.CommentText // values copied to the Items.Request[#seq==n+1].#attr.ReportingName elements. b, err := m.XmlSeqIndent("", " ") if err != nil { fmt.Println("XmlIndent err:", err) return } fmt.Println(string(b)) } } // Uncomment the print statements to details of the process here. func copyCmts(m mxj.Map, path string) error { // get the array of Items entries for the 'path' vals, err := m.ValuesForPath(path) if err != nil { return fmt.Errorf("ValuesForPath err: %s", err.Error()) } else if len(vals) == 0 { return fmt.Errorf("no vals for path: %s", path) } // process each Items entry for _, v := range vals { vm, ok := v.(map[string]interface{}) if !ok { return fmt.Errorf("assertion failed") } // get the Comment list c, ok := vm["Comment"] if !ok { // --> no Items.Comment elements continue } // Don't assume that Comment is an array. // There may be just one value, in which case it will decode as map[string]interface{}. switch c.(type) { case map[string]interface{}: c = []interface{}{c} } cmt := c.([]interface{}) // get the Request list r, ok := vm["Request"] if !ok { // --> no Items.Request elements continue } // Don't assume the Request is an array. // There may be just one value, in which case it will decode as map[string]interface{}. switch r.(type) { case map[string]interface{}: r = []interface{}{r} } req := r.([]interface{}) // fmt.Println("Comment:", cmt) // fmt.Println("Request:", req) // Comment elements with #seq==n are followed by Request element with #seq==n+1. // For each Comment.#seq==n extract the CommentText attribute value and use it to // set the ReportingName attribute value in Request.#seq==n+1. for _, v := range cmt { vmap := v.(map[string]interface{}) seq := vmap["#seq"].(int) // type is int // extract CommentText attr from "#attr" acmt, _ := mxj.Map(vmap).ValueForPath("#attr.CommentText.#text") if acmt == "" { fmt.Println("no CommentText value in Comment attributes") } // fmt.Println(seq, acmt) // find the request with the #seq==seq+1 value var r map[string]interface{} for _, vv := range req { rt := vv.(map[string]interface{}) if rt["#seq"].(int) == seq+1 { r = rt break } } if r == nil { // no Request with #seq==seq+1 continue } if err := mxj.Map(r).SetValueForPath(acmt, "#attr.ReportingName.#text"); err != nil { fmt.Println("SetValueForPath err:", err) break } } } return nil } var data = []byte(` `) mxj-2.5.5/examples/gonuts12seq.go000066400000000000000000001100621402172443100166570ustar00rootroot00000000000000/* gonuts10seqB.go - https://groups.google.com/forum/?fromgroups#!topic/golang-nuts/tf4aDQ1Hn_c Objective: to quote from email ================================ BEGIN QUOTE I'm actually dealing with Microsoft webtest files. An example can be find at, https://gist.github.com/suntong/e4dcdc6c85dcf769eec4 It is the same as our case -- we have comments before each " Under it, the requests and comments are grouped into this transaction. Now the challenge is, for *each* request with a comment immediately before it, change it attribute "ReportingName="""''s value with the content from its leading comments, and from the content of the grouping transaction as well. Let's say, first 10 chars or first three words or each. So for the first Request under "", which is " no Items.Comment elements continue } // Don't assume that Comment is an array. // There may be just one value, in which case it will decode as map[string]interface{}. switch c.(type) { case map[string]interface{}: c = []interface{}{c} } cmt := c.([]interface{}) // get the Request list r, ok := vm["Request"] if !ok { // --> no Items.Request elements continue } // Don't assume the Request is an array. // There may be just one value, in which case it will decode as map[string]interface{}. switch r.(type) { case map[string]interface{}: r = []interface{}{r} } req := r.([]interface{}) // fmt.Println("Comment:", cmt) // fmt.Println("Request:", req) // Comment elements with #seq==n are followed by Request element with #seq==n+1. // For each Comment.#seq==n extract the CommentText attribute value and use it to // set the ReportingName attribute value in Request.#seq==n+1. for _, v := range cmt { vmap := v.(map[string]interface{}) seq := vmap["#seq"].(int) // type is int // extract CommentText attr from array of "#attr" acmt, _ := mxj.Map(vmap).ValueForPathString("#attr.CommentText.#text") if acmt == "" { fmt.Println("no CommentText value in Comment attributes") } // fmt.Println(seq, acmt) // find the request with the #seq==seq+1 value var r map[string]interface{} for _, vv := range req { rt := vv.(map[string]interface{}) if rt["#seq"].(int) == seq+1 { r = rt break } } if r == nil { // no Request with #seq==seq+1 continue } if err := mxj.Map(r).SetValueForPath(tname+", "+acmt, "#attr.ReportingName.#text"); err != nil { fmt.Println("SetValueForPath err:", err) break } } } // re-encode the map with the TransactionTimer.#attr.Name & Items.Comment[#seq==n].#attr.CommentText // values copied to the Items.Request[#seq==n+1].#attr.ReportingName elements. b, err := m.XmlSeqIndent("", " ") if err != nil { fmt.Println("XmlIndent err:", err) return } fmt.Println(string(b)) } } var data = []byte(` `) mxj-2.5.5/examples/gonuts1a.go000066400000000000000000000030561402172443100162310ustar00rootroot00000000000000// https://groups.google.com/forum/#!searchin/golang-nuts/idnet$20netid/golang-nuts/guM3ZHHqSF0/K1pBpMqQSSwJ // http://play.golang.org/p/BFFDxphKYK package main import ( "bytes" "fmt" "github.com/clbanning/mxj" "io" ) // Demo how to re-label a key using mv.NewMap(). // Need to normalize from an XML stream the tags "netid" and "idnet". // Solution: make everything "netid". var msg1 = []byte(` no default:text default:word `) var msg2 = []byte(` yes default:text default:word `) func main() { // let's create a message stream buf := new(bytes.Buffer) // load a couple of messages into it _, _ = buf.Write(msg1) _, _ = buf.Write(msg2) n := 0 for { n++ // read the stream as Map values - quit on io.EOF m, raw, merr := mxj.NewMapXmlReaderRaw(buf) if merr != nil && merr != io.EOF { // handle error - for demo we just print it and continue fmt.Printf("msg: %d - merr: %s\n", n, merr.Error()) continue } else if merr == io.EOF { break } // the first keypair retains values if data correct // the second keypair relabels "idnet" to "netid" n, _ := m.NewMap("data.netid", "data.idnet:data.netid") x, _ := n.XmlIndent("", " ") fmt.Println("original value:", string(raw)) fmt.Println("new value:") fmt.Println(string(x)) } } mxj-2.5.5/examples/gonuts2.go000066400000000000000000000150361402172443100160720ustar00rootroot00000000000000// https://groups.google.com/forum/#!topic/golang-nuts/V83jUKluLnM // http://play.golang.org/p/alWGk4MDBc // Here messsages come in one of three forms: // ... list of ClaimStatusCodeRecord ... // ... one instance of ClaimStatusCodeRecord ... // ... empty element ... // ValuesForPath package main import ( "fmt" "github.com/clbanning/mxj" ) var xmlmsg1 = []byte(` true A Initial Claim Review/Screening true B Initial Contact Made w/ Provider `) var xmlmsg2 = []byte(` true A Initial Claim Review/Screening `) var xmlmsg3 = []byte(` `) func main() { xmldata := [][]byte{xmlmsg1, xmlmsg2, xmlmsg3} fullPath(xmldata) partPath1(xmlmsg1) partPath2(xmlmsg1) partPath3(xmlmsg1) partPath4(xmlmsg1) partPath5(xmlmsg1) partPath6(xmlmsg1) } func fullPath(xmldata [][]byte) { for i, msg := range xmldata { fmt.Println("\ndoc:", i) fmt.Println(string(msg)) // decode the XML m, _ := mxj.NewMapXml(msg) // get the value for the key path of interest path := "Envelope.Body.GetClaimStatusCodesResponse.GetClaimStatusCodesResult.ClaimStatusCodeRecord" values, err := m.ValuesForPath(path) if err != nil { fmt.Println("err:", err.Error()) return } if values == nil { fmt.Println("path:", path) fmt.Println("No ClaimStatusCodesResult code records.") continue } fmt.Println("\nPath:", path) fmt.Println("Number of code records:", len(values)) fmt.Println("values:", values, "\n") for _, v := range values { switch v.(type) { case map[string]interface{}: fmt.Println("map[string]interface{}:", v.(map[string]interface{})) case []map[string]interface{}: fmt.Println("[]map[string]interface{}:", v.([]map[string]interface{})) case []interface{}: fmt.Println("[]interface{}:", v.([]interface{})) case interface{}: fmt.Println("interface{}:", v.(interface{})) } } } } func partPath1(msg []byte) { fmt.Println("\nmsg:", string(msg)) m, _ := mxj.NewMapXml(msg) fmt.Println("m:", m.StringIndent()) path := "Envelope.Body.*.*.ClaimStatusCodeRecord" values, err := m.ValuesForPath(path) if err != nil { fmt.Println("err:", err.Error()) return } if values == nil { fmt.Println("path:", path) fmt.Println("No ClaimStatusCodesResult code records.") return } fmt.Println("\nPath:", path) fmt.Println("Number of code records:", len(values)) for n, v := range values { fmt.Printf("\t#%d: %v\n", n, v) } } func partPath2(msg []byte) { fmt.Println("\nmsg:", string(msg)) m, _ := mxj.NewMapXml(msg) fmt.Println("m:", m.StringIndent()) path := "Envelope.Body.*.*.*" values, err := m.ValuesForPath(path) if err != nil { fmt.Println("err:", err.Error()) return } if values == nil { fmt.Println("path:", path) fmt.Println("No ClaimStatusCodesResult code records.") return } fmt.Println("\nPath:", path) fmt.Println("Number of code records:", len(values)) for n, v := range values { fmt.Printf("\t#%d: %v\n", n, v) } } func partPath3(msg []byte) { fmt.Println("\nmsg:", string(msg)) m, _ := mxj.NewMapXml(msg) fmt.Println("m:", m.StringIndent()) path := "*.*.*.*.*" values, err := m.ValuesForPath(path) if err != nil { fmt.Println("err:", err.Error()) return } if values == nil { fmt.Println("path:", path) fmt.Println("No ClaimStatusCodesResult code records.") return } fmt.Println("\nPath:", path) fmt.Println("Number of code records:", len(values)) for n, v := range values { fmt.Printf("\t#%d: %v\n", n, v) } } func partPath4(msg []byte) { fmt.Println("\nmsg:", string(msg)) m, _ := mxj.NewMapXml(msg) fmt.Println("m:", m.StringIndent()) path := "*.*.*.*.*.Description" values, err := m.ValuesForPath(path) if err != nil { fmt.Println("err:", err.Error()) return } if values == nil { fmt.Println("path:", path) fmt.Println("No ClaimStatusCodesResult code records.") return } fmt.Println("\nPath:", path) fmt.Println("Number of code records:", len(values)) for n, v := range values { fmt.Printf("\t#%d: %v\n", n, v) } } func partPath5(msg []byte) { fmt.Println("\nmsg:", string(msg)) m, _ := mxj.NewMapXml(msg) fmt.Println("m:", m.StringIndent()) path := "*.*.*.*.*.*" values, err := m.ValuesForPath(path) if err != nil { fmt.Println("err:", err.Error()) return } if values == nil { fmt.Println("path:", path) fmt.Println("No ClaimStatusCodesResult code records.") return } fmt.Println("\nPath:", path) fmt.Println("Number of code records:", len(values)) for n, v := range values { fmt.Printf("\t#%d: %v\n", n, v) } } func partPath6(msg []byte) { fmt.Println("\nmsg:", string(msg)) m, _ := mxj.NewMapXml(msg) fmt.Println("m:", m.StringIndent()) path := "*.*.*.*.*.*.*" values, err := m.ValuesForPath(path) if err != nil { fmt.Println("err:", err.Error()) return } if values == nil { fmt.Println("path:", path) fmt.Println("No ClaimStatusCodesResult code records.") return } fmt.Println("\nPath:", path) fmt.Println("Number of code records:", len(values)) for n, v := range values { fmt.Printf("\t#%d: %v\n", n, v) } } mxj-2.5.5/examples/gonuts3.go000066400000000000000000000016571402172443100160770ustar00rootroot00000000000000// https://groups.google.com/forum/#!topic/golang-nuts/cok6xasvI3w // retrieve 'src' values from 'image' tags package main import ( "fmt" "github.com/clbanning/mxj" ) var xmldata = []byte(` something else `) func main() { fmt.Println("xmldata:", string(xmldata)) // get all image tag values - []interface{} m, merr := mxj.NewMapXml(xmldata) if merr != nil { fmt.Println("merr:", merr.Error()) return } // grab all values for attribute "src" // Note: attributes are prepended with a hyphen, '-'. sources, err := m.ValuesForKey("-src") if err != nil { fmt.Println("err:", err.Error()) return } for _, src := range sources { fmt.Println(src) } } mxj-2.5.5/examples/gonuts4.go000066400000000000000000000017621402172443100160750ustar00rootroot00000000000000// https://groups.google.com/forum/#!topic/golang-nuts/-N9Toa6qlu8 // shows that you can extract attribute values directly from tag/key path. // NOTE: attribute values are encoded by prepending a hyphen, '-'. package main import ( "fmt" "github.com/clbanning/mxj" ) var xmldata = []byte(` `) func main() { fmt.Println("xmldata:", string(xmldata)) m, merr := mxj.NewMapXml(xmldata) if merr != nil { fmt.Println("merr:", merr) return } // Attributes are keys with prepended hyphen, '-'. values, err := m.ValuesForPath("doc.some_tag.geoInfo.country.-name") if err != nil { fmt.Println("err:", err.Error()) } for _, v := range values { fmt.Println("v:", v) } } mxj-2.5.5/examples/gonuts5.go000066400000000000000000000036251402172443100160760ustar00rootroot00000000000000// gonuts5.go - from https://groups.google.com/forum/#!topic/golang-nuts/MWoYY19of3o // problem is to extract entries from by "int name=" package main import ( "fmt" "github.com/clbanning/mxj" ) var xmlData = []byte(` 1 1 2 3 4 5 1 2 3 4 5 `) func main() { // parse XML into a Map m, merr := mxj.NewMapXml(xmlData) if merr != nil { fmt.Println("merr:", merr.Error()) return } // extract the 'list3-1-1-1' node - there'll be just 1? // NOTE: attribute keys are prepended with '-' lstVal, lerr := m.ValuesForPath("*.*.*.*.*", "-name:list3-1-1-1") if lerr != nil { fmt.Println("ierr:", lerr.Error()) return } // assuming just one value returned - create a new Map mv := mxj.Map(lstVal[0].(map[string]interface{})) // extract the 'int' values by 'name' attribute: "-name" // interate over list of 'name' values of interest var names = []string{"field1", "field2", "field3", "field4", "field5"} for _, n := range names { vals, verr := mv.ValuesForKey("int", "-name:"+n) if verr != nil { fmt.Println("verr:", verr.Error(), len(vals)) return } // values for simple elements have key '#text' // NOTE: there can be only one value for key '#text' fmt.Println(n, ":", vals[0].(map[string]interface{})["#text"]) } } mxj-2.5.5/examples/gonuts5a.go000066400000000000000000000036231402172443100162350ustar00rootroot00000000000000// gonuts5.go - from https://groups.google.com/forum/#!topic/golang-nuts/MWoYY19of3o // problem is to extract entries from by "int name=" package main import ( "fmt" "github.com/clbanning/mxj" ) var xmlData = []byte(` 1 1 2 3 4 5 1 2 3 4 5 `) func main() { // parse XML into a Map m, merr := mxj.NewMapXml(xmlData) if merr != nil { fmt.Println("merr:", merr.Error()) return } // extract the 'list3-1-1-1' node - there'll be just 1? // NOTE: attribute keys are prepended with '-' lstVal, lerr := m.ValuesForPath("*.*.*.*.*", "-name:list3-1-1-1") if lerr != nil { fmt.Println("ierr:", lerr.Error()) return } // assuming just one value returned - create a new Map mv := mxj.Map(lstVal[0].(map[string]interface{})) // extract the 'int' values by 'name' attribute: "-name" // interate over list of 'name' values of interest var names = []string{"field1", "field2", "field3", "field4", "field5"} for _, n := range names { vals, verr := mv.ValuesForKey("*", "-name:"+n) if verr != nil { fmt.Println("verr:", verr.Error(), len(vals)) return } // values for simple elements have key '#text' // NOTE: there can be only one value for key '#text' fmt.Println(n, ":", vals[0].(map[string]interface{})["#text"]) } } mxj-2.5.5/examples/gonuts6.go000066400000000000000000000050371402172443100160760ustar00rootroot00000000000000/* https://groups.google.com/forum/#!topic/golang-nuts/EMXHB1nJoBA package main import "fmt" import "encoding/json" func main() { var v struct { DBInstances []struct { Endpoint struct { Address string } } } json.Unmarshal(s, &v) fmt.Println(v.DBInstances[0].Endpoint.Address) } */ package main import "fmt" import "github.com/clbanning/mxj" func main() { m, err := mxj.NewMapJson(s) if err != nil { fmt.Println("err:", err.Error()) } v, err := m.ValuesForKey("Address") // v, err := m.ValuesForPath("DBInstances[0].Endpoint.Address") if err != nil { fmt.Println("err:", err.Error()) } if len(v) > 0 { fmt.Println(v[0].(string)) } else { fmt.Println("No value.") } } var s = []byte(`{ "DBInstances": [ { "PubliclyAccessible": true, "MasterUsername": "postgres", "LicenseModel": "postgresql-license", "VpcSecurityGroups": [ { "Status": "active", "VpcSecurityGroupId": "sg-e72a4282" } ], "InstanceCreateTime": "2014-06-29T03:52:59.268Z", "OptionGroupMemberships": [ { "Status": "in-sync", "OptionGroupName": "default:postgres-9-3" } ], "PendingModifiedValues": {}, "Engine": "postgres", "MultiAZ": true, "LatestRestorableTime": "2014-06-29T12:00:34Z", "DBSecurityGroups": [ { "Status": "active", "DBSecurityGroupName": "production-dbsecuritygroup-q4f0ugxpjck8" } ], "DBParameterGroups": [ { "DBParameterGroupName": "default.postgres9.3", "ParameterApplyStatus": "in-sync" } ], "AutoMinorVersionUpgrade": true, "PreferredBackupWindow": "06:59-07:29", "DBSubnetGroup": { "Subnets": [ { "SubnetStatus": "Active", "SubnetIdentifier": "subnet-34e5d01c", "SubnetAvailabilityZone": { "Name": "us-east-1b", "ProvisionedIopsCapable": false } }, { "SubnetStatus": "Active", "SubnetIdentifier": "subnet-50759d27", "SubnetAvailabilityZone": { "Name": "us-east-1c", "ProvisionedIopsCapable": false } }, { "SubnetStatus": "Active", "SubnetIdentifier": "subnet-450a1f03", "SubnetAvailabilityZone": { "Name": "us-east-1d", "ProvisionedIopsCapable": false } } ], "DBSubnetGroupName": "default", "VpcId": "vpc-acb86cc9", "DBSubnetGroupDescription": "default", "SubnetGroupStatus": "Complete" }, "SecondaryAvailabilityZone": "us-east-1b", "ReadReplicaDBInstanceIdentifiers": [], "AllocatedStorage": 15, "BackupRetentionPeriod": 1, "DBName": "deis", "PreferredMaintenanceWindow": "fri:05:52-fri:06:22", "Endpoint": { "Port": 5432, "Address": "production.cfk8mskkbkeu.us-east-1.rds.amazonaws.com" }, "DBInstanceStatus": "available", "EngineVersion": "9.3.3", "AvailabilityZone": "us-east-1c", "DBInstanceClass": "db.m1.small", "DBInstanceIdentifier": "production" } ] }`) mxj-2.5.5/examples/gonuts9.go000066400000000000000000000024711402172443100161000ustar00rootroot00000000000000// https://groups.google.com/forum/?fromgroups#!topic/golang-nuts/2A6_YRYXCjA package main import ( "fmt" "github.com/clbanning/mxj" ) var data = []byte(` `) func main() { m, err := mxj.NewMapXml(data) if err != nil { fmt.Println("err:", err) } fmt.Println(m.StringIndentNoTypeInfo()) doc, err := m.XmlIndent("", " ") if err != nil { fmt.Println("err:", err) } fmt.Println(string(doc)) val, err := m.ValuesForKey("child1") if err != nil { fmt.Println("err:", err) } fmt.Println("val:", val) mxj.XmlGoEmptyElemSyntax() doc, err = mxj.AnyXmlIndent(val, "", " ", "child1") if err != nil { fmt.Println("err:", err) } fmt.Println(string(doc)) } mxj-2.5.5/examples/goofy_map.go000066400000000000000000000004741402172443100164510ustar00rootroot00000000000000package main import ( "fmt" "github.com/clbanning/mxj" ) func main() { data := map[interface{}]interface{}{ "hello": "out there", 1: "number one", 3.12: "pi", "five": 5, } m, err := mxj.AnyXmlIndent(data,"", " ") if err != nil { fmt.Println(err) return } fmt.Println(string(m)) } mxj-2.5.5/examples/jpath.go000066400000000000000000000125731402172443100156020ustar00rootroot00000000000000// gitissue #28 /* (reference: http://goessner.net/articles/JsonPath/) Let's practice JSONPath expressions by some more examples. We start with a simple JSON structure built after an XML example representing a bookstore (original XML file). { "store": { "book": [ { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 }, { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 }, { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 } ], "bicycle": { "color": "red", "price": 19.95 } } } XPath JSONPath Result /store/book/author $.store.book[*].author the authors of all books in the store //author $..author all authors /store/* $.store.* all things in store, which are some books and a red bicycle. /store//price $.store..price the price of everything in the store. //book[3] $..book[2] the third book //book[last()] $..book[(@.length-1)] $..book[-1:] the last book in order. //book[position()<3] $..book[0,1] $..book[:2] the first two books //book[isbn] $..book[?(@.isbn)] filter all books with isbn number //book[price<10] $..book[?(@.price<10)] filter all books cheapier than 10 //* $..* all Elements in XML document. All members of JSON structure. */ package main import ( "fmt" "github.com/clbanning/mxj" ) var data = []byte(` { "store": { "book": [ { "category": "reference", "author": "Nigel Rees", "title": "Sayings of the Century", "price": 8.95 }, { "category": "fiction", "author": "Evelyn Waugh", "title": "Sword of Honour", "price": 12.99 }, { "category": "fiction", "author": "Herman Melville", "title": "Moby Dick", "isbn": "0-553-21311-3", "price": 8.99 }, { "category": "fiction", "author": "J. R. R. Tolkien", "title": "The Lord of the Rings", "isbn": "0-395-19395-8", "price": 22.99 } ], "bicycle": { "color": "red", "price": 19.95 } } }`) func main() { m, err := mxj.NewMapJson(data) if err != nil { fmt.Println("NewMapJson err:", err) return } // $.store.book[*].author the authors of all books in the store list, err := m.ValuesForPath("store.book.author") if err != nil { fmt.Println("book author err:", err) return } fmt.Println("authors:", list) // $..author all authors list, err = m.ValuesForKey("author") if err != nil { fmt.Println("author err:", err) return } fmt.Println("authors:", list) // $.store.* all things in store, which are some books and a red bicycle. list, err = m.ValuesForKey("store") if err != nil { fmt.Println("store things err:", err) } fmt.Println("store things:", list) // /store//price $.store..price the price of everything in the store. list, err = m.ValuesForKey("price") if err != nil { fmt.Println("price of things err:", err) } fmt.Println("price of things:", list) // $..book[2] the third book v, err := m.ValueForPath("store.book[2]") if err != nil { fmt.Println("price of things err:", err) } fmt.Println("3rd book:", v) // $..book[-1:] the last book in order list, err = m.ValuesForPath("store.book") if err != nil { fmt.Println("list of books err:", err) } if len(list) <= 1 { fmt.Println("last book:", list) } else { fmt.Println("last book:", list[len(list)-1:]) } // $..book[:2] the first two books list, err = m.ValuesForPath("store.book") if err != nil { fmt.Println("list of books err:", err) } if len(list) <= 2 { fmt.Println("1st 2 books:", list) } else { fmt.Println("1st 2 books:", list[:2]) } // $..book[?(@.isbn)] filter all books with isbn number list, err = m.ValuesForPath("store.book", "isbn:*") if err != nil { fmt.Println("list of books err:", err) } fmt.Println("books with isbn:", list) // $..book[?(@.price<10)] filter all books cheapier than 10 list, err = m.ValuesForPath("store.book") if err != nil { fmt.Println("list of books err:", err) } var n int for _, v := range list { if v.(map[string]interface{})["price"].(float64) >= 10.0 { continue } list[n] = v n++ } list = list[:n] fmt.Println("books with price < $10:", list) // $..* all Elements in XML document. All members of JSON structure. // 1st where values are not complex elements list = m.LeafValues() fmt.Println("list of leaf values:", list) // $..* all Elements in XML document. All members of JSON structure. // 2nd every value - even complex elements path := "*" list = make([]interface{}, 0) for { v, _ := m.ValuesForPath(path) if len(v) == 0 { break } list = append(list, v...) path = path + ".*" } fmt.Println("list of all values:", list) } mxj-2.5.5/examples/leafnodes.go000066400000000000000000000036111402172443100164250ustar00rootroot00000000000000// https://groups.google.com/forum/#!topic/golang-nuts/pj0C5IrZk4I package main import ( "fmt" "github.com/clbanning/mxj" ) func main() { j := `{"jsonData":{ "DataReference":[ { "ParameterType":"test", "Applicationtype":[ { "Application1":{ "ApplicationName":"app1", "Param1":{ "Name":"app1.param1" }, "Param2":{ "Name":"app1.param2" } }, "Application2":{ "ApplicationName":"app2", "Param1":{ "Name":"app2.param1" }, "Param2":{ "Name":"app2.param2" } } } ] } ] }}` // unmarshal into a map m, err := mxj.NewMapJson([]byte(j)) if err != nil { fmt.Println("err:", err) return } mxj.LeafUseDotNotation() l := m.LeafNodes() for _, v := range l { fmt.Println("path:", v.Path, "value:", v.Value) } /* Output (sequence not guaranteed): path: jsonData.DataReference.0.ParameterType value: test path: jsonData.DataReference.0.Applicationtype.0.Application1.ApplicationName value: app1 path: jsonData.DataReference.0.Applicationtype.0.Application1.Param1.Name value: app1.param1 path: jsonData.DataReference.0.Applicationtype.0.Application1.Param2.Name value: app1.param2 path: jsonData.DataReference.0.Applicationtype.0.Application2.ApplicationName value: app2 path: jsonData.DataReference.0.Applicationtype.0.Application2.Param1.Name value: app2.param1 path: jsonData.DataReference.0.Applicationtype.0.Application2.Param2.Name value: app2.param2 */ } mxj-2.5.5/examples/metrics_data.zip000066400000000000000000036014561402172443100173370ustar00rootroot00000000000000PK5CDTqAx?Ǿmetrics_data.xmlUT RRux v8& ߟȮXve֞}\SRR=":p3IfLt/*+D#@ >>egH$>?,IU$riy]u]U_O?OQYzyϤy]l6/v,#??9?]'EYuUw}?.|E{*׳Ͷ2=].O>U`\i ?XІ;{QM!ËA?t a%'6͗-׆;%8=j9= өW$ WK$qW~mHY*#ׯﱽ$tTS [/ (sHHӜY91RMKI͛%Jجy t~E ?ǔ~4)QQ=}ņ홼m(k!vrAړ LaqzTLJHqlN|c~iJ_kRnj)A3l;7v{Vn䠿 iCKk9s5dq_Ờ|P qqzX?+jjPiZv:@f0L}+;S6FO+SQܠx Zs4>ΆQM]V|?{gZʨ7Vw/0KGm_¨w|(ZZ||at<15m1t53I٧:7nOks;''6.ob ͦ9 j: 63t ?/gwB μMpA[E唑ah`kڒ~1aF7T;~~P?χ{-oW:%)5s}w|CJ |Zn.' )y=}?;=TuIb?z&w3_]~詡{OE/;]Y1y v/WݟNj[n$V|I͋9z7TtҷZt<;O߽dx?S-TZVA$M|vK%]$>уE6v-]o'V1TY\zgա}Gpl2Ǡ#o+\Ol zyo  mu<P8ӔHc3v⢗g`|@YN *bzlqrye`,3Յ¿kaldU];3P\wa02g[^8ȮZni˔grL)qiw+\Fz8#)Ľz׈完#o2 #-Y.͜A+00ws7G>.en.䀘fH*q9E ,?)~Q[ֿ{L-Ο:w4q"Q5Q1b7Y'ai69NZ#?l(qfqivᡱ8c8̞#!iB[K:8CޤFԐEkrk$\DeKKxypqEdCt/6T}%D̮k:-nJE]߳sg[)݃kkml 9yQlt.;>bjR/D$WG{*:?/8NSp4)ۀKkO@fL&r.=]9LV]l4Y+./G/^.٘|s m|-\zH(.|Ƿ`M4c Imc_C Մr%$1o k4,Q#]r[;(]BI ;ā ew0]cM$O_5'y&qx .+A,X gͤ1rj\;#4ɦA~ЮHchӂԸGe_'\~l/w PԘK f^ gUs5+<xJ:Ww;{r6lHv|܉ "1MMX#mVɫU6\ 놳+ _UlDS8>aw I|h7lxoztgGR$R:u#Eߝh W:JD9K &ztNwc܀Iijg;6mv x~ΫvZR+{ t?B[-ό;TF]uuڻdFށoiL;{qhӖkGHdUDX'41.bl"FG>vG~jaLd bGG/Ch[Q|.p%n'&tÕ ZTуW5V`#^^mҺJ}?>X~ H>9~}5>'J,F]ւZޏ ױ,,ע΃ׇ[ydC#29Dӄ CK>1juXuas~pAmǼ)їnpcS`szgIS¤,@U~X6A~A8O7REMFVDm6x1#O3Jsn6>&"M?CqۣTchX ((ڔz}(fhapM A:[F@HBs*:1pozB :3gtth`T~'1{HA%F-O3 . c+VXOP\MG.#t]JrdEa%peqAd9=a-%Hi5Q|,qVc3tXSogSesSRKG6k_j+-ox{ȹԜAx[CKh]_VMPoF逍6Hߤd\jwN _S.,$ o29n^,pL2 BghNlP#oh?Q?v1٭nw=/Uۤ>#) 6j =D Ks򽈞P`ER6?ne[GLȒmsJڅ鮳]$>ҊhTCqVOU6vPrbF*_N1BcdZ<,i^]L]cЕl%xq29v&+*^/j0$'/j@58'EzXO,"'}*4t;Tͣ+Ace24Se]n9vtï)em*E1qEb?,9l:ՌÃ&4Jݵ9X3le{D0C`*w? IIwzE4_jCc5 DݔjFinD. Gk:."ѭb73!#)84?^QEo)N> +юX؀k.Ὶ z&bDW;,#l}rx2ϒGޑmгr4cv2/N}z/hNڴPN/_Bv,v5,)=1/p*m!'R{:N +[J͘vvu4J62 3_]6Pɽ07(.F1Ɔ UWЬ*7G@K @ IRYU qnh ܪz$U 1NO;R {J1"8}j4 R$BxE /ԯڋ8[Ul҂jB SyQm:6&ܴܲHǍmR 7})ǟP1^:^Nq`AA{o0йcEs&\ЗtԱ#ծA4()tk\^B4ӸJ#z`~,'!xд:ǹdGhtNǕv[MٷЄڽt;s 諅F i} *ukR-5mH3{wxȢsg{$ Rq`*kRUv =ş$ۭPx|I2+ .]@L}Y8ruB`){OeN`b=,j5-qs=❾UYװZ?G 6b?*ݘX-59cFWٹ䵜=ّ1X=AEאVm2g\WuA$k5{_# [ I{f>h]D=-G?4A6?X'XYrwfPs^ě^K-Mw˛@@NKߡBkA_>(@s1< N⏮&-Udip0,2 ?tAV!e<ٖ_&B&pkg*W`Mm'3ZR<.j lgzqwmRoZ^덳b[l@9A.-jgs&_kLl<h3pkVD5ުQ.]R-3=bymjzd/Y &S7AV^6TOux1\yNɹuMpM/}ބ 6y*DJ*;A 3RØ~rFȗ%BoUV qA׻icXq.)5Gan۴OLd1um9ŏdzDlB ,5pbs/V"941b.<[btPz/"uS 9tgd>w],|uV )oƐ$)UJ Rc-1ZrT{ޑ>y_0R-zJ&MGUfKz5EVk: EN\M`tSVeqyEc#Pړ5WZ;.n(Go)tQb$Лt봎p, e|A{50TSv/ୟ g̖͟QUyGӜa6S])c ["=GWy\́ H2}mʈ6͋xAZ%3w'ڹa_Za{1:C~A'xf :=[?rZXO9)k@3֖h ^(pN\+ffa] 皺r.0z"?]:! 3bo1ȲzEy;DzkPaLsއq,6d.@!ͮqgJ+R6XaX$)e24'ACʄ`\s Mk] ȍD9N)Ō26e>,=bj=/nbΈ+W70pF8CNuƴmEh9|K~п=d2n7F4S>y= hҖV9e!]?xT]X׋;&KG;v>,xlqTP3v9)&SV5ڛ r)g\|.&E?ro_8Q #.,H@QWR^?qvݛns3U_L?YMY^OR+.Pff/-1w<(04CX]-)?LLQBu86'i!T\%{' NG2D/^T/YFȔ{\1:9)sx@kgJRpu32:#9d}?M%{9~[9 &yɇU &%.a.[1]cgJ9tE' )8֔Ulr@|zR$wHW lRFYUTk"*R.ѣ/JbIfrшl7)(2R.o@z$R XACktODgA?b8wn63~Sgwh4`d?4 uW su 'RM Aܤ|yPdJyt+C^E4dius + ci0n cMN6ۆ̀g Q6邟jlG.!M*#M԰>֮l=I,1\HuӔ2٨-k1d,%$ p3]pe~)y"ɺ;e^ɆEvϙ}9ի<Oi d7^=YG`^T5]%7+"=SVN[* \ѓL\?}"F̏Cuqѐy-:<+vsY-w܀2%swRU:g$Y #K8}8SgꎅE>)bsV̶@,jʥK4?KYR8_;LmvDX1eY%gF5E:?ɴ U .;#liCWxl.P[KG|sin<#>?;f]p6 żneZwYFL6~$Ԥ~:mv@0k;ѝ7IE[NJ.$LOg1ɖ``Jrc⶛dSVOkbHR/L!&̏y;Kv8Ro#c̈́C  ͆ub*ې]+ô6'$lO)T_ Zֹ ^pGG|DƹlHp9G/2a6Nm1vь[sOߊUaWCdߘյ̛.b-t9e}u?ֱƱ/9,`psqUb{ɮ0>e#(G2oȷTCK $0o:">%HlЕlYm"XCP=\u-i<Ƭzi)sknk/Rǚډ&p{*__QkZ3AK9E PLXWstQW:a2$*j>G®#3V>U%~p9r₀cG*֑4FV&0ASH x~k _g0LB/PtԘF|:gR T NɎUF4PRw٦T҈(bvSX JdQ1AuwdiE;%ƱiR l`S~o$QY2(d"/ @H-s# ªD,<@ADb[$#@ tN )=S6q^#`y%uZ^D⛧:D.=_j 5j&dž޹in'59}#i?IWJAL_$靃jjhK":&a/L-XI?7!W4ozW&/jAV5dzt橰=02H!1؟JI9@!ςݽx*rM|iSD}A-#hB7YZ~}p&>#5.ϓa?eZ}f_ҜBF]zd؜ꨌ6#xBERl@.ڰU)C'%Jg%t~@aݽh0KpBn d ﱣ{'̩0fz}AO%*?}?`,hvn/3\6!I iFNiC8v46,3+V.}g=%= h1 :723K$6⛾a|7S0g~=sWt@7 v2yNg r^YJxG;u;0~ hrafz}bN99 %`{NH+4?lEޞm)[poiUE."]读6µa{pTan ]HFxqAb#[V#x5u<* s7ʸ\Qljx?KȮHu^!se2@JF+m  ϲd4zSԷ%rv]I Ppkg _NYbR-ѝ1Y<9vUy^:߼QCUzNB|]U9mS@bE GC Qnu`oќ0ӳhs@lOE¸x/{.l.} 7 锸\Wi6,oLC ]"Ao#;Vrj̦$C+|kc(զX?CYs;4? 7$!{!{_A1J>TZU>MX-}*hw[ZJg Xg  ee(}w.j jcnR06Ub{E(.40sͿqW0IdqlcNT|Z$sKAq|v:ptZnmo$D*;gڇ)~4)gzSP)1i#ݤuL>׻hPq*=v?MKF(g@mQk O*> $- ЕQ.in]µJq9we4]U0 iv,';|(ϟIPĹa6R*MR=?yL̦: 4E_eg~% {Kq9DY!?4SCo[Q'wXM9akvդr9z',[qtY%>;>zb6g ' } S,ewET~?sjۄ%ar ӧbO:qIpgR}1>$K0 _އÈǣ~_ǵ! O[Lx=GfrDqBCF.Գ,.-c d'c%|9c}m9GLIV̔\Ck{O5 %X?Н `H,A+E@_)X NӒCqw}UE`7B/!5Jԏ1{eru\@Fsge߬'|#j' 9kO@0|}3Ma z\flJ**V`_i*M“! ULnTM`ָ"T1J11lgb6]fDlhWhSa GpY ZEJMV b8@膦Hsj4"a![ݎk;"xǦf͍M%nEXŨrPO]p:mD :e*Wt0wga51MbTGr̖s i]\f*J4\+RlZ4#{l͚t qIl͂eVs`".Lv il(_6ecVM|8XI#+Llx!jE10B"㲚씬^Tq!@ϭ~2n5OR3'2G2Ĝ;x7Ӕ`QIE8)]J^0HTuw˶Jɳ66{jtT{ဎ)Z&%XyC5< p,̉9bhm)7L|1/8q5',bĺ8Ǵ3˄w7,c`.uIq@ ہSGuۣp$$To$M*zⶤ2򷟓XSip8 *q/|rBn(08Pό` gN 3fo"3] 몷k1 (T| y^Bsa `וfaSzt]h٥ Hb[f0/#xK IG).ˋ\z9JJr0*E=&| mԺ!/..C.Us&Պd۬ϋ":Gqx78'(zd@ KNc<$K]XFׯY)♣D"Wo/e(NUE輰HƈU%aLfh/ohsOF@@\0U&7oT^-tsW@K~'rZŭF ijXԿpRq MXZxF?\lW^ɺ?f7_ ~)R fRf4d\ ؤiӱ}8}ʿpSepU$B,[g_6O[^U0^ĢARVg6 S: ={F¸W)rE7|'֠厅rbuM~X8H3 ЉMY_._c |_?aRa:HT|#xç4Nl \ׁeޔ(5zm`kCkw+Fdo,.JIU3c~}Zj Y(i3uudatt ,?!/lT.ĵԉMQQyl]w Q(&4,3STS"UEc6HY@`EGYP51*9%d;~uv.4RK3P\JORR<|`(P;K jY?TC1/hu0O6WzTrh|"%3 +bFIP-< UqfkFx((lU-6 狆޿h "dН8jDw%szYq[}*HsSEuǘC*ثGA K9_"܌5$ tOs 2~x?Ul_O]ut,1e1m*M{.;B9/\p&SSw C'Rم B4Zt> '${&T%@(סӫg>,q!#_=U1MW9u/!$^֑rCng)՚c@zϕ*|HԩmOpSv (.vQ'W VGH2 ~%#4# ߖ5DG# X1w+;B'tQ5%)́dGS>hb`/K*Q HD; N*= ݧl囶r9M)-˿6XdBCv&W'xl#=9H/*?|F./~*cG2T-P@4Z.d,ݿlvjrcHGQ/C u냆=c{ qyt=j#%/lݛ[O2mȡt'OC^G4cQvhNǦLE{iu%y`Z3 petRIvT68mdSB_֭5,),IO'߮.|H> ~p7,Hcˋ@z[):RPF:;\QRp݄b70;EO$L@'}+Z{AX f5\;_v$M^j.nkqї"$ J)"/¶s n/~ N)M<#֭>MҡF9>=E'={72Lͻ=l3`qIiٲg\7t*fjY:Y`*#%&Ƅ9"1#JD(?'3e{f,"N<^EUR?8fK!_f<842n9Y#StnFv9]pwc^診(U:K3[Oq_6U8 5Of!j8O, B2vG6RyFJ ,^ W&հkvˑю+3yR3]i?=]eCϘl'ՕkuNwLx׽A.@ 78!7hN xR|"u@fZ30w'ĆNw]# 9/T?_}`ipZ'$y]2V~@B'ϑnX@;yl:W[i_(܂FBQ⡡6ֲoXcn,eTPG7EG3a)8|`T: Q vÑ+YKq`;Nb:MrDy';TwaGjS>D78I]n&UsO F5׀|=G5QQZɖ}hIu}OO )*+[7P$3Jz,孄ӬMDB{ԉ ]u'Tdn:\/tLpI$fS7h67n$:]ƐLvs(Er?ސ B$SyNZ+sGہn@6I") lNX/kXE{\һSmj'{am./oU WLCl7 V.%EȓШJr4+_6@K J0G5<Z0O`mp)8sAweA# [e^=IhLJVv11h4?}Xs6pGU&:'TUaxGh]u-8( -S7+">sX8)^qB4ְ̑R[0T!\eAw&6Er"xZCWdA.K:XVN!fQE>~ݣ^{m A0"^{zT Np!7$œN]AQt;A#&cB5UEp>P(1..TdZ jgPn&Qth]7, LˁV)tH*WIK{ mE[0``-1-,=]nuڱR6 zzfs'Uѭ_wi7&ړyp 9*ϳlm@&J' G`Ҭm._z*Nа}O+M#"{ԧ$Lhʯv{V) t=X;2doIJyu+|…&}ژ-4Ō `` *).lV%ȝR~ۉ g~h!u'ԏ_M9]*mHArHQݿ|-'n0jP}@iG O꧲JZ˱ҁFFf#ڇ9w{/tc^R`y YjFj)vπz"B\G$=d[|]l1Mm47W44/;%?÷"9⇆mc)~C8KyF{]qu7GHxet)EedCIyk<^N]>hpY!QÆ5&d)(ڡg7S` \'4mpQcV4@Xdc:qǕ#GlUP?Ѡ'6EeRuDMjb*!MC,H2Gӑ4ġm]~T@y$[R@zv;. 2[U?(.5NlM4R']7Ш P&*>qvD=8΀.Vr@`a R#k4a<_|gp&M9)]"tCQID39ӷ;JGKk>B7~}А0XhJ-1 M$t$vDB)],dXVâ("V `/B$ZTuE8gex{--tp4s(ns鑘FD|.ll<0hYB-RH$Bq0.Z~ŐmG}Ť)D{|S >qJZ\mlais uy]_mGuxJ>u@!$x/ %<_=KW A#<fL@ )㱣yf v9I~2XW!:bXw{!{ݥp#"oo+З_G(8\ ؃(45^c6L`mnLد"KECq@ uhӥk &@{]E2BxOƳvHaӓ33躙y2*aBq{6QC Ƥ՗sDmIey3|Yt!B5ę9}~P/gMØZadS"ncZA"/XCLm\m1*Hh_䔳9BSE"%jt}-ϟmAd/RE*p|g !wnB7n_23b񸶴$3].> #m ǚʕ{?Iy_DK g6DTP Z?% %E0h`=om}Lix nh(F0L=9H> E2=!iIh3<;JZ0,(T!pxyQDBbu kpS)>jI4H nE@:pY x{)Ck(vc-;ťC҆mYmnW=RC*a MpAèD&!soVnu^f7Yh+6 C-DOY=D2EdM-W4+{&K)Yb/B4^*:|ZPyu0=YJY[ɖjo],rKD[1h ܢhXq2|x$I*_c1WPQo*] !y#9Q.SW5إp>˥H0fnq%:\XKTTt ]Ӱ3ЖpQ 9bCGr\ejM/m/XR~8'i0wԔݧraX& Tt) 慆#PXXNP[*,Y66s(;t$`+ru*cfrnF~R£rnhiM-a:ǍDɔa۲v?%f=֧ ,ܤF9cdz6 Sd94h&rU)}`}n6C(jQʋ/Eؗ]#GO a.SF\Cꪜ~3*0/eΟE e6nAjBI1jʐhҞA?~! \y +uFpL#Yt|z{<";\T@<9gď&y!OTZ`P|+!fjQՓ8k݈"8@ܒdWwՀUa6 ^۩񲵶޶^q1>H'ת jJ̟E:K). 5WΥ!Pfiԣ6H>[R\`?_3{ */;5L1JY}ғWI bnXpᖌC)z(o߭W)]l`X}6oq]w0A"< l{AAǤʋw{v<UmJKNі/aR~!_.7Djza`PԂJnLt염 pW*'H=`QF+M0nOD4q՟TTsj]{14JF'EY  'uo!TJP knYOx񚜮z=/V /``{N&׳?u]?mTD(Ax@'`!Rlzpbn1H!T$*FϏOTEmr/ T9>YC?XyMWJ&_Nm/g+ֲOp,s\ 9{N;]QY&TI5C~1;f61'UxH^r? 4φ|S9֟KV|*m51ׂҌ# 2>~ԋ){V;RT\T.|:|mV\@먠#<>A@ ֡1H}(*L)?lk?c'28mJR=<PEjB~Kcs_fkpFSPzߙ H+!z  IO)A's}T1yz#Ċ*$w!vŖSq=c1Y$Qp@{*T7_ a^+1Z{ңx4 492 F ||mhOZzBɵƪ|ę(v[b^Ya UJ-q;!d]+?@zwt*Sl*ݽ,ΕsQ$WQb}G!2;"͟rZmݬ g]^D@ =aCi@C H8ݧ}MJC;"Ja$kICL)U_|%-VX_1GX?٫eND*\^-ɞ ޽BMu.x*EG5+P:%Y 4yV(/jqɎ_/cʕ`D~A0՝A_FHChX<5kwt".uQȍ\2nyCW"dK*;wBJdὠ{?2CK"eޫ #'xd>MKлIN(fܑ]~JOD*#R2'$}O8b*ܹ'f2Y?WNTa'&h vE괣](09>V-\.eTXu]J0ʻOB9_8ZST%k tFƾ .Qeҫ,o!_W#8u%ĦWJdbi["Vwu@>Ni*To-] ]\ )n(/̒/yGM[܌YrgJQ`/)xjDGc" ۥ}@ƣ 8J{`vj\Vbwn0]oj?fo<:{Tx %eS9Ti- ?`QR]EG%y@8\T(.[aNO}>ud;@F.\}az^ r,ώ.FvysL{ZWU~/~SS~GdO20B74j dbFMW oc|K'JGy))c<,L. VdQ3bi>.QNg-ڏ۽o F qJκJ}Aãe_Hu z{A zNҸF7O\Շf4V&6 l ض2^^²-0|@8T'u0>ݧO_:ev"?flhqi(`{J|M] ,R լ.Kz<QRiG T>n>&YR>wV`HQ)+\LX.QW yŃRٺ"׸!7nY-ChkJ8A3HD|9I|:h!=x=?2͍Ŏ|d3 I.H}-_vqsϲ)}qhr NP+?. (*U+䩲vEzLn7vP^OWlܔ24|xG O&Ƙdڬ|r6r=M}<7@JS1-0ERgx4`11UP5 zLk8~>ܿ:l ~Gcf3Iٞ6r,E#WB t)*W/'᝜8/ntFx-K yCm4Qp0Icҭq˔oU1 A!k!#ĘmKXbFO4DcļzILf͡fq|Q Y XGlm0@MF*s(͐԰4-GCɷG@y3=2"NR5w >=~cˣylC0Wx8Iy%CJ4І+a4 *K!*Mg,;rAp Ԩ&~뛈K.Mlׇ%rIgLbN}$0]&u[kRe((Q .7).5ٜoA4!]ؑ %]WHf>nY:=aHL&I~%Ni-aX:$5z}cūN /c_hOE,V<U({O}9m@Hu Eq ܵ=jw@R#|KArG6~0rh7C 0ҏ_78м݆hweihОr:/,рšK:( `迆 kʇjˇŠ0DzCII19Ab ۤt 5lg y0ʼ)Ł {5%8EPqDrI6=18#jNWf/mEtֲjC#$J"FJf5$V㞻'tŖjq mn}Hn.D"NhMO47uz4L+w7ԚnPM]U3!2VGbC7')u=:yjGaj6fI;3."0u@ΖX&(V Ҟ M檴1tf[h51 ۆ h0SzF@d_{`y3gܽ`Nwd/s@8wW:>Y/F[dxm _$LE@PxPަ㌠:L{4J<2πCh@ɜ@=<=UFx+%@? D] ʺ)mRhQ?ws5F<"cwpKt@$B&o6P glǭ%! LTW9Eg{VAMqq)IS|8:}tXpfYɔoXv#N99kW\R~ͳ_߳O[OcfE,&u&  _J eey]?Ak1%Tδ $~wMTCF5t+pK$C( RW`T/<*Q{up+|)~BQ~mV`@^坪oM|!E=BWTk7<L_? !X 7i],9!;$S"z{;MB'F|ӥ37;4@E.kn@´5J18MQP5-1<e{D7[7ۅ 變B6O]-znp\R%&soeWQz7=Pi~1OnhUH|8 壿#Nkn ye\vm<Ge3戴`q( [c Z1㗈XP3gQ!l1%$(hW4K-Ц- IPv˳V+MfO풡s aBdAΈUfƾ?zfð{5VAvt2ߎ O@e?I %%-tHjj4gITc}4{}b8At܃MI2EʉY)8t}DD5v~ʔ5TcM۵nilBT_'A?~jأc_zpBڻ%cc%9=,Cs1 ouTTp #QZ01Q0LcP6H$mVb J[91O@1".E>7IƾѺ"وt~pW-Av%#zA6S!ߟY*(eCsi#Hѐ"p3LT#_'(U}g"ZR.%'l#W@ks Rlx~<% Eu t`l0w͒sI؇@hrlǼry~ zӔ qp9P-`Ql%QPy 5LmŮX Լ)4%vDQ}z gf溦GsT^1!0ؗm^)R}ƋV rIy% 9ǔ0,/pJih$ # km7C T8WG4q-WX2ONt1,KOޓŲ'm1!  +٫Zpܥ?|Ey=%IyYRH@MB7</<^M tA9;Q$oAvxCH[=kgzj Z@X~KȒ"7K+i6OX<`a`ZۃzpX:ًKC\?*n;&$IOBr5)ͧ ꡩBR`2o~?u gACQz|M2^,%BIʆXRZ便T|-S7O}K{ь) 5FI7gMPl(٣2<%]&[_q\*2Mpy]"JaCc4-*N s'k?H: $ ?#K95%!. IKF́,Т;&٪"b^Bn863vL)=Ԝ7S봓}1.o "_N\]gވz_jŹV Mr6譴Ou:ًf;U+{LKJ Lā)tjۏRKTS2}lDņ:Sh!o㊗d0V|.aPks=Kft6<㡓2*Ǵ)IZ[6̫%[pV{^ZO(!ךšg}2R-0P+ÉcM7,5qîw @p:p x KoeU-dG;8Bee;/(O%1PQ6ԖlI#;԰@Au?!C}B7Ӷ ^8CR$y9tVr_xdҊت~‚CW:sd}mL.Mc[XbSb<;iƉT]jaY WzUC09_mH*ѿE0$4ˉItٌ%^n)c~-753*np=]H) Y% akڹD::敫H$GkȌGRE Q ^v o>=)2'9nX̼D5»k"BYBl )iR]\;m-sU2)֘ThJnщ2 vsbfBELX/=ܫ47{ֻPºg;_[lA{J]L8ӓ$ 4܌cDI*q0%h"oՁXka؊$!)}L㫚 Y#y5.Z]09U/ȡBm vh L) #O+(Lң=Mrij:5dԖRO/d+)_~]T3W{Jdڼ=#;Ya`JR15nƀ_2=wd{c[8Ѯ;FٙZR4h0f8~YvjfH*OUo3"/ .K!JzwQɣ3˯UW&tMU7$ RWC7R8nmhXv|sBIS,ɮ UHB>&-}Qe{q^?dD¢EE}#RQ]ij>CNHHzš1n.MuGH}p9,RS$5~XI5'qcqoY VkXFR*)pK'кn5|NXW^#ӆ=/fgB6F(I!@۸$LZD@l9n~NJ}b.RT6m /c 4V0`h%],otr-1%6>02LP7(2,}(Du,:(%FuZ񹴌]ϼ{ sַRXxXg `.0$G1xEs 329̖F3.칱]-X`z9n]Gtf0X0LS ih|RW<8P@h jK"1 i3@jg1G'c(OVٝ)92^MY TĔLWVr6[S$9*}y,gK%g;kG Jh(k䂪Pg(m qxd;}ҟ.R-}qU[N q}YmYG'e˒S i=>X)R~44 J/%Q@42/y 5ChT>▲j#9!廪%2i+tY;"N!aE~AޤW;M+2*1V e9)QT[qK<@HVFk;^,x^*e:&'>9. 4࿰R,M 0@EZjL%,~$}[>Xr&C6uZ%J2x`1M(,>yF|zvtJ˱-Wְl ~L& Y@/l?UJD"J9/"G W ͚xcÌ}aĀvzsK32gu'xfA]־Q:1 &.i(x([:~8(sl<”PIO#Q.{U'kQ=Y)]Q@|5RPQB Yx>۵O T ?K.\A~dlԐH2b6\m;npl :$># Tf0xW@"I(Ur=,4, =nּj"˪WHQi9M^Jt#h{|XRE(`Ғs҃6ݚo _ZĹQ> ky5Nx-!.hi>4ͤG(6gb| {Gr9KctYQs=,8 eFrB[8%@1Js2c:?[ĠKbSu巑n0[<*#ӫ&k{i͍Ԗp-LG("gaDM_<4CAJ:I7VLAP8=nk&1Y;J=)MݰZfv#4,LR^}tC1SÀW'dxU9 PHllmSN|C_~Nf1òj5a?T M= $`24}yE蟫5PPv B@5*0v u妴mUpR.<՜&I&[!_<kx`",ăE81Pb~m,XGY@L {jF?9$U!I %?h7`.K輍u rX/|w U_<4D`ү }6+>/>TZ0D[F*ء=K gxR: .8^Vu:T ۨ LpѤHx{ཛ@a~T8|"5Ar `oqbS~$z 1ꯇcZ;<ԥa1)v˚k48 qB/b D"{Py*ڎ7{$}@XφS3gQ!;;cLGr;`gT&&T{z{v1nR'xMF:bVX +$4 c 8I ja F !ps ڍ* ~l ] ¢;S7 ?Lq5#$apj2]7JtW7oz6x䗛Bh3Do7]m}~qwy8%r&# F_fE$ j*t!1˂mm7׷3*:!bEKQw fu{HDD2y_QK}c9۵y <|EOv|ӹ1BzS$CQZ8_N$I(,V|p^ք q_4ߺ싘(%2w$Mʬz}âIx5֥_t&aXٶm6?x,ώ.ulw9}'VVUTT"O8fYdBYvQ%'&ӻVK/pvtmbFPu= yʴ [^@_|>iL;|99ޣyx酼:,UR"N(*e_O@̺hXzc.bUӀ P&32*[;-<YϓӂȎH!I_7 pPi R<4H"S,i#MH!8X= P4t(|4)qat8QP_s9FՓ@b{ n0DCTG$MyDW  TG$1PR{N!fDҺE P`$O+@wmz1vI={`Mu3p-K.wfyRF5"-/UGSx%eWyzl~ yMvh ~8G  ,> 2 LBdє!նԏF ; rJfwoè N{Hbn()#al!NkŊ߿nn;M?E8j< ج[RmA\.W)Oܓb?2v},hel^y8jCU;*[>"ӊ~5rkP$-}uwt$ kMoSPIoY55q|vT|NY]o2 @LdM-{j„&#u( 'LN"!cG1dS`D&B ݯ'ȇ`y Ĩ,_.i.MQvxȃnNK+AHpx>p\n֖5A` ?ϔs'5xr 3@٩ ՏaX%ў7қzGPJ&5dRPP7 !%P6IzނR_H^Z iP4#OxRAbMa.3Kh^y鞞:f̭lZ8$'~NB (f;#+u듦&b^9B:?5hޡ1t@Ң1cL]&9yM9Hp66CxMT99| .s[ PvFv%otPҹ'I!~U qZ3ߙ *X&oͺ#hs5P\ l)iW LD\M  ʫxNGAJlFG2 QΈƒ`d/V}2*s5G9L 1t{|t;|*&r-!^>ik,sb(b3Kʣdl1\ɺzALyUD"';i(._}$4?dE MnuRZԛ8rWX^'TQc.bł,c* -_1L xdR|"^t9\WH)n2E"OڦHn[+ObE\&]\-mÓ,/Iǡ8c Avb9 crI2ow$iCEB.I9)=x\e%/IJv0a'ޙo#_kwoTnHӓ?4bMޏWbK܋bî}SxO8V䜞+'5!8@R~P-mCdcԔÁ/X.R&3@no${˨Y#!ǓpztH(@w}qr"ۇ. Pg6t]vo,x='=$5*.K 8RI'*dDWCRÛ^!C>?ɜLaX%z"xNd{lL2$r\dF6uE.Y* U*x℔t- (*(G9w2:?ș!RܔGIOv"}b])H z͛{ʤ;U1K2tfrB 2_ЮeQޱ󵐲UPP12@i7 X4is!T({OF:z݈[(t7Mj"+f6= !Z}SItn~p aBnV0+f6_0w5$##i0H[$kcѪaH~>H؁y.8&M.cp&A X0U+Nj1sX6?^j]T7[DN> s.xģ=kff"Vc5tUb'Qw ٵF1g_6V$Sc|y&qXjnFԊdq+ ›(]եF멘[(.]hlv+/WsQa[w.&7]ve@P7x8绖ST0 p# IY~J-' k_+@f<:PME,8+eOE PfLRJ!nFsaF(91y0>lv,zG{x 9 /\?+nC$\eYf!r4Xij_vMݮ8GHI/-2R`&9px2PzM ;S #a8.M6ITdϕOpA$ˋO٢2!oE$< GGS8bJ{Bݣ= V [FP.*J_]yD[L]}ΞO/jDYUe '{[7U0(KlIkµ4 N$XBK~z)N&6tE88zLɬO]W T<(ee/Ư=nVT#bF{y*9}X43O ;MOgchً$^b0EyFv[SOJU/`ބb~ 2;`F, e Ȥ̈́]D ۇxb, ªw\;.TKե_lQ%dψ&Kơ??B,<Nt2A6+A)w= x-2*JLsC4N0HM%^ln m1'r(n-= K',^r K"W;LQ>T.9q+Yݏj]#fx'R%(/DZ A1$oxEX (1:K:&+cbУ+fCQ$0^+~:sȨjYRz _Z8]oH[a$[H`/bmX@&Da}~B>S6ru,oωM {T {uS%Nhk^.4YHSN+*aWJl8L,4Uh~*߷( -d5b:r`FX@\Yaօ DF?B6o=alRHy~jPj{HA zXXA+_9;biO:S P5q4wq%3wWj{ˋ̈@BozӀ ˳[P-3Cnş6= &;w>u[]7w:}8SH8w7y-ov  Z}^l654/um 'D=13Aaȑr"5-C Wg(̐úDo8 F ev6a5Z,^RD> ˫ #rEFQkƬvLEs5DqѲN:7zۼ!ZQ['kk$蓛ꍯ>2E>B<۵ӗ glj<;h;fڋ?a6$5Jxcoѻ|AN 8oIxIigbb13 #A=Gy:g d=eD! iy6'*(Xs!،" :GE_V 2OjFz,bv072G0GK34'WyKG}&IbAR}sʂ/#ܖ=p՚7}`#\2pMܡDcQlL4"#ޜS{p_=}/*_T1IO t+&q nxԜ*j' ~$giI{T;x3"Uכtf5 }a/FU))HvN_(b(r{( q8 X8ȵbh("$K^?Q14|@Daha Í K PQ͌DoZPjYf4ocEiL1$ᢺ8~z ☨\F"P1+@XڵO4*j8&Q!ZH hjYjf1cx9(n΋˘!.&dFMY$+'B MFgP@\gD&:TM\*S24~>D4HDIz4Yx6'C un5ƽ sE2)$۝sE?M~x ܵ@ֳiaسYYx*E"ֱ-mL葻Դio#W'! j}HLּ ob&V,dGy8еA;a]朒l oK6Fb",Ú醵)#u;۲vjƓBMoڣik8/Q;4V36&Yrɻ( 3ǵJu(4 FO$"4y:5-5Ǥ (j;9aj3v AoI޵659:3%w <5?}^ QeJkC6M /ڰްDkN 7K2?Kn#}&9Gj9*2҈>`zg5ԵA0}~[uHL.4 q@uކ;T?2Uî#>i.1!J0|3V$*6φ׶ {^RP9KTEcòP-(1S:@MSŮ[ P'H>i΁'[z Ԍ2# sW\ŗyQd@Kz <ePY"~%O:mj=xMZ φlӡ% 6)GHG8Ʋ&yMkNc%μ7V+pX4V2铖AysJnRCj 1LC-? tɴJί[z̡l}ФбêGaSިR5>CTd q =-6v t>"Ɛƃ~{/XI?P0 Mtd{ji lFdd  <RU5E!C"KC8ѼDGwf#78Ns[߅4.pC^#vۍ`P BN;x6Y<~ tbq#fg?Q#M6%y7Vpm!ltêdƹiO?SnOYMUKHvs"LxMܜ.D [S0&W;l^yAmM~$Y'0vI_f<||E.RXG!A)(+~q0\ډBg۽!Tjg22􁔯ik nAKmH*𙳨k֊@e mk5-Mv\0ѱ%eRƍ(nIghvOY}vMmuEd#o'[pr54qѿ>ޥ,ݿ /A?TybĻT1TD ;dlw'J81#LC14֝g,.ȶ[tM+FzqڕTG% 'fٴ_8gz%:[_R w]O*eX n: \=B#:Ƥ@qPfyF~I5`+4۵"J7W xk}hp {szmخ\O {Uy5/dC7x>K7ſ> 5or_$蛾T)͗o#}iF1[|Y;MFU -5~Pu =ڿe`Amqon/O@ <@]ޓ'. T-'nxLbhHN#AEAR=[L_4VgFɖp`ˢVV fxj賈{O(PoGC!֦K,R/{ȿa/YAFI)ߓǚt9rpOȎ}ҷlSwZg-P5veŌ4-A^*i#UVj^z"p=q^yZ=@SizX9]MM)_)dF6TW y|Ŧ?#AU"Uy' ٳ|al&b`]YTkw8QFGpËuE6#P,~Mުhl|\5ňa+Ǚ`y?O+S/ D[Lif|+Ryjb3(>n'&&n]f3уC 솞9;isq^E%[:|yISRS҆^=`RΛB} >/%mzX&BS?{+&uA",.rWy&EB4t?_eWD2~^(dX+=nx9!Z'ͽ>|n]t ǝNNQCw=7fk/o[0JS@C=wk!'h?o 9OrVÁyN,>@,&լnP8lxBHCFb'K$> #K[S."϶NgǖM*oCXtW "NpƊnTxW}{J 7Iz5/C^i*dE `R dr :]~,3 &YC7 6/,RT^r9Cz_S\&YEo R4QRtk4^V t0.ίx-d ّ: uBde>&Ln: ))C&bICʏ&T?am6^0^TdtuEqgk,84*t [IcX6C ~$jhh.#]tx ᥭ ;6k'guuΣzHTKqfAk4PaN!sv2@EÔaxȶFQZmyK pZF ɆI"3MGRk,iBXե @G~ H z e`Q Ӽ\FT S*t_krCnTaſnVKaUCGӪzbBF-๢;lgɼabp:eUWQyVQ\ շz?ɵӰ`_K!'@~K^EldV6'yrKs+Bb5'91Ql+0{0JѸx|gܡP'@^VW=5 }F#6F3T1e n4^N0T@Lg.tyZ(>^Ab3e$lIa-􅩉 eUxI#*Tmq9 =T#ԯWWA_LMftF:_0(;މԚ7pQ:o-ctZ7 ם}ZO0‰7@ӴΫ(u[H)|aޜ s,X%6Wu?vj6ϩWōeUYYKD7zgZ/$J]xɭFps=ٺۢ-mj)0;C~gN- xMj_:gn>$L:]P:ܩ?t\{o8țzBԺgӄٺdؒ\X>R6i-rˣZ_C|!D%K+k(5tnݗ_H[Q6jO(Cx$ּnuE(;r[!X.^`|Cu8^d;|?ӤV9(_MVibZ^?(/=3@!>4&K!)ѧD"vIpCiG^y*FQ m q~8D]ӨevG:"1@\A'^G3iU}j3Kz^,&N%[.̓0A=]MU\=2);I "lngmzAGᄂr'EM:d\ѕ>8`j+y q7:̓ޓ6FUY-eh*[%-+y*֜ŭW<_o0=`xrA_" 7lh."f8q~6]jx TbO uy,CKd%>!<dM5q(ǎ3Da.znÑAEטr¼;lktDD~{x=xpd~UEs'%9+de}0R~.4:YǓυƄ?Gk4\(bESoinE7ۃ'[m2u2J"bAn`Ā-S"#ْdR43ة=:e $wvīU>X!Ũd4/_J|R ]NS{ ^y^QZ*Ѐ^tv̀, 3' *p{63N\k)™&/Sta0s'@S]H_NPL@Hf0!R=pz"fozX ՚E]f8Cvg]"EeP1R?H(tKV[v`vᅮ@:WB! R +@j :NH|C h4 :ywx(B)? 'b R|@ pH@RUŧ<ؾPZ3V90e^?DsGƹ\_ m6CgG3eA fV \'=Q%$j/UFEG]C8𙘩 mJj#@V :Y9j4UN@g!ՂËfNC2յ䢶> 9>^.) ϫ^'wUtx^t}ʆF>|tev zw}BD*{߇* !钫}-?;.?Vj%2 gQ P+*VV7!!@ wTHʫ|ͣ46< $*"05|7Y|bheZc*?. XUboc 0]|W9&_k 9~z< 6aC P=ܲǏex8/8mLD5!l+2L܇:UFT6WC$0y Fu(pjf0Cɕhj= ƼY余q|6`)KdL 8c$P$ߧݧ Ht,+>$b9\h<1"4..|ղZ2d#HG>iں!?8\,eE%970~FE,qsLJFdI!YJ1"qs)]%YX2&4$F3o>Ŏq= ի2̒tjP28*;5tAI@0K \MsKtD_aQO.8I/rRb(xӔQs{_ғӳ\Nq`Lj(Yn@}H[ #)xPWhlzK B`I_op .KZ> Ң|gPȊgh]Q.[-TuΒYuLrugRo^Gȋ4Q./{;2%Y/1j=8Q(^聽T0 G]ݘ Fca?Qi|"U [ sIJ-e̫wUL;GVDP@x&6>5r :rS\IDl3K!PBQ1I1 }_ao(#w)-:`#g@ƘUIu#AR'^Oo7FFy5y V \w,oW^?/淿)EKdEDzqjyǻ9gѠmZϗXimAg>(.:0F6$SUKGcm)]HnaP7J6(ڀGN˅&<ܝ XrI(R֪Y@fhNCuEQө0?af۱ -T1ʥ 72[=1P?( 6IE4TӦxo_Fc@4l-r2=)uNK߾b֘dAdH:U_/ ˵W c|.(*RlQ :珿j&IWJJ<Ɂ˯\O1N,uBRzm%BA;R e"&JҔhןMtY fz{Bҙwp& sT^װ-/MA2S_6F<N6X8MV}IǷƼVK /ITISA:=/Mi*iQe,JMn}ή/Tьx Q,;kȥK*r"͟t%%+B`l)-jfX%!y RFiuy<v;ǰJ1?ouʟ`J5]xR~ ˥<ݱp/myCՎWTKP&E44A-}3G {Z ,2N XEׂIԄWM\·K\9lXL0aAA=< 2 KXZHLdz 5ɞ 'ًU6{ӌ.dK 4 共rm7E UjgcB Y{t.P;n|^!"K)6V aW51N0x(9/\&`ZDn'"~pA:ԕۼЮM5 fkZ:.IrŃraʅ˯pA#;Jǹ:;e+w0g*ijS~u)d-t F-ܛ40eeZh_FNPph$I?=> h*K=P. aI$KN2b25sk\(@|xMӳr7P9yJN%1CX9"E#x![Qy(POxOR?'s^c+ ָtE߳N)C\i~$-2) ci`]<#!v &:{WϤJna@V_=c $&H#ck i Nd![/C%;/+HɻmYULtaZI3܊T=P,~k+db']br+Pv _ WW_5U+]MNP./>|] B .nn[ܬAnҰGNVRG@_G/a⬤*;F稼?Bu*Ū#H7 "DLHiV*33_S3V&cqxTf>3-ѰD#Z0b5K}zJvOƷ5 _#7A6v`8t_[  ſfBNBNC=oV\%4* |DRSn>:rp]wGne+3CV=%2XV삁XPEV'%v<,?|gdW#-_!ج}+lG"?~/~T{Jݷzz/`X.gx6?{́1sYgx;80 HkS F :1'zT4s' ;+t2C+YAeo od!gª}ق0bM:ˀpXyLSSFW#YlO+_s6i76_xf#kQ`*0¤0f a\LwN(_N9<~il>B6*o`5piN~u{sF󋒔CbQ@X5ۃJ}+x>QʌO3CDxhi%mp˼8 q[G )Fw et,-g&}8=:'Q)kyԗT.(0t`vİ0.WKIy>^x(^Q)P@^cZ!j GG59;d []<[US^} Q٬&?7,gp:zi$FYy]My>ү?aj Ia{x#ͲۤCc:NylT0[fA;uࠊ,0i!,B[LWvcg3 j?K\j',(팫G'8 ?pL!Җ<B`dPg r3@l2dEiPeWD "2KVl\g 3M֥8sQ܂j,mmD!gN`aPhaO/I)h_>)1}};m)Us O4Q5tJdsV >RBngH4 *AV {nA"و.8Y ܐ Dr[&4%W0Pu H^_; 5Q<zVuF ;oAk/2f2Px5X.8H\YnA7ý %TVgtӔFX-OW\O緜+$'<ώxE#PZ@--(= C5u ? E|JW8-eT3`@w{GFg![-ZEC/Z@ qE:fxXMixؓlfь/]/l'@a>Wнi{ç1N Hq".:!:W4/80ԚZċ:BWld^]I#V}xn[PF :`,y"wP$q?tHiqc ի,撮B"tUPI'ǚSE pIJAT%j̺)޵E-Bӓx@*.0$ ƪϾ 6W5y"]Ձ u+XLpP\% Mc1CA[yдS@5vJOBv4^+ U]|g 7(?)P iTm֡d#缮8γJn=B"i..HMBY|"2GH6y %=P/&·]$MzC2ܝQVab5ydX&"Sڢu~ Oⷅp0ھW zI*LM#Eqͤc*JRcQzbS(q{dJxAVVEd,S4L89+;3edJEٶ#J($z2'DЇ"Q X"ޞfsј;'jC,>~Ba[ӑzG|ˆMehP|| n}REUiXzܡ@Ьd aӸb]>$M Ljg0q7%)LAFA.V%4uָGY6Bs_| 6dݝ@Ł1,E}d nvPt_(q[ 4# 3}55B=X6<rEDOqJw -oz~ Sp4Vp8z1NI`Q}ٝ17M7M)}iG78AX] w 3Ԅnp8(ڱ2?FsN@kM75V !g4cC!&,^ v]L+S'ʪ?-yT#l.8#G#%){WgD77ö!>=,G/!wtTY5&A(Z7'03"*]%@ /Y>˼H[>:JAFsYih*4ĩMy*Y_B>zA2-JyiitJ/9# L_WEn#:Rb08p0=p;biW]~EMOz'edb%,< foZ=u&4a[Uމ2f'I4zEx$+:3؜ ,DOK'xp O*Xזt n%w_)4j+ r,:, xF`3~Fh4wzmx p%D l΀(@>v9!>k̄/0@\'-''V}B-lyu)hf _{(Eo뚌> bcʬ9 &ah[*h~>*樂YNZ¾E^m%&YO>/(P){n3XFU9m ސyha8۱;3\A Fسs7Zf;cm/ YxQ׿}*#@{{΀UUr:%3\. ZONk>~0jf"eMU'R'mGΟJCOu=={?6g?6?˲[\ KC0$cam +m활]@n^ԉ9JhPPyBC@'c!)2c~?(^!z} }g/ Ek t[%0 (nH5'&V1:UdY-=bR}1` Rvd؋*[='[<7*SDaӷNP(UkOD7b#&o603^·͒prTX, M0X6fw#v6}dVo?H ^۽~U/7|:IU~&)"* O&9.\!#2XR_DW:AVoqgCmp COTiꇰՋ/\b.lxIY; yx#H"R$XY74);EBkK}oi*/mvy{iyܔԨ|L$+,~(F"eSsy%U[]Ib  -i}? 2'!ۛ-ė|lB( >)߉LNRq-(vy[Y*[7.r! Kɇ2@3F"lfjA/I^+;71QP8˂TB.IV@ k9ѩ/ *-#Poe" ]5<3 |Z)? rՃ> ÅtcE2h}&6{(K~%tK(3FV4)V]ݯ 2sQ ?&-p,F>l_z&\npA9OJ{>ZDVX.1NEu 4\7 -%5gE(6$ŢFE Kk %ۇM >:!턞!9}601\~".LoW.FIpZޯ& Nyz+@o[xfkĒ!ҁER6voQ1T-f \Qz4~awW h[xhҶ]#_Ǻbl4'kc>0Q΀u$ej _ P h0OoEf)ȿ|o_'ih}f"Ob?,=c@ltvsR=#xZ#(\*jl/kM7+ eyUI S\;qLؐ"( _~om\gT1}u f^"M0 VrqW8 -x\ =,8@HCWoTmB#Z@JE[eexSs:㤢 ] ^I{/@ &I>߈¼7 uˎ,^G}ϟJz52|#?K=MrHr%) t\3M`Ub\ӾV8U IsRfOp Jg.x5ұ@Q> zV*jfI榒|͋x‹ܬby,!1tJTha͊`Uruum"q|!e>T?֤Iq6}U|*5t 'ƪC>]7vaRzxn"$s G| IߋW Ƈ`eeTg\)$>]~'CS `RE>]#&s{x={{0OKxisu4$O?XB]df=lFh[Àu6rf9h{.دTHHo(f&.q+NIIW5C'k\Ѯ>"cˈOYBDKd i뜇  (ț}FuBf0$,ZVP|0$Ƃ`(8zr+qh|f_LL:pK0Zt&8EN'DF> k<6A oR W`|*Y>C@aX)0S]-,pحO%W,Ռ)nnUEH~tYt8/|;=4b?q$E?iVw팵Q%Het/ " PJP *kaz*IgƧ{6[\8A15avn!qte=Ꙝ3R8icn4WT%CZ^ee&UZ@- u$yJb^sMb rL[Ц<g;+5%QՒ'يky*+DrKҿm̪J[Ep*IH~nbp:sEۋ;/#`TSHƷA^e]ZG\vrf[J= 'KW\{"NԶCFZW%.o}Mtwf$H{aVjMa\-:/_=:**BXXrǦ9OeۿfY. LvHN{Xu 6Ǿ}:Q&t޸ڼqٸ&/S1mrN;˱QRgp-7H.qAR[\;%WԼ#nP+L޳$jʦ[*`K7fOj)QR: {_! 8šh^kgڗU![6ݟf}3A۩iu$bJ}Չ?RJd[hYhe.uAQ_ et K(a}5Rуt^\~]QnFGUK^6EMk[24u0_ CȐG&*p=OLFgtze [# B0k?) pvNpCZSiۀ:s N-U^٥D:nm FWFl]Z!}Dk$J_>22~YeVeyYZ%:3}s*7 8OՃu|YU,5յnG}۱;CYX5>NN^xs-U4yLzy@}=xb%,/2|5yl\<]n:] 2v)=;*m'EI iiz[zhksuӸvn+,SN$({02D"?uIJIN#z;&5\IS=/.7  4~_Wi:6?.Ɲlc ENcuS7xu{\Q#vн~1 <ߒ[X VhI>T)0P1|@Qq<=ْg: "k^hr]ڽ{_)gai{wi  u{@ƫ0Y=K> cT3j삭װzDŐ=4<8> }>(9GԗR8S+6z*ISrV3u84^ *c>ͅN*Bәm9hW}%9=%m3-;4yNuXPRJ.s i)&S@K%s4(CܧN)` ͣygtEZ$JWgd@Z&Y_˵ *ޥ4jxTT˝e,,7%rvA&)G[5і쨤\-X 0<@Ħgի+su{Q7Zj$fu"Z?KC[<*-/ڞep$[{ېR#nE' ~R=km+/cyɀO8yJ{g8B+xw d{Cz:R<#X@EY;յK_ZWP; SEJ+bOKG;ވQ=1!B"X%W Bhu4h[ -ąTr}(8J^\URkɪR>J?W\:ݚ疴]:V^..+y#űI[Bn>LP} @~,ILeT1Dgڧ2]^Z03"O2l5)O!5(?$vxיр?%.7 1r5>ٮy)=0.m#| _XU`145K4lΚ&+Yce'V??/twmwnww{(|8NRsy.ݚ]0^23l=/%i6[V$g*Ic/g+ 9{-NU<2c]B6Ƚ|b'Ia b`ZjSasJ& D(h<7͆iP:p\XŔ?p@_>1xQuI:l^@ԟ h/QI^~Qp$,UDs[~/2ePǘ/%׹{Gjÿvw?\ ɇ_9y0%|/aUo V [)gC`?p?Ⓘ[ƟW扂?+YɣxV~nOOPd˾!黑3ld:.SÂQvrcڝE%=. (Cz3&Ԭ*FUZ&2س= k ,؃MtZzT==QxVE>CiH˻΋˔<+%~*\9 eA||ڪ462Bm0-52 ۋq'bt,!NBpng,uI;`bN^ n`@TˍnDYU>]c؊Pw--nVr3"qn@c< DO{V4> H,U/6PaV6ĥ *E0@xw.Ŀ >Z,ZV5ن!=fPJaJPG@LL  +x/kIoMmi I:m]n|9I'{'77ĿFG_5 hͰ"~>?w|Ie{E96` OC}3kAw'"X:Kkȷbjv:<~܎n'byƙ n]o"(͉f/I<~)*7 ,eWdB2J.B}~b݈KA1K)3΢}7g\m6u4GU&# {peQ9A.d7w&aϓM$*5cg:GБvx! ;Cx!sV8O2Fʡ:~ݦInŲW-'ub\+`h_;XN$S6N6zIS& =+;$A]g:J3AV6@%.W] }Q[=-_rhlo|!خjiLg؃_  _ @PsaZbBk'?7iSy4]r.-L4_f%}r\4_hOtZ]"(xA5򪝋/8ϾZ[(#OOIer&1]%s*6:L,#n(MӷPK}Wq \aܩbg:0 ]Z:>'004pKY 2AU?2loSXH׎/vThEUU]ۗQŠоN'Tݱ lC(8<x<)/j$K;%_iu zQToR3f)I,eL,*zad UT[uZmB Qg38l PKP|?g6\}_%UX1C+p(:Op0NxIp9ܹHLR 2sC^v9DWeV%ii*n, лtP|_*˼MR־`+IlS˳"-?!@Еg,cJHX%PH^֎Wugr(^+7=? WrA~XԥJx1³?x37qS5Wtl" moDϊ$2  J V\j*)%txIזZ8. `Zʰ#ks\I&,IcgvJQi -œ: `fgAЭK)ws9x#:N\r{gGaFvx}ʪ"gZ$.“03YZ *bY}t']Xz4YʍmD("?qG_W_EuVʿL246o/L(lK7/6|^jnAW zDx.a~1 z,Glue_qA! jտ8GmPxҴ2ͣhY~bV T5UXgoE:ktǣϑE}, ys~ gvįs_jc1s.>%};m0l76qRp 5WA3Ϛ.clp ?zO;ݍqކH \3PgHޑߘ[ >LIR?k0iբTUX T;§Tq%wv[ݥzY}t &6\wJUe1y t_p^\+~'knnNC^_)C ]\}K5»[%ϕp&ʼZ҂dr]u2u-̈2}Z_|ۯXhX5} Զ&нUYcC15ITm4al2T[_fdOjwlX TrZvQZV/OWI[B :9(8Aj$m?_8Lˏ?s0C;Iõw)YU]:;ڤ7|I9)O~ڽs8IF[yoJEqǹziw.99*oiyt.YX, )'Dl xWzV^[jܳ*a[h!dkHN' ]E+2(?#+$?E[Eg}*=+CXw.^qrV٠n7L9Frɕg+wm9 <ٸ DytW2D.ou1+qB`* yk[Uܵ;,/Č8?u } ԬGTVnw紣~)T"+(%M1aܴFzHXSDa[-$* 8(qdm&ϻ\r\\kӉ;zmn 3O]7]C=A;0ňDtm I{r/K߈(ͭ %c/J!sxy#I\euؠel5ݰ*Ys9l!/nr= m}_N?aÕv-;ӋcG'uY rkJԙ[dҢf9Mv|L$2c" vۜW0{LmT':i*4So%y<^б &{Puɾ䶻g K:k@n&g[Ix:,wQr=%Н*Q6/B,Wd؞ͿCؕNU*[ߊx' Л9c,XT+eՑ+UCviY9NYTDΫUQu sƝ|}p-uYAod]S<ʳk:C^ zS'yʲCYq9x 5ӗN3Vڎ(fSS3̢âhL (*rs8Z^\;a3Cv?_$( :>k8i5KHd FoUԸL9d_a:ZzkP7&ܓt$TśA_;;kpA{Yu|?5 GϯHJhl}%l 9ݰf$ub#P&gBCrP>w#xI#{4D a؅iir+@QK Lε2TN{ p"p{Qkxo:pRU9q=Duqk4yIU|"cb4IVR/Z2ol$_b)8uAhHPXϢMx@gxt-*!a{ڭB*0FG0!bE( H#C}^uuW )^E:ensR=􎳾tNO⥰-nI>eʽ` mՀ9/^Iw)/2eu#;. 'ߙNWi؍6ddUԖ~QgwP<\N%1=/z29!oh䧍g8uCq_Vú,˳M^ߜg$[yP_! |wyމӡWb%,Z+5yw+_iV;U7xͳ/ #{1lUhgy.wWUk=bߎHD_y#OTF[-/)3Xf~B`gMro%ΰeŴ0$%8w֓0<͋(,{JV6Xd KůaF4 nJ VoKj)g~istVb;gȸ7e_l[>O\5衺'wI]z)yG ˶>}HS|cOkTN篎"{'KAZJ|ˠlB5f :ir/ƾw>< nd.U"6+5y2VZA PZ٥r'*!w']/`b&^"+vw8vlH ʑUnz'G|I}eW`eoAfbhl6rP#;wIhb()xwZ}tڝJmD}M`sš.`#G$v'٤O_W;MqdG|6Sv/-s}L耄֤xHC3Gb!Ȕ?tV2XJ͚OM$~=; tn2g C\wiS[һ&͘osOQ<Ԕ%4[ lbC[(e2&{6CۯQIP?E ǀFv~&eK9Hަ&wW=PЕ9hXĺz$ye"h!HڎDwDsۡ@jB?;)V|ifxY |aٿX߷H8 -%쳬$/Vbݗ=,'xtOiN'WeMH8g~yw䘓#nQG*'tP]65G[Qb 'kZ]C0PaW9a[US\RFlŮȪ=/,F%jx_v7w!gRm}\gD(a1.$J:2 ٞC`7yB+aԕnXd\niSy蹐~94Lzyɕ>&1vMC绫AZY'/ur D-<[fp/WEn>6^!5ᷭsQ@B<}Pau7a=GyO:)Gb-3@`p5WmvpY о n8daO]<>~#36\xۏ \]ґO44RL3թ?ؖLI\S7YAXI6W:uZ)7:Q42}kԩIuiu_k}ӑʪ}sy$/.oqH2@&  UG8lM[JƏO&nʾ0Z7 (MIb2ȲxT|PvyAȏbdrayҗNg}P=kk:W/U֚pH6B:#݉fU\ۗb%+ݨu% PYS}ko&I{Eq[N=PJR!? f_!>dI*m0* s7H 6}; CMqt$\/x%a^U ۈ}}i{[;b^Z(KĬ=Atk_RMN'a4aDݕ>v2(!/pY;Y_XBym/ެH$3x\8ȕT2;@q]8ЎEف30@aI&6^)#ץ(=]Fgv6g[S( ڠ̊<yۚ?4TSZ:]!OPNULB UDS%{{g}5N_ m/Ea^@]uyCtButNIekvFJȷ* dd*",Z:I+h@)2giܟFLqOX3ʊ̜F=r5>p]g&9'4{{0{St%򂗩>-A^}6la,-^c0qW[LD]%cI=3sk'C0Č3{;ZΦ1b 1ӗ|uUSssV05t2Q;-#L2)+S W?`'GU*RJ½-^"l)F| <%Y|o琾 x-[zV4huG nFz,U~3SU)}{B'1| g!464}R4Vrz\BA)ҺS(->W,+<"hg ~&}Vq_DxvǑo:dG˔$OI ():FQ 1{뒻ztk. s'-NzGբ/Ba=;ÇsG଻v}s^d|7%ό}x)s̒aKLDⷑg1xMi"#6![9#k%8˳rZoe4a2l9Ⱥ*rU"Nl+0) |ֻْ+` e=D<705?V1β"Nk(Z-(ArT FoM׀m#qe9Y'`27\:/1Q1QQj eRV]W~{3tT& 4 yRyY̋ ƒ8^]^Z[6En0Tnd3Yod;fE-5}/P?e->woNA!߿̃߶ɚ.S#5I0*f!P0;C+WJt(Гvj'R\oMog겑{@'Ͼ)ڷ1J gDCgLn>Bug . u9r;5'-&sx("b֮‡xRK:`JP^ T<DGӭ@t8{#PA-H*oW}՗yGp43#\AGwIAm|I1۪Xȕ"Q!j^:ժ'H^H}H^)/Y ͛W)c*_:x9'.-͙R1 aS/ZYw>O<3mCd uV4umڹii8Κ=R lyU 2"Rgz6V(A =pQBV]>JҽzYAovP@}x]g2 9$X_v g>=FޘR籈mIȔ8ВR |^=ah'ke+^nBʷVeTK]j)\ortX|W^jE}u4ܫd/0"/Qݙ#!A !ކM@M^}(ʎx'1OԫX;?M^`OI^E{b j@yl.:6C^*_$YrJtK`"ћiwZ"?hΧB(ݦa A$w{ TͩծR<Es4370jfW,/f٬/I^s1鞥Nmۣ밪'tRI~ĜT̜l1іwUTd t螫'btzKd<~V7 _  !yÐmGi:olH`ܢ`2F{-p 5Ĕw J#Ȭ`T*uӏ:mq_9È+/&i!»Hub3 q>,Ny!Z'!6`=ۑ>t}ס"P=YΤC:g=z4y:c3s`59uTq_:(4YPɾn5@V.{b(}_/KvesĽ Ce`V(,:֣rZ&No"УN/N//gGZzz뉻:^UhT""h'eXY,ͪuWw UKeԐ?6)+, P^ANK7(h!l]Te~y2'cC{آ?( 蜉ߺGX`v&Z!n kUXB T ޖ2X 3͑t 5Cu P޾3T\4܎R/jC wP4'-#XpJ܃l7%ٓ`ʒC)ޱzhPXQ;2_`%Lw876wp+ju?>.)ҟÉCpya+v"nc:kejgID|iݻMZ$^C'#z@nZEP]dw4FíozhBU9T]x ECuߪ|$x"5o ŷzFRo}m0-jǴAIlf9t#Ip̚㯑H`fyT󪻍똮yht!GAjCJ؂6dH䍷+6AG99FAGbtǯsܗHZϿb1,Afp5XA}Gol aWD^M HZmt"{N469,f$,&Ggl˝$utYW;("hZAʻ0 PZt;Xj)]o$:}X[.we},t`;W1[IV9)`+|"RJb a9]`4coZu)qKp N ňtN;a(tUrFE -?? NR<7A`9|La{Z:IfduS  eevDRH;{ƳF!Z.+ZM^6=XEN+e((޼>uV`5ET͛Wϫ%IYr!DPy~1&o]gن<[6lz !P2> #ZyHhzk#Py({f3SPSK+>~VC>$?D%fI$Oƒm0ok`ewen̓N $0 <<)ṣr_~h]t]f]Fk0YkkguQb~2݂ l=\0$W{9L]2ы.N7* o/"\n󢔾}gE*mћySK]phGy͗:zk*CF:^Iv6[^ Xp1ͅ m1`Xjc˦j&>/z^ZkJTUsn(I&sTcp<\bKHm逝#,|I)o{:ޫL*?qvz!jrɛEꂞV _Ǻt⟳wcPaLg*E[)P݀Y<^QJVnM/.?MCǭsU2A&'ͯIg &srv_q[:M }qn9j`NcO]Zgn"BK#t +M5*,dΣ"MGF6]$QV9n[Ç3egg혻ҷhtf%dRs]8ä2o]K_d;·̷U*z5˥Xk4Y0Si; 1\I?r#O t~DUFMן95}:Ed1v̯cm[;bR1pSTFd8y5O<[yy9vZSP?(Rm~pO۱] \տa0_r.w@ŧIuڝRXcЗFتt5Cee\'WV}vvIJ {Bq~Z?.)YaJx+O#ޚ|Mb3gy]CUR wNMXNz A{ P?p+C؇ {Ϣ1QZ-BYڗ|@ٮkHQ,4#]BBY2;]<r/Tq)'|#ee*0EȊmZ2ICBK{lqhpZ!ir@7u<~z Ɗ_+~`%7DOt WCzug_Jta*EMv "@BVu|_$oTOyQ;ƺ_mPdzM]Y,v4]vD^sG*cd푫22#婚HGw\hƀSO;P7ױ<3$ dM[L_?t/tuX1oW“ѽk/4v6UA!iJg^*U-Z>Q֍{3=QMo\)_G"٨'-7DӬœ"u8:?-aS!!7s^j~yB2'p Dhmc䞼1^ FB|E5Q(ˈZYnC8l*Ӯa_n$JJ_f A-{٣uK{F3}nD}K<޺qsI;ԁIՙzu,) 8V?NRFYXK}[2ޑg\gsV<>@(DX' 7 hG>`g@QSDi/'EU'۩գ/', 6"R_ibvķ$]:f]eQ-y&͗,Sz(,GhR߂ &.no@{e4 ՔYv*Mu'>(NDi&בH8P׿P ݽDpXԭnQD^o&w[a[ ޚRk2o# E>zaXo|Crޔ\#yT([Ko6H}i#,SmEVL[:L;Ӣn(f3% <^+;r`L li{?= ܹ~Zc&>(VQ;BZ(c ws D7L޴ -1zKs$s&\&d^#no kKujM7WhodLawy\V κJVQ*Ѹ\|qn9dg `y!"9D"{3 xyT0SoBW:4e0G{lܞBe BpU\of]~6\f|&AggnZaQ60:p_&] DõXz`D-c^GR]ViQAYZ@H†saVW?OY+ZjkQڽfr* #z]AUW,&нo\׷>+Y@G',eTAQc+Y_w.E(|w\dX^Iv[wbb4$98Ȓ4<h,abEi#?? a y ]gݤYZΝ4f{(= ^6>BG",f0GIB׼bCË2zo0mAeV2B5g͂o cqR"NށzP8cvL-./APKy4<.㣲.cpr~[X3f. (Qt9-vd|o*_1+.3(1O(zt^\~]+]4O ri cWib;=tFG@x7]OF98ojX鲨L^dʸkILPnVcţ5V\]2d}QӨu/Ȍm0?-u4ՉQ'ÅUK7q>G%*eY&A!4 ȍ*yhe APmAַ(Zz">ҳ`^Y>!9#-HdWW'aP>n4nui C` [~geg!R8'MBZ6&X=|dU+3,Q̺>nUp@Z`'#i0+.^iu&޴g]RHSPIXSJxEV{H|w[12SӼJYw;Q5]"7: r8l"u}׷T'BQ{jl-t\S"/&wZ; }лǃ́-#f5mzG;_D'NA ;VETA /׼PFdkɢ8+' 1 PvKR_w}Y+lsT,a'Njv6ṿdc-@C`MB##?݁:4ҁ 04XIiHNn ֿYW)_%6|\6 *֤rd׆j&x¥m2pLÃ]m9BQ6`*W$! edt<5/_7,MGvơ /smLg  txjD0 3м,aR/'uvߣv ^`o 5B;ӱ}5P"2ZR럵ہWSNYgDێL]]<åImuE3ar['{Fi4{.&Y U Nj܁j;ϠdY)ɼUs9 ľ̽\3 oaQp>V!e~6ȥ,,1W\BIDF \v$-K*ۇuUղF/b|] Xi J3b L٭v\qDzy'`̉vKO27#I`q|h:nj#ol0֘ tf**U]{ֳ:"2 OZmOU6\.N# @ @ JFU&mW7u{L>.keqʋdX9:ZImM:w@^5-ݮ^~eDnFZemiqUkH~!*(wNj.Ż!y{Z$g q'W;23ډgt(H}qR/Nmmd:A#tTM ONVdnT$#tNk{!gxvY߸G$Mz[" ܥr9'Ƀ. q%&R2p KȘާ')Y &s2]y)66|1<[ ns7Żs^ 2̥0@iJԷŇ~ fDm *іM ;o[2K}o$kly`"'ٶ*Olg<#XzR|#EJy_r/ۿQZ zwuG&kptòY`6M"Vgw3a!Yd,Hɲ x'07hD4J*Mbg<iiݫ ܋$忻&͗wV{lw( ZuU@Xb3f-y{WAro6l;J@mgtFPUD׀F@FH \8VWʌ\y%B[D02߱ U'i}'Y_Ĉe$AiW&ܺ^ 3V8!$i^Qj 4_{WZs̴t 03:yZ.0@}~C{4Ҿ}LCwaQ1$f}{ErK|'*W!pz$Kʄ`/Zzj :Atvtu dBG]`RdCe?5"uBB*b a<5S\0FzS-c16?Ż鱄;\:Qύ#{QmfNf.pnn!s%mij"|0>,q,+ѭ_|֤WG=:/6̸1њ :h;5L}L@2 I2:vKx Ђ>W}.Esƍv>L30 )Kg5K+.vw$-cƖKa]%.m&HJnߔi>ߗy>|7ht)pc>)!3,*mK1w31*h1)YDud|N2*^C?+qB]QUt:1?BQ寸B:q"\)wyli,.[W/0-./JV򱘈J-;2*WQ*vZ$eR(:$0KV9pe(Fos}$F]R. ف`p;QU[ƦD7֨&+yj-r">tīTKzHo{4u=D[(} q;*jT-[JQ@Y,2y(O^yQthWU\^ӁB0 0y7"#TgޱH].BoB%hf@:^~ LR>S^ld%i0E&н\o/up`q%`]4э8s'G?! Η͊ԕ̊ӡ{C&puG\sG;`|)q) L7U`:zCC. *Go 7ENZ,N͕)#lBsfjY^_} JWbp Z)s8?lEYyi-wԕ5TX}P 7 7ohD]Ј$-Cp*eEojJVXc2w@9&! SARJd̏qz2WYiO<4n`ƶZP^wK2zʼlqxtQmhpAC1VlCڬ(Tt}}E %A ԯA`#.v"A.xBqqhu\!K˖~ ܤ|{ɷ,WBϣ5߰YjƓ<&?n@ޤ!@hrs./6Ʋ M3`D%5 Pb5KV/&yI<$qlx&pHh{K($VFENU:HMdCٮv d>,^|i*zjgI('IҾwՄU<5> WʽP~ {+x ɽv {+^Ax BWȽw {_uD+D\R#L+oBIdnRv !Z]nYI^F]v.-@JKT^tA =Og#ZhcXS]'Vx6Tw"R4(TPR*w] C} H;uۥZ%ADZYR_b tV}" ݛܤ_?1M6b1I^Wto2y%fLU<%=sB)j)VJCJ&(qa!͸(2%AF\me/JG %PL~W˔ǓQm6odWU"~Ii&IhG^-i1J2Z;;c1{dȀX] KI/9V ]Wt7T[KVU^yMR (V:[64h75TǡuuL*BX؉M~Q{?g96V䐻Ji}d=9 Yr`(*׹ƂJ?|#$Kl΋NvARFO12x#;0F<|VxG  a~T !9AAI#EZ'#Ax~I@~ٵBH1*9߷yԫLPnVf9wz E g9J,ul#QċlEi;!R сPFh5:@gtH+LRA tU+C$\0%/>N0:SifSꍦqU}a"Ft<$P/ViE+I 4/EGf5c O"4mܢ9Gg68CnpP3! Ag78CB tp3{ѝkC9|bV׋F804( roeG'v@o~CVzZ0^P%}3OBھ AoeO_BmŨ=-i o omv̀ڐі9G ˝a2z\\[ݩN<68UOd%v3zI@ܶmqĜSxC[ou&:0AWYi4~_C3WT0 ]:wYP!;U n ;  gޣtBP5J5ũGFx07a@~O xFO B5HTiW|e/dݘYLJa' *Kό1 "SOH"i!C|cHQbb}ڣ5h勆Pdk@א,n6"^7!R3"5 XԖu3l|ILƒPu~UA]ުxē쳙+Ny݌@EG*XnEa^ 6K8OJO,͕.%S@|bl*s&}?rzut)ZEQs0û}E( ʪoyFԯVKVSl o`I)Y%r-CnHW%duIVsX$o"oau3j~)˄B1cii"r9R4juV7yn6q= Ryk/71CBœ-=ۄyκQG)/"Rz'$$$ag@?3.$, ;j&fl&fr&Agf&!gr&!gx&gx&fp&Agr&g|&ff&03AF=`3U}uu!}}ԧ뒔0gfToXWP3*Nb,I.S<"h @޵!@ 6wmѵXDLa»\5#6N.Gzz,m)[pgu,Sx7?6YJQ_eJ?:,Va5J+8}޻i.{y;%73>Gje*k&eof n^}yg|̣dRfTf1+u^lqKkgηb/,e+idIUVac):ь:@L{5 ងh_X?S<36 i0 `+4XA Vx` `a+1Xٷ!f7X)?t*.C/iDQQ]!LR@j^ ߭M:k7LZFs| tJPԝ48E%ĉC'XV#(PިLOt!DqH (jD$./D_x(Ҵlk[YEbr7ーxw@VlNR͵}h E*wj T D d)Gld+yfk-$dU9U#':s6")}V3dˌCAtE~YA)b%d@ L*WABF F%lց&pQJBp+ɭ$JBX+ $JB@+F%*QwCQҲJX13e/"[E=Y1dHB8X20Bγ㗇觼 E̳%/Z yqR\£BؗEYGl~s~{ YV0AU==*r•ZĂw˯-lY1@e(IJMU>IZ~[j4KJEV(/]ddΙp!@$ 矢:3CԮƩ!pZ[S;M+ {ї-TSщ*r/_%ѹMHޢD:[2TW=PKs3#1ʖ|w}u-x;w?זDL|ͣ4ÔigF9 D,`:]X_~Krg*P/5TT6 ʌb6? ? A[Sy+\?%'I*D fyyW}q _TqRG4?b^Gh,#E!@_@}"E/BrnI:ٹ0҃eNY#EYJ<;jILJ&l+u:t[m˽G&AQM[:}g};po6,@+vjE_x$+CNJG@|XjS/`L0!e-}`&Ο+zzϮ#\y#O!vReCR ?!Re o-C rw.E*^]&`dɚ4=+?5IqP(u,U1E!\mЈwx(TZnBXu]9㯥7QrP"5Jl^XD%3l8ҽN({s:#섐:vv)le!׋1$b[to~t'? za@ÀA=̝1I/;"-o.޾af!XyW2 ʸz慊l$<*l>C:IX57P%*V_IQ"(yꁁz|(:TcS?4c2~=w] 4Hza7|^93_[/mqm*˒lE)yI2QpGesLSTkx9/^t z>ҏsA8}Ѿr׫ײsLӦyLvϛ(b'rCë[|yʼurմPz1!kK2pea^Ҳs[&u}7و(aGk eiZ;[BXG 9C*m; 7" *کgOUr$'ZB \Y&|jr΍qHZJ\ J)PN ;%=$N  a@D?dţ` _<=#s4UڗΕnoPЬP~zs ^p݃  y0ir/5!WX\aC@gf(́Zv- T‡&ckހvh'{ü>/+RꡝKl2OY<9XeF(>ˌ"(;8֦V~t}Tl? %g8Ѓ;`\C?`wa;*HV mh(q(HIfm *?qǢ 4AvSvvo*0IgZHB֦)d:{<ZաqrvP=>WajflFgPL;oĨ3U楕4<[Xj_IX!eZL7_f.+(Mwt <}!f":ւx3H2rUi>vK1]q(W/Oe'DLY&ze^B^pø*H[4_fPJ=|ybk_k% ux<51-+ :aa-1B0 .wu@p~'Q9~w! O;A]rEa0 ]@w A']@w> wTD8"ت#Z+T_ەn/s vkri [MԷ@kiZ3?k%N2,LZFZgSأ 2pyry\mqѽ3`q)>zJ"~,Im ҘlJr3Qe D1f+Ruc{{P˥"OQXN [}xEnUwfCkfyE^aFgn=H5W]xr=f<H%pC `yUW/<,QJT!_ WO8 %كfB=e ٓmɡT#f\%۫,s2V;T 5ިwm)kvaoւ͓_ü]Тl`aޮ> W*Ef=waR#δ?5ڏZU݇S?D na?xC(YԽ4ֿͦ]!7i,a5 +qI TDb'9P܍DSBܾƭ< q|w a8)=ީ Puy8n*0WhS:,sT}H0EǫŽu3O wAqδ.!#)|EϚT}]CD fָi6A^>w~IY[D|{,HE2x,nx)J*_y?[bOI'>4BtAj7uprViiFu\= %+JYu tHx,nˣ|5+KW,Tq"*\:Sݮ'`e4K{Ux7wr+L[h ZJMa<{5IH1O]켾 IOȒI@'.CR'a#˴7Q iYBC՚?]";G18v@PM1i:ٰg.E7bo b5l!Zh1HM?FP{}?"P#~W)XsQ= ")ݥ^ѓit&C&4.b鼂]%K4>en7{BH6^ c#fO*vbu\,4fd /oFǜr}@ b| i3l{ O.2v43ȔQZk" M hG MFM|4G)flh!FM 1 B&I\QvȢ(XFB49OyTŀS}0.o+Iޚ<'/\ѯsuUVN)/oC, f* oN6L:̥--k.yˑ(bR|ЉTR&S 7bq(:jիB_U&zv1|a2C,p aAoA:bQ!=խ}%jV-kGuX"<%&S]YBk:0I;@ZߠxJ|b<\4#4DDJ'=O Ewahq |p|𘧼-fl3@>4N `ls W֡*Dϣ/ I?HԥjJ-(VݩsJS)uPiz9T6^&-"5Ľ !ZcFA$3،bQ@bnQPx?f/ $ox&@AzLg&I1k“K0q3Ubj"Bj6}4.똞Vxβh^2}M2Vgzȶ cHSc3*#sw=N ,"SXg(a"ىCbh[ &+^GZ'7KG")s^ 4m:S֑"CSZh@g|`&}̀& ڝ gI}[,Y*Ye<}gP I;jC-s)/m !Ã:1[{2٧l,$RZa2z\\[q%xd) 5 _7Ǹ3n>y]Lý^Qz7~rH ⻵C]ޥWx>rز[sC>992;U+5Y\MPJrUIDۂa׌РjL"yl t%)!J~'}wY4 ꑐ#7_?ve/+($t8ŇLiaBJxVg#uAC*9(H:1Hm?I֮<,99s\³8gyBshy'OF;<xPxD\R (,\?,#w@1m53|`m·OLOfzl\W5 /`ӆ̰;8>ZwH>+-Պ Cv:`0}WYbilBA]vc*pF?چX>CW B`߳]k! #L'ْwsGhu6^']AWZuVfئ*5M;sRE$;HnJœagSE:"}iCs{CT$]yhʙ^mI}VlÄ'_I@4ayq .5>KV@۲eUDMO12⋚&ú)<-eڝ}!DurX(լڐ3rc"Z滑ɳ-SRy=nw>uuⓞ)Uށ?J5fKpЄӁ'o ҄nB((hG<M>KPelm*}R EkTptFa#ɆoۡUqd 뼘 &A'PѿǓM3iYDԷ\TqRC-Z\7 ^$|ny*LT վf@k{]Q|X(~>\#i0@;w)#6NOc98QV>3T,O18Mn[ m vk ]`m + ,y /y7ebVHڙ%?f 0ք ۊ7X1 T"v9[p+>@}/Оέ?8~5W^W''ylijT+UA?"~/T1e;y^iPeO}.&cox&?<{|aö6V'y~㋥ﳾڨ+^~ڝA6_kO e{h {h}hKnY-4쮜Pd->biy2 TcI;䉺$p7Psww} 80u1 1O+t#)E5͓=7'>oLCig)[h)>k8 `^Պﹺ_^)mb^A 38~d q\oEo+nlE&YwvO~ {NP~3Γ Z}d#:ә14c@jƀҌwoĩ 3@eg&7WCuIoJ>uSbyp6c[coa;%#LK_璙Et\J"MIvN" .V5\u)a/D!NLĐbάճʣw~~>_ן ;@mٙr\%] weEYģ7YoL (fAؚ%q3P7@m>|j1oS۩:Ɉ/M3ᰳ( }H$0φ$k/"z͊PynI!VX χ$KԀ/ş':*Ɇ.'#L2S9ˈ# Ue>&hPگrb%[29Ulӛ4TZ"-8߮dt X_L`R%*w0UCQ~;cz`q](x.仾;&XI2<6?顐zNG V"# hDtN"{sfmBQ}nyVPt)' Ew* fhF&=:.pF@8z5@3zM\~DG%Q($sOpSWLCU4UY+1E$ PNk@.1C>ҥddLeV?m`\qiFr3U}aOߣ*׭ ߯?lLmKY[ ~1r"W/+{+< C.^ {t<ҲY*(;C)R<{:&cvMh!!ZVȾ߽A`&"K۱&HF7dqs14튤E-ztzoE%-8Ao S -M*R OC8|e8Cpc_ q2)E8Nfggj@?fPq;)G|O%>}v/i)gw~%/w P z=xk9D8„pq3~>Qg&t^D ${IO_ٜc,s+po]EVY'9TvK' 0=戄fD4%D u u uuR&?#nROBeQMưodn5#[cy=VxLՏ0@: :e_s0du} HzԮ Gc{T9i3Y\p.YP{ZrFfJD᳢j;Y0ŧS*q{S7< 1՝164FU'뷾'tֳMo}N5:]mziNe]ԤG^~{UA6q16CW@Y^4k1~;iC[4wTpk\82nȌRi4ų/X/813H#/^Wdu!Hz8QUY`FrТ!0[Lx,Z~r>}]Cz7B׋a% 1̑Ow?>9OjHa%ÇLƣ7HD/EUI`"6?J) t4ݑ(;צ'"i(TCߙifXHyEpw[ٮ[S}NpEk N$ v5]"a4 @;t}GQ#_NԾ"o]WٷD}@doX7IKӑ{NGbt]q Mg#u] ~nܚ8ι*k,fUJC^i_L9YbFQ̸Xs׭hB- 7r-*>TAĤ\ћ΂P6ΣP$W,EjiHOw:!ӝh$#w>Y[5kQko!ojH4ѣw6DZZBhc'u{Θi{f8ڝ sh 4LlAhd ӿ]/Hx"jq `7ƼwË$Nȑ1տGSm\U$T̗2Tn/˔ݦ,? ??G&:B|9P!̭NRYe|[]$/YS;>.L3 `_M:IbʣEl}L[*i,+}.47U(/eɝ5T}v "]IV o3ϫHʔ^z72ݢ}r,E*:d&&h/*Ǿ<֍ ݚWb#EW*oHR9bf\-|Iof,)yϔ7۹NJ yfH@7X|߮.kr y;3K'S|}Al )x"@aٚ15m ggybPԇGW_ ʗ0 AJDŽ*/È<꓅? qYf/|-[;T{ѺϹY[h5X"cz{?I@]uu Lq?I^RjM7ί1Nh5 ̛PDo#YzA!xwhv5:cHWE=qO*kY7y4@ Vw Doz  }z -jyRؓ_ṃdÌ1df$yu^lX)5M\we"w+h%D1$K62)*FP(!u2AZ !H͢ F )j 0F B)g Fj7snAL oU'ZU%9q'h8,;d]'@.|f9#g@2sANѼ0n&r>1`pf}5@m!ٯϼhPO,EU<ɶIV^lhy#դ}\F@k|O JZ} ˷!Nh_:X!ϬXf"Q<=Mj4r5ST G NUQ0{8HeŊv8zx2 q/&}ƃ? ])F!2h9]~s=Edh//hU6ZTWd.w^ JsBC!.dLkUyaK "fu /8m_@LRVEm;֌ 񯄘q($A.7 FyBȷ|8RZ.肀]h ntA}!h0]p ntA.7 FP]p BltA.6 Z!A7 F`]v BmtA.7 FP]l mtF ]ټ@6 FotA.6 FotA.A F\B0S+)_}-J9m # /ԀRF w[StDf@uID3P@כѺ5?s\S%(x+AKI";I X enPvDg!-qpI2h Dv9h4iy9H7F^"Fw Ck֐q ! Լ!@>`@;S-hG"΂`eh֖LƂ>,-K.*q@bιøH rnm˒p:b$'40oEANs{I}LRfׁ} #[D',Hn{n~G/ێEDc],w;2ʾYwdLߕȨjq0%٘?*G~1V0y1Θ`-ZB k ҽoM(%Fn %sfd\˹uC0cOx,R~u>Dc\-d-09mi mS@ۦMA6vL2\j#k3\e¹xG>ͷ2,Lt'QU,8^ye$/!b\U}$φNQ&EqUa9zlVy֪ $c#?NI]?M/ $&(/b+uӗyrަ= B6VQ+rn#dOy2m(AmI;==UK3.c7ϋ1}0sy]=  wU6tk)Q8lh'dLʜy,u`0Ft.Sx1[uPСeċIPhz!0>^mzL/w0^y\ n`z*p'&=mdE"l16X (0C^a{=;ECsvs\,%ﰯL>ʢ[k^NkkKeqʋܸ=@$-#(-3D$ [3n λfС$|t!|ܛj kiᎯ IJX|;(c[8e%8b2+D_/8'Qi9>KE,~XsJc_<*y=D#5Kz\BT4Y)7.lUvdZzIr5TJHGi$7E^m<Z)ѳ0As*a™0x7L7a܄AAM5al4 m3"!}p~g&ԂSQY_i0g@Bc Ѿ>JiZys 9]WeUhY_e>ZAj^ݰ9 qjU~Qpn$@U?DjQ_مczmV?NBcM%b=mPΓU?[!@SͷUJn>$_EQ7y_iV}zQꝑ_A`ά"gV@{Ċѓ*֟ uY E kwoC5ޅΞЀB?=GÛ*h'Q#֩CsoxŰʻZ{,xrVloU .ϧ;'vM2d؂or5է,[~Gww. %TLR(cQ7@^N],&ռEٶ;ukY&=s! !NJ!$..W@U6\L>@ sNSD*Vz5ԳD켼IoK]/fy&dgh DX0:j gB芬{wݽAC߼f *sZJQF%J<^A7FxG$ԓWZ Oq4AUo~Rp6{o"-~hF N[NioQT,aCiu6_ܛÖAW \D5N왫]|ك.9\g>e䋲Sq]~S"<.\S-(siVxv@O /KSϻQ@#UZߣ0hH]"WQ$^6a}^Cl\Fg&zě#J}Y2/T!`jgQ˛窽Hd(s7P`ރqeur䩂h=B69.#xKOIh%GD[@RY=k%^JoG#qG!:#DPA`#D  8BtGNi!:#D'sH"iG!cmUg7?ܑ6O,/YG/dllOd¡r30nse^}@o竅n r'*_)/Fӛۿ6o4MJqyS4oIY>Jۗv -3K:kg4հ|ˣ㔊(](iyIE%/b> po+ 0e@RvqxoYޠt_  S-03W~vu2sDtsDL#7dAcCՃoΆ-*O+/q+KOR}*D'OO}Y6FHîq~MۧgQ[0(]e)W-G!(fVcVih^d Mvamrvu|{Y :^*nm_'uן `mK<@ED%vvu\ gafr.{l IQiH1'0v$Vmp'zRQΕJЉ0̰.%0߲ d20:yfAֻP%ȈIX;Xs=*(ὭD{ܱtA'b!B :5OYQt'O<ͨʍC\h{N6N(킏<+9gSoI{S6a5N·=k]LE.F@3 tO^ @KFp#i!C QGh@35"QC3.y `QS l3gcB ݐi` YX(:P ;qf6R9Bm["0S{)r ڽ{8]]I(/>h޷Ŋ GJǞ- A!J=gl9|[9fr%9yp$C 0]km߱@Jte5Aaƨ/: Yr1=soCB==z&ILBL완$35 5=kn-BEE#pD0Ǭ;\­45&wތP`$t8uqo[̨p0 pִ7OfI)Z։sPTK97?nq"(um&)0$cT"xV ֵANϪ#qKh \K8YP 9,V~yD@:ai61i=|FCpmWC0;9;=Nq%qͣs3yDF Ng)OZ&x-sC]7ћ~e//5XW/~!Ǐ4g`>z-hQ*u־ &[ n^Σϥ*%d k+f_8QVKLL[ZJ i:?ݩ0zS"|,*<**P&:^h&, )ǻ;!PGڸD,RZDBg`tQx[Fw8LhQKԀDy\$% 蝧@I GR5x$]K"^CaN)BY-.EsXO_A=3R4L %[E(ǼH3^ZΠv/Izs'L%by`2k$RZu e=an(x1N|^Q"\ܿno"$[9E@{?N*<J_#L5'z ({B7з hl h\y4u &YZ؉UQT,\eVzBK?g{;fww-]Su_Ȓx:Aw͡QhmBՏ,}d%}w8y6__Q>"Z3R4/Dk_8U+x+Nf |L gLi'DdδNT/v\8l5z>038[Pd"j 1Sw|fZ=_]7=NYJfJl&VT69Hv1S<|l](vZ`^` UۡIXE]xkn NڝBڍٿct@8Ob'=I⦡ wfgvA[$u'N;JgIRLk44,\%jXݿl旸X?%`(ޒYt(k ^髪&R<(i_Q5EYv~x΁C"QU ͎7./EzXVW_*jM3.~'[3tk.aU X[,ϣ745WϺ"ۢQ$YttE DHPq"G[,UMpLV_M{5BYh#17i$I`7'(*q~L/SnƘ0 ?񒟲_|90"۾y>Za!VsU* džu qx+.h?@! ҟGG:!,R9E*Q R;׮<-yD+b}Uɶ܉Pu`QZb}0jQ>zprR\SCapF7L}[ý3IM!āÏw\/drahȁCIv, l+rp;} si~zY؉?Pk:{O$͌ԓ?ϴ~򻩚Y2)nJƝ Sz;9zؒr=c?i>~K(*1Bgn?c@hǝ u7 h"6t( [gE9S_Ws+v6g+إ#@z7cC;ZIf6ep,+ !xЋ0c 7"J=eʆ(q-Ʌg2Ux,?E&87fKqXヰsRqDZ i8ۭs ͏'1?$j~H0a @B k?nf\2Nde+v-6˝ʝeB>w9Rl+FIe?#goӂ<7~F__-->K%p~O.(!boh?;([ LU?|LK# .1{Lss׊sNݠ w}WjQ$5^_|_s7V:U!R81K-N;nZJ}f7}+](oĬNeNU?ӟLuDnЌIn۳ZC$D#\8Õ=N"?0GpOCb3,iڝ0FmylpcH~AJ<ܯiAZMy:Se/"D%y}QU&_݉tytGn/(day+\y\ݗ%@5"MX3EP3EP3I`T)BpԅGdgggggQb]|+$ğh[h[A3r[[وZykG⧕y^7vcկD&apK GKUމMئz&Z?k=еN?@ ܎`8=keA,e&u,?602˻ƖN Oprnukx9{Q ~?p#D"]Iv%J>'vO =ufE@tWwД%uΣn ;pFM"""2E7E̕P]ywZ VC6ds`r7}C!#++7& 8yT0wnhe9{{?nYڜ~v91~NmMml.~V,I]7J}8ynY<Ƥ&vRxjӻy tYU6)$H@6❘Mp(0MJ>M`2^x;/siX&DB: ud}Iy@a";Ɖ1х;?8P51<:wE1nܯ۽vH0CES⼳?Q=60*rTL1391wf̐3vFL,h0CX6 fqԝX11s: Pܯtļ Թ臲L툛;VE({(dBhiw3Igf{`/)xA{hK.2L9;q4BtmXᇑP q([6Q?s8#~ߠe~|E(- %N* %Ns4e'ӭET׽z I5eix?O%Zx ĀWD0 qavȈĮnr잙!5ȮA]]CyQx?ػSEyJJZT5N2<}v#/㥾뮺$uEQVWI9O%Pv{y\9Bk5 |{nN>V /{ ' T#bWHmQs6@79'_ҧx82zk eSxQ=ԓ=(^XJ`Z84\HCnr_t la&+\U$¬@a W2A>G}nmc?g|dGPBTd-`U u^J&%V3M]ſ!mf?#$uK , tpCQ[FF'D"E91-X-]FB_c mUʖG:Ʌjc2kDNcuHvX2 $2,zX&aw!O2#G<]]h$#FX 3Ʒ|%7ݖGÑ&-zhFP"Bu`(%ɴkbT1^ԭaLEb bg!%G? ,zCtkY 7uDglλ>ҳ t[$m+G$x ]%b)$0`iIV\/~G!SKx?_L_ 273EA_̤9*~6f,샯"PH0 CM9:)vLLd%1+J2VD~*M5 j39JT&SM2zxWr(nU(9;^iXؠ~j"(CMupa0̑ u-Y1˒f mrU3Zqk8'o?Eu{ %8Fw"1.^G[a^=5] ې &rkTESfkʻ-UdJDRd?ZQg6&ekHUN$Cp2*-Kzt͖d8 Oǁq/ԓҀ1MgA3k}_/%dk`)k$-m]vvO՟<6LwJ2|]݉*Z=/]8iS Wք+k•uIǷIC{XuSPWvEqm E ?70{ 5kYۇjvP<&vKKۍq;&s%k<#WU@ӓ2)Nv,3oAh64vKvW%%Ί([șɐ6xxCox݁0Vp,+p:=ҿ=sxw,+KDSBFc RmTF-p9u+ocbJ՛/t  ;h+nf8Snj!uZq;!$H@\+0ǝbz" &g۪~O'<ϡS@q^7 WnAB,pDetO ӂjR/|w1. 9C7pǼTТ E*fzXmeRĕ@>NvFèu D9oDAWIUP6p_`Çg_V$lsYl1+βWL߮X1;bp%g%p'X*5qYѓ[ݔsuڔqnylS^FQ1.S֍j@©\Et Y@@Èxui @B:g0wX@;Iq}6azcdk4(hw˟}x(jTE [hSo=aaؑSC9q)kkJYsŸ ZS2@ YnѴ΢%?:FEBZ!?ƭϧ]yl/#ߙߣ\E˷K3wjE8AQ:N#穮 jN90ՈbVOPjD BtV5/ 4w0|^#)N fYd?(iaduC $#u0-]٦s NQJDR(AYB9#ℍWz sqx1aE>y.2n{ |tIu &8L] \ p'& GicJ'ɤ 0*wo_b|'K:Bb*J {q@#&ٷ%ؾ+ta2bb{/cFYlYՠW]k{aRnH'~ށ8r˸pפtCC lB @&IjsY@ Ol_wv=t;˓ ;{ίyV%e2H,R8&~|8d{Et1̧Hڣra}\2GQ{~輞;`<<zb} ]汁`A0pvAs~$&J5Lln֩2v|[}?8Q%1FWw#+V`{'+rҢLi UTM~j U߶|1h9j-L\-Ox_feGvۿb'IfX ,N' `Z.UIm=szO4.|IB1ڇi᪨BeS3Og$dv ]t7>@Z[P8]% ҲjFPk;#Pl#a ~a2 9bn3d0l@l˯OTSjXI&߱,/\ ]@gHnHn<\TK۞3i `mkړ/N?E)=P4nRl Eܬ΅:_wP%_~֔ cT %_1qǭ e N M#؀G3 cT! w#2!G˥gv|r >E/n;U?ڟ*?q _T|WJnK X$M yUZ0F~xʽa<_'Q/gEVEG @iRVJkE7<2K=}AX)QJ YV%&MӳAIplAq8nr/NhVpp nVzgz> "SH 4P;lQ3!" 5eTgTF#:-.Fwr#hR X#9߅!H} !\Յv+C{nb k̬ (bfP'3aYXI,;jWd8ސgCOmTӇ!tR.}yp3TAItD!-b>@xJ[bcg7&td /"?"M7ިVQ0s^%*I)24M cAxE/r0{P˨|bDh#qQ(ZBNbHV"Yq ` 9[EDm *U;ڪGZe3,("RumnK-AJחYIMr^fsRP\Ϣgb0e e (]Q4(ț)7sǩ@Gnx1ud!w^C,a N^=WKQs8xdc}ɍ}$3) Ȍ}-T^B}׳> Z*Pq#˝x=Yn ?vCҾ"[B81]nm;]^zrn瑀(>\[!"iݺ±?#j쟛ԑH,&7$ﳜH 8󈵊pcPx`Co3~fAp˷g+Yſn!j%(H͎T´ۨ*ͩhwWQ)T4B YOΕ~ 0^?fyd旳fLw֑>fmyTy/TɁ1ӈ Ä!vF2dY+&"s暠!Z b44*hot$.ʴ@MeҺ3W Ub=q!LoJF>Do cPfE"V,up4eVd{(z_  #fӠ~uNܵ?ߌ EL_$s%?y:FD#IGkbtqO4rFJw?9(J]ޗk?j|v5O$K',ks:WjL=Rݻ(tԾb2^Qvn|&ώ5p64)hRkRnR=;l;86+ũVmoM{7?׽(oXΪ nXYі.4{E#:NUuDAoo$k!0@.ST&=0O`ûʴi6u#W4Hm8ŗ\h{ ^=\ %ӷ4Lrf^mU1=h]=tA#L#gOHxD#;0#h=s9 ?F#ɍh$>4\H',.jRf{zfgxg"z X9sakd{欈9m"IwnjLZi|0ŏ?^'.[t^Nz9 gr55iUM0M5Z]En&YB-Mm m%XLWc0vB$N|Q&Z4] wf1vuK=Ic%8j>D ؟ "\z @OR4˃flZ7N ~*Is;vSjFp3k8=9b(NP%` Van#rq} 5Y{ʿM@ѿ z6mߎ)68f9v}Axo#x#j_X}Ϙr3q%儜2 T +-w@Pun .`(_x ./$tJ[ڟ쯭bn}M@l9׈V9KDhpz/Xs_Op4)2Jih+v;x9Yg6 h,6aIV2,y]E/.u" ]F[=<Zd2^*3Μ'x6qG=oL țq? 7p?b $P$9!iI̔$3%)LdfJ)L$fJ$4S" ͔HhD3%ϔHhD͔HfDrsLfJ$8S"ΔHxfJ$3SYڈC3P0.r]Nnp5=Ҍ܈:ˋ:-^feÁnR(J!1FpFpFr-tF#;lHΠAl\m xO̽<#T$N̐{y^ Hmgq0|Bڏ^hfUI;31Pj#Y9p# 5*T~ڷwq{Y;81t#KF,y8%#K"FČ, Y26:WZ ɹLf&鑩Y7,Y j5ޔb7JETʷMSPkLgwk>7J}BYƩ3 J{.#n;2xvvZ"J+I|$J+In$J+Ip$ʆ .ޘ }9 C9'8mˀ8-:)uEo*[`nT10mFa},IYЇap>cR2GsYo$XK7@<,Ɉ.- @Pg@+; Ώl8S7+r)B_aIJ.v}lGrD {X&Rtˎ8(㳢0=(GQjZ[U^ Hs"㿿k=J2;fB7C(/$H:78WBeRߗT UNpyPD?5'&TvDڶ,tH`Ufb&jeڳl7;&ZYm\A̔Vi6^ypkR/%j2ě(_ Nm'N @ESX-'P)Whs%d{~ lY#;>lh8YyHh!G%f H|#:t>z!#F A\$"  " IH,E !\r@\r@A.rDd\$"x!( AH\8] @`;#:.D2Q"|\q! =C8>݃D1]n-§3{^ܘE|ڋmL&(z.}ib=3]aE¯ízh{.*t{S ߳i=B;E`,wai&?^CW,~ 9]K+_Id>C>܂&IѥTTv{jn( ̜fT&8ΏQ~gY^JG=ЮaX1*n;&F}]8QeR6yL[!d0ߏGYOߪ"OX <׻D2*)x`ukL2HݟM.-G:NxmyC.J =˔`26'$mI),0ɛB6$o CML9_;J>Ex{SQQ+?Hc':iSDH=BO{2}t.cv*nUd\7H |MB*Ox~ȕjo[1NvIbWܵn(K[x4tggۥT i9$7בS+O?d$ xJn Z0nR.oh!SNVI1G (1][@no3;+7%Pz'1$c|{LkFe^Rh"AP=㤣D'@F3|UN . ܳjVӗ4dYhOޟ]Us$A "7w[%*ÞJH K0Z'jIRZ|koV݄90ݝo4e,{&{s..B׮rAv\FYhn5!w7_,r8 ;';]Ig8JRy=`qaؗ0>Is;A?ҍ0K B"#I $0~!B#Hm`Ψ|rܖ γi>QE^,s#Њr"$9{dt\я*γ,@({ HF필z(^-|I7wg$5q/>WGI( VAtmE*8.Ydmtfۣ[t#{/h\d-҃}_=ֵԦP5˒IgUd s;p&F.B3+ ??; J! Ӆ*8L,R0w:ٲ"ʳ "38dZ߻{Xޱ \qJE^.a=ҳrTt޹#dt!_8`~gWA g>^ʘQ? ʗ˩9SgہcYQ@ toޡݛD777a7u`> P& 7KL까3*kדD|ENC(4_e~\9QXح twq,82V5VZZ|V"d׏̙o33Fzg|x 1vث(vdϒ& ݗE=jr({"vw|paz"\m]yv:Ymf9 92߸7B%V YA9jNmv.{#h%U4 ;~^X-Eg#{?gWIgjo@pxO15f2gwN0"KQeNyL@%t%t׸!`7"ɟgm14y rrPʉn@e4f!L00ZǿDgOKet" i.+!def[3ϞzVg8'Of/ʪ6BEXX#0zY 5B z6]q *=n>pV;7̣[$K;݆MWsg))6:g)L%ͼaPwB,vƴuBkDC32ZPΠ[nYKĮM0TY  φݗ3hº//aox}PidfGk5DYCψ1y3g}vwSSB_tJ[OE|%# Ŋ F4NLѷX0R>ˊT]'ccɽdHOJ$( Ζ|,;U}팲/ 4nSb0x~ _PܘZW&NVɪgv:A{D=X0i b:+Փa,u6<)U>܏̊!CU]vWWl]ωTKءJ)k2vf@on@1Z y}%Z Nqaԇ;xSBټ}hV>R=ȉ,Z h x& kt=9u]csq3sFi0dWCJ]qbd-E'ܹ[LXߦ,/:-7b jVZr -AVu51Dže_Pޕ@nR'}ʼnHDVc˰'q5打*\ *굼O vſT7^吷UWOJ&*2 zcxqVrn蝵 x&O V оU7]I5Nم R3YX\w@E*W tnB Yd("]MZϿnkAP0ى`872 f{RQawg X-δQ\%\p0a}x`p`Ry2Ҙ#^{3A_"Lgr҄_U }4|ٛ\Uc*F CZ@[&{r5id5+-O`Hdñdի3pmq#Tt1VB= <ꪭt/z:ݯ>E5Wn(WYI eqk8@\f /=yV.[_p\UcIQypc6${Sʍ\sc: ?̀fh@T@ļ'90:W<0SӐm8C(mhQ.,ʗr{%6[OźQ?ˊTo.= yIƛrs2+w7k?bgRhJGH2Z9)u~}זHs$1l'fG>f/QYIȠΞlb8]f?6N6ePv]d?^8kϣdQ&n')ځ /Hj dHl Hb Hn Kp=Wrsc༷3<(FBKp$eY_f Ht Hl NGKp$G"Kp$G%8Y#>X#%8B/I. /; @|NF $G2k|$Gk|$GDxk|]#5>Z#b"H`Grk|$GBk|$Għ8IfH<ulsfuXT2c3_c|O^38tkw#&NdѾޢ |["p["DDDඔvE9flS"7ڂ9Oq!w»T까Lf0bݙ>PzV>➾w՛C߿͠_d[saCxy.;':';硔}L f0#;gx}A9w"ɣ(<o3H 쳴8_Gyw~~(NAkwkXA~#ljLnFa2j#ۉrb#'aE%ׅ%z;ԱSc,'"4ز1H A>l 2I0Ȅ7f!p"$ C'>W4dHJUn[t4@N.mG_x!b.usZ-﮶rUB$|FʅEo}^ =[#)a0m@9ֺ },'F6# cp@Asf.DhaKDIdH<4`D3OFȐH!ēIhH$!,{\xg/xe;!Ζ*Kw a;NiE>E|#$$Z`|G{1fygΘq{Y=l) ՀB`P`e0}1Bs#G8GA=:zbw,GPG/P:z$葈qH=B:zt葀2`!`9Q#29t|R?dB9큽B_'h1q0p ֯}cϐe9ܤ_Ż4ntU֗ ,&*O#NWY\ *-} l!/Ȳ=;bP\NGSd# rX]lFl=+7d<||PtEaG//slqǗs.n| GѸgƢoNtS]e|̐zcid0Y0e'+ʻs.=|ygbDhtIynĚtk.QpF3[wvUkiͮl35w!@-c#'Km[}qZd_TAP:_!MN!|^Ww~s§? ˈ(WB^~f0ֳZϫ, 1ɓ=Na@ml0§*|lsX(cZAZHjV.fKz-6FhuM FC!x.a'xHy=xAٹ9ڤ̠9qH"ި#k^-1HJf$pM?ϒ霔~[WJR7{6(J Lb8"->T0w#3܎ywpz甌Ta/pp2tyw7KBlU\d9|xg$0=# ͝? $􌄦g$6=# OHjzFR3\Tg$0=# ϙ<$Jbz^c3gZc䠧g$5u"y ILHnzַPxT}WpqSk8G<4]edޝ()gTj/LW@ƴ\%޸VKOj[@N}Vʼ.N|s&#VgTc= + ClPl{|C\7T>1#lݫP(.Ds$&@H7d݄pAnI $&I&sV)4ϴH-5ۡ9&泅 }6Hč")7ܨp Q$FI(UD(qb3:/UGtTCG"8AX4xc|b"~aE@F#Lă  uWɒ{C 'oH ՝GR&?0)c>c؈G2L pD-p׬Q4H9 FczD6F@s|vtpv܄u(8"͂Icv QT`1 lxS8f#`9zr5v =Pym(6Q^ZCk9GD3Hf:x:|fʖM}?fe M} #PDJLkg= ϳIjM2%G$q0$&$<%)GfͱqMAd{dGx%kLv>aR_DF aKb ;R u4nr&y[$ȾFt"Ŀ)n;zHC_jBEEi ,.=c\2^)uxv2cQm 7 `Le?1fvndC] '&-$`[k[k[m[:>M' ۖw-zh8̟ʥ~(C3 UP؞B!Q^}c@0oBVFrrfN}P kfHޤI63=hOqf|nbQ(]buծp.v*eSv^uGgnv8bl'S ڳ!t&4DXpjڟ~J~ÅF%xE<6h@HE1g!]s>yT#KVYtO8\=M.}p̓Y$Ej MYHk3fG6T'Jb#&aepB>9TR8f~s0H62Ii߼P9{9 !6fTm 1 cg6B=BE8>VQGi?JMG wG )R~= FDu*hL~]5}nRyI;̌== w8]npt{j9Y]a#cZCΘ{3v :+c9?,nUm0HlB(xڵJUnϐE+, 5*ÛT[Kg> 4jFjA;;5a=,2K9! 7"t]No6~ C U61(xCs41 ƗYF}p{j=~Q]\W3s~=+lk}rW@V;q^(-!vBWs삆5jhVGi~~ }D[$y(\W $f1)7:Ϋ/YB^VX=&"fxz]/7E^Cs"*s;;jƚCP s2̩ XBC뫊G{Q[h\xdb=B\B6 8Jo,J2譃WEXhY׭ZYպY1 ?f9Rψ6+mCTut6QF(򱌓N Wy_{˗xtZde S'{酊J}jMho$W@ 7NIPd}A@:V?uIi@$߀|?`"V_P:MA`N(;E QDj5軏&>(9/a[LOJH^z_Jϳ$˯|4ڪ||5;q/*Va\$_nIK{lgL ktmylx9EEr ׋=̧_ϖ˻Ԧ rB>]Q/#/-r<^_XTh2'዁'-O'Yn2[/̛LqnPgnػbrd'1`ݎYVy9ԓT;h!,K*;OH/q~H/D90hoXNDUaL:exNޤ74M:IxÛt&,I'oi›t&I7tM:QxN$&74M:MxNޤӄ7dM:m1E 7]lx3H o ›t&&I o›t&(I' oҩ›t&7I>IMoxxNd"m '34A\`,M',sVمJ9d]͚*fph3124]% /4sҿ; qjBY6UyKrX0b-KE[>+wwӋ(n;7V Buo49ҭMxoo"Vf^m۱oICސΊ& jѹlUO0|46]qd4fʹݚVgf$zqK‚dƴN d`ͰΨyT2 E`REk^N%:Ub{ ,6=pt'~`60]\Q pYa3h {z@Eʱ3hI7mFv $g @ꍋ`6Na3xnI&zp8܍ON 6脋qZu Kq3n.htj"Wg6̌uDX@uWV>} 1@b|M>} 62BI=6YmzNGNק5Qx&-pf=Xf\eә<8;S/euчUw}%\꒜#\L윮YCdUZ/_^' 4SIqs4_FE3i}1xag7%GbSяRmP}0+qVx!u{QnEgnBa{zaV-ۆhvx~LCeLkЫdj̞-zVr#iM,.m7:G! |~7ǻ$ 9pzوO{#7 '0-Bҷl  =$輰\JDfF(;#hk0XÂ+x+먑VNzYl"{ Ӳ!X3wYyGDsYyciӹlvb+9#^QX'cKYQ+̊)XogF1G qޔ't$m26#]戄qp=C_z 7@sfJMDo\OcZX_yD[r3}.B`6 AQnmQ{$8D8Dt?0-՜G-^TxecThDgES~.i]$кߺ|W`^޺&ms8eӑʤ{H#6-"{NW)B,n&41 ʥIW];I/_TZoY=?_}2`@sm?,,Ɉܶw0huݚ+q3HP$>$}HgUDx_F;ܙ#CYN@>X#08ϕ؁b+j|ƺvkRqtm|n$rS/q$܌Rα@*i8T'VO{/$+ :߰$~3%F[;F,lDJsE;b/G6MJ Y׋Qݚ%s-Kb7_-4B]|vw兽^DD C/vW sR}+iL[D$/u/+F3wO="}/60*Ze}7*%A&Ig=~H߼ҬPS[ [adS(K"D3H0ND|"'|"'|"'|"'|"')DrO$D|"'|w" |n$c%z.USWг@u0m80`mDp?n"<Տz#2ynG~VMڝZN)5B6ፒUk}އښFn(_/.ooͯgs<,SKc#t,=DQ"x#y\$"/Dod0:lNf#HF`y΅F` ?0$Drd c"=[o]` = l:?fKk@sn(5E.q--|J$N^cAr B Z[S z+NrV: Yu*:!q NV7,+oxAiiQVא ]8B#$J:9t(5AlȒj$I`s/YvISwA%)nlݽ Y*xS ΀p  sgA0Zg#93!`zB"͇` Ɓ`#ئ@| M $bBqkIئ@M+{Ƽz?E L#K@丘D[VbQu݉=G@PκW^ @0'߽:G8)my캺V Ik{jf6I]ok,Bxos۳H@~ XSO0$( ԄD&$;5!ɑ\ Ԅħ&$55!I %85!ѩI8OMHhjBRSvcHRSԄd&$55LM$S  >5[$dlEw+ (e|WO/(Ur7j}"'MVhg ݡZ9wu2 0 c'"eZC^ڇQ7zSgdn 56U?E" h$֣+Ū~*Utiwqѽp}:J> a6@zԷpBs-Ub umhx~:E\! #u':mqDim{U2g7YXۿ*L˴"ڝ?k"PdU93Oɱ;G2(7%ln^բ,NAk8@fAf7_)qVe զ_0t沨dhz,rwNP;_<Hd{T 1c$Ht[$Y(qg€$th EB00"t)2K)\Eg̭&i'h\-rN,V21{f)i? s .Y $敐WDJļ DbC\%iUfE#YD"Ǵ&,lŧţloo , =#U<#WfЂmG،msĠK%T| T;a0OT溏k`n+1SwM @ve\9ƣrO: (OSk#p}Pu@[5uKTՅz2Lraq*rq&bG"$A޸kΜnc2P˷\V anB'|"~E~E~E~eӧ ~K~˶dUۦ rG6_3[k_ Սx=1vN_0E| OHs >lRn kJRhWjG5 ۸5VO$ dz@P(Dz{@Z'd|840NX0oJlG(79SB vdkl?|j%A &zv$JL3k%!,]NGX*t"C fDd2vۉ'@.ͥ3BtlP:cPXTw>qXvNJP)z8 iu*qtBw$=H{sT {t -^`8\!8BγR5Ѡ*uPh>oYZDkG\0ƘF7:Ay~d\L\u xA̭ T #$`HVV"""A[Ex["Ep)yi]{enh4of6s̠Z~./<8r@fEԎB(üaVe*w>dx:@_5$ߜ 39$^ݭf"p89=ER{-IZ$kIגP%^K|ݍ}rQ#Uz-hQI7Rm/ONP7YEI.bt$I3O'SݟM.&ylnd.g2V?D ! IBš™_9%r8F $X0+%`Yo W;VSH93+T0S}{ЛS>|^(]rq`fx,!Pçl<ݞ> ;Y[PSz ޮ‡ B}FuXꘆSZ(WҢZ:43+ZKφdPm@RbYrop<;beeZ TC},Ir2<-ewIG&t~v_.ognv9B{%%1NWȞyݍ#GA,wa#.CHX<]Sqd(چi |yHtoYRn,*E~gپ&$`)0#2Ǻ+< a>}?(F~SIs2%uՂ"S`P}U@II434bĶh 1{Hq4:3ݶ+`/Y2^q1r.S0qxz aM1!{ G$ '乗_NHh5d;5oӯ.ЬgfƪDc^uw zo_x$BȊ5TnOfc'/߂j#:zcVLᲒǹEȣ@[*aCQy"?Dj]5nN PJsl(\Ve:c LxDS)* EuS;mz.F37Y*yDuݥ=|2~BqA9 4NH݅0^1WY~Z{z8Ax+PvƆu<5Ky-;.Ey8%>|۵T{7={p/YVp^˸_(gDmuOBʢŘ@Yy.݆G:tלy.Go'Y^~tbvsuPUv FP݆(͖S| õ#oͣKOEeNDeGDI<8ڕRiI%.7S:|t*NIi΃q'$qNpᤓ9tB('eU,\JW:A)NR: &jKl_:>1OκR }dvF_60;,\fGLF fw۹' myA~0r<B馒"0GEv܆C$syUƃ|vx:Z*Eq 6-P /%B)VhD(6`=l' 1\4 f%رk~) Jth E\no6kXYV!/֓ pe< e*maG6\'!J#ynK7!J6N @t(F%pP*L@JP 9b G(M$:{ 8ف>OeJ@҄@ ԳuVxR4Z֓ &s/y^:'ybh57c qc:~933#(iaVYb&rI9rR=n JHm O)@+տPLB[)vCӾFj[uSrֿplmIynw+%i\k(WOZnۆ2N|0ӫHZ)5z! oYY-6Mo6Hݶ]o׌Ծ6͆k̐M*72SQXN!@7lXER+zGVeD6kh y 0{1,6h\ CtuCMuZi30FճϦ]gF_y \̦ kq\6i.CZ.u__%FK"uA%egET &ڈU}ܻPĥ|(X\>N>nLNǻqH2IJ_%$Q%}A:ٗY}")7m%W\F !DĪ-aSŖWyֹV2Eq { N9U S<֨:%i i}8LC05 $SkkkQzf&αruI,5jE2-"L\SĚlGZie*7zn׻M:Nuwy9bRy\y6NkVݝX-{whџǞ PMCh loXE2gIϣeA; rӛۿI6ٔ8Ǯ*vIHIXIӿʣ]MoՏ$+YJo^:̏$~v*Y毲two[}Qh]8/w1PG^%jOd̳퍞'y>A  eX!2)X5t) Qz7 /EdNš;k/%,I\4/L+l*"Ғ[qӢaq-,S;|J /W <QYX&U"EHj$_vJ&n|Drnpă/;n}W#ZE/{޶ x*#ېŁUM6V卣~XhpۻK4zǎ8 @ce@ |u,1)](l>3Xӳȸk9*`81-!IY42^7QԯrJf&96pf@CLY5a;LsX8|p<6<>3J5J7J7J6J7J$`j|7<7l#; y]#ӄ/F*^aeIqCUCUC&Cۖ1 oU ufmKs&*k\gI /R}<%[o43˸`T7c+wdy@VbE|2:gtAys/qt[@]&^lVrEd6@[29x#`հ{-DDϣGl%&(M"4IҁQAIf&Q$FiIh&QFiO!2JӌoY^OE2?Pg ؼ^r/Hb&L1JTQר8qKMgs)ٜ7OMMctD]~OPy:Wק@rNdz!?pp>Yyc|0곘e`}bZFu#>YGr>t$W~ I>Y l,}QyIi~l=A ZSZs*|B!AReXxS+v͈j4 ,=-:ԛ4j)@؉cZ ㊣M_nxwUX@UY6ݓ% }'G9)A90X۝A[ܳ<"әmRP#&f%D({6HHxg=1p!7 z~ja狄]x OՌhgH^=΅&Gёg Ȧt|9uM2]:2m0fD JUVrݳʍr볪t} nQپ31*Q:53-VZsS+{KMO/ +:xUi~4^қlRLo2dڽ+}HETχ"9~;7((!2}3"E4Iu=[DWV'Q!Y:܊Ҋ9qVVVpVVpVV̟H˨bb;jCt{bF`2*! |\^͈vmFp b5uE@wkvn3b3uLWGe3Pg4VÞ#-z/-0/39+=p~ۢ8/q}/0`=Ҹp}6nFe=x=ױs>PzobrTR'XS!`S!pSҘ9!J6v}mA^W2 ûS|u_^ig~$ɷeRJcJ$W 4ӑ8S8 j(Ue߶ZN#YqyWy4zskf_C=8ZY%u6ymp7gvQ.8y"\2n'= >.2e_Lxˤ 34q>䀑ɺϙ#t$E]xtv?<2k}Qc Lv~^G)cyϯ)%ߴތVQ'fg]g['2Aaa!!.cb= [٣! Fy&N!CWW lI.E.E%#}';Q=jAj}K1yR];r;jaG&]AB2T)GGA rӻfXVLMg <Ǭ.;wl5x(^(~8}*ڂ('Dnm?caO&KWw-ēy\\Uj6 PY/qk*WVcXc"]nؽW?^~,3QzWŹRG#*tY+ JˣeT,2 _\''﹯AZ'_dDZ` m}иFe'k|c:5CvӊJz,di2'$<86%̽USܫhlMY5‡*"jXN˱p^iow}%IsK!( wEzf  vv$Ihg'7ch8̂yq5m\\:q[SxZkEڸD!' 8"J ғi/@qDY9ksL__&!!t4N_BpDd a;);v ÇrRZvRĝ>n@'&+UU1L$qĒ7$Cʤ00000ެ2c7>ڽϒ$qQnxNodf,oQ2ʲwOwq&,{~o[,2[\vE9.†]Tffkp.c8@8NI,OUK aEm6ejl.E2N#jˈoe11euگ*7Տ2_d݁ӶGqvz>wBi-@U]+t*vV&J[݁~ 2)&k)7(chq*CKd60KjU':ɢT"B\ #<ɀX\Í\;t4c?5D-<5 ւ+R晽 Jb{P`({EvRa=͊,U壂]\7UMqsQJO,ŽZ9' 5+nDl? x@6Ej1ٵN6x7 f\MǗQRf:q$G^$Jsp PdEP)BD(_OW Hw"]RGtH(q& xܓ n$ٓ6gO= n}$ ړvhO3Fb "HbVۊZN+gź,.cءξ\h۲v)ªڄ_' 09¡*BI"pKhҧxUW%ggEvZMr,B"XMmwIRM 221HYh]OWQ\,x'l[nCgj!mz:s,wHA{FH,N5i4:ɀFh$;F`@S h$?fKkl0_\ øÞy˕=d~͔~gʹyNLWfߎz]Vg+*zamA?!1Osqv@Liz8U`, gD"mM̬;1fc=ST*RuCj7 g]>=)yq.a "HϜLp=@Iw3f$a\v :!"I Z7 x!t=l \lC6Ow?hFOz\zB VuԧN*V1o3nno \$h$`$IƹW o}=ڣ[{2ld큛SD^M2]Do@=cf[wQ|URܔ_.U" ͹Z*u^Q6d}W95^ᐾc(yQy/-PSCUg"CQ_̱3(-Ӹ*ɢKa0Gk֎eMl-KʄP:ղ0?vV3I PB_*'=7@SkP\ua8J3d<0?!!$4!yCHpBJ'[ HKV6Y]OS5&W}i,( g:Io}9 g`Zږ?Ӑ]a5tnsQG`Ud^p-Smr^0乩՜=AME moSy(iW/ԹαI٘ۯØE/Go}ZeS|cexf?btޏ*($C[+-[|p 0cyttr95Z-w_%fl6VUJ[C.F*򸧟Lonhno"*&2~H]3$Yffm|y$=ڧoIh5 hf:Rps^ݵxN#k8% Q]_]#wOOBYtO7$~\$^芳KBjeZ._#\ 3d)Pϥ" -Q-\YY\]E]joĬ/._T(FG{ K0Sڋ.%i+γWejEɄ` \R̜Fy\Ĵ2r.ka16a2nٻQ[h[K)*bƛr3ҺjN9g󷇴-ͦHF:wӽں(\XeDco3jKsK.P=»v}7;E{,b3j^!P!P\I6vcpR۪hh;nvm Qv,IS(i}w>r"Tw/%V? Cy:$Y_8=Ě5;0۔在b!ܷZf̢'_u_βGo*7)Ƿ5۪ETF*V d龸fB{=us,A=pެD~jz횦vcH,9G/h_yRũ䠗9* ~_fomLi0ݕf&oQ݈v D!%mZ&6ᗴI`I h\&%m\&%m.itIĖIfI M%m/iؒ6 -iВ6I`I M%m.i%r飗 O^RF-iĒ6 M%mo:ВvľM%mY&6-iܒvY&6CD9\&6A M"Kڄ\&6-i6aIvIk΄]5'6IpIIjID MBKt%m[&6I`IKڄ^v&9@Xzω2j!ZobZ$>JР@9W*{j-4T^ign$~anOEK'ŏ_9-ߍsf F\ԓ_-Եv M& G+@4Yت jr:es4Q;Zx0:KL_F2J u*ɢt&Q] w1&u[>6gYi:zLմ{P3v=ĹW*?6>if1c'2f"'{mxlڏ pMgOm4lj0p#T9L0Qϕd%`{O@c P`48dzO== I2tB&aP{LI`zO{2tA{N ?'>Ŭ1a{MI`zOB{lzO=aޓn$N 4k;|޻~-dٝŠZ刺O?R\i5{6/rnvw6z-B=B==´=µ=BhW)$IhۿgFd[/wD/,u2(:l !][G 0]KМ}0?nLv&+uZ32hU/(K^"ή^Fk╾oxīXџ_YfP%xo"1 JJȮJJDHc@BcP~ g.gs": ❵LFm@T:=P@OV)TkygpJgSX9|0JWL26.tL\ʲB&<*Z\qΖeTuJ胚7Ptpn(RPk //ikNrOlZeE% MT0aOjtLyIES'xH !c&$pʃ;12C#"@KQC>Eb- }r\$БFbaǵ{d$Eb!H #1$!|$Fb,!dpFb!d$sg##1cԆFbqwʴtYw0)W2#sϠПِ|wm&&[d{!p ̨27,0e̔I$Qv^m%J%yE'4\O Pa+?cCqnp>:^w# d8Y@Zs9⿨{j>:=w}f`P5cguFqFm 7\O_T:=^-'6t|"$.\z"顋./ Coʨ “MFpZDj)^4_`'@SRyUEyR<)X䫺޷{SV qeF&giYX>$nS({VU+b:pæ~\a rċ$X 𫜆?$;S«OeQف*=MqbCF;=*;ZK*/_Y^xU\լY׉I]]gիnluNZW6FꐰGI ,U|4Ex]@sΈ1ySevos6fO*57qwpCMXw ?-*6MB(ٽAY&"SbX8YLFL=5m'`h7G)c+O PA¼w >fE $B9 ?٩ѝ.yT~: v V^[uU} Rlo>n~>@N+aUXU57(jlPDݱ9)jo2u=i;;9;:rv~{T uۦSf*麉yP4tx3:dx>l0w1d9@X'eX;"L-UEv*eԃ7ܦu? !{|8p݊MKL=~1w,TEM%T/Յz2mL$boQG)`@ܛ¤L82A!B2eIp<_9wgieBtI_&:_@q2e˄}gI妌9r>@i h9aм򕂕UGV$zu+Q2H_*@`A^0J#g?-1vx,s hGю]ϬC}M4G;Bv1.G:`#hOGy9&an<1^pcHHw\='gIۼE 7<=D:I2̃kuEhO'e@aXXuP]Ɨ(~q6gL$JR{ˈhӇ9tlzyFOb,?!K[fy 7S$L3E :S$L3EB <#L3E 7S$Lp3EB :S$L3ŞEN.yL3EB}˵L"gMm~i$PO ہzh#}?I!x~ zL=VlYN3]{(6V9Pz_v=;G 0w.e5鼢=n&uDEydq0櫫||vqwgQ*9 e@gLg/0f„Qv.i"eԗjl$8 8 8 87z䇞NbBȶi@IܪfvjW6BUE7T}md V??(9gETd/ݤL(]ejTO~XAWPY] o+ )iH;r3kcqcV Uª_SiuD LdQݳw .= = =Gڌ|wR0_~ ;Ϗ{$P{*2#c՝ͧKɐw齹qLYi fΈƧwc3vI3WhbEYg.}@2~3#cᛟIK>! }ph112v6;I)\~g߲zP^63޸|'0|N$(0P7Ic[/kOZ9<7JxcxƚHHW*壊ݡ;#1vuìjq"=VZ qhM4M4>> Df52ф35ѾcyL4M4M4MZŠ𖟕,qf<RS5|hߜ5Y2NLAd$!9^(>1(=.Le#?.Vn[LT?m OH?#?'JɩZg \ 666666666>]_Y 5.R`ɃQ~ .̗+%g0tv+z :ǥjnK&LžalWk]V35ϢH̑#3Gfc[uPfHcgȘ92sޏ4Ȟv+S0lRYq~z.U;ňQ>:!(6ޜlwQu#'E3z ABGpG &@M`7slcQWBx(s)?)byD τ@h^{&Nyq{ Gm<襚Aaa04r!\#iQpUa6ڮyzT9z 9|$`>|0`: |%=\_]Ertӹf(;8ᝑB2-DZw>eTr]Wqkd {;(6ۚc>gPK5B s,ge;ͅ ilz_+-JOЇ_Dd/VXk{*}Mt+GYkL#$K7i}Z3>>e_ '])98|nL1$8:`{o ,yyyyGe{t~@vL6Y{Z&xf!W:#W[nVej;*m6JM8L^2-׊i}[1iW9._TڙIjKFj_jZndѲLcw?9M;#:[w7P>to O'iuJIYDeՒ]Z`Q<k'{㻧st;8 d. wAھ6HH{;[[nOffoo p${wl\.}} wf&U5G ՝l4SQS5z5>Yn_oȎ.3ʒVZ+7_A֦\|&kbM@(z'ISp0<b#_[JGow"1% ,$H T&afqh =s{]v'>@;|Y:h`XۡʍVmϹexS5=*Zpڝ}a@Ai,'bvn4.;tkL{}:{tIto 7  >ALLLLLSS0(K0CFsrp3lBxL>7Xqhcʣ^3UL r {tF.mD9=/r0&a 8Xf {6a1$1\$*gؾmaO{L߷y\Oi]s嶫;1(ek rH#`4ɭU{ OXuwgI. yg_gSꦯt_Y-Z%\o%=N"ۉ(mk,FjF<1v`\^ݺ i;(DѼ ռSߠ jյodwumaJ/ V5Bupɲݬ9z^UO'8TL" V6)B5)-,{LdnRԫZ(_]!8+YY2ϳμclQetgeiDQkvoBˆÕ=V3~^8fب%tOa pN7%Iw3\Ҟ`4:7ɫom)/vʧi)nDQ+ ڡ?||UtǞv1\\a;kܱPp@0Ot=@ٞpe8& &@&#.nqR>a@7 @pd #bÄ>uӓmB ޜJ\ %>\.Z :6]Rc,YmV ETs:aݞ;Me[4a~lWF( ρ,4f%0ɳVw+0I({=d݌ piv? qa^aOB8z93X9$sHPP'aCB9ty$Z}E6+rm|%X'|Ks槷3ww]+T_l>;εS?+TU7bQ՟?jP_siQb[]Qt*3́\[k~.U los$HVE-}yv1H(81ٟReV/ zݪEJ4= H&["'@:/W+тd&;l:6e, 6(JOLF 0ʼnAjodilf|~t͍Ȃ'Uz"w}^XvJVe JevQLPs^ "Q {"=] H$5ܞHIawcRwdrbx*ÓfF|F7tDIF,E(oY׽H0˪}74{/ZWɺ>{_ە0Re5RcT?y SeW]p²'E-^}(CBޫ)z AOpZ=?PE N'x=kF%;?yAc<:IҎFXI'Qp N6`rx5QFC?ǻ.>+yHM ~1^UYt2( rR =eO_}){F-ƣq8Gn[߫ 8H!y}#CEч~@O||c^Lq:Vt;&{Qh{&x/z&ː R4^ =zܞ^a26Z!= @~Ya3\F 5\3"@SM (p 6d;@ې10q>wᱺ2(0mX9Omp[;ۓPe$9A>o/x,#9QcѸҭ{0?)dObpBI3'oxB ('}dKYf \uɓƸʓ粢\ V–nU5 ϰp꟧ ogȧqJ#zDAA@ D|=mW۵'3FxOL""*_ؒ13j׈gGoo`<U\W2FOZ~/'(p# @7:h^<i`Cz+|@7q/=O i_HK7nb]Ydxc5)Wp%m7$ w$*(|.6|̇)cgHǼ]lL$F KգY 5wDNR":NhJd)Ӕ%JH#Њ"㘗 c>U^~Bɖ8Z$eTdӷBTLqz'7gnqY:<ά|1fiqfg1fcg}Eu !:*´Fk$wFTTSk(d"bDxMqM kp\ F?! %>G3x(1"`!7`)ˊ3@F}Wxqp;ozçx sB ĩz jWsN>9%CY& PgC<ǣ p.{B哫NF. u0=wUR5$yxcURxBBL EXY\Hد1x$Q=؛ˣ@^* ytKP< U \gG~ Ѡy/Ή\+EVT+"m|E뙦i$.$kS>]EX 4܉&RU"ep0QAEimO 6x,q ƞG3S` 67xLs17{.4q  0M?)׆oڠ{mț=/buNT&i5N ܑATXC1Y!t+ Qxo"x"f+5A“{^kߏJʠtj¤38HzA]rW6}SG\xBŬb^$2w;BAB}m4CVji‰IFT/A/ yrC.goZ.= l,J1ViBgtD˿Q , ٹ8+RR9r&+Dr 7*T+o>~"6CTo2I3b]в& W)Á7'՝4X{P)js5#Q?V嫙] ֬.U%%^#^5OiQ vqlwK $m0+o_IC҄!u0T]HOӛb;wy)JL~W3`q)u()hi 2Jׄ(d /Y/.Tk($a|]/=`עьyX3=X<- {@]˚ .׷Z:CJKJi}>Sg# 눋Taʫ5"'] M2Iv;YF'<{xި,LF$ SPo;ԀB0;TqOښF({ < |oSEEaj%ZL NMm016j၀.E?_jRRBy)dž!]]kW!v6fCL:] }kfӟ y^4Wx5/jVZX>/4VQN rR27pRNXTE ĺv{L*z빭ؚI?6e[fyxW jt-x@%DtS.њگm-0厮bԡˠ]BJR%Ln-;B@k3ƌdr)6YE $kwNVq1;ԭЭ>,}(B![ӺyLwCǨܭԭ#y:wnuϭΣ9[y:tnEV1<[y7vsZ:'tsJ:{NVnuǭ9[ry{ϭ#9GunuNVnuNVnuNVnuΒj8l'(B`gJo^HXAiUicG!xrXF&יQ򏯻R,;S<R~28[^wl]s>s rKg̸K\>&)s/RX;'L+/] Ͼ+# =\'H%zv_,rcx )Q {cY0fr> +B~߄^ 6aTK'{`д;Y(e U (9)'XN3r Nv&XN7,3.L1r N|4,'`9[[|16ԕAl!q@ $70 䬂d#ʙ$iuD%QHXUV ".ԯ~){<}8Q^0(A:YlDLCLiM9M1crt dǭӉYj`SeD=4AI,lDa/~A>irQ>DOM.3е1> pfLN1 L=<"%?}>$o } < Şv%(Hv&F-X^mRj7r6U0 %z:nX 2Sw3H+PEDBFox!_L]G2KY)l0z33Q4I@|x}.'}:<#{vP{'0lGҬL@:G@`xsQa;<VcD(oyfA\@`[f V(QY`> l|`bu Sme WO>34?4FEf L%DvEvx] |{_OOPFYBpw1'mL|pv$D}9óx3!E˳~QjeY2z ɣQ9]Ev K*lI$〞.9.yHPD44 ޹2Q.''p сR 'B8L1NIqǶeg7v&n(4-Tw'sB]ΰi䐟i^D>EƓL.m1f+̃0I>Ek)0KQ};gD݀cP"P:h S 8 GW=5(Q1{L_*P)\CBjyzDD,z:%(|pv\$~[ׁ!voҺ Iw`MƄN id!`ωtȣ$@pBiT{!T*T'W!aI00 g HW_c}ZDmx%& iB]HΙC $1EU4e̊*)6▇ 18NjxQF4 |+EjB>UBa&l}uñBfNb78DGt8;H^vP۸bY]tV'Uz5 (wKnJx˻d{cAzQ@ l->: gyzUVۋǤ0[B#0RAhNBU<|N23JL:),׏,[yAj٫Q͍\ƀacqQ(ƤlvY/@(X9 ~ Ug\&ymUj],[iץUÝzB<`( .7|ǿne[Ő"AvLe R&:a>|/:얇[St+ǣ# -Is6}S=I)ZFhCD#-#L4Nv5aAe9vn"QhlQajKo#siwɪNhUTى޵"O2F_@1SIՎcPgr#ygyRș`D݂ƭ{8q~+|!,pei񄋒K_ O&cucs1,*o%`SQt7Ȑ\Rb87BǯG%? BxӘ*a~^]7)7>$ͥI6fWbɦv>~38 SXO))'owG[;rڇAI>Yg|XIKIA&º xOu;'H!."w8iL٠׋\iƯ^}U52eN6u5q;_!i?:O۵Fvxkt`ZSF9K -p 8O,3ŜlC]6ݮ }#˸1Ӓ-;~Bogyp[Ѵi 6<(6I&\.4n%?S'f4L&z&{.i|j J=o (P{O$}ŕ>`¿POg\|Ѐۢ`5Ɉ1V}7.m΃;܋LND'y}cP=7/sEO0fSeG~ţ0|;/ jG|\8dU0V D,%86fhFF!s\_'^Fފ)3)I Dѡ7Guʏܺj֑kvL#ӰgD%_g[hz`?0[Xa]:"e.bpL uuR%;ivUη}~$Vy)n.җG$rE?`FVw =^,+ʌu!? Agv,rYR%@*ȪgUCA2rH SNs.#GQ2OPU%E߮yj':>{ Wq)ml.9u#}¼ss\n\Eé_>j3/lkȀ}˿\U{k>_WWNc r˳BaؗX kZ~PF%:O olE#_e mZ;2xY:IJnCT(e#:dGa$u&#-u9\#=1lp{`);R4 8 61XɏDw:sR>"m4M^!lP(B1nF F€l/`u- *N`9yz%Y#P7(D8ͶBn躃+*ђVuSn斏a?w w5:*zQZ8{uct>RU,c;9{ w/D%If|R&vuK}E'^ބS=>ܬ[gN*DC"s%p;N?r "&iB( Id0:4U_c\'rH*u9ttb: }ƍMtSQyl^Fѧby?3223P8#dcn?!+fm:ܐ*ߋ';#S'"O8g؎ʳ_VhfkYITO@cEşpJw99+֦>-?=[>|\hdk>`ZvZ l9V?3՞|~Jm–=XBXY*g#>Tk Y},{`|[bb~u_nwP#VCE"'4gAI)6H>kc #G5U;`K\<8$=2u(]h{q:SҜ} S6EV< yY% <>a0m]#K9̟)tv?6)+XO[t .zzpէy; /gzĹ}eicO<Vepk~4;WDy`jz-ƤPu߽eջgƥ#P9I(a8'<=)4HݨG틞F=epvɍ{Y規O? 12.4u眳 _4p,y+v'zQlɭCOmd]]歩[UmϑJäf!PL"{&R`GF!_٦R4Mrm> z,e~Rtj6hǧl?ݗ*]| '?xx2-:P uԖyU%a}6 o@NtJ~)iˍS :X6ԋ89Vj&5.%dcv{վH˗iqvքIQug aQRaAdT^YyZƱoUH!P.S6B=Ow}B%{ 3K$5@k{sbSh`U7:}D4Gm*l>|S #ǃO#\V.nŖlpH!aN (n0xO2 .:+ H7V`⹳*t13u3*-_> &nk&nzUJ8Ox}Nh}c!o»oa='aNO͔:x%"^<(l煸&ݩ Aq'OwAX8<=`4>@jP<۾r)@_$2DĸV퇌h a%y9/b;oEt;KLJ~5Q7J}dBm}ouBeBPmX>=vJ|ex\ F{EvJoev/W_2`W\ե9r "^ d. \ KYܶ0o^9 {CX{^hƇmYYv}%D:?\ZsQd&|@MrpLk`'T~Gv3|(.kn[z$t\#Rz?VUYHsV}Bp}E8\g~ePעC0*.ߥaRϒUByY 7[Y 2Ѻ7r/]9i꥓mw Vm ̘aBxb{@[yqbγ0 R+=!3Wj33xC\FݳO_;t#sxQԾ]$@'q0 :dԞZQ@C|\]YAݡw l5a|%V<˓D)$ lj*ؐ}{S!CO{Z.TeMGRV7 8)O)ӢΒ W QD?&wxjs$L~Ph8H}إߗEzTsY1;V XUUn_>,m͓呲 `8ڑݹJ%1Q> 传CV'Nl$"ckavg|{.k!g0P,~.gǪ< &xƒhvVY:7dwB8nzou=.aVB!K!,ƁT 'jtv={"Qji%hfKAC* GthIflU IsBϱy'[]>S Xn)Hv7V8O2wt#:cN !-5bQQ_ AY.b@g} 8VTK`X,.[#f-W+5q)B< F5GĝQщ ]7:mj+7- k %9UqV6CStG2lΈ*~&_F̾.F*>9KѶ,h;9F/T h_:d0j9ߖ ³&7<Ȇk'-)ٞQȥE[eCq<k-Y v[MZ̋>]Ţ_<D߹ENKI~`P3"h#KI N{ ‰J%6Avo3܉?tqM-*W{L㠜.!zT t /cmp]zΜ؈)G#6Kgo!ey^&4-n܅[SC?Ie3\M6gKj¾.@1")Rn:j?8'/^9 d.$U\鬁K)=a<%;s.ݽuz6$aM.Q;9 w9 W&a0jdlr D|1S4 .I;&X]}P:] GDbk|o#obhpk-"ɉZ),|B=`EHF4di:ݞuiWb}nv=S(F4i6qL}֤dSlGtV8"}^U9thܙN{,clm]4q~3*Wn,VY@̠霁γwv*g-徴I,?yN'm?n$p"4<5gDP1aW@aN pdG-L uN/C1$ g7m?Y.mEl4xucO~@ Du1>]w h%st4MR1Oưs/J2c-D&OK o- 'ekD_:t(OL?Z=`}Z LRdX|AT^#S}AK1Q +&ͧ($Ϯ:I~t'm bB4#C<=ɿ#I1PV+=rEAwe(̙U~2Nڛu# |P!sHe^> df5d3+~5ZJi]Rm>;zM* ϝͽĿ,|{됂o ^ N$_BQ:@aT̖dF_y]nMvˮ@ Nph}R5єl' QD'h#q/Plz3C*$;0%7W7=])^]0Y{ C h;^ #[SRnMC- d.~$fNdq;>sxf9*Y!og\ aE)6ٶ|=$\,ՋMܕmN+I'g֧5~]_.HhZ2 ,z_WL(/IتE{:UM7!*Z)?;: `@dg#We?754~(Hޥ;3w. ľ귳u{WS1%gU4M-*9! ^OKQ܏>!O}p"VD⿉ ~h6L۬HY]B\h;J|cbK&/ ZRQHwbnVF}WGAք'Ôy<]']&Hqȧ<..$IwmCmݜqTE S{nkd0ӶOJwn:ZrHmH =%RnS򸨟||6/=pf7&UVzNh9=IB ;*b!.+ 3 VXsww]~8"L4$L 4w}Ҕ"?7ґ(3^<(nSIf;bD ^نZlp`b~l2t*XqjQ xҵispcw1,/>Ͽ|4"'2W+ֺ_O6;HC yz_Uvlc4Uw׹|}.@)≼*RuX |] aLڤ 8!M$DbsORYA333 W+*m}`#Ϻ?DТE϶J|e툏6/N-qvS6 >}ŇbT^wm3}&χR%J<ʬ4 q)fnz n5hQGjr|@x#L6XvBNSx2w[R i ɋiu2C̔\EՈm\/%u[}5Mf:4P'@b5*68\vKOBQ:*tt(Z =A߶@K{#4:MH{=L V2ٓ1zU?%}%b,КG .PFQO _Ϊ ' H8,{㢈~4Ӷ 'bCfIx!|9('ɂi5! Z=D~aP9!{l=4qM+h*SA?-z'˿QG-$i`IU?6,ϞYݏM|A6P],ru ǿ>*4eQnfoaQ,1qSX] Wk1҂WPh7o =|3e_&bRz:K姣zc$TzBwf[-ϼK]y}Voj`x6g̙'Q(B~7dTl`ەI UWdnwR@pN8uQ "U2nUF/!/T'ɳsWUdi( pTQGiuooG#cv<% zۈ"(Sqwb4}X"&M dhQc:$*%<~M 齃9>ߐ`aݒ\t[=r;;1SXNJ{vt 7v>`䀚ػEս9|eRzkyK.mBv4A@o46=27%..gsߗڮNt!F2ky:VDMG/hNԒUl-Lj/E)+f3 x,aӉr)p>Y9wd QʠANFKr;X;Γlkmq~]E5~n_Qto=6 碑Pj3αjD2^x.y#CzFPUb޿$=k>Q)>49*sTWXBjT]7jGM@mճ(BT&Ԙ ї@< d4BeErӳ?uc*zQd"ծGlPzZi* i駋suh'9qR :V>L t֪.¶mEutܰL Zlj8QɆL7+S [.!Y2N!`/ K>_)V8,WIff!#M؋?@mB_K̸nNd}n?4oh; i6 ##<VV?H8 R/Joޯu-uA'I?7| 2Yi%F.ؔ4XI\oHP+OQ΍^p.]$ gHo6īWj]q C`l#+ CR^$f>~S!j_0<+N~zt' vj;Q~: qrF l8F_.z}Kw~?pA [,c30B}罣rm')ÒKS}G$yMvá]VlVtĺ,$orB7<b~a53Ey/;䩍*_U,\I?l͇^Yr|,Ǭ yyu %"A K xR%K8O %IFSe,pcfZUe!2'P4@'Z [8x8MA: ckM2) կPQ]7VYއ2+b Jiwx%,ޡW/cu VKT\AGaJQkv6f3=H3#?el%D 9tbVa?iѽHNbo4U22Wle$ Kis}J75_b790xEk=p5\dD&AK,9 A~7\0@52iyM"s/<.cL}`$7&yf;-S &"y(9P d0(>]ӕn_#={C%zxO՝ O)paKn&wS;AbJoLb2|:xD1=6|&bS^\{B5nڟ576 $uO:tRTe|n}ry/z#YeVdzN;9|_bحV]c$C.Xl)zKR*cp ]~ԴTnuvV;Yx !t=/Y-wǪźLb= >B`+;xIr1v!u !Q2rF'BElB7 {f2,z)gai'!Z/xj[+!Άs:BZ)Y4R)&t@ "TTEAgSF=Y$1ſk5Hݧ2.WeGRv,Sls6VKjd ˮIw _CI`V-OKCr,u O("oV1RuN[Zy^<`ە'=#IS;^|eT9tc3&Qhp{g}fw?ۉ猟<;6cJ1N]¾ҳ {,=|.uCީ9y1nӅ{ZS;0KSf5 )2dgO/0`,g; }|l` )E\%rJĕyVJBqخC^fR%ݴ6)?^W@|N4QO^s%*[1mFQzq"2.Kڶ\; cj+MyGx M|e"Q;Re&Jnc"+6Xt_"[}'SM)+&2]ف2 }_:n!q$MVC.fY8v|]{p Pqt~e)ɒÖ h\yˑ217C7$6KHXCv}AE?&\Ea $^֏UQ'5{xN^rJduF86_X[YtZdLwmiKZO BnwO'z \p7R&?n܆ Dg A0̘`yk#ljEPc#$r5Kȋj])kڧ~3-Vbm=^f3ku?2n?$ 13V?dN)fY9A`QֶA}T?U3}֒ Orcg#IסE@^c<|g/#kr/I_9J^mI]}n74ECQ4B󤩳j࠻~6\3@;PM~x3MHa|@zR?$K_1\,NS׋5Ui-.[_䙙/&Bg^mR]_usatuWje̲/|=4B\1x%4cr1A|0;ؤác^Љ'd$L'7NZ$bjDNg]?T eCܯPZu.9/l MIN*J{q߀U Pr'Q- VX$:O&@vql߸R=y ~n?LP̻ 4鈚![H%S)FZԝ nj.)Pħ}t+h3〨knT䜒u TTz_NpO˪^.gVD(%nϯŘ v|/;uMcJĪΠ^vIc=؁͝JK#$d|^;"wԶUVd6u:c<`)(Zê^ 4ffѤ^R]]MN #NiT4%kEP~(c0Kz:< ԝ|NJzG=;G- bձ|cD?6;-';nhsy3Sc`yt)Mw5i;X{ۮxtc`vn0>1w#E 眳*Lms|7_h ee+dLN/'VZO# .dIWWW40NGQ@@uй ^> V 08$ DT*>C3vM:OO>DG%ŽNu~Pr'Rq-n+C|( *<, #زrxamAHm1Q≲QJ*ScϟŰ.Ky/kWp%16A7*ֵ?A54#}JTˉ!$5Qǘ҅uWJVS4O>D7/Sޥ,_m " ;uBI3m}1HGWO?% tQЮ6m08 Jm'*#=$]LYO>JA 9jVRc1͉Gj~%hB0Fb,P( 96ǰ(U7.diSr=g7n^Sa32C|ker3.{붔kåxCKKj}8QőnP% GfuHBown5[{ ('Ő7jeh7 5IuoF?Oq`Pg0*;@r:2Av(„vӑ'Ystڶ| ,w(<|'fX\Em7,Jm3$|/}8,mi8h?+sXwYId_mv&V4|/ª7K0Si4/˗"/x,Ί?<Uz77Z*L_8o|Hժ_-Zܪ\qF)YuYe7lZB 2!~2 uR %ݷjEzLx;a\f[uUz$+_#뫹1Qg@{$A<"*>x㱑RfY<ѿZ,\v p>VdVcm9Ё8wtKDj{0OM-<t$S%{莿R<' ت|EߴOSߜ>2.";eXUc.H9؏o1Y:['MenTO..6O*bVy Rz@紌.-ٯlVy5\|ɒ@C/ 1 W3{*\Gu@<aj=||4c}'X/ԦPK~'9sKͪIcŀ҇W<{HoH <Iu&YvG# c!+V<G:f e9u6ނC&uuG}.;v<RV,83^ba^&dȕOgP,p m:3Hpűlm; eEtW-Z_Mod)oۖaN8Yw5gBpϜPnv.=l5F@'[[G'^vhlõN؅B+#NÖe5"i(%8w>@4m2sJVQm eK K=mypFYKG ֭@Q<ɢ =fOTY0po==` >ңz%P9oFfè1lҋ*j":Պ }ku#S.Cu<P HyPL_}Hh','{=DZACx͓}[ t DRy!{`4#g*>a/4z֡G|1+t<)Nc>F>_KJ]4:d`ذ#$Ĩ8:=pAg#D!\T4BX#m]2NBCh;,W=nqgdǡS37XUeCw;6<`] &#~7sCa5"^|tEy]lt7PYIB? بNJ%Y:*s;Qۉ%QG:ggQ4Tuާg%.5B3c |)2.=Q1NH;Ao,z|m8$҉WZ|_&#gLZ, MB M&0Gi1 J)"8y0 Μf uOkH=/qIy0d2M:h5{N牭 gӱf 7BmŸPtn^Z2b)Ơ Gq]p!~|@G%xG-R2O72rWk[t̯BŅ[IJxlz?ǧ}ܻOVt#Mt88CbujO'g2! 4' “Eī!*N@uPvyD,fNvNJ٧n\SF5X2QY9}/ؖ/fL[4 OWЙFtE/3Qi'S,unݷ2J^%@wFiւ!@)ImġK_w镀RmMꚡ"63TQda*Y"'ZEQ`@qLLrmwG~W)[l`Önń!ȇߩr؄#hH$y \32 uv!ND߯$1xD[-{AҒ,H+=2g&CW#| `iPKgӕ"Xy~ FU9tjE^*& E5CdCRaqU*]9NmþiesR?וmyR5r0UQ6D֊%8#5!pt̪MJ=k?ʢnDžuñn;%Tyc$Q: &׷nmźNa>wa^N< y:Ҍ$*5տ?"h`XdѺk`ago'xC>\X3nvu5r5D5IT{;3Y9: 80ĥuҹׇtSI2B)I@uPhR+cgv̻s{-ST6)74LKbPȞ4rƩ!3#hP$.MĦsnZP.ZX{ӍRմ#DSBI088g*L7s)W6(Ď@gwI=AF2ź m7Av8*_ ;k,+ 29̎Q!pJQn܋sv kg )9s::whvv*޳CK+ )D7UP߽Q' ̳(q?6/blG٧9X3$%mG6Aļ/uJHruyw IL'hCVd˯sx2u;(6٩Lg2n RHLpvt=b͉)#\` 3CβpOD"cD0JWahP3CJO2B*)D w.P޴<(WLw^<"29*ʪ{lʅcR2\~[A* б1a&gBCfH͗;"n: V-i$+951X3Pf,!2"շǧIOf!?>ɿG[O:+]a׾sP- aˈN&|^%hrR弯,Xd9o&ibbCNb͑XS r8K]t$9[irϸS)k܁Wұ&xAI ZbA `*?B#F v=d=O&wBtt%\/H硢5K6UƻζYһSVB,=l؈pr6=j\ߞ[MXuYIF*ӻX긖ҷQ=n̸Lތɔ8&ѳ:m_]Y[,4Tn8:V1މkS9{աw7E[g{vN@4~*RYf; \ FxǨC°^$b5)*DZ (bJpʷwT?A)PAv(\H9'h8<3٩rc:UX ]sDSvOMEɦ\9e6KX(m0!z;Ow/S+o#x'vgx7A)q}#W`װk7be@*?}q=Kǧ9J -7+_!0;D?])rFsM"֚e&Lƻ 605)RC2f'Eu:;@i,ו7 Wa"sJY=r_RF14ubֹ lk'1[|'&i"0ˋ![͈(7 ,ޱcLAvaʕ/^:J%LGOMޙ"p9\4E|"Lj! ,o8@`5|yP19K|lJ>[{[ O:+58ԤWr⩨iBMa'A* \ryC@=D8o:3vXJ=IS$LTm"K FőmڔF*RgBr:ғFBE:1'E\>;p."OGDa2EP9זej_zM-|v?0l\ųk_yZ.s˪ &m._ )NG+2T_'EAYMb]quQ-l@R,Uӓv }ճ鋃"r0΋Ԋ]|B'Xu!xź7Y @=Zp5Զ yz7n݋,Ntw;CnjӘCt PP5Fs "\&P!˜p)*:`_wa q%Mt^ 6]Dx6 ys/U>Ym&8`Ӓ9Mu$3;ߊ,]TUhyNQUO=4|Ux )ix2!0xy2 {eTs2*E )V99v${&D9z*=.|`46't27>d܏z6h,U7):a}冈!6p uaRC (7(ٺA8_CkJ!wniB_9RaN>@u(ޔ?(u~DC2}vKaAHO:u[bY9ɸݚ!`w}.;ٔ:NP{_IB% $4l+uއLƄ,{C+7gv pp::!9٦J RCc[:iO :v;'Ui1{ KDRf1KGQou[iѬ*%ݕgu!VǦ haC>qf W3~8xz.w\ujlE°*Dg $NJslڔhg;&ߗUYďMRֲPXp1S`+ku l#-;RYWbAe[ĊW;ب58{6" &M4yR*R(Xʍ0aC}/wI}'rW*|e%UT 2gk1hw+ch.~r%xO芤 FK8I~_~ ;U,?/g둆H8\Y'żHJh٧ 8VO#cm({3))OeK(z-Rǎ!7z; ՗oAoYA M|0-I]gyz7'\4VrZh)xߪ쾪@f$W3$Ix <҅*p1 ˄mM'&hUÌKrsS'E M>>keEB]^1&ʞJ|:ac_/:v (&?X$FK.#ev},vb0ZW˿hUk^E7y,xU<};'u 1j^<3`H娋y0[!A}Ffr@  ယ|ɬ[q#\$C<31_؋mHƂ]U >2DBG6Vxo˛/&M@&1Se'j*[gFDLi2e眗L6822STv=i{b_OąhҺcɖ1٨9!{βY(P7ח^Qĥ@#A O۵&,&J0 }fl,U6'dpH>}%DC5Sv z/ramf2xy|:u0>=6mKҷer ;m= {NT(p5Ti+ۧC`6ȹk͍up ! X? R(ĭHh֟`N퟈Ѫlbe@uQdJ-j2,1UxeX N|ӡ<$b=fܝDNTkಔSG@~,Ahe,b';ݬH ?؎Y<نɐcRlڡ<7Cr[rTty200ܯ~UV[l ,ZI/=ttz׭4!̙>]-q˿y;c"rd>]Yab{}wj~ڋR;ǍDR!̐Wmdza(#,u:{Ʀ&̲B3^,4U ;+R\u4׏<3$"l'Ep+KT=+yTBplb ~JBܦ@kInN \=ҍVDf4:UGVYӥZ%y, Zd=nl=`EwLBA4E $2rF&h½MMAU"RtL0U1Ӵ8dS%"l_Pړgú%$Ok>/۾K& {o"j7[rKN]q*-F %ɜBNY%őOg?Ц rB% %;t eRti @n+Lf7bZ{fKHl2|龠$yEΗT[>@_(7bH. I@ֱb:NF}7.(G\q2/Yx.̆7v˶hVrH|G_n)*q*4d8oJ tW,+dwg(+d MAUo‚6ߜ;1}U&_v)__. &z;17*7 Mޭ1S,-.52SzYRCȤVXS˿YSoI)CȎ|‡m ɰ2Z:Qa?|11xށ:.W`2H/|-|$㈴)?-LL`?5im.:&9u@EREzSP_d̅bWkPj#pgfR*~LW5sg D_^+@2,&_1/"4V,OO?5}Kţ;{ܱ|4ZGB<{C?7Q·"[)ɒR2bGU#Yp+#ʄdg'avTh;W8|b'/S(:$g(4З2_eAo|B#> ]tek3 Me:Ť]m`w!Qe-Ne<fE*V,^ޥ|JBv6wXE4XcٟY 15b TϷ{_EVUW.$n'FIG0/{]!ɮؚe/gL$Su~ DdDB8q`Y]ޖj67=f. }0"$wwlw ٩eKȝ۬|5CG/ r}D5ob !5~?Ez.g̀3ۛl =wVc(f9 D [j, Sv (:y+5*A߇Uݛ1Yf*[69f3Ve^n|Skl{0]t*G}iZ$(›_h2Ice1^XWaȼ+~aO"{RUq H%Fhr+߿ S:U_`QOǙudHg9,7V;Yj7E.ס8YpgtTQ_@ŷ-sYd)U4l_x.FiTpM0ŪD$Smc|W{8n}""a+W=/ Hsbw7 O'Z|J@拾#tbx>p'}!,@sC;}\0׏K(#OF)wSqBQVĆ iQ$?ۨCW<:np)LOVv02vd!EO7*|I_BdٷUy6eSbI *+Jɒe WA.tU9ڄC4غ/1 oWv0ɔ?}֖_`lP#CSL[Je_1%ۏN/}Se䙉W̤H^6I,r,N25?JcL?9Q$$*c{8\|/SNCtא<]dQ_y~S}?w#nPt辘5}-rcai^ny!VU7,wWxW~^wXQ ݔVB'[$aCT )["sXt}} KU&By) bOq O)#}8׎h6oQHWlGJe'`?T?a.P =3 )zڞC3)h`Nɿd+]n1Ӷ;x-?]<Ѿim˺}Hld[YB@3cxnS䉻;!7bTwl'kfn1VD?dEft˴؊ﺗ bzp"t }NGi)1,Y?޲*+/Ys whph{QrmE1\n ~Uδypq2Q#g_]{˾x"-te -T^T5u_1IBTcZd.NSOSHp0C7Q?M:""l"؝OӋƮJWssy΄,8G>uVŶ`Fi%C0RfWgkpTHo=c9AߟX*Q+'vyԂʷjt#_tlu#k@iq_K,>Ajձhc)cTe p@c[8 ITΘՌCv /ޱPn,t8:`wbT)a%Ve·JTrk軏q@ |6o@cS.r>dGS nNΔ07𘼆E@U}:Kr톁S5&Ԧ:HYOߚ=4rE 80/"c/y.?sjE"U]{Z,}{(f-Pdpn;+6UG;n{$Hqwp#]&& Cu/ o!k :\ l֐䯿}է2?Î)ۓ >()G9<2nvGgVL0>{S3s# T?\exaޜ;D])N~_Ac PyIsT6obv2[GkK)e!Ff$Lc8gU .Ls&RfÔǜ!bݮb?rp2b׬]GD3o GE2ܴԹp /~81N7Mn⡤Aym׃MSaҷYmŷRЖ |feݧ+#lL.''F<2p>YVzx\iHor>;:elyzBؿ9q"Ol+Ɨbk]QcĮ.mkQI9N2n3\΂ S3'443P@0+E&^ލ\JΗQ5t*AQ ӅZQᴒq2];]*6ݕ/+W" ֝.zn'mg u-(|9)a{UT.` [ZH^f&gŭ}5NAx&A^L*]tbh w߮ʿ҉qR= \b3sn>4'qc>ё*V1[X@_!Bi7ߝ A"\5USbV%տO ~de?Ē,Kmy#~Ɉ }^oGR˖עHn th :Dp͎zGWBT]QY2#&*?hrtP7{հ:xL2 d ̑,U'/; ^w-$5NR Sш -;k8NprT.!y n_['zcI 4spDM\uL1C$T}H=:Iz]K S14DSGT7d@__CVmvP[ cmt7ЉR*=MOE*3⩢G ɹdv;ǩ}ƩRGg23 ,scʔk㊜?dgrSv "ҟdQ1\vy eaJت|EoHnP$thpY<,A_yYnļx&[E! o!Eiiydb_Yg;݋a*0hB24ՆշIhW}gŨ2:0d//˗$,#x^'tnW]GjYKTMfn2rD{=^@*ަ̝s~y/~h ߬1qoPowKy9:R!Y᫮3UVc H{D[" KD*-/|>FSݼ[MmGl?UFu2< ]idF%7v@I[eLQa _+~6_d@ -[nt.x\iHGZ',X%+Pϭֈ-Wiql7Qt_zNN/;$=E:$W~Spǂu|TAv_^f&#ЙFt`gpI'XR~n2 z-OS$%yv3.Oy"u]NXm)VZvIUoobđ/纜9,OB5KMN\3l}*GRE6Eځ@sSw3첣l8;{*LRw[I=ȁAj!ghcֶ5GՓɯ\f¶ L\|pwdGnw6dкSpTFq2[䮎‡ 3ޡɝ+B7M7juS!Ul[\U(MІLUr>O]]9a27fݢ&Fjg')1+WYOĴy+McdX`'j4hwf|ປ'`jlbZ3FL*9S\P,mVGb˼m:_Mr-įevBWf],2")X^Y eYkũWu^=9h_YP5uf.wæ:S8Kڕi95Z]=팍_Kv&ߥqnϿ{QY,< C$m "`v c|2S7k5'n&R-pdv(΋MDh Szd}7T]z6{Latcu8-,[Y3dY+>1.:#dSET)5ϰ4o<2WueVc:m- c3a)Q) kC(:ϒ l[אug~ O({o$ ׇS0 @hGqxF_WI) kOd')+wRz fдNtoNC23Migku/VG!UJ~o14|}w^7Irra;p8 h}AImym?ʕsG Wv" lTߕ31hibz%U>zCm4]Skov9;$bs&EKa)8Y5R̮m_)\V r!N(*4dR|7**c)ċAu'[$mRĽ..[I%ᨍ z'*O6U)0 *JKnGI[%^c??؍ yop%:!{m0 '#61ѱ1oФLʱx$~Ȅ+޾D@gYHv`Rem+~k_ZSau{b 1hAOłruQ:o ZFzk@J\ dKYҚ;VSMqפ#^TkQN(:Y{"ZKX0T"f)U??"s%Ky; mՐښ$=sD7։y3S]7_"+sz|MOOX#;@G yԤ>ˍM;¨Y>ąғhY A5qeZH̐/ uhA=&ܺD+3w;(Cr@ {*"F^vaR?,>X6`_C*+؍j ήs\2t<-DѴ1h+#} *7,>okIv߾7I 73$Js٪Ң|dv )07lbd%QPOpY'4pwe`?Tﰍ"s8JƐ#quKb\q*2hR|PW ط[Jr3젓љB>6,Q.Bz#mN$gX d5K>-џw<(E{I176LOCO_,q #]t+% %5b/A^ܘn? Z<d=*Ս2{z@&lYvN VgibLF'3жV&!1/TN_/I`1Arʑ1҅&ûb<[ix)E>"ߎC;*Bnc4E݌@%س:N -Z4!^wи8|r 5!'_IDNk}aJDžu2y B`A Z8gs#y@cnGU&$e&4u0njJa$PU?ҩIT歴;1"uwOdEC CUb^P`i\yR:x<^W(18xltoUt_ȡԽƬgg)N~`/M/ReޱhAӨ{ A;ub!0F ~Apܮ MS~:[DZW2O- 2i^xB/vJ15j>rj#sl^D"B&QCIOj*u>E`Xq^k =0.Ym'G (SzOLC*ypR c;DhQ|a ~y͚5)(+Mx vJmļui0)1O[x9Q0Ox@}t{Y )F,+ʁ3&&ǒޯ{QCS=JA$55?Aa|>yKhZr~rnOaLnDt}8MɚQ!8i&v 5+1[K,Ƒ%7:l8 /4wdo B9D|fͪRʵz- 3Y@DG'13sSxs$}tEx Y 03u)rt MҸ@~5<; Uw*d/*kzl|ЋUrir% .G[aR˫RN( S#;6Rm{'iQY:Gtv*[!0_jWz#f+)=F/Dn+lZs'cCz" #[ڼ&>C6-6Gn͜sζ:+]i3kS(A'>dy~!RYȩ(pd,^Z􉜊5|ER\}]iY~KV u!Qy,5Qr |Jf4jCAYj#n?Y=i^hcv-[tOZѓcMĘOn32yeUs)e&$y}6N/$: wABɮä8+_gxVˣp@HK n֭4K$ |hPƱ<rݾђO빽E7-ӝA j qpu#t8^$;4hPgYH`#o^AYEb,J#zqݯQ7!6밟̡CY; onEӚRjwH?G7 F|Wuiօt$uYya dMezHH tDM+Hv.Nį%'=C̾MLrv_̡7XVXYݥ(Jo͖=M1?/UPu]E(|*oӚ;Qݦq10 v%:Vg(Κ 6p͉;C,Ulx`b#( NuW},JR6Z.!&I:NZ럪<)$AuDi*E ە}Xy|}9hϵpHWdK HYcu37:G9o3dqb\H 5zTnA~x”%ER48=bVNӁ zߚ&^!#!3Ot&u}EG<{%sĜoJ:6VS:k3Hܡ.lm0`2"㐠) G`kc}i栞yTa$1"U[Q8uYIVl^oLZ\.fuq! Grⅰ7ªʄXe(Yy˒cL`8DŽ!ߞ$$n0t o4!zV%Ej{E8}i p[c%sKfAf~&yG`݋E|v,N|AA. [kFTly^$}*xFT CR2 zMXeɠGj{2%9(RѾCxvfY4o2XSSY2m9l8E׿iigDkbôah p"(W Q =uLT$6/qpTj ɷ*]OYę`05#%piAe+.=v tHz>q.ϩ] ҼÂ!ݟ:cI qvSm" $+_Nw)OʌĂp~jN3zGZd D`h#D Qz݆t5kvyCFO]d  7΋GvNBnb2WU=mXX-np{pP:`h݃υ޴=5A6 ,ZG{lX1+\CK6rfe'%`DQ;goy'f=;/`.7:T31Ӟ]$#=mm+tRd<ϯmVn=ut\Uӟ֚Kg$Ȱ*-b r})q Ȱk`jB@"><>@ L2r*(]S =K:MSuR%$oՇSvǢ6QIXXJ-/%+_ ݫV&H `Tu%5잍)Nt47B"YaӆC]U(@sLբd i9T;]Ꭵ!0"ou`?ju"˪yp*<ԩ♊( _-Hl>ppM! dZR<)Sdq2m܊Z"oE88 3rF(6 kbS0fvu!gW Fd/|'mB {Ŧ)dQ R!5Ndy79Ǭ)1e)Z `&Dn25wn乸(wo3ɬt\Щr7V :kdv!qy&dtߢ" Y,)lj΍KlXPJ[35ܤƀ_–o:֏ >äsV߿pt|*kc.ϏP YUۏF 1"R[ :뀃jpZJG`McUNa)Z{߉%j`I6ydA/(ؑL:`I}yďE)%sdS,OW{O: 1#?X[ DC.lq7dO5doߧubC>TO;3G<43~?:gtumM |̩) pל|υUrBmYdw:B]ê B=]ѯLSqg/N?xJ{xQb^51;>sl=;1<t(gufúQn KaӦxMYl'YP16 t"xV*;aވ߹t-ϔ-UBRU)d1)4YcՖcRO'C[Sd<SzגS%Ī$1BWt!aXH.lя'_rf[K p ;Y~Wc*] 9_q}%BMEF8DRցDhqWč&ĭ%$j8 `p:IX̊EXP"mG&NfZn&?D+nMQЁYz%S|-\gN{M_5/FSO&gjp߻f|ߤypŸ~2 V8l-~Ǣ~`~/.I>38(.sP'`YzA\0@֣Kq2P's knPG(lCJzwxI8R )ڠ~lsWەGR[ӿy IvO6T錄P:dvnMRGZd9U4+x~$h@ɊwnWA0*bY:2,+D@cV' ,,_T$6(;CJc wy'DT9e%Nv 9."͜z $yiR!kf({|po"ȋD*kÜ&W%PىlW)D}5<1M"1UERlJàGNE#!'d ,r7UK~2"SB=cE?&G,\ss}Ty3c \^J$K~yrD*Cnl@ bзJxb Õ!N_cR3X,jy/y__*fiu@QlbЪجH7Ie:;uG(29M#;DGAҤ>OyׁJ\V$E/TD=p}74vK lק"΋ ;A!"徨bfĢQ;8Ǩ)iAu_JY<]^ݜ7dԅWū 0ڧ|0}M(QXP(« t f-3BzbW+rtd2d19[V7ȍ %:,CRm$fhKމNdg3w|\4:M/T"q071Xm4wjgz ,n =n| W7^ڰڭUnfz_82bix91r!ujX:Cpr_Z<8w4x+sfiє<./eȶ2L4X2ƓS<>+_~{Ry@\PG`uP 0]K TXg)XXuĔbҋ/$%$x@WmiGhx&Q-~Q}fS3*d7a鶏{p&o ۄb5 bW~.i])/}" ĥ pr䦺سF:Pϊj FdHHtI)ʾ8[7ʟqn^M]x / >dj+(__b2: Rޫ\DŁ![e lleE2޶D@n#˭rR,&!/[7F:!d}N%,l„+O)y񞋐ON -IWo;b80`%(+?撘%~ ا+"FtYR]Ș4F>>>nҢB*v% bwdy]oRW޼@" g,nNa >nIm5iBuf3r;1k(7b=ٳYSalVhWd/EǗ k_8 !}{o*y){p{MKXFH_mwsw *- =m0#g0`'px[M\^ p{Ran|pr-echCZ[f|0fHzQHT;7T4I~3>p%8GD2{+ rĸF}O'`ZJrsRZ:ɹ2iu6>9Xn'ݰg }.xC@:~a/KcBM&U-}Ȣ$*^I/ 8+'.껋фL7xsN EI.7Iٍu*x֞tEYaH^?&ņ]qdY%kwY>F/lB,,. +c paTo<@C%hADXZ"J}IC){ǰBŶ3#ђJ4M5] !kŚWqP@n' BnGci Bv N&찵ЇOWlظf no EʴVǧ HΩxYP<5<$sb:@F'LŐ9ǜx&,pNOQksPdg A?K+ S?P>Wu0 "ܰn "\%~luӈ#ҫƴЅпK$\%ΏϬPNC'Qf5e1׭.9Ec5$0@\=ZdU\%+4\9xG:LCChcL70K?%fP"IՐ(;(J$4Mr'I~2:*OwTȒF{5Nm%C}n""1wAs;N܃wMe_N^ -<>uz~xy#aT[qo߮ʿpQ+8Yv]m=}gp257 N@rĝyN9>˛gf2ٗÃ-䗔ȗ#/A.gҷ!+4榥dcA֙"rL\'Gګ= ( )Hviҝ;M\'Njoѷ0VW,Vͱ~܀aV$IHA~L[ z^uBs4FWӪrC|U[$g~5O^.$Fp1W\y-E-òN!_7?O.{T,(F2+[kuόR+y:o rՇG :/D  .7Nl$RhF#SgֽA  IGnhTn zlfE2{Y)/_'kYȮn{.Al!d y{šcT*eJ2۲Β'1#n.$gwz tReA'NƯ QN&o͍#Y/YlYڮsL[<`(1EEDuc\$*@E!C Ho )G>$~]|r, d%L<pg4+y5dM q:)}GZMlVT7 <ǐgp/aA.+hh-e0;ndgC~H1T7Vg?e "!"u]0: )R(x 2*U7fn}"H锩ܘ˪`{&bJN74Fil ,!lK 9X >YNpFؗς0HĽNj$k Q]Nx2ᑊ(ãKͰDpK_+Bn-Qq}i'tpˌ>VT5E⫸vR ٰB'%#<.ǻxa8%[魢+]]z*Ĉ^ߺ6Ykk'T;,Vvn“?qX*:>) y漨ۊO˪I#3Xd?It<}d9w>9a|<B 7YJ3U~"z4&"Gv3a dXT:/ͭs.0Kq/-O -"6yTмȚq`[^j=߃⾇ݷ9RAƽ)p# ,r+FT @=o^Qs-/ԥݧhXȧn2<2+- M'G1HBw2 !vR᛬?^ncnVvXUwymͷB]ѷ*OyXL͆ 4s\po)>}ɬ\d-w$:ƙ<_l, OJA,4Ҋ ԦWM䭏_6W\o>.3 #2fU~u%l͙Zq-US2v?G%>,M2BzAJIJ+)kOXDXg|8-Scsm^q}yy6{ 1ZQ0R;Q:4i,F*WQ*&eO$Ye1enV|+⹯.[HM#~ tqVeZ#$i#NR~'&`nzp\f%Ui1)ZӺk}ߤGCzrʶN4픈mb0`5$m'(MĖ ]5) t@yT†fy0E[U!rʳaJz t#x 9 {uU;鞧o^J[5@S yuܶG^]4[o2J[z\iq'F]W[&{jVk*7+\EݰB%jxhQ P.a'#ϔUkl$1GЋ ]Rڎ7!XO|#C@ Oվo3H2Gt|ڣ֢7Y Rv9q)G.&%iPs[ӄn.|_rsr߲!o@mS^iY|2âQ~nf,O<I%`!gLD.̦n{ $9v 3a z LYrlsWoҢJ`M,Am.ݗ6VY[G0\ӏF)moƇ |3s@YV"EX͡ s(R*H(JC_<I}>z2H'w .D;!Z~MzzUk^_eNB[Ȑs޲ ᑯbFԇȊLZo9)L)+zP̘#2ݺaUf;}%ڦ%Ҟ+׹qxyyT'xڏFke.daa'Plj?zyGiOm1W 太yY,^}phsHd id^tSv =HTb2}}(= O`x9bO'}'PYR7!h^2 }Y`;Gk xDvuY@|Sh| ]iX'9D,CIͳ*>QIAŠ8zyڈ{DlUuJbd mWMzJzɅqS;,;D9D<"'|?3Gv TP3]No<(R;+;s-O+*=/2/tƙVvr1c8DbܖWk.]%R8[FK *3IC/4#5̼<9bdw9K2oU.V@'[[6DrVohG}U)qSA@&l9Kdtddda5t̛2pě9=!7$[*hx]5wŌ}rX˶II۽"LĿUWr:CoU~t,Sg>}^@6FєN^ m%h#ﵑ@(%$B2NR(O8IAXKA!83d,}tnȶ&o d_&!~ȓN/ aܒ%9Ē pZIRFz I%)!=mtJIb ?0 8gg`B\puWEQc]N9c}Lql+xReY4ӼaTO#Eʐơ>TzUk@m]>'?5w h9P̒!f^Z.˚0pѸٵ_d$2#ijv(S 4,3k׵8n4@NJmq14D[fwk vhx,}%0wl}j"UjMj0L".,+0儬/<*YyҚY8 zEf,%FT# I7jA-^z#b@DC"nYnIe+Nj67 `I .ksL [T5+0z $V{RpY¼ǫ^m2!MU(?`AEg[%+34DNڲ~'Y= uSnҽΡ\I4JZޚy~uqAO}"Fas'uN6ta-eeN's? ,*N8NIǽ'\!d ]0BI;,)8iB ;߾}Zq/ t]mwb_ fde ?aDQ>-BT)\B57_ゔU_>z3]m^^ ɨoET_%eK݀z~ :V&8)[@@ѭ"U:UIc/-/TPkDh{#1+ѿh@T!Ykk2J^>"<!;ϸ.[FE8mnJrMZ\^{\TRV$jSVM) S5,n&r}]K̳~'k7b3%>-&ێ40uƢJġKF)WWiG9x܍T :CtU:bk %zŞx[xq\^yJqV9Y?J'#C_e[ȄEёOfq$Q]ڣbq>-;Ow#V_j b) Å\f9ŁrҸGP_ Ʉa3lLz”K߂!lQr5jY)AWEcl;F6,)B4gPr"VDeeQy##gs=#\™.Y:뙽1Gmo `7@7tI8A~E*:}۩vSࣼD{^&MG9BtO֞-rWlQWFO"]<]SEO<~»cA@wDzQId*ZEU8L{`y6)_#`ڦw;^z=eU`ٶ݂=,+">eJ[1Ӕ-$<]Aךdbpgy6A~+B ѭѴeUnKӇ" "UE)Jɉ<5KR^+MW{v$erp6a-mpŸJn^&*>$,A1(a%ѢaV5r4+O $QJK^J~7 %x`߽@ER C %Hw8ȷ(QBf˴rT_ 8X EiıOVފ'/{>UHٮ)Dcen\x/ (u[,EIJԈSn3hN@*m/QzVgX 2B ajP 5bT[9.<q-6Un;3ե>;#u{Sէw79_Gq(c 9QjyC{_θ< fnݔߏ^r֔:#TY5e/ymY^G@Y z>9t>d[BW;+y5t yPY!ks!Z ûkglD4Mc?aIaU+cT].dfǡSvGI).]\G9gp8g¼=/1_3RB9,R]K9N9z|)sT=)R}#@)K諏`KA TlQSR}r^ WpSߔ,[ 7" 7^]X_b {ek{7bnA W>3!q5beU>eazD4L*,S.yònmݱB uqbH'JdM)|i,gC>qAO[l Mh4xml9 AO#6enfgzF#Y~$rW'bZԶCJ9HPy$z潏s^ZssҜU0g9\ﲖUَʤDǐU]1#dؒffed|~XVVg7O445>YNcR`5d;]Sƪ)e׼Qzn(d2Zr"*!J9iY$mUcc eXmyUPqj2/dj}샚,MT2-;N(* 6磌sVX=FŴ^Mr'yѦY#9KT~EkZ!`  cFsjimyRV1>I^ЙB_L텿w x&o=L_bvh(:ҲF\BrUj8KaҠU`@ c0 ^hˆyk0]ز4,o&9:¾ {]^fm"#37GLa91Ɋ;Kt*̑~B(4OO!G 5W ک<-[V~OD$S{ts:UGm(nnI奃T~e3/ (U%ܔLW]B)\z}걀?&OGM{ a4EfO?׾3R79Ĥt6nIv5@[ !e!~+oPJ`h $u 5 I}EY8wmR)M,QB-IK9v\2U` (=ZhZ<:t v1MFzG 4A%ԉU`ggltWhP!X{P[TJpVIG&ݔ]݂[T]}QBDԎ'14CṣD HsPh8 eִJgqX{/dWJ[tƫ˩OvWVbt<'iZH4AUeHQ.? hޫG>,jǞ?#|c>Oh#z O]cWdҕ僡tnQZuVVfC# %ZwWpO<+eȇ$**KDNH( @,o2XB-l*}mZ UӶ->?WW兹HCᴒfzjDSҞ۔ߺ&ҹ#H׳ U6cJh (440m2R p8h3NVPI4ԯ@]jdo)2 Qwxmo5[vp]xw|& b#w: g\ RXH )hcOXBQ(p.`K-~BSXC8A_o]4}kb g"OZ"]<#UC~ʑep.ijޕ bh̹4t*cB$=N$7aY0 xiv"uO 6n^?lx՘nXNR#CEhB,P:A5a,Z.Ux49ysB1't>z5Ĉ"C3 I/L4,O# 52 bԋK|2#G7,|\ 1ĭ]L1K#YÇFr僝ݲ|;^qg P/ʞ浹F~dns :ǝ*w'\NaهhyЬ\EĄ;QY71\c2>K | 7 AcΑ7yUX; C 3a(iLzƒn?.Aʲɒ,%`o J&Rש<2o:h}5 Ddz>Yկ*B"E7邛b}2> ۤVb<=uCؤW6 [~xF/oZZ-.*BZoi/qk'DOy3svZnjK:€a9J:^M9^TՎGai<_"-@ԥkЉ/ff_턠XX7'H|UZ}3q182`%'X}ZY*,1,i1DMO=u.fv'ʳGTutZQV\*']qQ|d2IL_qY4+ѝ7ka;5/>pjU dEg8P rB`;jec2J.#%.^8Ϭ&+JN(Ęp8qgmKjT T.xjg`g' .r5)k0)1`Lm=>,{3F!ctpSF<3[CxWyrbYso,ZצbI65TT-zV~?مcAngVcdM+z>8fR'\˱-j`x3+ᢾҷuWѷn!8Lq|Lh-#Z+J[6Û=Ӷnʭr@` d#>0QR`G{Շު7?A#ȏ՜ix~mo. uy{ֵ+wmnSzNuH.b1r>LxCn愵reg}הaL5Ib@/*( _9ImgCU][ĝ+ƨԼJX#;gF7;X#N tL\c2v6uWF׉@}ZbuwТuXu/%[&S e_Phgs=y eb-$D=i>iIFF-*h-L\V*OXf4%bL,4t.c'o"vxu.CqIsL MON QTTWϟxV S{#>=م):A@qnf@ڇkvHRC]O?(,I}QUTV%cV J(zKca>RԉS'&%ԥ@"\_򢬶Qrl2tZ0:bY.[5HDg/Xl?=+D)wme[̼s1?7_~ZC^>3BY*[#/= 걮ayӭ%,/\6ɃV?|;ݹʶւ*[ryze#14Sb&8'PKw A`ZSwOWqJ O*jLM&rAyV{בkc)͡経C"wjTz 0ĽHu 6}^bիnXϓD ܅r3@ڳ&3!JxVvl2G)tdxk~azу@]QsիXdnXf/Fج:H?qsBl##G#9Fؿ#M_P~|I۞7e2ZB鄻TXD)bi20b< C!8YC+fBzC$!PJz/B/y'!D`/ht0ht0h dH7;me5$hg \ ,EGj\VᕊNKf4EilWW'魻Un +ne5|}+ CԆSu_ЫzwsFW-˅ԍylBy'xN0w䋆WO,Q,+}aڍ/ PJ6Y;mzHnX噜hC1" b򕔽ˤhKDX)+7&zI7M7_wrC U>}s,z"ȟzhoyKU~5J*,s6U+^מ;Ng1C)6nϑͿd1XVwbFҩ?jm^ND'm]@#߷ttUz;ɫ䜴&WUUVC"RvXDk^'Ze6g„mJ"ϣmBY6=ר'>bf=IګoVP^}SA2vorMOѭ'ӕ`zRi&Z>H` >%vCbhFxBjaPٿJRf*;,TJ۳R9W۷ O/jWE"3o;[ځ4xp" 2VLwc V6RBe.(z ^u޹7;lFN9)cx:TδWUdS a*Α!5&:X}YVakmKMnߘWd3QOJg 6V3$9C#Mi!^#=uѰX~Ȏttր @⡂* ZήXJlF Bw3;!"(xĐi{P4ǻdDxƎ4D=|W/X,TP*e#O=TOMRYX}&~`V¸J%Q7JepD$ElQځ|S¾1V:p1sYBEDB:e_-J!UFx-%3OvXU32Q?eoƐI؊[$N@]Bc\A0z?HnwqO.'tҰ9ݭ ]/+>Wi֔Ս>&x|RneLC/eVtYRKWyë[LsG_!ɕNS䘂羔I2K}LbФ)V ֿl'^j:߲/C0M:#"M3cB1 {`;h&8/N~ԻD3߉"svm#0WV7Ze WѯqP2C'3"+g68x u$&6}Tvg=KaoƶYfǔsV5=7× 2zd=gy'~*s4FۗUw)l j{@ o2*++"TV7+Ofz7 M.8ˇ(+dÐ 5 ˬ`1̚>cYVٖ{2QN+ Jzyv)&k0fV;d ?Jj'= Ӯ׼nH^xíEl5+X+(ƚNy"Iew遉wlSƑa8:ae"FX)՝lG?6a72^/&fɲ#'>pPފVfXTRG.O brBaʡ~ pTb/x ecx|,_?YD*/窦,D}Zq6zpWe1if֤/Ia׸Gc./82!DIGa^bGtZ ҰczOA/EN/US^5S.I6 17Lo-kS̴L)7]2 ( a U;B^T P4HʆNM]7wT.ɝ>$拋;*>OWF6C׬oߔԀ-Lr嘡ַz$]E_rVbͨ^wuZfӲ-L4*ß带'ٖ0mX`<8Sw,h. ``ݸ~"0ȶvUI es}6y(ƲM>:4ۃݘm*,e,nAw,OyO{:jZk &9"ng_'Hemom{70*uOՠ~P@X?e7reGq|p!bXk<pQ!'3XČ}@W1(8I7*IB)KHK 8% -э|"+wu}ݹ)y³]u&r,x9>F߷Wyp.i6evߊer xr78qީ*=^͍Q󭠘ˇO<+^kV<Gu"b5a*Ӷn-V-_oْW*'ΦS1YUN5Tzy`y'4cnDyd8BF@!F&IHo*&j(o.lپ&CB2+k^M7C&Mn:iEVbe(Y­Hp+8xăs⑎G<%Nނ=s 1m/ƒ-/ɹu t.xvJ1ej@w}J'g'}{'Iʝt[%r9S&d5+1:)#|n|XFOy%E$LIʚˋ;]WijD)Rf/{3>4@V)˸ݥA4Fж W*YbIO; TOXq=y33_N8+F+_\z] D^?N_5WXoq@qMgPc#RTF1^F46jl㴏ٸg;N=h-Ш>R (t*MLz^<6їח<^xUvkY;S0<}^>gA>0^d)԰/?Y mxUS!UGm6bЌO[y5`++6]b֚oxXhZZ(wn^^v2Crބ|WV  wCk }իOrll'V٩^7Q((sY YVd&2\1*T,J_6hC*VOG*.ғ(Ըx0V}7`cޭHSRbUV}qGz0?Ho5&5-ƅOHs^@:shjvS_햭pɞd| +HjP,&cW9J$~_QCXcCp皧[5wL,b Yk,7&Sc$1MFbbZT:45~£O,siN?XʹaE"VskȟƤ&ֲ <`O'M nyf(D*y:y6`gmw.Ǭ`{7 Ej5ءQzJ/ [mU3*'2'XȈ~iƃՖc\ 6kӎs5tzgi 3 =EP_amrdowd'*\n)[WTPbyVt-9&2RJbD,{y!e8VwJ{,.$ޓBsx3d d }E!>RB`>AsxcqLsX7;2j]x|jftP?6[agl)/w)< Jx81=v7Kp>+(GյYewF?$cw(dRCLej񇮪DZ^[z]=]eIyE2 c\17Ӷnm8)O w$cgF`wcy\~+k?Q!..[n ew"k7"@ϨkOAGQ=k[&.~RQpT@L @b)^؜S Fӯ"@y:U  =-\EB|*D)e&IXk2P␎B$H4,tAGzCh>O9.B;K!WbܑA DŽr208%hqQjm/;86 IG.cӈ+vv)9o`udaϗLkM#!" :BMl LʭŨicQƭca')ƲWpAAߜ%ZT8;)<}q Id=-FJZBbi~{内BRUװ־ڕ ;B NIYxK `:\n~*!cw9p0!'W|e+R9[YUn=A tou ԋLqI{9@:oE~l/zі2"{w`W;EM91`?'XVx qJ"Ƒ0'*aLAM;7ED8a, 14M ˭(Ő˴3X8:gh@wh=Ca/w.E&18hP[^޹ Z"{DgN .ʽ?YP?0בy5DJY^_!6k J BTR=j:)83?%B^wWH{"A*s{'?2|r$Gr:0N9BZDDB86FY7zGDyx@?DA6Kq7Y8 Ya_BZX$)h22Ls#('UZITKh)@)ꒉ`27F #IAP '`XYfࠠm<N&ҶDlPCB"a7Ç/A(k\/J-@LP%R"7~C<҆Z {oE+&$Z晨+!wgOyS_(3`ԭk~ݱ~}'pw@MΒ8(-c*&4E,$,v+|;:ip-z: Fdyd\$TW*p* uYE@u{{Bk4p-W< vo$ )E8 dOMڍ{U4#+ ibYGPQi bxG9EYeYf zx8-XFs=}eIa$Ηdv!] 0>X *P~ѾFM`$K>ytl̄0e@Vp^0rxn jFSH; n(=^G!X*vZQI0`9UF#L)Z2N F.ꮘUڹuAbA;?U rI>|(FjuB|c[oiI[0S^^Q-gKY>NeO`(*8 ]쉀~Q^MG?4 $jKdN gtV U H7+ρjkަSϽL!C^ \#vTRB-ikytgP{{ =$<)lnN;,'YYS8oYYFt4 ZМ!'nB&[Z|gloEJ-`xQU ){H9G.Bʣ[ÉFLIBi%BHޔyx \:klɞ$p?;-Uޔ:]VPlv6q^fv?ӢGq2oi8z`&X[\yԀջ<SFcg-I#!I.쁺d4He(vT(hd9DO[Tm _nщIsв,ak`F87܈EWU^}:D ҳl >P⩙P\1|-ﳼ ҜM$l(@ VGUe KZ(f4J(XeK90﹬7o:?7iuy?SG^Qo85uGސbcğ4fX`hOBK'dž"I'9I%{e2`2q*uHSAӗwFc'6@g}׭w_EfjG'5_gp'qPhZ^Kݡ1b.eP5I6TPYt*r/5ZهadgGqe8>xõEQ ξeN8_[}sHViKgmIg sGH;Txv捼 Tzon+hT?"EM7dz i;?LݛD)u~">`@u7fu ,ი0)_kli)mKtW'&X2ө_MftP[ve* ́F܎S֝Hz+} aT  "!Oj丽? nOdI^|YeCWoWtEGUOƒ]v+ Q@5|&Uj;,%G5oPθѮÆ{u% EXC9Soʿosg;876RzJ"V;E pvKzϝ%ǹF9 MFE/!j_Qh%XrU3A8{ДԠ)sx{p'tg κ }8R7g8Z<мsWR\^E>H(W {ۯK;TAddv=)ϓe9]°bu Z5 ;OpIgׂ?rNv !tr}ڳ&Dn8F #*gwR*8(+`#!@HtuC Llg &koE'9@9)_#zCQ|EԌ3|}I jR  ^<UM"!Y[@_2~ {$ܷ1e2)di\GURvoϵW;V{Ni NJׂd>\:m Ӈ:Vh>E|u̮ B}^(I3'?xA 7I()+F`:X}C#njecHcJݝKXOK$ AI\`~I JzQ?'<0]74%Q(h/$AY9SIC;Y0/PdK;!9d|Ld)= I6F%eyۖ!MtN&X!P* 5FUm4)-{V[y׃$'*mdIZLОTZm7 Sv"2R}`s.ETckT;0H;wҚ(ڎUkp_uhBOPhރuWkq@;5-a_aFZRZ*s𗡎SOK7(i'"42-1?yfB]PQ-D9JRqK{rVԼzO2/jˬu#!ƺy3''8W(e?;Μ +4O ('ì=P`Y<|#~{ b r gtE)C]o$.c;k) ćWS{@9:@GT^S"r>ͭIH[xr)qD:&S:B^z~0movԧC'Q(ݡp4>*caKdJ' 4uL6ڢPTq,@ @Y8c&1_!hz. ޱ@`kY!LDgۅT–@z$Q&/dKabq*Jщ'-PE915x; SJںg[ ^ka6\`xwH_Dō[,K0f`qi^qaP /Qb^d@I~G'-n*G0L)qNI3J|iQ|*H\EM ZLNoJ6q0m-7Guާl İQ I&2y<Ă뚬#egIDQ ! 532OY^9#tH]ϿO's(@ۛݥ;rtZn>|ՕոIIrwm q ̑؛7 =I/V2w!FωKrOȗa³WhbFqN}-E8VSpb'OF;IT n'zi2a*+*+X>i2uȔM.cEU1,BS2Bugck5f1ZK!'r^8PD=v'dNRuO ~0ҝ.bfu5Vg y.čӆ4gu-3:&`$Ə>hCihJi,Zŷ1iAm^)H2Zð$i,!ScPLpoߚW=al=ܪBsǑ:aL33/clȑp99 v.E89x 1)pr+!b)@ rRI:%Vnü Oǿ *Hzv̚g$#/WUUVn ۚQޥKgbԤ$g@O4ќȔBɄ L'~mya5*uJekQEX CoSaKL:P$Y/NžmhGIִ/ſv, 3X.jk,ǜA ^ WB0m&~):UtnB@nXn_)79@)1/J3 -(?ih1mI]4l5]fD[~#Ҋ쾥 d l1<`ޏWTBy&,)CbIޞ%H/o󷛬eIIK62"'vG:GsaG\M6jV|lSNnv2Uc*h2Yybr‹~7|KDߤlL>=Ιk0odڴo}eYHjwq141E_U__Ye|̀{paa ѱծē,(N MO*֣졦;JqBĞnXaѧHE)f^$y[g`(i6GX VC)ŪRmoMЖWS^NyWhXd,#t7n=D6LOs?ks' WެA;.9ˊ,@$+COEpm7ZmYDmwޙщ[6}=!ՍA_ uֹCV|HVヱ|: $֫hv*ķߔ ˳߃i~>dES̈́ ^@¬޶eɑi/];+,5F,w.0lY-/w,ǓVIYFj_X,b* o%j}<*Hռ,浸XBIEy׏Lrӟ0.bRG+A3qq}#>FVb#ᔏujpfQYXJ? (}YEh{Q)ISyM,nz[E&V ,̋ʊE #~D=x J'=3hl7V.Ezw>(h|&lugloF5O{$S;xjqk栔vȤ=uR-F9!H.' )nEb:]0,fªh!O05t:a9c0Xy`@c wUʝWVǝ4jX{1,g^/ڦW7T{U;iL 1g"FFAa)++ sD ]A֔[݊'eMڈq2=X'bGV;'e C#0QrTw$,o{͛#(o)ϊ55۶[ﲖYVܷV&eE(QQ$Vi-;֨/׍l#5x); ¼3$Si6=lA3N?$9g?*z>wc%BLL4c=O><0ݙyfm#fnkp+BV#JX:# \sD̓Tʼ`2 6ٰ eeT}5"n ycv]8&5VBX%,A:wP@/E9 @*0"{=Sf*[ovW #Iz5k C>9FiԴd=bD n^c1]Nӈ e)bђ|pmeJz ǜPk`| E#X*3A PC~DQ#[Zn$9>Vt0tcpmf".tcY6rknu?j.VVsҴtQ>@pRY |psQ:9>F8'3:0C=HcϧOg9&N똡қαF !{TY*P`5Կyšd3C_c> {y(\* L.E@c9Djp 5S5Ĉˇ:C9v89zHǩ:Rd\ e!b^#."psM: u`:B`BN% `j?BH[76wpC6t⁤3ob7 +U'!dȤ8p:@HI> 3p)07~%1;DM8pdHCGQrxkHc|1ЩPA;$F.cp@%RIDN"l>)!C y爷'TAwu-˝ ™VHyrJ` Iq2D"b[Ob*3oO")Ua"ؠCw&M̒7Rޘ{wECJC:LD ma)Y,Xu yt֝Tr P@SA _P@ſy=%aja`4誀| hA[^mNʓu',ڹ˾^AgGE|,ٹE'8Ce6;fgr" >4L0 K?&2;zgia{jvJT.4k>|ǫ_,O0[_}m-IYumU:cjioj0N ]KoX<ǒ[hZ)ݝ0(ܲ܂Hxe1V^<УҐH?'Կv1i_6=B$Aę Cf2[8/{4!_ в٧BJRSQ3ܞLH!2*k!>[+RffS@88H}?6 95?qF d:Kb=pqJO2)ɱVI=ܮf[_X>dЋ_"p`nfYՊ14`tHь;`lp:m)Glz%nr`ܶ~֯VbZTpR ?S>N ۛIg_w#9';g8* E/=s9CאKxenDo FqkKE{1!dJCLJB+-e%w2m<|M{U Ԣ7h1M`TT l(VoEj2=q2FK=y^xOC~/o4'4z*-k&e TW R.HZ4,u,Ld;7y0%sݿ8SJ@sBjTQ]7cCG%oVAB$.*$71~Wȿ1( @ޕb  wqMeD}lTFcFݗ )j`z$(k\gIq+SI6 #̙0Ao!c6mom&z}^PUM9(SJ==qugt*Esn`W% BߤM)fx&j'%8m+l'aēCj]븷 s[kByE: +{icg#BE}Wp}!C*:Zu/)!B\-h:/D@{b Z\=ţdn_1Bo(7oRVV!ӥԻ0;BRrK/ԘN8Ҿ+ꫦ΄E9O0RD]! 7YZګyJNs{jV;#+<`$SiΫ_xaghFwQOOv}y*hy}l^>d/\1S5fe;y%nW NpCFc":1.+bdB̘&G7Z+)u-@>|w; *H ,#dB]Q.U`N [j Y4}?sXOϔ| n!r$s`kPEzf|K;K񊆡+?0pZ^}zn3s]!bY[FrtR%jtޯ {ߎ~8F  C&5:\9M5;7YYߟ!0FʃEƠm%2PwY2y3"0~c$K){7d04D`;ܗJ/:+:yT{k QѼyHA2k@0ޤo& TZm~K6*ٷ,-Y7ƲEe{=Ue 0淖M8)"%>XAmC&L?3.pK}5ܗnXD Dx# &lwyՋXv1&сP895)@T7c'Utwp6v%! ِb~ɫD,-v"dU`FN;OO[m';61LXދVT-5tv_dEmICY5evmR'E)jU(̟TClm1Ue SC m#硻=ߕz8T{TҗWB-e.rL,9bߝJEP:=C}7UxywXX tA;s0,"t֏1`Q頄eMPN`@9v[>g9z%" !V[f HY`Eh5 `vBd}+N)XRNMJxTqd:{K)ah]m<)Ǘ쿠, {JzoP!)O[UE*t䅟FN2F8Czlc xOiK*6- )礦4P\jF T\i()Gda dӐNhb Ul_I9KV5=-tm.)oؖ&A|*4+[Wyl4Z;;h9~/Afe)}nOOYtJƏ UQF#FƪC]1UϋWIkz\,ډhz]{X@-!*X/4 HXE-/'m!UzaL%Hjcʭ7>HuBa۝ ЅАJ&?pO*O4ؾd,*H2}l{&b:6o2/1gw8EEx)h]FχnZJBPܡMFф˛,U6-ZІס$ߩeWNXdNYFjNHGm zV maÎZ?ޑ YR`NwNvQЎ9('8H09n@#NqM'dE'K^cQ"᱌M:c(@#1'"P ޹*Vt섑ju4 ?!FpWV\p5I%^$Q/9K6reMP7eƉ 9z ݨ^䤑NR< "o"yh Y'w@;ɅƊ׵Yݵrw垧o! +m[/L:pMbV Vo3iY4Uey%o?/\>N;+Rx,|<^yQ塣ctNQzS<]Cr]q[|VkX<;zTK}zd袁K]tea Xj:XiW q2&( ЊoEI ]=%z$L0Gݞ>]Gv Szn3s^7A#:L۬Hyu]Azb7*Z;/>}4b/$1˅{TޥsEuv?*tjcu|zWztS߃x 6+CDÂ@1Fi$=.+^yHكwLld6XWĜiJr얇wwc^@{I)=MZ \ znѼrD^PBV.B_ׂ\K>b'񝦤Ppy%=w\Uƪg;njW<]կ1Yi6SH:_]e,~C8U m(XSuuwL ^udNX;h!sWIW2XU摩v9`zn9R#7OŠ޷j{VVellǫlu ^eM|f80*~?V؟2E5vu8F߭mU~F ht{G&gD\esaϋE1H׬H1YM*D1]?tǩ|=S;2=mS^\ ՛?"\BhJ5sX@8W " YL ,%^zi[ɈEY41Dv2nO@`qj4JOb{B&lmLF văI*۲meI(im#wO׳{3שj'Fi$Cd%a];Sԥpo(.iqx/s_\9%Ȋ /=C"(T@D^,Xpo,ugm:lA`}5/rLIتg2Za%~i.,cF ]Q~bt*w+\@ľ>#>RZx`zwsyd۬A=̵lw!/?eEv "$g1O;y'p8`l=AN1l|n,z6au:A_ࢻ򻝪<|ׄ) Oi,"g?P DfnlbڸsPJj4uJn$)sZ u-mYI13A\gtt%D#X2H{Tx8(X?ͻC` Hx8!pk?2Sj)ֱdc.E!E}8CYIhxoۡ3S=ic;oe{Oͯ͸UEfMw(I9V*@ɟzOӀA/Qi|`>q[dԌ,^|dHs6Gde[`9AZfLpZ9=@K7'Z;r"M+nP*N& ij84NeXkc<1:X%|d^}ۚopZLs+PXv$Ȋ^n%Hʭ[,HTZnXHƮF(YwwuQ0>; * YŸvX\L?oW oՄ5 j,Wgv̿\}7./JΠ!Xg{ D)ѵ~p*bC/TGx#f zMq f}a0q[>\|^q,qPDk.訢 WcwPǠ~8SGeb+T]!hQ{#Ѕf:(t֪= ."S[{lU5Syw;& C\h{w输X5bbsVWU^Uv셫;Hv ^c %kM~WQ+>>/ S, 'mKSA L}ekÑϺjĒs?~jok|Y8&m2c6dgzl nqH"\2ϱ nsv&A+^d uZI[+V4QBFD;V\)ύ=d-I]}mAxϿŒt0hڬ{=(ƶ*1hZy4rHצL!+Ӈޢ= +!L8p0,I*oKZeD>yV57[hm=҉WN7,k1GP&L^!%?]F^t^t7^ްGfQQ\̼3j ai fM&ڃt w>a;ܚ&bƃT1 l/].# ̂%1o߰Ho8i\$Ee`j-5;p >_r;Ցefn+r`gʘt ,<ݑRfwt %<E( x =S|,*QC7q S,-p`E-5(Ҫ2Bm6@36rƕ2mGnӌg|*wyuC2浙Z@qhj›%ЂH?9Վ6Ab0Y q]e|u8wGI ׹S'?;pM]mypAd#<3jf|5Ϯ?vt:b!e[U5aZB SעK;p7)uݚrY񗘰?ӎw~RדݝS3i 6YVcdMۨ6|zd_([j3=QMPS3Tt^dʾTݾ)ip>-|brk`x@ެ$ KzM 6 (̗pἥ`CVt}s}Xw%\JVزXO)Y:a”OA )n>J(Sg:]m{Uf:)\zR_)Qx_֦*[?4j꾪5JjP2Ԓ){ZbmԅFX }bO‚öyטp4$cYLz9:a@O5G ׶|N:4獜|)vуl"UϽȻh^k_s,Jd:qjPrlR}Cw :6P#\ 5,[p㍚`9~[-%,Vc ] uBB_ҏBB&\N,oY9f ^Xľyo:1=N zӫDB]HյNRHŞ8ޒN 3Q'V "SrYYD[P.Dp<6?G.;V57nkVue•乯JFILy>euŒK/ >eu)':ZyL׿ c=CY:N3{~hPjQ0H kq\hn8u30rl CG,ݒfmVx!wS\m$rh-VB%4:+ݴ1ӊ;cOfף$ܵHnpnnԞ(\w:Lg {?u'PB2+9&?cO^f ?9?ɑ~ō=(XNnCN^е~3qq$LΠ S$w m9$#Pfs(KN+uE ђ?5痐.˿oa\ pEqV,O99vHgngJ"'ʏQ褬c;),}5l:oh mWP4 Js場x$.~aq](Ę3fvPgW J3v$.V9Z:+wZ9ͻ<x;'?q{Qٖ>иp8YrFk+`@Đ#5YK>Rۻ1`#/1:C8]Ç$nEsC Nq93*+zG ReDֵobvxB 8Gvkߘ2Z;-,㚟odX6`ݏLu(1NDɤQɈF|c;7Px"L?0nWv&X*aw/u^g ̳ȪdC6ZDh ZtIFysO)S{񾋖w$8笮'7"$vNNgU}۝˔օ1BP {JJտЃ)끕s/ڼv6$5oy-Q]`hM5PSk^-A8oz<-R$AfU(¤|\}E{xWh}WKAXl[ ;{x>9-h O!KF;fidYJE%Z[y%*gG-!$ K;.I2y!&'KHruT,Z:" AMTq'd߫q=4ږ6d\~ISP4rFuAz[VL =L,t ꋰ,޶e[5{q3&_y_c{X'C|~h'JřU OW#-ı J}xyэ]eXQ?g%x(`G:ԙ>y_B>V)r}LPT+ln&K TT=H&uSn߹ǎ#YHR%!bpIZl09HMi]V:HkSZ>G >X(YL}Em!T~*eSVӭoWpZe@R(q=P/q~ 5ɷbDhh 419R )JC144_եu- 6pm5o&ߌxUX3i,Xp+#V5PslglQ7bɍTKǪߖiV>".Ԍ>*kK"ID} 4,2',#f>?Jsٍ0*Kq[0{YpCKa`QL(b)  ձ`ΑAZyv9L,!5Ĵs |Vd+k7€P| sX U},y:b84I,̻$$W<7m飑amZfiϻX%t%ZBb*^lJXh $&Gsj5DxmrR"9K<#44k 7_ oY 43=lOJRDϽ^tR5-\~$KO.´Dk@ζj_S0ٔ%LS=D/17fp`u^>\{ÍCWo1=Ĵ,Xϰ/e'7+Gھ-[^Y~(}ڎm(.^ x? P>Q[|OQye!FR/%%z#ETE?R (zg(/!?\V)/*+ ͟> #dSsẊ)??@/1+ҿoM>Uqɓppr\?>ޒ_k}O$V,c=5H0GuW9ްv,-ÊDY׃^b]^qY;ƪ l]p5716^M`A`~ի0h2rbQGHT-KugIlߑ0xf?<ᢐABx^u8zSB$$>zC.e$b$:4>P0ZJ/k~|F6Q˸:8G_s!ah(ݖ T}`m;(gD>hF Pl2$'(&'z @`}lh\e]/bd:]ksw'QPc)qþ bX>}E Gq:䔡 ?d0BL}ŶqS3 YI/M# Q^m "ohL&\L9K81ݤUD+ kR2!Ȱ"RՉr}Ŀ*祐=#+nY feQt%PʗGby_4B&"ɤ)f:"T\eLXY~Fa}D&A]_+%T*@W#CȓwU@I!@nMmB5p%&LB_<lӟջ,P?[o/ز/,MNҞt1|.b6 ŐzVbD@ VsP5{*ޅPښ+L{~3os(tU$ۮJ9z+`?VU'w-$iǑ2]f@\`NS)QO%$ Grt3䥈|_Cړ5YwF()Ȋ̾hR_G-YK*ryG"L\{Jj&5XWV󋴹OHs7r?֘H\l22ɔ8v2OGMܾIX)ܵAN޴2doK36ADW^YE[YݟJh[ߖE?+(z L7N q,w1-&o~tea9]򟫌dͶHKUŪd%,QXZPT]"]P_4uevKy7Xw,#yOHAqMyM9Qwr{?#PCK24t8ё=#Dg(qGѡâ_ш!5= Ȼ@ܿ%Po%x? mKq@!&8`оkZ;JybURx.KXJWh ٛ281"iL˜eL0!"@ }sX36) $. sÞ n^ڿQg_Fn{@0 aQ}V_Q MboLt  h#8=C}>Kh/.*ȘW 齖g ]oU0u3߹N[ڒO/ΌъB?>id/J4췫WQ5 WCki,Fd8ľKun!l<_y9󒗡?<֑]==q;&HO7jT o94,R!ںQ ֵ`VHDQRCe zh&],޺>}ao "N.0o}:\r$X2-_TlSNM͸HtkS*HXvjQh*-mpeQnR_冯Ym[ݚd/௡o1"ee| ڈYrup_y EGCЭM79{ Q#-zB)=2*te+K+rm;wXo)NC*}RW3=%06jF&ׁXvCwMU<.ui߷&MYt^X pbTB1t{\rT+UW]^q~"‡jwrkY(g!vg1iV`$5144W/Or>6˫J _dr|z(Ѹ5o䵀0nX@\`ȧ@_\/PNBע/'BAfEvMY XK)q45AN3~cyb- ,%<7|b*!XnP4qCӉ[N[:a/@cU7<;P8>kwӪYwZn{(OݓJJ=<57*+uMkw4SJLr{RP 8Uل<GZ sfv1qgR/8}^9RvrL%v]L$K̩z%R+:t1DH9,j5QQ^:5bReMVo"f/k.7nJD1E$۲y =6o5۶ +/[`u4)-KMn)uԾ$zY(K4o C?64ti^N#s-]JV r4U)죿 @R-J廁^D2/¡E,F+a1C_Gm&ks|*;Yȼ?ym@X{k 7)7|,W ގh a̫2 2%h V?WG?PpO>/Q(GEPQ((LGQ}^G.O|9$Pp ǃ >(H@R1"oH@hC!mp66@4=jVVw/] p=I6:ڭ"wkex.RZR)_AQnY $dH9tXe홱Dm$:l]՛L^@ |#YVY!cbveQ ,6aüViX0ㅼd>=e0=cQw lJFGQGxC\{' ͫ*W2W-n\x02E=xdOR sw1aU@T<تM*vZI-C %䞰ow@Ȼ,\Q>M2yC-Πɛ )xXQ3|ѮWo52tAƎ=x ѵypdԦº@)x uCCg}GhN͋ :^V*OT'i/4yԞ JGQNOٺlKw 'Rw/}G*DWI-y[\h]Ҹר,j,/<Ͼ+ 1[cBWܾ p È~q9dBk=Và$C823]TwT!~{y #=9i+<` ^4vrRtػM^@G)T4Eʅu۩4I^&PqzoJK(lr<] [Rը)_Q8?J4gLEU(}`ygMW8dX4-j*B Cst@QF1blIo-S 025XR,z֎e-r[-tYeP:yؾ. dx3%(05K!Z.1 D"(ζ0LRńDςPݫӾ9t]J*-hȬN">#ЉY!5%E6Rdi mӴtcf{ن(,}cJ!M kTzT93!?Y.ou{o[inW笲ߏҜjL&u>K]AYm&AZYd;Omlf>bYA,{ot~Gr6e[ 5Jª SձPYȼ)VPj.RqAm!,-Nw㔃 JpL}Sa I&,>[}yh;RBBNTGi[eҹTK[݉3] QNQSh!hZ^ r4,j+OT,ɳHP7 HG|\\w cN,O0O0cˁ&ƷlL ۻt֖ `h,FcB;5Dyr-AX绢[Faɐ%+xך wDB7 ЂNt$ItNMS2ЯCʣG'"v> <[$B3U}TebCкqKl^T_Ut93~LtfV72͞2ޣϑ4`Fz5֐;F͓jĠFIhԤpS$"W &GھNފOv7}*jQ^)y]&BwOOY:N\UjesCE]*ZaԕDy^lwy@2](rLR(tQdoQ?x[+b[mJU8ӊ;A1\\=_\Ql=bj&#HS nB+ "{3'dm 1K]|ռ`aX*'MX*l]lAAkycN;8PV1k u2em G67LTYU3f/,⚋EԉVlS !=6) "9嫷υCA_(*Z0rʗS}{#d%\RB*W!]@./8̠ZTn"X9R{r%rVYVՍ$"bRGͻ+k%<[]\w𧲑Ixw2OHj13t|܃MD鎎y!Ǹz[J_nKpQ",B+ 5%s"n.J cVFć}c<;t[e^En69PWf,A;Y鯫zvW讓WF i9@T\V%? SGT:؂ /ff WNLr 9J69ٔӟ⏍s_T{byPrU>5?XſJ<"Վ'у,9d]mB{=uyXIwOʝjCPQ\0M 5 #D,F6w"o+jXN ~߮Wo5h wO+^˪\4re'ºFfI$7m&-N]9&X`7V`>RU:\giW w)˟[3Ao~{>H|ju?GJV%܁_Ao u{<>>׬0͏^9_D-?0"V~*{"UBxb\l@%{ҍ#k iwo@o2(]RFE3| ]y牵1CX>#ֈei:I8zeXwE\vDb1 +-"\^9z69JJn&#T!^I!l'!!L*H = aEMz=ie%?qɊC%kġҵ2:}(KD#u4 9R7'ĩ5)W~hH7f3 x4CeB3'D 7bw5N`R˯5c/e9x陉 k_jC~d*EW⡋P;tAutr(Ʒ#b R3I!p%bZ( 1}IšJ@@_oN_ϒo>;` н Qv(݂*FG{ŧ&\;0o0]C`l=N?>f^(]+P}3qO\*oFVGu1퉏6fE^BquUDţ[ΊW򆃾eU&;Ђu^>0MJP٦/f^0ġGexmc]o"cIx…;(ɾۄgUZg)XayDzp7bz1x'fJ{á'VF*ixa}l(fesX 6g{'ZSP#D>RFE]cvW74nxéE/ymQTnS\J}},sYYmY;ߍy݈ ڡ9BBy 8npBzoXn_Z."fTF|qUꉪ"7}t%ʲ9 캛}t2:/XE 5뒮DF(z #BkX/2@:MY7dPHAyê5RGVႽZ ԥoCfYn!PU,E#i>]B1-Mkq14:ѹM<ǁi臉1@r1 UMEsba/ $SvcFvtqR2qa˧H IUJ\]'<.Ŵ{QOGHϋxʧ8*@?g ~=,aFI ҟLtgj&^ 2{9A>Dڡ5$$eULZ_ghV=Y ηO`ŢAM/W&xW_Kg#ڡҿyz=;FOb,?!K[bj̼"= c.)yhC[I4),d{prG=P_={I}B N}NHv|Ǔ{PR{8dFA Pıx)-ὓ 1C}NZBEZBEN[xO\B~Z*p*J(w^&yI݇DMPw A;C j`,;"4!t( 48{N<8pX͇d8p,=9ՠBe1PQNCENCEɳx'!b5q$/"y͢3k_1 U&,_>HCױTC4QcS= ;? naڪ$Bđ\PN2(ŗlh!%!xB(BX8#!ğPf<%(;|$)kH*Lx&L{nǸ)7mhHAR;)1+B "mpn/aF"GIb@v/ CY~DŽ;aL4N6l-cZ>4:PSlav0")Q[k*iԬxB}˶F5@p(-@+:^vW,㹯u1('raŚOWw{,>BXo1T=A. cwbicoi X~1BD(H!*r߁@Bޏp;/" 5mm0${YP~V5Fbdst-+јE5,@7*Z}لB̠%")Bg\ҐXV[ʭd!rJmE( w]`xqvSUxu=^pQ/ Mze3 ϳjPTO9IێFJn8UsqbbbGГ4_(Iɒh99c s#{d- hhdfŗG;m,թYC". oVaު_A?G$ҚH$#7IRJs "\4^RJٛBV_38ẉ'O{uAn ⤰i $؞<{3I ',m+^Dų\si)T;Q+@gpnNG43u?lQ'\:Q>"S,療WYiW8<_/e.(VG"=GJc|؍&z &b!81ؔj -w,J=\.D^OBvd)q,NeN> q~KՐU9^F[ck bƒKd!p.[`}:;uG%^_ٮ%gTַ8]f?U )[λuw SQ#+(U+pur.DRL8@$sRڠM]hq^E:dmqfR%KEdU3N lG#g0'0oxiןb,3f|Js|J%obr1CX,nxyö r53-- [lm"=ߛT3],NlH)EÊG;V,Rܞ-dD骒*:*&܋u.DD 0kǑqe1c= XrOfF ؗfA  p8< q+thy{C[VVǎzV^%k3;/`u-m7hpVbH99}T\'#Rg#VAzɏWV}ƀl9/ NT ti pǏ&^Z0pP(2ڢ`"Z LZmk][bB,D*?} 7:K$JZj/|˯9bgL5V&&ﬕ6t\_A sDběqSv ?d,~g7Y<[^PJx| p9V ~ хC'gk[6:X8X}tn0 b@[IL iWY$Ҟ*Q$kd6ߚ>Ro*ZwwGe !y,=  Cujp&u@nZj%I8o%kMôbi.*V]-'!rXh.̽c`%Jxap:;(z!g&ǂXS8Y@2+ɪƀyqښo DӣSUvBC&N TaPrKnZ~mc^c_Ӗ PyR;j/tmwuȓMaCFSN" S~ evp5nuQ\s>K&m$^:YފsO(֦7z7 UxI.)zhr+zfJ */N}H{ yGfm0fQCd_#yp഼ v7]8>GD4:^g>wׁ>#.;qNc^UjLp,/e%Ѫ9Vfgy(}(V gwzH}mwY,~leg]^hr3axXJ@>{!|˟J5,=x! 9J{5)hx:^{n lp1]QO(}A(BbyCt[ 3v?ÿ.X67AIwǴφ.%JV+2a.u^ })fB?wDNB0! aJ:BLOgQy-|0"Q$w,yi⧘9l A.y5:J, ,lw3 bMs1}޺v^Mv$8C*|>͟l~px3)SgUf"yVCDš^KClYE<3gSB5JX8LkP8kFޓ7[BMVчܿ"-3QG>R񊫽{ԙ>kj܍˻w7p~K/1T1Xŏg͎d8a3&y^]*O>PQH$0]kZg%}Aꭐp#ȏF[VG#G t-df9IO4^W鬔fzz&b󜥂VLΑp.D6]څ8TThuZ*SGgaX2SyS)BYD8Tdu{8ễ*|6wpuP$'//aUurA,*q$uvٓ}%yXY8Biu9egecoHCaXgxЋlҥ)W*o@uʛQPVFDςJ_myE h"{ N4ϙ]79&e$ 8xW; dV"}ځZE`X Uat@UaJy6+F,emb~MDxՀȋ,-8+p$q Ѹ~LZ>86 Zpݞ–KqěXT8syEW(.Dnw{Il.AZ:DYCvP|S}s0;IԘ(>8V CO:s6EAs<,qp˚þ}!ɐF QbYv(cm,vC0K]F`܈SPhU4PNưz^2y;aJ*eۼZڙ|iE&9(nf7EYNJGaR3V T\Zai_P5U?GuQz/Yk^0Uo޳1H變tqlIsv߃\½^@m+:I8ek8 jģ`+&'`΢gCֵdDE10ҮIpѷKIBhn@iK [!Y(HJ S&fhQ" Y+gH4hʸ"eZo 3;y:6Mym]]S2eiH@T:GQ9Bcf)8<{ևEG[ Xk1?.<˿ȱ4/Bڀ`STFe@(O[WѬF^ UU]8]NuHPcZtn,F-tb`K#qfiix+k RΡrXXSrk*vSx~$e8iZaa-n!#-3%U9?$U.23wguYn}vUQVa@u@#A:КVm퇧˚gc`P+u2V`:4LqׅXI٘N9/cAj( )A(%ˤ/"L9}UQWjvVe0TdeNOlW'> }fc  [hOR+bG!4"cJTokGId#i^Z;s5A(B5[k xcz<}.rQ _.Tm l|ҥQf U/ MK?Q/񒈑^a~1xAq1w{x,rO;V"ߔ8G2 t? |t*$lh/,Lx!VJC^ʩKJA__ϖ,E1s!|x4[a$x /Qqe,u*&v)9s qg `}ҳ'?At"=eÊGrKE{(? 25lkM ȦȟEg˗*FYUw9+ ~LodQ{4񪬢$y|[$U!R@ gDzr-|렄.R~4A cDy]Br)XVg5ʭx5d"Ea]oTrHi!fQ^ދuynæ5vYЍ,aiZcYCR .+JWJ`1鳐 EMr֑3L뺲LWxlis ǻr}1xn\k_?gqJ'Yw}N"8 lNj`#ThKʹ3^t6wL=g Yv_}|4B}w'če2ҷEz7C!?;7Xgۙ固qoA 7;ki8@wX~"{Ww lKyk3oL}"qTƵH}.}Uj9BMe:/T\ oE^׷{5jgs0brg"˗,c.,;(7UYD2-_՞?u*ǯv?3z0 q9LU$@ -YS?핳Ho:.j5 {*Hcπ rn*.EG^Guŏf!XWiMY`V#pq?⍟Qi0To!aޅQIԍXQy}2Sڜ'aW{Y~H!Ai;wsN98E/9\.=OKUḌz̍ o^蓟[/WR`m"fhW'/\eLůQ0~^e'9Ahyk&?^7>}7LXFMnȚcƢ@&YUA{4订c$-aȳ$Rf{Bnd"p yb/3U$;;S]hس<_3CƊ#e<ڴZvAƙ/:/Xݪ(qZ2so-ΒY{O xαhCYe@%a!\n[Uf xo\YG3li^Qc~*88=BY,s1Nk\ea|A9 ]QiS-$;oB LAK`HU}-gw핾&^2TjC8W0@hdb.Wu&Hۜv>fPiA>SjKSTl5ZY"t!3W-PHy$"j#*ddSe3չxrq P_foY1~{wC@qjZjJ~?w1_Z} h_}<{'Uev\E˿{zBW3uh\L1 x-kZ屠bxW_[FU4Cv_,i׶L|8}Hf\GBMeC]\A-0uE7T]6+'`cE ]Q+ؗbRz1Ԭ#fqJ+&5a#[m1ݨa=JTmZ3e"y-J;@W:N'Q^Y¸Ƽ-rZj,JDlXzS)ΫZKT2RX<C!rs_d@{i?ARS/5 I}/*%.OE{2`ǫTmo2%R6%%xϑ(~pYUf_ ݒ>b9xq'a:B` $5܍*myêHi'Pm5a5\Jp\ҕGto3<U;6/ +Az#ZF8R;M9N֊5L\NKr`ecj+R{ C3Θ@#Pɋjιr0y bI7EÔe zn5_&U4*eUWq"/'+|}?h)_0k?z8]naטBՠ(gzAk+E\1-CՂ"okxH|uJT*KH Sފ]_ɻ]<./GmǞ@҃;"!2.oMw (9)؁ Y$hm*xrΞ31x%Ƚu}4Wcf9C=Vщ @7z_tB?׉o8|S%3@V+ʌ'A< ,|0Pwdۦ}#_;yhYH=X6V!Ҿ(Ct{ZRpSg=}e;&/bo;u'bS!Fxx/jY>yϿ=+B`!U!( 0wa8Y@}s!#R. Pd7@(n6:W/e6=݅`e5w=Ps@ ݛ5Čh%j>$kmJطe?h݅ɀD0 BR6zWx) ]A}SV&"Ǵs,밹&~_HRg$PzuZo'|[}Qn] '7" |R[iD>TNǨq166"nfא8n1,Z9t &#Zc ߓE]E6Q=vP-aQQLl"/G BtWǑ3 Ҭtu1y'C*CQ,ъ@Pe z7=6@꺙1^VvHa\^)Oq $Q7 H*qq “Aq%7RGg}HJH 6L.o/Ѧ⇵݋0/gz,0 Ҽ֛,5 :0w xTo*[]Ϫǭ& ۠9(OSƂֻ7ۖԳb4|P T]1Hf.0_`OaY]Ղ#y?&Zƀ9W6q+1El@F`eE9NrBmÍo߫HSYWTV=R)-HM4gDqzVb^aϥ݃+{$r6lT.;#2L/PX^J /ԑZ٢mYUQf돊 H_yOY7r^oɇ#fH3r>$RqˊnG''| uUvA߅0loTuvlm:C#4/ E}pcu n)X6/7R9TyʓqfxZ_gOSd`v~PSݿuN+$S>eVٿq  (eж'9X{zp}B8A}kߥDAT<g,@H1zl7S'N &As"f2{iU'fgIīNI!y$ϯoakBZd~~d & h/,ČR6.tuJ!^L|!"IH p⽮YʫPY/Q|2Xc MQw@k'YY>^d1h z}+`ar,rPԢl㋀+k,[%(Mii/9)҄1_amu|KీBE^Eyު5[V/,^I!y%Ѽ5bY @S4°xq_dEm(hGA y d=ˌ&Vlj:Nw<:L:x1:ݴXJ:~q TYyoķ u+M~UXWZi/U,i`uNi8^ 1*6(,y$y|sǂIuP1lyku>~|be^XmЪ՜$A K(fn|?RRfU1ܜ 'n!}[p}F0A,t,CD"<`:#}/qt<&U=e\Væ zW *Yk)#,F\?1h/&8$& ĤRwb[,A*>$K-$H]sg%̻13Fs:&KWtm%_d>9ˁP4(W˼P\LJWdH;PKle*)SG.n gu 8R &Ϛ]Em|TDj.B}TΌ]#EDڞmLWN߰H_e%[noiNLu,b=YdRC!lyb67" YIWYų$o"HЂt`VC2y MalQJg¨ĭz-ߟ&JBVIbnsE&BVSKq~.= QPxpϚ P]rB"p/ZSg#OJ~o%< PjNp;3 uYHeZ88zc|U,(%fi8K(g+{6E 2J#"_]<(h{%C+<4Ky>؎ SD @Cs}\3w qWvH% -߁{\I!pd?b}9sz)i_mn 6~DOMQxw`\i \"oqIan~U/:`u95ͤ\_Sf_!][v]sKq̕:GUQ@82c,HѩYj<: ,I_,Ӊ_L 篯҆^M2Rw0Kv:<*bmD91hȁym# -<|0F\e_-"?P\w.:Y=C̥ȫK?Bx* MくP*` Q>l:$wmAQ3e(,NWnWj')cR#rHd̤ɖ}98x+ȡ1XK%jNp?+|JzcxAVlEk},QwNI.eMO'x":?TLV>x. pg׺:|9U繙]nf\hb^u=yY˛>RT&Gf/ xД[S2b.hԊ!sF"-6-JoΖܲf*Fx)"\CہxDN̤S!e+ 7:NoGaă'/-WL(Ng9I)GUzYpskZODS,+OLeAw([5^S)~[*a'E./c?M5mm1TN/U|Bp0ȯLImltVGDgGMQh'+X -ך$sH)ntAv^_"VkGrx̮:ﳻ ߈Eiy|d^4ALς,tg}b җOOT׫g LJw Cu;&Hm=TFkxAO^j {TEB=YL$v)YFb-MC E}`hZ)wTųXHy޺GQIIqaw9*R7:ٳ}!6lKj?_K)zMl!bKԿ8pJS&%'R2A{qjCG>lNSCwrXd;R@Xp&^Zk<%鼂%MY]y(q^]-838f1>7 x]/h)Acfސ(iT>kkDi_ l Ztm`\떿ߊFF]'6Q.レz;@YCd-C] cXin/9ޯd/=x >YzcWa~#+ &g6ABeT_)KBP_UYtj^¸|5 76a`Wq"壡,-d롯LጢFf8ѵJa<'*%=suT9P,UiZl{nUIFRad|Wd}nӭj+v];:IArqq+2&oZͮf78CН'8 vO̧@nÍEBT\0-;0ڛ[a "Ht!Jc񓓶Sm_i@'/ܯ'tCS{>?d"BfpOṯKuwuyT.Qv-鏕g UxXowΓRrS )4vS#K'\s@ϓ! $mV*??+ſȶbI-dOcnۅ}jO^3nwhv9oފNÛM93^[!jgϩM-s3^MZ8-G,lUǭ2zV=uj~R }"^q mW4=h3qGNyeվdj)l;s1gM0h2oҲ1 .Z.hn>e~Z= q ,ɞ{܅F i.|IʘyW|͇ 7fzi%Mf{ !K6!q XӸ3}7#XFZ՟#{@F687]*3:`1Ϯ46u zdGB5I\$A̵IdϬCE))5QƜݧJPX?&rBCi |gOqkJ9,OeZ.Td}2k u8G|xqkBJ{! B YNb/;v^`L^|0BP<5 O`U= )YK9:<+vjˣE:ux`aܴCtO :y:s?x*)[B;1<47<y{xJi! v7uRl' OpJ<хCh {i=:ts={im&Zaކۊ=M:Lm߇l HwۡXG?7S{2ɟci?}O^ڡVU2,Ur.(yl_)ף&\"ny L._GUZj-v2LVr(]4٭vMATBh1u V9l[s aUD/Nh gK=CtGۂLuO8[u.]w'Q8~`)(4a*[~ߤOW PG1wt[t.5|m5 nΫ;;jO^ u[5{ bl_DFFųW SY~zӚlt *{Eֶ[FrW0.,³$YiL&6DP_ P~[F駞D{,)ժ(Oj=9V9VQ'/F}B0J7+NVCS xy%"NJXi8a NPȲni@TFnL;`^ӯ=0 B7^,Šۀu=a//l~Al nӵz4PޫJ{-Jo!,^U˯7,m+7R![Մ@EmCmؒ# m]$ Yh]R:~OCQhahTg})}? '~#Vpc+g%'Aq^;=g=9W?U4V H*s "lMDP~Y[Cķ%Ա@NfS2V9z${yӽv gQ+GϳZ]eBi mu VUc.^㨬rg/Dl΂xr1[OU2 {a7 D14]uuV[gC`EZ{v@SE5wu4k@l/„={*gzN S>ެ4m$* ЌP~(cAʏU, TkV,ʋDVZD{ k rL-qjCoĶ0W=Y6gN ӦK+ߋX25U6:tyKW MYo.~61MN[Հʌ'YBK{& y/˼A"KY]Lybu2C?A,.bv\{sᲞsaw4TsPKvv;_8P "[oۺz72[$~qf"2"T%X |rE\I)rc N8l<bՀ<5GDTK\j6}C;m3P1 PQl(dQ{CfίxQ1Hܝ) YϬI=PVgkG^Mcw?-yꟙX}t0G=+M O|H(ŃP?#|9BV'p,Pn8Jڗ(oetw`=JGQIj7O9Q]*@xW BQFy;i{d7LvWU-?ײӛk z!*SP]nATkOzI"6LgYyc&p?јm(f#rϐe4LI%l;n%FS:20w4C?TxԲг:!rbߧYLQڎ1zkn`qs +n{Fvs0͊LYRV61ړ򱽉y^ejȳ)N娝z'/7gUh)U87O@ɱu i y6kAK?Map5 U. ɋb%NL| sX3(Y)3yN녡(n _ B=@7UwRMs^uEYbw/jng]!ۉhZ7"JkaH!>A ПWeքsVsOQ)*mQ7m{ *p X2`u-g9`4s&N}OPиi'3\u bc9]5+0gH:X D!'=@j9(0Yh! j+gmNOia5{5k,,;1*VB#!Мtk2I.%,w/v3:J4EȌ&wZWj'2ϳxc4-0w K8j-z wrPQ 88J̠&z"]y^I.q*G5C@Pe+z=ꄷHLӓ}(%rrJ0$Zpr]0Yl=О‡ R/Q) H҄9NK#.ΒĞ7Ct(CjnX͢nêX6Qإ&= =IEI&|9oAѢ9t jIwuUYIVBxj+~6ˈkW>^!5@sCfnxᲵ~n%Ol}:D|] x GquA:Z۪v@#%,Lɤ Qv HMFێ);!C}eF#ޡho3*uAu}P۝OΤaS?ګ'Α׃5ﭫHva\9sKӷdtz=[9Xz\m[ {@J½ $$4%q/E>v=692ʂP̳Qm&/`./: PY_9NTS_uan(_J^|<,{/@uN'f}i<5E>_%ѪrwE-`$zˏNvL]$Ui KR.nSplapE ^p7tl)ú;8á];S=]n'0dW'!*kp9K88P T1{6<-{Q_o eB~xmRӿ2foKI<6Gg`#CAɖva0Hi=PBsv3Tیiݤq4C Ggc|S1Ihl ,*{?[sy*+ֺ{z[8xr8OOQQӠ[`e(^ v5rQRf2O*'}/X ,3c߿y*( HQ9YswV1ӻTcfAXA*FgGyvQe&4mv}5^|..hu&+z]]TfMK꼈ˊgmâ/Y9&EJ':^lΣ".2xۋ+&n!(D:2+kYG~: =e巺I0erЭ?흽@pgIeYqe%yjH_DV97v1w=ND-CΓ:GHX{BS\?m1AtMD^c "Ku>s!K6{a^|վmn8gdƾ-˿.9' 7³Qo;Q676lf П奣 (]tؼ9Τ}G}yo81JTjHfochފ"pN-=9x nYk8Obtw!Ц 7nt ڡH֠H_24~x9huX"zVbs-C D N;A )I:iOTe}IJhE,6$6rؐS`CN`(M5`lr91{g3"J>6nk6H^d<&\~ Ȃ]t8VB4aK# Z>NMwn(<{Z3}$g3:ZcGF`=FzIPRZK6ZƼຳ[2gV^ENPkoU *b쮭|tr1yHWtkN<- ߏӧSTR׽ {Wʈ13Xry{&svׁ( RS{hxZyḯYc¾y\wY:J^ՁD]dqC.>a t\t.ߔum,%*i0x`zEiGS<[Ӹx V`9Syœ/_.!2'w&PM и^<088(`^;@8Lv1{|.$> Y5f3Rt_0fjr&rigWT2`ˤ1Tne%66~?*Ģ*E(ǂ tYF4.)Ml.g u9 _\TmLV |hYq^Z|)(a(#ӤV0ޑEzY/ [8;:r # cgVPm▏rko-/;sݦ3UiFZLUq;V*ɢ2?)}IjP[ .kܥѹo_H2.$<_<`*'&g ,LBxNQZ, t qSHhCnf9!vQy^ 5/Y=[20co5:8iזoCDITBx:\I6އ{cgzkS6SrtyDwa=Cϑl8|γq_ϥGsm#h>$ 4SF1@ ^5^^XUg[к#v`[!Q{ YvK+w:rt~<Nk@t;_9mF_.pT8ydZ%[M:Rv@*TxAK^BEuZC6GN*pNw#j[B>ttk*~(IJgc.bO-Qi#$خ1S-қ,ZDvl0hu;paGzđ-[V.zXR}UKO~d;h.)4#rk"Aw͆ +h4Og|FROҌdf(N9VxRﯤVt,QV N"0usgw,и_pf~r^.ҿg)Ю3BKi`<ed8*̛ʕJ{F;;.a8 4\:AH4fߣDDy(ت?KUc19}OnG7'QS.zn+k),loe{k;4ye⓳e)x+hQ?+~}['Njv*@c"r"{W 7LDŽ,V̈ ̍ez6:]Xg Z Dx!Gn۩`w=YY6#0ւ=/sm&nzzgtAl>zw b~N1{{v 묇wm'>3aн~#zw{5~?kL~GP&?峟`_'m >Y3=Kh$#Kkiԏ rOo[cBAE]A(=o5{#( $:Oez̙DX6ȖR{F09 cO@ǒ&/Q!s_y <?#g>Q'KYIzXn&n1L:S72;;k>Ϊ,ϣvuL7@T&&*vAG-,U7wl\"{NVYBN_sȖyT.k"N]$fabSiws$4f|.wU7q[(ؼnOJ (n])v[g2.)2.՗oKݎh-1puj`c]dL9qq9{Py0ȠuiaNrQ3^v]I*}$ н <޾ˀoM$l-&* ҷƣ9ғպu&g9_={ȓ5kDOkS])7gA 2?iqrSGp=<}#^ND_TES=ES ۰$wLxil~mF,ǍVfQ+T  k?6](o׽*u/`9Sr+L pAjmߴ뛏I^ CLg)+㢚5App-(>FqR~[V9+< 2Xmڼz=\vR8sxHbk )g sY *.+sHD氊q$.cl^G|C"jj@YA~A*sm`fͤHI&s&MM":Z%^,U#ar c$qط(8o?u'ֲ2BCC@ZN\r1R%GFP"QNRzS x6}E<R0 zL)Ulϟs-bb& k ~!.ʷ/QLL3u/&5F\lc\U yp=89Y Zk,t]ř<։rl"ۼoeՊL߿CۛKy݊|XQܡ& u*o?d O{:8\r~YSM֟,2g O'HP;1h8oT?<ˣ؊+e4Jo5{Td(Jtm7]Qn@ xP3ڳJΖ w34R^wl ̶/[0_}[K4(yCx .ı"v=7,ԁ^)1vn!4yGCUop V!>^)XmyHְ6zBbn;hhSNJh vOLacU:X"T?Ϊe=:GKԐ4&Zo. fnκp켪,N7vc@7uw `&eql'?Z|v˃0x?0V#z#\z"9΅A4guى6? 7 7#9xȡ 鹤]F!zl+VŎ`p1M ).z_ V_J=.k_1xUW}@oT8"Xݙ|`Mt $f6f>A/FH/js!^{T GyN0&LXo vA#Xf +^W3 !zM $@!w. ![,R 9s*PСKvx籔Vm=^r:gA0}M6b`?i8# X,!A]~VxSwAIj5|1MqE2‡U>أB_Sϳ&?^YΪݽs%pkuUzv MEGliGl|I <{uWʈ*=q?ôDEd^@xKsw~ xRlblGO$qfPAީ9gӜMSO.%.nO.œ~7/KB> qؖ0APÈFxqBzRDQZDdv<^fyA2텊ćVpzg4(}ј9~~kR=;5Pڹ%urh{6I٘>ߺ0atGI`5P7BUγ7;=b՟"kΗOq:&8B=GŅs6G՚tmc?g{YhOvN{bOvrQ4)>|hu<4Mγo|:Lc0c5tjF+%kZ@n jM87=׃{7Wt/S%ݏ˜[ 9qb hN}ЫC삺{lƀ;#TQUHm (XY_otũؽI ~h$܁)L]eJ|5oFD?jע)m-ł#%dF3*r),_GH8r F|q3 "=i>G3uu!~7IyXNu;$~ CϪe\8PHg ŏa0,@Bt s Z6eOT9wQZ%@τ( "|KB?r^eug]vcvHR#jY '{]B6yxϞ8 !=#ԝb:(`u|sQj5J짷-G輔u@vX|+kQzv}a۬ZT$ASgAE;dV]๻rEE`daC_sm̓\%Y@KK(}RqQڴj/UvJ@@C?;wQcX Y7- (!#`H&.e2]RwE!UAAZ bB܊zo!iڿīg$iQ fqIynKKgm&4,ȼ\+&G kUVoUދRWr0[,f)⼰w(H/UY!񐊷Œ,Jط(Oyu\Lonw%HlAa"J!#۞W!m"2+%"%򂗩߄C`ggӈU!PƉ7J3'X\lK"&0ԷI( Z{>Mҍ<2yiw֮ kٞCbn!a;BHcQb[|3Fܮ.3N_4KYUX'*e?~%oK^gT Y4X=0mz-,])~{[e3p]?,IZb~(Bi M4.ܵ. v07e3Ë2[VOr8+jc0fSŹœ&/-M;\ JKf9TV,c9֨ӝqU$mg^S6w0}*2"*.wv$`;PeڴEB^1օO+O^!ό^/9HǢj gX4%T[3(&/}gxs^xDDN:\Fb}xUc.qZzib]4L?:AzbߥϿ̣p. CjV KbKk+U fz~Dq#2R|KZ+묛NXfQh`7C-I}Yˡ!vm4X,wbw.C)Y1½ / pn8vxZLی[FZ9nc&Rݜ2j>;$G-zS.J,.B#>Ak3ڡZFmV=e\Ve.fܕá(U_ן^[⬰vȪD,e{A̋Kr)*.gw((]Uy:0E!)#80DcTxאNatn8D)Gr(4xK^o Zϛˎ [4N by?a'fe@/YS4+͂`m7(0ϳ蟇7B upέg 6'rV%>k\걚wˀ3d%v3Y?:;F f& $.L.EQ 0)2?)%0~^A >@nmǜy|{r;ϣԈbtL;7cNȻ|%PPqQ42y$;q4:Y^;Q歕\CWY1959"P;īh'|ܞ̎-'|nǩIB;⎡7rB`e[GtP5x=gw\m6[, 617\;*"{HsN>X(*EEϢDy@ d ű"oĩ;a5>@wúgO\P>{q! 0зDv/Pԯz+u^H3.R<+ِPOiUE.5QG))$o4^eZ?O )0ó}'w߱e|{~`bc7b,Ho2"+& adDP{L>ίoۙ]a%Zy&R V5K0oH%"K}j49HD8.b8d{q"FՆͤJ>b\1WaD/"Y,@G?NaHY.ℍ(on/R4$| Ϭz$h Hgќz1vXL֩4 0ݎ@zvF)f(띤:G"%F;hqk4Dۿ\T3 R"o`~5 7H6Ӎmb$<.$KոK'QLl'"P;#i9r#(y$teCGY~E":l*s.뜈 $AY̢'Q{0_d+Mx]Kh*U"4)NTu_l[chy ԝ%aJ.}X2%W~v 戻t􂣐<L^Es~{0Gk`t,CW.MFAQsy'ѱ|? w / Eߐb-8@uJ6S!ʮazBYHrAdC!˺8HcA0jܜ^?]74 nju&UmxLCY4_Y0uN8d#<6bR"#Ro |WJKa>}?\PP-8J^"Wޕ!v- w# o&q`kXuৰII2=I<d9 ,HMv>(k5D|"m#KI8w0JBL$I #q7!~,w")rg QVQo%7?C9-9f9㛟_h@̹ݝig ͇t<\HǣN΃t,N vLǤ6;pLJc ~b۞@˗s81ұwCj w)V̉,P\9ә"NWY*³.089ӕ?Le#,@8qĞ= 8|(]o7=e`e0yTvl!_⹧b p7 ``-=]D8㈦9)Fޣ###"D Z]`G[f;M 5Е&!q:w7)N7m/әM3k6{831Re9O#uvG7N#fx3n\y"dL<u8F p$;T7[7 AG@`0&}40Փ6Gr|׮6. ^Q-#+w#ӑ ۴DʐۄJeŸ*3rʰte< d+ A3K::+blPK]!Γ]2>6QӱӼӒ4#[ KUsB yUDoG.:qZ.c)">r/1[IIpHN丹 NM:%1&CB#MɂYᱴwĒXZq'ELY::nbzbNYSwd|Q4Z>Y$ϹO4JTZpg2_D/qqN:_Y79H~Hi{uInqq^k & CX~ͤYJW?i*IcZ(N-nBl.pEQ%ޣ6ZYPyGi__+ɛ!`j_Eq"[IU/:~_V2mb:]-rւq>SnfWsa|$J۞OF@1 2{N&ƙ֞$d!{=~t_E'gx$s1}jS5c/B=¦i/k |TGeh@n.7a ʹBRLى+9 -Z*) u]>ˆ2aɁpE]Ig鲧X&2qFQoHMoS_;ȦK}\*jQrhۍ:#ꀭv?8x  y^k 9yYϝ]wqe9t;[?;e4F[ M6i˼YQ"T] h۸MvyH};<4Zt5|c9epqP Bwe9ݦ,Wz eɯܗܡeL^ZގsՀ(;vs!b,u;kiVy#rh&BGkL|k>H}#A_8Y0Zj+YS¢=]o&|Atܛj,K[~3 }y9ڹ|zwZ"} ؎r0cL]hwٟQxD c=ل*\?gW6TsP2@ė*֜(K ԩiHS ]@@H}#4A B U[<ˮ8}'gr對q=7`g"Qv|/l"[HGm3aҖ^Wk:!A *Wc gMbeZ'v Ceo-]&`w67OsV Gj͕cY2 ;a((2+4T~lhX'!`^ʱaq< ә<: i(gz|+Vay,DڹSiL3'gw9![T"QNRWQʹP akފDIaƼ\ޥsKѻ' ȱ [:**6WH$\zhuq9FAN;D%W= s@Jp}Sϳj6"_xfQDgY;;sdnE\W$ms9j, mYp$NuNp 2[=DL(z ݟ{^D i#561uS_Ϙ=U2J5=]_ u ѽX*ˣ ל6z8URӉT# i.r -S,YyΨoQ(MAເOݓ@ FDOAHo.84]Gl0KW{C3G8ĩZDw|zRm;zB~oQ.`.&F2]M٭Qz%m(I2˹Z"J*:]Ɓec:^dS):O7c.kOpF7P~exzsEyoCC,uU烖x6Q^@Hg#{+7 ܷP X7(wyCJ ݊RSx+JAxYZ^c  MF!VPʗ&geNc=' n!U-gv(BZ`NJv-CZW3hk)0uo@ij1rzP! ~bKa/GF($y|[$Urv|(.BZV&t Ż3pXx\N_rP|e @XDG=8Iױ gQ vĬMuFYskk |B^s0PoQ,_)b V!x.혜Eم:hN/4"-VX;[ލ:4 oɤHPg D\W!,uHEꞒg,ɯ1Ae:[pPIY\x-v̻;)/rot2˪tyP^-,3As.Ⱦ[j4Mπt6Ľ1h/CzC;-7٪缒.k~i9oQ^pP8u9At +8G@꽧p@ s^i=Qd(ngϑXdk+꿨QLtמHPBj[8@W өR qN.Bw%U@?~1=| Jȅ#)}+sXK bH(s3EO| w!/Y&ћ{_ t̩oa B5HVUd:#5] !5'r b}L tVJdbZ\.mϜx5 M/=Gwq4h,eqq:#SCr܄r0$v4(kwN9<'@} PnjDо(JϖIw9s "[ewF)oz <#N1x _Fqg2cJUo:7u& k"0'(1s3LTjL"|hb^Vy $? K-UK7WZ nQ^}@L-Bt-u$W;,3ݙ uN{#ŋ:$ 68Y_d*Ij@]b>Udg,NK*Z;aN7 @H)a -]5ּ4?΃1]! /y3H};gհR,rZAI(Vx ^]}fbKOb|C0|=h%KBAjP][Jib BoY=~GXBSZh\?PrrZk!pG+5=XU X't4@FPz拡#714I&|`Hi-^t)cwL+C%؇(w;OB%*Ņ@ncamq&r FJܲZʜ| 8#su֎L+.Bl9gQz(*HK=y ]MQӅj}9t$sa3w֖_98- pxV8Nz6ɬ$KILo<n1u{hDDA(X#N+FmԞ/^A'("Uk= ώA:\.[  Rգ0OꄠWYWY>Ϫ4ڈ||5; x%WH ȗM q*-q f{%ebҗcϣR u<j),ʗpp9~*g&a>}?[.RMGCC ٜ>Ebc_EM<;Nº(9Cux44:|c '5/J-,V{4ϼɂ9-L{W><|gO1`A]-ZDQAxC)RQgB:t)"V-NϐlMԋA[[4hZ*YJe Y&g`|o=y:>l$99eGx֨p֨\kGcyKrӯ؄L|K%22+-!Q^Qz.NWM6xΒŒiΚ,QY1*J ߄{@aFMa|rɪwтhE,>0puAJYv-6UPCjKPYeAK!b! ]QݳO6R)~cf"3zS΁)GC!0..p^cL(UÈj@$R0ѕH2g-o#PrzYs{@ VzIniBw[ $ PB?~ei!So@ubI܆`/l}zT0 Hm *?;EE7fsx\KsWʿ hlq8Tb͒ϏZi{ I֗ NYOO-*S%.W2u&`reP,70DQ!,_f !RJj*){ZVٸ&,_`WL[c!y+Cyw;bjP@~n[G &IE5jOمX+֬LgҬ.]~c2T>>ytSPODODDQׯ!uHu\YX78r1ƛ+Qs_\7|dYRo7"72vB] ΪǚSvb"/G= N}%[յ3qc{ZlQhZC[mGa&gƬ vH{{?!,aO! nְOxoƾfey4ݭ#G5ǏJxc󟇶JK0ӭW041fAjFcJ|~2O: z^s-Rk:xX|,iB}8nomZ72G؛ãZCa}m =/ |߯Ex 9 \g~[A ]F'rGK?Qkϫ# IPaA*G-'(UZ/vN' ^kTЎqNM!kNFܥ<<ϔQ9Ia4*q752`{+"5ߞKBK9( IL{K/ @iUYf/< h xmݕS>csW3 mX0$x;'ZL7VYgOZqPy{Y n[xx[IUrGōöųo7{V5A(2?dE.c .p3lllrۤ'j{W1N/o[-K}tFeǢBM*JXꥷm\fϖʗ˩d:*ڃDU,k*T|IH_L-z|s"2Ube`#wЀ!iת׳Uv78M^ia/YeF΢qa'F_My~#P^L\8#33"}U! V0~>\Q H[畞qyV=ˮݍOacD7cP\B~HbN^>Š||LlLz,ʸm1p(Kc'ϰ/"j~xL)jť8X pAw?īzۯws<㦲dvX&TIT ոTekʍK2^r苄dap /".p> ();(eީ^ :Y{ldoUSNŒRփ/K&Q"q=J($]Yv>qnDgg=IG63{>`f 9y!hrR.P]PZ$.m?PJGVih\]{[0ӢV_z*iȢn`/B'QqjU3ɆdӡeZP~6ݬ@dj8uo;oVfUro 3<W>]mhꎉkjkfEןX@j iTj. M.):٪xz1>CţنHrL$&n(VVٯ>(by2gO0||w;9]C=!G_B,dۍFx($0~ׅ.QHb.8aިc!zw0 efIv30ޕϳgLzӇE#ںlQm<)To+s!@N#vC IzeW1LHA :Rc4p@ngm(3ĊgV9L|;b[\hAy[RmqTi≀D#0H4,hlȈ'HZ4˗TJ%|QPF<]j6W5l1" cPÚ܀p*H!t{bű ^r[W#_'TO&F0b`^=[]Z77G'>8.7QruYsS2)4S;!(u[0Jk3ՊG`jxp C3C =[q}Mzf(JDHz!޹gVLY=_᰺$3p8:[RJHh!;@jUGA,h6*-ɳE幋Z\o1+1d Y]VTXETToqZbj35zJhص`H|H-X M nj{7s<}~4ǯ3-o}5"0ɷ1!F MiATUfn%ȸ&zzM?eK'QQXUϖ4iϘDH<[zVKh$Aĺ0R; K^ Nz2[OBls#G"ow x:Nl'$O@7I7]SR rvRrktSY8 uYpo?zf?@(b2\GQ}:|]wp z0@!ʇ ZQ>~zfCu"A[cTxp@Dz-TU /uEw&)}ʈon3!B_ Rl"LV]hK ,UUV9@Xa_+6(38o@( ~]->>&nx0_;Pl'`ǰ(w_D[gܑ|ua$qF4B~8q䋖a1/ӥy y10ldj+O 6+ lLLVkw<]5sQe7y1kr/ý/Z-O:olA"ym(n=oe8KlȰۻ%a{gv, % O){XދK#mQ 'dƥ^^GqBS$Wa{-$GuMڇl#1嘼rލo&}1xXnvrH4>`{%e&W5:ImS ۡ;0yN(w#wX:%`l\[By:tө#pNs2EY7N6ЭSG朊8fK$Ff,}"/=k/um1lgx\?:YO`Pһv4md0;g31gUP+vd樂@jY[aQ;o [iY7[`=4|\-[caJJ°hfUgPuՌo@2s91G5rN5)^eVkɒ rN_h;~fjp/Cޑ 6|v*ڝ2 Y-s"|1!/G*HѤy:ޜ-IE"ƫzYo?䱽U4wʏ/MݐPQCX|(HO"]Σ7챐YOqq~%y|'~Oa*co~ #gG&1R0֚o9Uek;O.1"S1B%ב8ڨo(J'p)ʻGpڡ\q0Ϟ$qL"Nt:`(lC(w9֗QImȣ._EZNc}5.7p@"|'yT TyG9^7_T?RsEr'/I"(d]$gw801"ߔb9vg/h[1Z>d?xێzi# Sw$ŭfB&n3䙂LRݘ[ђ:;HaUVn'ךQMcũ$븜oTs8m&ޤiOv/S^co7,-J0 ew% S:]|9 ڑ 9|$1T䨞p9ůsleLgN,o}/ٞD<~O5}ۭXs V_C|F+= Po?N=(Tm!|gji7~ƴL)iܷf#N7fM)ڞh֯MԂ 5-ˬ*ݗH[fq%Yr's;B vg;D(keӥ:vwBxG-j'WCyʜw8XֹSIu(^͔g& پذ@h)P[_a˛(]U*m./(WTXٰhɋg27?c`)ls^Nb:_y~]FḅFoF; *>syVfݲlͥV7 !&J\S0PeN{~K./"ٌDCˠ1+A~VeiDJ =PޔWYV!_䬜=KʬseUaEC o M$ i:,? zC܋'?ʼZ*{ :sV}Ԏ3P :3c*9u 9~6U"cUMpMl.CxSsp^e3:0 t}෻ IBkhQ~M4feQP_Gو&^@Ե/R9i/Yy#'bզ-K`oD^O$(Žȹz3u©9EoG@aeDz|y%:m8,`4^oC 0m_Pw BPA(o.10Ad.GAcHm<0{lGnsv$ّgGnv`(Xw[R~:m>R{2V[U߽w5|ُx[O `nsf r*.t(wϠzn#}y\j5p ^E dFfG]snk%NgR+)=3TlKwA$\]| 5? >Xg$Jọ"γ7:/uZ]D -KEE}W RgpO~6N2$J.9 қeMl1UeP:ŲږK[ c=aLJ5vt?Á׏YČ|w)uF2˙e6Ӌ8SA+m`Ԯssa29*/HqwAy ͶBQ`ʖ `%Zl#̕= jFTI@i0rped,iR{|'II-0nEbTefid+ ;낢 22*=h})LzfPo/Hsz\J2G{_9JF:rA)b1>te ;| ś q31Br =ʼe'M ZJq_DQb)#le+_)z=2dX[@Tֺ(]e3#_;΂њCWYfNZy/"ZQ fqƹMBb+rCV4S DCDQ  seq1OޘQTYQK.Ȕ .'wK\qY\\T{הK,(΢"wugr2rq햶sdeTxUBj<ú]h @~cPV} BkX ZG|aࠢ=[W^I@4PvvZ q3[W\_ݥ"W:gߺW4Md^&fvf|]+g.DRR(S"Q5krB0pPbp0CdEe hnn$"NUzcȉkˬN z'q}T0hMp>Bq~l/@o`rk`/&¯~ie @ Lݙk { =a甂졚2I^WqU3;R3 <^;E A /i=G땖ߚoLl 3p37pmɍ<ș8 Ҿ p,LqRU.)ŧ_|4? yjrq盡;k;'LgA~^Pɿ~E7"G[YX(i\$46fi*1kdoE9 Q)<:rj[Wp[cYN̂f2(dr4KD4tLcʗ*$:dQ>+MdEGd]pvӶ' :WeqQIaJA,bΰz`N!LfYTD +*ɖq-r'=[>Woi>,砌 h$_J֥9*/''rv|JL72{?L<$0C'pn,eF*?~,T `r?QtE$r[+^:_d_*R=CD0™ްc \ iFGڀ L ͷ8@Fۻrٯӑz H\UfKcf?LEi›F4;.~&9zNeXm8Iɉ4{ݠ^nY9B!Y\kc]}i"@݁2GRC[[WV7d>X^A.[4($Lo;'F LF;$r $I$_eUJ7̎vh36g됥(^R^q+ Ϥq,SKi: <آ{iHC;:y,wcδrgRD9@n-7;!=00GVZ/ C//QbGP*߽ 9{FMXٱp\O~Ιe8qόܮT%p"x &wyzACP< `HJɣEHmV05F.Nq6<6=HM 1rf,MlSjF[S"M@p43N2ς :J'{9ۗ(LS& jY|3phCސ^])bZc-roχI$2גDcQZ&yr&XŹ+cow"0cu*ye'3P-r&}>sA2t_-CWNvq{rJ`O&l4{mƢkttu+m+2WRy'FZ2Yf]k: ,Ш(+ ##) !qzAOQ~?č9r4W"sp/ bv@,ZYdejh Xi^ճMB wXbv05bD mHb/IJ#o;BD8gЄq"hAt 9c kfHֳSK\/϶` ijs-^cQ>Z@n}Nv6A-;`9_VmNQ<<1uKS(oQ[V9<*CdS9%eР?۫i? >߷梕Zٹ #lC,HiKYwy.q[Ǵl+F 8^Pw7-87@HZQQ0ykMwNJtcT2~r,S,GdJ@R\>\uV#.ERX.X^j0I]W[$F~֌^_5t0-n.ز ̠igHrApp.49uU.Wٹ0SJ\%cf` ^DǗJӢuQ!K%lYNDzqF\J4ҷ+}%^u[FoͶ̙ oсAB%J%m~eo{,dʕgZ=f}C)7ˆY$\*G0\)? +xܯ1&/5eOӲJL9DϏb։o1N/I zyQچJ3 Pc x S!gqTF <⊕C^YP;w3 nTSe4W7'8F-h6,1X1w"wr#fX *1ْ"΀ې* ubms~^Q+דV%„/L˅*~ö@ɩoV%/eTwapGr!>s>F:7i̢|fOlD!G5"] BB%#!8xPodWnl^gG2Vck&gkM%^mfN{®w?Y$ aH)cqԢQiQ WSM=道@4 M㐗m!KX+;4LUl2$)J!{af8ςD@16@ۊJY unCpD^d/e0.n[fL#~qsus2/. "8HX=O9C#?x._W΂_03{!ALo`8۷~Uἕ\}m&9VPM)C U5- }I_j Fb,y>>t$y$AzsU䁐kQ:ySCx(9jsu 8w9*J8:yz-ˡbX ET mPo[>-J&!CqCȲr <y4)(5oJL^8ecxm1+\gM歭=&ucit ^ٖ=;qe-\b[Az r|ŭ K̜_*51͂Gr"Tj'u&UvF3So "MA^wYZix7u lRbd PDf}tZҮOCʶ>^0Ank6)k2+\ψրJ% a$׾Otr#^*z5mAHp:#+B'] x Lo\ylmsLjN|\!lM%oY U!"iO"妌jAA%\h깷9iX*ESϺIω{OOa]go﬑ɮ.7pP'psNH8[vQ|:49`[dz3 &NYJItN:$SYy5{"_iL"Ѧ^xgmJiޥUZ& OB0/2(w[StA$>e:@]ȹI|*yIQWhI^l331aMRITFHܞ, ۙ+U䠧c Q"@=*-TLxoh2E_@ o`pβ4{JAȀ!Hs:ֽ{Z0LVTn/qh_ +ӞʨomeRD5oom(_9)'N)߹ĭ *+!۞e$;<DQ4@ptctjV{P/;֚qTYԷ(XTJQ3CRDEv)iоYEӂh;T-Fh02Aj* vߐoI tX8c5 %j Z0]ʁjFR =.GY->gIC3~2ȾZ^g 8,|B -qnܩ"f,ȝO*vo8R;S*YѸs*;);XiG=qͯL ΙzKTjZqg(c8q\Ɖlʮh p4N͝t'TxіM'P~GђqCϙ¾Swut^t!2HmK6D:09;Z!x~0bC5a3tBZzvyJȎ\m%}8X\pne.x\ON=á{Q߰Xcu Cr*:~iE1Z?S"FV6^eEB%K^IU=]PH L,J?^_9{xc%v(C4ڢ#iR\lJ=VA<-yj0BrFɢ3 mPeAl>HϮ?H;T *gC',=:icxxv#@m@kHƫ:5"]E /.k,g2^Գtu/g3^e .g^vVv|Gy\G*v3CqhsRx|]ݿR<1/\dF,-qXgњ-%.})xFkY~M cIc Rԥ3$sR7 eoYO !PZ4*Wljao$ͧMR|I4NHWE拊5f }.@J 5JAl5ʽjʀ Z wkBĢ5y?.>gzL=s6䮌c^{I1o 1Σ9¨q#qTyN^3<€ujoSzx3{Z_67^XibK$? F=&)D^RaUpEN8d G_pI4Ֆ׭*Ua.mM8rIqKJjv7uIۯ4oGNNȲ -@ P5C.)n; Bl}?QR,SVM8)f o-2XicYyS7!& Lܧ kJ%m O%.1% \Ph ֒#d"~o^əd"e_[uɈڥt&'3jUsZqg}A.NFj&yQmFUɷ}@HxR&XoЖXK%KxԿMC3p69ûEMN41r3S&괈xXP<\Øbdb)9.5 /GxKD4w IS"'nKJ:b1yO^'72h$RioFg5oNwH9;<yYv+8$ИXR#&(шs1@U?1^p01%o#3=Kϰ:ӜLa4gKt=oA1hV_3Xq0b@ ّX[DZRnb'Y0̓F4mrNEbUovnNLTӠ& MᩋAOk7JOj&Z== MHΦj`Ӵ,&el)jfxV_oQϢz-p{qq24O;|rIt,lm,! ~c}=pzxۡOUW?)E-g݀&?ZMfU֓Ҳ#@0OVA,r:n8&QY|5;PDPdrpЬ3*MȗW(;Kwz(Vvxb; 4JܼQ`s̲˷sۆa @9Z&@{El~KbgPۍY9kx֜Eڳw ZZYIKGKYE[>s"A-cǹu "Ǵʑs Z\;vFEt8-aL:"hҤe%C)rКm߮5h0Znsӈ2f#a:dVث(CL3ƧGzKhg9/+&,Q355L3ᘊt~Á4J;j4'J8>y1m}T5FX&uZrV7vc/TPhk߄Sb2Hj[nބu#! KXg>>W|}]rߑ'ô_'CX3M4o2nBdI+G=GJET | °y,n!-_=ǯ-Dr`ƕcZ2k>`S\kV{VTn Fuz+)ޡ]Dm Bb,2-]Zv ƅΉVǞ)~ݭ&Yg,)[ѿ gEMcѵD%܂3GK9R"IJk4opYfOx;mão+;t.?OFC."]Xv # 2 2`yf"uX@|~#޶ Gw~cܶݦ ^։QdUۯW/E,/i"؊ə3! pr\ L@V`;#-:p3P|YF<dI U="`높TY/IAҦoyT=t]j^15R3Z8##nslo|?2E7RM9hZq#Ϙo[6"YQ/z㺡'M}\VB}PW*z- zZc㜵X뉾T!h)8ץyQ KZǗ4zٻ4كa`TJag[! 1|n |B:=mU'Yt_[uPS!T% %/yGE;x8;RLPkIL{@tI=x'ܦhΤtREy 9ȥÅvY# 齵+Ͽje(G{દI-9JPv{ 09QVHj4 " ,mQ3\o'?Jp7Z{e B/no"}#Rw r?жֆ}Ԁ3qԉ)Z:g<;neW26d-rߪNzCwZ$CXؾA2? fIO^:sK4#6UUvnRލB[Ô-{%&g!YD>Hc׎Wn4K`F"s)h7mn!} ڙj@twTm2}cyiH>/ʷ+ʁA3&?.$Z 'jn3b3P fHt=ɨ ^ɕ쨋:dx` 2j¡- 5i>%R,[8ʘ)9m""qqzp4흯j Eix?Y.r9>|GVsgeʄKjیXLjüЙdûPr.nPSN(>hffZ?fz/Y'<3S|㍷n#2({zFUoѨ`'-\{=/t+D-)__;j_qVCn&T{RNRDYnAZooxBW?\*Mά/i"C~ŋ<[@y {@" ū\%O4 r~9~qjfA"z*HY/f1Oh틳?uU~0%Mr\wnEx1-(cį_]7a(/0CʼnTDFd|'7JdV<`9f=U0 h*pItN3^ 5}/>R9hk~jƾy܅V;*H"ϭZHVe4l‘']ӡؖ=Kߐֹbn7rCB09M"KclG*8Zk{VM?7%kԪܖ} 0= oyG=5^V=.x?=4OØhcEHi 4[t2j& $'‡KX}\5GƳ,ϭ=z8uu#0!J^D;`vr=p&*o`-4`%\$-$VAG =$XDLmˡi09Oe-uYT# V}G+ a3ˆ 8\+Ct'M!\F%JаTJ$/4wcI=D^ >B ]opئo* 5Pf6򴤕Vc+Ob\y% >կ"a_Ju>30,z>$ˑ)8DYl'Кp2}򵊷?ŷR`c1= ijད .WQotzXm i&d>Ȏ ^x; ^s^ES0eRDEf:/eke4@x_-1b̦ڇBf{ze3Wviߙ rIi&`>==`V\~,0? (bYrԏOրPqGaǛʕZ%8YNvM)ry m~=7 g=is cdѳ5`Vwnu,.FzK,LT丈\։*v׬clE7YG8iŪen*8,SLַѕ3iqA_u4),?exY$fGkF x7m |Hx*YW`=o;r}7M.?僜ƶ+m U,D>U{QWj7ҮA7,OY,]*m4`N~a z%}m<]%c훁P\eŔ2 QvBd81^S'Txtj@fUN]}܂Ƀf0^֗1a};WnS"˂1tۘH4;n)J{U_poOe΂9@YbYjt@oɌ]+d(Wܶ!iWF&:9뽢U+myHfДh6q<ׂ#7{<6a` O7}XԌV8py">'Î$bG= QɹNBAHޛVmRd qkyy#dJvN_~;=~o{#L}[=\z|U>j vQ[$0:z{k'VlЁgY駍<ؾ'!>6lxkOGM@7|V"|VE~nW|>tn / 67dDZ~Ks1Z˓ޮ}Pե+D9vuitST6,i( L>l2_w:7Wp aB@~rq$_nQf` q>?}tAOS$Eo"' ~bɟZAm+' 'vծ߷% D6.C!\}n'pǧ aOmFc#FEM~(}s5`Zgs`9U4.࿿BvE]Fu59J׼L'lpkCsA,ۀ0 urc LmR[/)Ō|@Ql,vYk1OLn 7^`їqWbXD!:_+r}VSah={0Ѱ?q>N!d{KiSBvЬ{o\`p z w\8|g;actBؾhRKu̎1G9.ss~'2_s5vi_u}!j^'q=y@W+PE;7]:_{ DKx[{>rHiTyЏ:eS >֊d[lӨn쳓KSYӋ TYDt| #PѲ @-6{9ǐ%VB5_ݫywDZ iKXDμ)į7>Nj^ceel^h2< LO\!2l`]G5|4u!3KF.$}d^FSi% v-7{ǟ7ȆkZ|fQe ~>tz'-cws4}_j;RQ7'uӻUg$|TNFnC= I>-_~>Kޥ}+1I˄x -2 I͵5ޢwO^ ΍nMɵ9>y ?3.91RBMD`@ Bz'FL[mewi(16Px e~j*CfMUհ==Jxq&'^݇E89~NOI}Xm'SXt>:|Z.:' 0F4 O:;P ەŏv=V&3z|2,PTګC?Cwqp!qrk ЫTvQI{;1?<)6O7VID?K >8L~7y/\O9yMaU106/Icu+nD`6%*^ȧ@Y8|l@e ^&5UQ9p ɰ0B>h.^QB2|l=wQ9f{r=@Yqr'&YU^+ Ūyتh,ִf9@L[EU &Sz]yN`Ӂ/"M7sC}&yǑ'=5wl imOEeCO~wӒl V7Uc6HLyݳ/Ng~](>{o T0t;=@K(| S}J?N~$nΘ,>s::ZQ'!Uӯ&[YFx&fxR]q8éWe{rvsU%JQ 3 wElkEcUUglg;LB!{1{ i70RC)=FS+S s5u2PR!*|\l2"[_:D!IqGN-vz6N?{b8dn„Ur^uz.>%䶍"KmVۖ" wG8ڼ8;T#i&t | 1Kߦ~3NA{67pRut7AKhp,Cv.}ۿ> ڿ5< }Ga{h$!7K>iB1_Vu`A(m] >0`'vjB쯶țv(~mL6uf7ټ X̶q7d1&kgo T_^7$NǧyUxt"pTc1+)鋼FV_1?xYu.\hQ9l_GnCZ}*=N]mP@Fy7S~ !mkxv&[DXHy 瘵kb6ϸͼ/#pIG8@YBVA3؂Kg+B|z`Y#miA{&&*B֧ 7䶾8r3xfǧǛ䨪ӳ>u#I]9arж Cwb9{csfs` 3+s#I'=j"s/TYwl'Ks:djo`) TF0/Zޣ3M:faeJ7wȔw먲A4o Ev9r y(ɹ:Wdb0;xz0uorܵLq$B3mM.=7ST֍9g[/'1M8Nz䴅4J\G9bQ68OQY%ȝcѢ- H&!u>yjDga0/a2+U<1,}Si/N~3;soA-/o؁RտA)aY~-KDꕓ Q_,:.PsiV3bp]Ԟ҅s)1ۡO^6svS~kFڮI; dײ>U|CO{Qyߎj  x._Fx$,gj ?i+nnE?ss Rmp7z |mUK H ӹKnN݁thJޥWpȏִ1`@ ^UV Xc&b@5ʖ!g03L8;= SgdQf6f=%YJS/&J_l_&.Tl3x9(rzYa> 쀧]LJz`P]z*3ٛ}nnLM;sˈF8yX,7''Yp08xΠO>si[M!c"<8⣪Y`S YQxi%Vr;a6=}eng Ze1D閒ڋ?|UznNs`2u,@EcKnZG 1ž8=tUa\)zQ#?q@aX쎓^V9-<5-ij r~l-8, O n6Ziob\-P1=X9>͎<-SWV] /F^.5i}s~GQ1MGMMGy!n3f;HM"Hu"Xm D"P}s4~Ͳ6D,R'^Ys ґ ڋ^IQXv)m0_tiA:06ACq#d0VFyrs'W|X4W4JkڪVv~ViX{yܬpX i1ז jWn8sq&-V}^9Jz\ix gX< Q7ݬeߤ6վsh;jkr$7bu=@@;G/.oMH>m6ƓВEO* fGe[ˑd[< [쫾ADJ `d;q( ۉb䧐-6LA]׫2=IZ(促Ec<.h/9c^FY*U'A1+P5mشۡόij+YAjzE#T~z& vei@;S `hFV< y!EC:iTc=4 rA1 x25Fs|]䮋%ڇh5DZ^=ݪusˇ*75u <:ixV5Rԋ̣H66'xM&v)n޿CwsdB.f]o3?VDAHckm$8+ nCQW$\M%;mO<5H6FyD=VcsVw}]7v5U5Yb#@LՇ[] P]G A}~R?5.0zDh>ќqv"kp4N:@^y8uMs[CYim(iubHUv6FZl9kZ˘4do*1*K P;׬Uu"W%1 \VM|CRƹwXB>G |֚w%T?ӄzA h^Ԑg[t6u?NahI߆d(d@u~I!~Hcf> 51mM2EM]_Y;-\9KZ5OP'"5h&# Vz4qi98$-!Q8WcgF6V}&t+REr?Z $ > Tml88 V$\I!EnT|rY*m>vNL ^$䕈/߬ ,q:`2 /8_͞OVysx&uЯʡ6(uS^L} OnvQF~kyO?Pdۡ<ȶWYz&g\/= $uevZs woU?M  dΊ(ҿJ3HT7/(/SP)Cѐ^-U+^È!`(|/?|שR۹8J[e)Tf+u*>ơd+$}7ǫ sGtRKhPN4In,8!˂kT7/\a#LL_Cu.Mܪf@;D5 haD׷HY=WǓ8d0{$8AY)h>vj74;S~e%]{ǝ4dW.. ;C-ZCe_t_% Q~w^E¸LW'0 etg]O0 T1j]0 u!EpǾ7#UgO|%y[-647$oʙKc[ 1*Jxi( (Nڀ}IK&}A0T ~턌S$ I iv/?7kivn&ˀ2L ,X/߶`>`֢vy N #/? v9 kue|hEޑBx(x,w3>|IyA1;wYd94+^*FJp8zW g K2\\`S '* 1^ӔxMjDAn=>C\aDB7m9 %}6=~-2~&CSjsnE*p^^`:S<~ʻ~>IcJ͹I&jZrLJNpb}ў b,\~9tiI.̀4( Zjʄc$;2Վ>$a/=)kfŨ:K|1ĉ9[4qm̂Eh].QA>>X qe`J,٫JR=O Mc,#|0 B$sru,7)K{ 'bJ}uRW@-ًWD7!iaa0髀]{vŚ(0@J!7eL\$!h82R ~0ے@_+.m܃׆ )Ii&eiDXr;{#<>auK{[Lpc{C`Sjk\?-7/f`ŭ4Om ̻-=(<'4pEhCz;<p`,|wm˸DtGh@k&IG@ HM~RLR`OS_SBA'25+4ր:s-;k7DUD9 b&(cyD0vtg-{ uc'[,gD<+ /Ev/0z]ΛAbL5>Ȏ ?v>FHVC3 S)+[cUxsPY[xc[njt;[/FxY6B4pmo_x/gFPcIę?X .W3O4xD.)F_M7']Erљ?VTX!߸Gs̭#o~/e;<@m??9gQiV_`WL$^?k ] rl .ʳ/[/~{!=LK7JxDrHU\G1cOwfrBB[!Q3 (٭DR# ݢyuSweQٵTNuTv>|UX$35MDʵEx&GMSpŮB,^ismp*cԆC`ng:04Wapw]Hm<,Žnna4[ lM 1 숻w0x3 ƭmz]=2Sm2SE~qyPޢ^,!93~!32Ⱦ '\,nDγSj!2ulଳ+̌6v\ n=x μbBH{+!څG E9sBl4p٬ #հsB}xuPwkә\|jpjE_&I|dFI!-F+Z'jY\\dfLg1 X-tS2HӊjGsy7uH5vJBI]2NGV2qʍ4ŋ 5Q!X 7Is?cyrQ q2! p ~`)!qIdqC!(o9y-: gW p+&t {dwqs')E!>J[ķ?õB`hOweQ]Q+YmH߼h1߰ϻPO>;mClC$EaEdD@O=٥`ҰyP=Ѡ WV)8iրӔ;^SɿPh7sS.KK(O791yܷj%ׁp!s<6+f}Fhq뜮tGȕXMӊ8ߢ|`tUM^G:~ys[Xr%A_wa]!הCa˾4./:TK+s[#2]Xӫ4ʧU6Цh޵p%]{8˺룏`Ӭ$mtދC`/tLpyPI.}B4@9IRj1Ӂ=qYn>b;'kdoUnB*VKManGb $BhLjQ3cݗs1k>eiG Z,w';R+jŦs~l>!|+5vjT0-_V E`jư^31uN=%mϋoS6O+7ƆIL=L08Bq:a*7 #M@2L xNTI3\&\ۿs2\j ޒN+ODD˃<\x,wp7H :/ؗ|O>d{NA sb bw# w{te۟.o|hl~ʻY[û/I!b.ecV>C|Ua7[Z)_PL°3vst~'zz0oZ;|nѩe`P&Zhs>@ pÇv0Pw[d ݑm&!iL}^kBLp# N{B͚Ɲ Ŝ+uW_jt#NHKjtwn)4F[c6+?3p7Gk`3"Hh[ϓazN)#i50q *|n5Ck _N$T,Ǵ,z: Nrz3Jzr\z!zFv~w{1!wU^ PУ-g]Ops(.|?z$IH;De5B]$bk>vp4W<.6~Y4'itFdq/ܱS9 >߼K1]| {| >c\-É)g˒ÉqMC3Sd:.XyJHt 4xdi9K) +CD?rt}/Aۃ9bU'}y,O|N7w ө*k}뒣]0ΎNp-JQ;V( RP.Y?aORga 6A VŽH Q-g t+C *TP%?VnxuIl?Y&gn{$L,0y}ܨ+N C*Rag6!ؠS9dRQP_%OhP>Դz{b&bV{KĮ[Z\܇hbսiqѥASv2C< G(U2XF?:7KRhݦɮ_^`+4v="CT VES="fa-9͈_ӍgzGhOb%-*y/Wv璸Kc;m@ UNc9|'g(zpnd nXbL=$o\*_֤~drEGTвFj/)٪-wJ#3(__Ooc}z\1u.UwКY;G;(tnq@@c*HWqL j{h^@)" uU׼ˢMwe8׊F>vs+t|X)ZC5JUMSO5eݦ|AyW)yXVpJZxGRV|լ {̬8Nj lyr`ڞ0%_F2XA8>ihLiwPD[ :8j;Eȣk06h'<9Z]EzFsd_R33#kUn"*J1~#*ĩI,4ePŋ Eyka"hՌ>/s6IMI"+s=.*n4$^P(hA'rA-@X5^GuWֱj:(y7f>[yͻ2j́r2㙓q/mi8P{"sᶄ@{Gh*$@iYP٬BgۭT=}w + zrNGzί(&"ԣm/䌙>{86QrOo["wԃRRb~'xIC9.FV&(D&cCiSC mF 1uCFu3 <ʶr= }zӌSw4~;lޛkCSmMXtāiT;dm<MD[ylSΡZxz )"aZ.?5L;׵7[!O0Q{d㔣KFڡ5ϫG0Q-$y 񧡩wI3Md7mΤ$m,ZƎ%˨JMC 3Ϸ<(8@U"]u64?)Kc_kK@JIjEk~-%5E9wcXUK<#=;Vc޳0<,ﴝ&cBvh šlc9ȥž6vGQ8I66_^-Ք \z֤}՗&#a$?alV*AJXo xQ5qU zI\jC !h̎5d7Sv9Kӈ)v}B^sS網eV^(OuLpuW=~G ј(A= ܽ. t,H©`id]aB=ܺ#l%͚@JSx`꾜?S]5V ދaEa^o(|nz P'$irܧe/'?ݦdeDΊ8fC }EgO9̂\grv7l (\ZG)Qj7d3g_aT(W#," E(k28tTϞȭ »dWA ىB`!`jw~=<vbVZQ9A.Or`m5V:%Ga{Ҷy/a h4*H$׃wo/tIbQg|28=z >雒rf$٫i:}G' C -0EM}gY3jqJ& + 8!Grlbf6\SjAn#m+njo1l{5S2g{Gԑ|&¡T0U98+9_=ddJ?\'"1Ym@5'Ob+#=[!%& XBrYNH5A: 1r*Q.@S /6Zܙ3jl,ښN~k* Wm*.E`D|+jeH|7`ӦVIݴXrK㮬Α CDqK]*{uH;O? OϢbcspKp'$l5 #:YW %کρD{v| 'o]y1+rmrY;aWo߾gTڵiͽmN]kwuS_Bp%rRC:}3c`(r9㩠,& `jNt i٭{MIZzr9lM"LM u"'ܟ>T@~@@.xI,J; xW vX3 ?kY >ogQl_251R{Vu3#UdTT,|u [ГݩR\Jawɧ~od矣PeX_VS~N%\3|[s X90$pVP1@ծn4 x7t"1֙!^z_4 iN+؍R1ڥ%X%;23 iҡZؾ>{ǚ%3V{ӇaIG4p// o'V[QWM5>n) N4Qq|5wDW? {4&a׾o[=3O_$n%=)2 mԟƨEQur]g^0 Zk 8M[*LeC'udOJl fd0ePT8C zY.@5Lzl:Q1] %_cpLV,?=YO[Wo~ ׺n~AԂa#QONNh8{q:N7A\7h\BE 2 wD Sm<2a__Y?ͽI9b;غ.8uag/+o_d'<M|ŔhU@;,ex. ya]"AgGQ{l3߸35Yl''o3A:FLƻol2܄@~߿+ILukG1בF~3w^ę7kj b`HuKQHy(eǂ@jrgbxz6HNPቑ7NVz. V:-+!ꎑL\Dʒ'K6/ucr̈́tz>ݯ̩) #qB61#+{`!v{߻E0\1LN m\m7CƩgeAm8U5TTkj^n#UesE_Q Wmo^(<1xq{B/Q+~8Ar:A0} 0Eun!t/7B ϩ]FA^EW?i+G+з L7(fv*^U͛i,,LEF1--(9J\MrX}c-˸t5ޙ]oF*m~o[׎uP܉8ъjFE-|4Y4A}βUCY@CW]27UMc SgUvօFѿ2VSU4lF)S]\)n=;)+n}e7HQQwC2bT+o0<-r:-_H-/,qifgKW͢;}>l1S+]KT:}Wi-qىP[@tl]Ξ$|j*B{E'XI%2n>k(тB➈ >&$~h7 kH KL'uJywWjiV4k! HD4BwE`?ٮN$|o[61*#\u*A٣nQfGFVk]nS>\08JQpW8Bs,|Rx}#tMK / Ӽ9jSE؞~M߳V|ujĝ9L ;HaXy$VQ" aUӀUĮ8ߢ}@ ŁNˁL,C5c{oсP&숿Y6Xt2f;xKmC al{N/vJ_ѩfA. HYG?܏2_} Zz:V}_&treqS8tDSɅڬH.Ol5L%.^W9q >+'jP&g"g,K`CD'fzj\>yZ9"CܯEjKP}0YBh?_Dυe8e62^5wi(rOx~uȥ2ZphIvGNԌ ƁyI3:z:q8Eѭ)mmAvm"5h><~P{G\do:Z$(GJG9 j=a2HH:|̎OG LdӤ845I;2)GfM2ݼ 2VmڶNë@?q4$L 54t$UGlkV0 n@]@0ⲽ/?O_$ERث"uTĤn\=ZzGÇBAۗ9X'ߋq]nxXUmS;NIJ,nD7"%q<;2L^ ˫; ,H"z.%UU3f%KK=>`U Ȣ-&ˑ urD~i*[pwc}J&"{BB!4.mϬI*w$vQE0L311 P"ڋ9) 9gJެΘ}DunSFJm$=D3ۻtXG1cb.|//v}wy.xI1-Cɹz,dk' z\pd+yH/$_HN &:[ߘN,`qlሜ-E[?;s@K 7 bzāBA89Ym?Gt-9@O_r&,X:Or0l:)F܈sbrd҄í2")jZ|9cӘ!ZT|Cu3I{Z^R0\MUHӞfvH[t-p+Z)xa@ٌA Xdv1MjdmXI 4ꪜ #]EhkeWXpM/G`A=h_DG}4 /v|Tqђ H-Ѣ4JQ~gNYpTx!I{ Ivtn\$i3fh;L"WPּyϜVG:[а%1u}, f:4U~-4";pQeFǿ_E zz4YC /!ī}sO̒@k]܇ rd`(_{ }J$pDza!*fcqOA%_wşm[v=Qg)斨<"qKԾ7.nU;Dxgŋ"Aȅj>W>nkmQ̭ @ +)u=6 AuxmR>3w8x5MhWK?|*w< \O'n.f2Tgg= LCu`.C_eq"ء2 OY7MSHݘ/w#|CYM@B */p$+{. A++oT l %ȯJXx/C,L$mbim !$yw׶Uw0][{3!Ύw޴_7/ݦ|CG?^Y^|/ꓰ ( ~ [.ߊLD\]D"U . $jl*QO Mҥ%303pySQZ"Ta͛ēوMީrv&.T/r3 C1GA)$*`r?2Rm1UCk׈J98sV,leY~ZFI)CQ+lUҸQ#k f w`uOh08_hN3CXiE ct=8;# ՛+Q$Gi$&;7sXe}fEܣ "a0]F" /֩ 8(Tp v0ʪ=zϢ;ABbf"(>pgqݾ.nm3*ÃR$8a>Plm3_%LS}p9b>Ew%mcD, 4 0M\_vMkMأq55o !K 0[v(sՈ:c?<\+( B猇n0H[PRs`5=HӽSxbz-$^0QO]a{nN8c)nJb$(rV퉔I(sF9Hٝ`SJ O̫;3 Irx (u3OT\毺;p,^@=,J^;NcNnjG2Ȉ]6T䕹$c9:P"}) q" :/%t!3`¿[;`)`c6?=,}TXE;A#QWyYQ$іӏw"|1\:uϱo!PQԭǿק'pS+*ڃ[dDmG 7ꊴN_(sɉ\x,8pj CQ^q N/+I>d\q<5t?+io('W;۷?;Ӷ i/":- VIP4<_7qh1gub@% eǻ.&oL^};t5-,3AkaoO坖G%=B"} ʣ^a\~5">QD[Hag^H!L:=)߫p0i9q~xZPgQmpb"0ҞCo=^o=#;{6aAބrĽrgkϟZAşhЀ-flYS__=OzZ Ux'g>L^ Fxى=簕^&Jxs Ëtewfgmwbւ7PA{Z [(=År)o3w2Tq^/ScL.qىPC zv\l3.q!m!V4"r&•g| ;X! %Ā_\--ʓ$C՚BM. _-ۃKu]J-A]:RsQ,G : 9?pSFq738 Iu^j7F vE`7XLnHLmTm#0O1rvCypuOvI^hzJXga2-bjl\FRA|xa\8`S#  ǖs~gUrrMi|02[oOJIAKs&$%*>joBAQ/PY^u'!6R_}[;=U\48P3حc~4EqG[|jp =Zp>`^NAUDsM%Xk{s1O$9P줸j !W'Or +$ l&ek`eupkv*}Px.&eS͞{|9[@ k&O8P{}c6( ?EY`&{k&W}JNU7O!ƳzHpUV? T3t+ۜzi: jvu_\Əm?-[5uYvAEYCG2sp{q-0N}q`s ޟBI-X.DZܮX_6Ïtڅ:bYM^mosǖ a4eD(X,z'.6Բ gݥ՛*g*ʹswɱ:<%kݴlXH:PC K"B<e\x S"PC"3"m 8A̲g&l!]φpƒ k ^qByy$){)fUqZ:{9A3/bhI/AEr3-SSwYI.w0;Q}Ӫˆn?H^SP0eV~ΐU0r\y}m}f0P( w76b=6Ʌ#WZ*[ wr}p@u<&y+Iӳ/3WLLzrB6*ҏ";BT_7.!k"☤C"uONUn_U~W$Xޘh{QMES$p6iٖ_IJ@dxbq/{Oiן':gNDm) ٩7'+al_Qdܻb dܧ½5 x 8/y'c_Y)r:(tU]&!>M㟲j{tY^UNGRSbIn`~ Rd :8qȦ]院U1l2d?4ȳ+rzC؄wb߱Sieѳݹ"'dd_~+xzp5?v'V]vѾI:F sV\Cjd,W v>JΞЃ]dF>Y ;8 Iz}eTwȿ^aTȪ^lD`9^|Y'!=1+lꏓ_8ܪ@_őCZ;ъuFV~mFw8W=;A(߹D\^0l/Ftw2$~@ rCHf9wA `w,"}l~k8hWqv:a#NҺ=s/5@CE߳pIs}ﷁ!A@ܾp2B-oeq\H-\fa^! {lg.bh6j('Tg)q$ Bh#21\T߉KI eB3\+W~;nD  _5K̻a"6n>˾T_!Q0uA{^Nfm5{֏ ]vjw2Wdb@x&骗%Y'Vْ_UdEDiѶrQdz2dhCI]o@g*$ѹݛ^{\0Z3;1gavXje|[į8(zQrQdGOŃ&ωO:bLzzRzkUB oh1CΆUlW+X įMw!Ä4* [F%iE0+u|Rdz܍Qgz cD|=W/eߓi^*=CF[#B2ٶ? 1;q"G8Mɛe*a]:Q|T 㼔D%ASy ~|} a9"Vpf=IoK*XS5d Fm݉X~GjLP+\ 2XPn7` {,,;֒ rvCSSi9X&dk>KcsA" ><}+ib:{.SI& pZ8O&D\%qпXc>K)x0,fSvz9 ' M v;0ؘv=?sߣ /n1YAP?gewr*|}co8y5M!֭J=vwFNok`7W'}U__sqww%$PI2[e-%6w˩W|n=D[*vBӓYHS (XZzl7zmus_cWB\HiUc i @y r]߈&qsABRp]%FB*4b8su+B%6N<wkosq\!ɮ7n-LBU/a,syHR/Jc9"db䯑_Սy Zܭz6W9Ϣba3Zק28B3.T@ iq3-SDjIq&)R{zz=ӲEʪ<7]tE *4Q!;0aNaЬ1SruFLBMOF{>)sv2eA>ֳFsU3+9,Zi~l(qTb $$gEOOR!p_NG̜tLhEs\'`ބU_?zjU]`ð T'8HEapDSUe&<Du GmA)pAUAxD` )iQo]yl:|ĥ>o;|=T?m@yI,IrC ҁvߧ6^?31Okkd--`-تp$+B vF,mVL)䴪Gs2 Ez9ndQP815+3(Ҹ{F n+ekh 0NB$Q@9\QESLٱ#ǿp նCRsnRdJm_f)QΞn2D{A49o6}1rwrûq#/$>yaRa|^FsK@-=2J4e9$ۤo"UGk |K ڢSEK*EV(j*7ue~4T_٥jM9KoKUy+FLtNq9&i+VCٗD_t*IX=^D%t<Ԝ3>T~Ы)ICiJ!>@uo]m+:lY%B3+tY>FIm$~3SݰaY%;z4K!vk98z'@"/ʺC! ;Yꅇ@  Z2@E孰#^l|ݗm>Qc@jP>56a o zbnǙEŹ;qfUC7;:]nL0F棐h즆arz2aPCIq?3A)*U>jT޿ڃ>JV, ަX;c< Gg׫r|ݩW KE#kΙ~)m]FS"xU.m907"YtԨ_5exic)gF89#(slτnvpvyq ӫ{W*ݨyWƗcFC_独- :1`JSڡ>gC{y |x}[SCw*~4 LY۸#euh˙qwϙc*Um,2l8iH p(B+v_@d=Fio`k.D(pV]hzu˗N~)g,tW`8wyܒkCppP\ KVӆ+>۱7jXAs1Vΰ?yփON>+DM j ҴզL88 WyoumAdZMi<_z;^=p~Z/H3оpΠʂ4b)IG#\I Ez5 $c0Ǚ}"nN9ْq/AO$L x/$ȅKrVA,r{%N1^ɛڀy)Q ٥C2===a>JB]gP?|`uCon #1(a2):[cV_mvP+@y/wFиWz*ϯLؼ$=[ m|) [DFces0was0 $FFp&yo+oFCT[#zjˆ:#q6-8!o&SڿZqj$_iˀWWsylD"{&,{/&vBƤS!O^ h!gU#]`'8}[p2 jyZR2ax2:ġcD[1Q&oQ0wNMa)Zx? bT.dk[]ډjhEKo =.ߊZ[X &…lk IV_ID(͟S:A_u Olm^=M #ߤVDA>/x|"leuޑ8QU{YdG&Nn)W@KU)\٨CwDhx39YWVM͏ۙL ц@`64!TٛεZuV`nWAQ`5%B_CQ'^[Nf(8oد`ON;YwǠaKCsめ˞Oߎ^(Oi^ղ5torXT3{upV p #eK_ۗ('ث 7}fRX5 %*'8a'pӲd͋S,ھg' QetH˼4p%GD1S^ ma03`d],˸`}s9An1g+# n1mPSRAtq/76Mv6n5T"矰SjC&)NdgˡwwMsiPIfcu|m@RxLbznvx+44wRu8?PYKb29]:D.6yKIt+%xF4ya+?ê8p)i OO?6J[9q3Xp>/<ALV[= C>ez /D;'O–Aq ,>yawS?(- 7ZyN)[gJ@n;{/Cfj%dLkGV {2P/ߊ,h}IKG&5Tڟ~`SP?1> *1-:|*E)fb+#$ACKl#U}lWF *8?pĻma>?$Ri>8DB 3vNO?VǠI8OY!u̠Z.T>w:t|G+(6ރA0SfBXQyn=x2o7 z@Q~m4~x@h@)g3DjڵKu"QϫCmBꐐZQ)P7uKJՠ8ǐDvE+ϑ.2kl"c$2eլ%~r=S; -ce|V"Q"Ey!ɜHb`M  ZZiY6SiVqyiAg}f#.~8G5CڡPZF5 ?L/P:wCKi3u)(-f,ݯrZ+3s?am :}W}ϼN a`;/K>ma= &/؉$z1A,u }(x8yk@Qc_ii2~B^E"=qɋQv4'Ea)%yS&NT!J@F1iNjr?2HW[ni J"Ѽ.<>i?w ! /_l/B 6%Ok2@%@F8MUɋ(1ED9ܦ]2e`>}]9Il!M]B6kB @F&'ՙʸeurMcӠ.N383 {⃶ ъ5i:@ 022HdMƗq E+~_'W{'ϑ?szߖ|:7='Eu}&tLTtJ㒇)S'vş?Uz_wşAv eY(}7G{* .ϽsKE^M֩{+Ke7); gn C;0ƃӧ-gAWoJONc.10n((E}yX_͕Nnb TH%RƝV@1h ;rq> #g7гUK}x׉RS );15sv^Z;_vb /AA91kN _%-բՓ~Ӿ?:k8dʉT.`ۓO~sf Q|Q7EU~_=ȷyU:|jv/QJd'M_/NR37/9mO"CzIN"qo^T K9(˘91x@F7!yayt8 g$79e'ڥّj:.hT 5X67@}"6_56-`n~Qȷ$atnku4ڮIu<v赫) Z>*Pu'/cTI6Қa&M.?%*iHj7x\O";l FגkaЇ-nGoPñ|F<,|ˊzPrԎwVr7%4 Gc78S 1\iry HΝI"KEtju!r;  # BF+3-aCj5{6; V ֲ6l0TYMR]P|,Z˾(`XiwT<7Ql+OL!tKQ8\U> oSk4:".8= Y@WW}"o=sɿn|єm&(>Hq*^lr}ܸfF/@ -H,mCzc^6x{`nH&ZZgV ZD¼I^9<7ab0x#\ZJOx^;sǮr?ʮ.p0x}!vY G<yn@]>=Ty!1;7~>KCjŦ1y(16Y e7ZhrsԴpCG$]j9<\8=^Ⲵx7{[k+,>i`AHy8a,Ljiq"_ k"edA"ͻ #, w/W 8Țg;[sdʍ7ƓfAS=ptYP.5޹ZÔ *J'pmo:nLMZ?|Yw ^_K0~-Yu. ?Dr;9(TEeΧSƷ fxؓVY\KXVT?paHJݒ0#LHDir9[hS62}yBSpeƩ_^Wq3u o֜f)ve|$ŁT.F[*R#?T*Y2q L"Sl՝L72]@mhrwHPծL"1` % vW~3=z#Հ&T7o\GӋ<M|68FIjRbd`c椠!.9lr2Ns1:CFeyHob}2הPOmf➒]^* 9f.=WoZl~1[^?]9`Zx{@Md( RgF蛃Ն:JE^ bՉ`>2jMG@fޔɹv\+8[tr&{#Io(y葲N8&DU~OS phflڞN͞q<ꌡ͑`r ĕ aXzԸ*o!obx0b@#(~L, gʷY߄` ҦF;|\㑗6x[f}⪆LB|Z_)Rj %kԬ9G84Wf$#!:D67($4OL9?]uSvq( :F!,TqͲN6]{ƫh=R'~}t0Ø$5|4vDK4A0T҂N4ਞOZz+RυfƦ?jYtwJB7hza8+I%m=Ҩߕ圠K觯VA/ #k,N'P %B)2(#wϕB_4mC"J_#U7ze)X{iHt+)D.Drda;C[{A$0(IĽ͍D1(N,T9*- fY&a\ȡı}V;K1N@ A3B!_`}Ez'dQ$H)3'GL8:ûIOc4w{7F g7LH#G.ƷSuT l+.V&Wa,#D!{[i ICz8Sw}rt8@Yeȁqt&m0ѥ朢Q=4U>ʸOb л21zvƤB16$˝V8 NgK*숟{t=^xƫ ٌUWD~}%, Ʒ9f;Ȝ,lD& 0 6"Na=3yh.YzMLhQbo_~1EM{ h}e$fÿQQ 4bX8c_79c%?"ܮUT͆-l3}wo?y,AUXapalJH3Re $7E}@!\,9S*Ñs2RS颃/ig#)=oїQ!WӅ)![8x\%Tic6O4 oA& sLM=Rdk(*w+4ynN/-Уw^f甚DjVۂ: GF+پsZK)gǏYq(Oy9ri!:ڍ+' 'D`syHӘsx"AB zݓ"y#".'FM$@m[ S5"ONʦ‚:y:l_9N뇙c&[ #T&i&BREC0h}< XDhde52O܉&"D|K(3E˵, y>h~(r6"ƀc 9/rEY|~exVAƳ,M+9}Qe\x8yQ3wO(q[1ֈYʦIQ"Gŧ 6:Գ(碸Cl .uN%~xm)YT i.M idWY!dRtCv+::6hр~6AY 'fSD( j{[0v.n:vnnD"H/נ s!Yiii!g8kJg5sc~zQ;DBVnZZׁh 6 U7!m^4Ag:&3p%@Ӂjfӳm~YEY*ًɠ nWU[K Y'ܩ8ĴwGZU ' E\~*NF&8lfj]c۰ɦ:Y5؈wŒ9ռ)˸K]A\pa+6Qn$7ռ3ĂSG-QN>(~LzXK%rKJ*<ǤV3Jqt*Q=!(QcA)KǖU\uv.s&H<**3N*ۧ~U>-JmU(Xzc0tc!wƽazsp/Y~S_:aqb;Bc7* s0/ T-f̥y*2iX! I(烝DbQfE& IARdvL އuah>^YD]9~Q эБ1LI^fr:29͂\<Oכ(?8Yc t2iVQqPѩЕ휖 5L%Q)A>.D̢ 2+ q -tHEǘpE"$[t~N9E 48EQ|E&>}-?#s@)=ލd%uS̆ǹju}@ue6Hk埲{0B6z7/+zW!vCG{ '~KW&rV $= 492 H s=^(~-?FF39TEB8)(vx82xԮlx 8R}t2@( 1Ϛ nR-:9[G-ey 0ݗ cNxk[3K8q(vQnoBa36KOB͒^ܣ/W3( VeU˷B$s|V5`Fs (kSEK7`X'QwTRuaF.ضqtIZ919kHj)"efǕڬ32TZ66XvEzGi ȯ2Ǔ^E$9/BXYzNM]]uʨL,6h G{a&צ6C m FYz1XV~KC::K35gew M} hxS:iNdrRS|2.ow2i O$|YU Mh_AQLotlay = {bc9:B)&/'SY4D uDl̛ǰiXfPIw+Z/"4fhݷ8b2f6,ud.h #V13B*q8^8:]lJL%n^06j%ªJ)C݆^!E4z]I>u k,.jKP7{y4Zy cۻҴ,*-,!qax*K9?D3O7lϷ1-?0d7Ĉ#aavmR>);-]Ǎ򇞧Vva3Ʉ]$riXQ۝{$8C&NprM,O\B3?8W> Rk<68:ݐ&Yz-2CC*V? CQ>pߤgJl] ϺRG7_aD0, {8؊W.YʴEyePu25d}aA-;9e-g"?[ML69"1e;@uCe7yM!c`ٝt3릇eb8(zV[\oh@ ڤwN*zb&,(R4NjIX\$/wC,VRvpSX/r#"qE~HT=Ñ7pgߚDZosSڲ3k'v-2;)R"v_g8ԁeTJGⰰ,, DրW8y +bIyS7]CT-\^r8(0e&Zw1N23wŁQ b*F#.CP` x ʜ Ce[H-f吧?:e!;1_g7u5o}:F@=$Fc/'ho2_M{HKW+{]7V%[yƪ+&;5EP8uP3σ]HQ9ռҳ KjEG9?!&M/ykjߌG]adXH] "/GE$Li{\ǧo|{'S;GXmeߞS;7n] ХJ{T6]0z^uӯ%Ttc(ʵHJ8lrZ+ޣu mR-̳^kN}$st١*ڲ)Iz`j}WI'NNEY M؋6Ks^ "fI]u[/W`ݔ`^yN^H7Bq9\l7{?Ýĭ~:|YNn]; b8JFv:eyj[{ʉF~&ZxIntUX={I &0Oq/ ]Q`H1hv!FvuؔcZ-=y&2l4wv w@b& ioقץI-W[{|N jeu%{T4WSR4CSwՒ=oNo^X]T>gKkXo+p۰tb']vϖW>WiīY_q$N]͡T;ͳL̝K1R`zWWb/F1潛Q_ګY6ZQ{Rxc$ZS zxV2ر[k}WFǣ}"],vգGyTm(˳e^ч?CCQSe|yvkwL|OcR/<)gBWn^d< x 7.rQ4)b+C gnVt3QVz0Uz"xͬ76̳ːS"i%O{N_/b(׳ :y NI;}Vc˯G{ݝ=yz*BlO{ .u5zi(uQꀣn]4]׍57/Ngjuw7x@m@yݾ/w<ͧ>4y  UX Q4_j"?>%ᎫzDMi&H:ڵz҉~H9u$bn_j&?݁05jk~Ǐ>$&kA'7{LZL-ݖIfSY|/:pei o[PKAzQ:7kp,Ѧ빩0jJUVvH$[ܩI=1+?O{&={wW9P{)Rg:/V?ݛd2u 5O\؇@obd,>?}[0 a0xe9+k"[=BexqN4rO!he} A]O)p} $@- xMEgvDbI&j"t0@%R:_ پtME]+Ή&`h1KQ,Y\1uZV.jtm3SnNHG*D֑pWn,$i"DzaZH`y|;?y^ <#o嘾t-e$Q"^|p+W_  X#58;Lv2VJt:.,y6eOqn&ՀPSKgG20MI`-.i*LF}/,}n\ꞛs;6l79\ j½3y|B/UJV4-#{ Zv揾UN =QPvgQ_CuSzT =w7z7a#rFA*%WjR߷=B/Nj0C5;+ rKƺҨGe'ۨ눃ʈ䵻wwuuC:^=QR/#FkoG3=R>}O'x|Ok(ŀ,.e>)X0ZBl;2_ A'<Ҥ3$?̜ZȚKw9,S0+G_kۉ* 戾A8n'CJl59Bbt0?mZ,wLovX@[\,F#>fgS?=C#b2Ǜ"(r-IsU2rb*`"OӉ9ʻV>.f puB}Ug4q^ YL< %mC;70ru:,ue'̉$X7. &jbv;ljT=GDƉ>GٿY~RBx$i 1*J|Zng%z(Uwdgu8ըɹ43wixv3wG=EdJ9‡r.Z.#zțӳDL|DZƈ[Evէ _!W Qo!8ou |xIVBxj+~uT r#+w]f׎f%Fu.Dԇ8r%wRH nW!-.xY }HЎick듾ؽ}}u?]}Lms\ 3 ?%YBϛ$A=F|wuԛgn}gg{]*t@4_}Uduݧinis#oz&6A캙>m~ΧZ8uK1X^:nuӧQͳId+se_y3],' ke;Ol ,Ҟ,E5U E(m9o3 )hy]@&uWFA;0Q`d~}|O#a8cլ1\5m\Cv։YyZ!Sͽejz*UO%4<9'Vr_J,(mfLn<}y4N ɗ#|νljW%wQR*!RN /s.CTrpK+aks.|mk8J%dN//4I{/U|s_ 1|]ά fsCχp{..Pls8QZ:[AJ*2ʬ|@`"Pv0޳ A'ȰNJ@ze4/&`SoE%iK. zF4 1Sc\0]?0aZg*b3=w>b K}e^< AB5 k$Ve^zF?׎Ǩr'j7Hr3sygy?m4kz`qS4u˵*W;T<9"`>>l9vo附C("RbITU?= }` x:qr!Q 1n2T* tS|9эZSGiP7l:=׽kz{`oZO_ \%~ =hkʆvmXeh1 Lu33fR#:LU&NlGRYx-]UeT,0~ARJDbAOa_o"K1%o@?^lC{ʇ`+.hq#'oI,[Uܑۿo~Af3TfOabwaH=LL߆2UqR*C%gl n ]c}}S) !B$tլ† ^lh; V8* m¹Yf<ݦebinzx4znaDT̟qqzwϓFLm3Op6h.YxMyvSїb͹~g' O;kby鬝t/W}|I::{ʏ#O`O qaM}(bO$UqyU)z0`u0(M+912_&Q-s1alx#& ԷL*> e#O;&G5PMާ'n&~c3:z %7}dK FmjkrxjyTkUy^E}`-ݐ*gzZ jK+䞽&sK@.utmJIWF]WݨΥ/!GDgaտˁ0%ώi?$S-@a3‚Va0QFƿFyUn0oAѳ{)~m[l 7~20}#N!8PE=.OMk`;  w ?>֙^)xրy`2ٲQԻ-i@}?z}N gS9H1k`]͏z|g˨(2bQjuBZ+`pQ~Y pMaUslINll}9lݜز5k}MwksEFq<[yuBZK^i2B3mI%{Bq66M= 3\e!:멤/t^'onMU*(멾fgjGS؋s|09N^wc2(qv f"*L<&='-)NR{DյWepq@N` r15f!gQF|on\E֋Pe)7Kjb-[0Zwgs~!\mhyCФbc?7ER\ mۘ!A[^+״#!] t X9qYm6UpYb6fVv.,X-m9qi@Kگx; CL0-o- ^HN؇$`~~qڛ ƛnΒ̷7 *iѻ(Qha<J]6!, h'BRK[7w}5:&c%>%P=YvTCvܓ dpJBǐ%fQQ V>HrޛU7`z6rU{/ׁGW,e'qXPV``y|)9_4f8g o4 ߂no" fEx[VLn?>v?>'uc [ =BOX2w#`v('}UN d)=QTzw2m8 z:+90oy"Ϳckn5^8oHv[ ItOv \3s%d;n\ 0{qQ}d|;E3Aų챓3_;igN\'(ϣ_^IiG%ǘ_fY?˯H//… ]!Hͫl98EZ=U'ZS+uB%d' ژgHI@r[%In3vE igN/&:MѳC s=< rp2],m,t^8J6uM%xrTviO1UU?9"ǒzt"u;9#iGA8>W';B{Gf1SowecbY#nw)Q)V\(r;vٴ :I͸t0(Z0륷I*bl1u9TV =:Z_vΙ7Hzk.;g}{1(fM_O=撻!o߃Kn3NzI<^,d_6(_Wq m`E!/2ٖٻ(J  UwR8ڒ2CSt}К5!)U8v%~٨0P&qUt]=P&6;Ku5U=i-~[3ͨ}U}?>,}Y|ﰇr318Aإz2 iN,w#Uqyܩ:Nӷ|C|uhn긭^=RJR1? g_1>d_I9Wݩur3k$ř̦rh3t4(>7Z1lvVF/cUDo'i~C4B^3ɽu$tUyg㇋;JT#dTtH+q߈כֿakfc*'Ɩ_\OkGkVaFj=gV~fy+~o!aH{\k_]2+(o\f:Y,-ݍ&9}Cex)wm~UAoPHӻ2KThxp@Xvgf[>eިQnݴ|.~yk^;vLzafWnHX@S練 ΀f8+򹜩\`󡭽2;7zrc'}#N`.&Dj ԽĹ8K_хBFPN]mhfEϝ8^}.[y. Xu"k57LR*q" "Ɔc͕xRtv՞5c0Gsb=YFwӫ3F۶ּ9y$}1eNYFi:{8}o|B}wd)U3`ޭ>/ G駜KRh%=wvmQ {bskw-k!΢1u^c/dIfÁ'ztnӶJ2k bVX` ,{7A D&Oy[&Q}~5űxguX}$4guv(QCT$L(B~JseeRڱ ꋞyg9`#\B͆Q=Fnb2 AzFXrfڦKR]wCF /]fO'8 }V8\o;)̵3 V80rf?Ib̷7HVs!nKD ҼC v}ړkoy~옪4$ UJmž6Hm3{a}cn෩ZR@S Ȭ~aM-xQ*oWW)ey-U^GL_-x^寷Na/'u!!<#8nN1sކ\K&&z _𼘺Q75ӔIkBs 'cprz'܊e(IYXw ohΪeŢHL'Qg B 穈 ׾пw5w֕Y}r^]x@Ə~״ēQ]*߱uwo01lbFϥRscZ :AaxZtKmEM `,[wX <z_$ CBO*sn#jQWŃ zRsЯ3ao:WHUЗpP5A'o [Dynrz` ow޽ۯrs-bI҉}zJ\ zy]q}P·YS'S(h+Ǖؘ֋Z5ū/3y, s@y0uIv=*B{dIc,>/zY 77SĝffF7 @$ugOnz6]2'nSi>y՚@Pϒ2$ND֝Dai5 3ǀTTQQ4rCbv {,u?? 夈.Hk 93hڀɽIwdz?c~{u_<I!@xdbIZ(~?<(b)}Ǥ{F gwt̪ǜ@m*/ru6`6`E-}D9Xs f 9I?l`v"f+mrɻtE&7ڳ?44oV=Ou p9ܴ4IID8xB2`hVuΐO"]CdMzhe &"bfB>uhm\EE]XUu,3!hxߌ67zs$[Q5ƦOK>Ħ,m䉾">:9Rb3 Lڽ*-9>1)}o> ~ f BÜ[}U|>A /@V1bHΗ=nҁO#X|͇ô(a틼8A@YA& 5&?8ckMri9Ms+gQ:pXC`47!9u}pOB!y%)[oȲ~ث^M.[qfjM5Ihk]~^ P{+wHr쭿zDw5~w7u9AoAnos ~)B$AhTzHq!$}3pH.ܩ</W'*ʞ <8-Ҙj>ũG` +s??Ê/)˺Ojugqyyf{1ϋ8 mz */Feӣ1G{}}hĎnyc]V{Z^j7sY3O#\UN2q!tj6N߾"/ټ&3u9eͶ` ln;k^-:UӻBvRlM0Jͽ"'s$k 5e= ?h~G!tp4i;8i]D6dO /HNyrY93𼃙 HD߄wԒL,ˇ|61DL>S/y{46Jjy/^]=zɼp?Lszc%GsT3c/f WѮcyN.R;aiz,R2yRk`cH}uҽrȶ|OZqpqE?BCz7u:7!f`o_A} xP8wL.:D&wbH_3/CZC3 ;y<="3)}VcN0rROvF,O|nB)N~lx,NEaX.M U}8<a%=Esz] g ʆP>^8۸AP? r|39rU콈UCJ0ץKg"C2g#,;|rǬx 1Vd'˙J -98TVtJ*L˓Ye<9#hV6c`qh8X`žT;mDOΡWkm3(P;H7+c|}ڐi)x骻ɀ :k& D0SB E0ɲl$n-pLj YV `Zm= UQl CvZ ~HQ7Fs̏Uf*83$ur[/wY[t_aK5Z}+eZ1rⰽ!̟ˡ>RFQCƹYg7 ^#=VwP;c3ާ<ngHu-̞g ȋ ZFQZ"T.+$I}h-9]blcu9S68NFА:$> {V/Xn37U&ѫ:^S}ݫ|СOڍz~mNQqucscXCn`qx!{zf^6nBS _|7VBrw .9Hٽ8SZ$?5b7)t`>lͽP ﮋw bhIp[cdc4B=StqWuf3c!Tx=6R\;"b KftH@wdd}*"Io u[nGvJ2n%VxISI<ݓp{`dt@ 68Y3dkw@x[]H*woCYxVK!Ϋùb\s4eCw39 _A:OiU}(~=4,@e47ǣԚWcÓOMÕuE?e{C:Y|:Q,[o C 1Mv:%dzvG?:x8UcHJb"V/ZR/c/mJgz`W!@`HP~es1NWM|&蛯-jh.t'r~pUĤ W+Btx@z|+(&{ۻb&gc,EF t諥$O{LDjB -i4N2q6ه4?2=`&W'8q7N۟O\]#LJ+,,=qv ?BoRAA&, "zؾяeER666:ѽp~u #=ګs #uجf[ ľZ1!rx='O mq%ps^%uF "c|7Aqa`6AL+t#5Lm"_=z*7qjL_Z_mMfƙܔ"e*Z(-JPzcW٧u:2/Ŗ<%sh]sۇ*qf F;ad-`'JvH\OOdYdK(>܎Tz/Gnu6ڽr7xQڊ=%&y` ܄h%fW-X]^dի/k!pXKVBC"9!^"J_\$ev&KM2 z_yuFzÁaQj9^eqC~9obZ}]e 0<{:nhB/uQqz[d:I#fgx׿/'γicl7y#4lN?`wb4/Ȕf1S3)3̳kˢ^BΘ8^fk4[OΟ6Z,0!wnc4j0+͔ѷ-!y{k&%쬚0m60vzmw.ղ EԻ"^ SϜ qKi6Tm* Mփ@<bpQVH{Rå\)mє#R+(&iD(nH;&c;uɝbi_pwp:V>l͓@2 (Up>5zH^kF2%{)Aukyu֟=%3RKbzĖ4Ϟt=1jE:k?x+$+Dq|%EWܿ.U=]!v{^ժoALcnTm=7O LI uc7NJNAt/^d@Fz\VCY894YTO_ȞdɊm/;mm?a޲̇t4bAij*4cDR 8kI |EQھroaTo(T) + $aXڗ0l-N_Y(˳e^чJ Ah?>,}Zk3'{"~?Svڏ* 躔p@}) A @ O.2sڒ]>o0߸ZXGүmE`ߦw0DDȮ_]̠BݝOLMI[Hsow\E T0#8ީXLT9[_Z̡5ֆIa=?}i1d[.* {6v9@v]D:_L0B #JCp8Ydۂtp3ԪĵM4ғJ.ǠS@c,i5vE%ϝcf&|&uF lҌ u?'P_Y/AQi1 Qju9:V:?ya9V3;}(A>lO)<L@ 35r-BrɅttU'NV?&1ڮPeJz[wߡ0@",#6,xd&"KPp݁9=*MI3 ,_p3aO>pg]5</89|xʵǝՍ˂Rtl^T4N҇ͫR섶F˴Dݺ$|C]i̤Wގ|}?Gs#zRlOԽw)6sнIX_SUV/YK뿯3c`T{n BK]e%.u5q^ǩRlޝֲuTw=jH|(L b;%ZuɛJ5c4^"yuC-Ưo߄7T2Bj9};n¥,"!% s4E,3L_ /8Nx3yR, A1&p.MO_܇g}U KkI7y'+3O]Z$E$yeGBK7L@4/wCx63f8u-~E{ ù>Ņ .q@m>"JROD9C߼hw,\tϕ3պ:Kܳ9BM#%@MuEv#&Rݏl?m{H]9!~M*yRԿGNY«aV_/GJR=2[` 3%z6bpQA;geTQ;Y[@ ;>h6D,NGi(z5B|e&;B{v/IljUU]œw=v} ׺[n9zWBZGujWF"xٺ8#l]zwƑXα[p1B,R3Lҽ 0JR ?gӝCw8OjP½㤘p5')x̻6s5̏^VnO}aP`jQ|/jsӌ$Wb#qZ RÏ@X{#}Mq殳P*C?C1Gop2 TdZ000"i&N:@ >XTS~ˋs5PݏzfaPq)roIQ~yqrS|0Hy! ZOkt #><䝻90f$֕̀fecиl,ݗ5.n㆝c,~؀Ҟ,&a&Pٝ玗U2Zs>Q9'=Z߲$@i}:s 7{&lGǔd.H3[]4㘡:΄:, ֭(\.< ?P,e`<~]*6|X.k%sQ8'}G2Y.TQ\fB䩊J`jsz*Ћ?q`˕8ej1}AqV]UCB5{-kT@)'#k鰴OO"pKT֬>WQatOm: {_^j_mUϭ ;ѕRtVlS_U #e4/ } GlGFٽ|W{~dOU!m6u+wuIރRzJł0'D"x+s d=H9Ky^-uȳ>7n~"hU{{WeV>R]|!J`@U[PofrŇt-N4c7K6! f)I3ʪJsҾenjJgr^t|\y^3F90cfv6fH>%is6 }dVS;'E]dyiK#9X*<#b5%.7)k^0l#=V]Z5NZn\w,`}䥲װG9#_]d(hM喇kzrk1ssJcn} ܭߓNɎN,5Z$]\߸[>hJ&\G]^8c{C\ydgA_G1JXv-s=Bytd;.רIǚyMK-5,dAB%GdprSG)ndNn4:H[["?>X7`pRPb\8t ,I*QzrϨxy1(aT{_f ordrO;+#=!zM`o#͚tXB&yEFM9w:G/$HQj4Zi=FԕvE_9Mwp!$V-!@l[z?FWKkҮvVgnW}=,ł6/A 0Z,oh-w9PUF/T8@yl098]΄M 41XrxjtfjImzϊAH뭌ӫR,˸ P҉47-5[Wv#=瑡hjNl%?lYL[C㽵e9OԂWݷ#Pf˻8A*(;K5b!@`PK;OQXe76XAJz'; PAXm,'./Lv,e2>@EfWt ϯ]8b@.NkSNh +Z̉tgE,|L@'v#\"Y0=>NLZ՜{{Er=ņMv+W;zI&*Dq 6=4߭g(uuF 5 mG7T,Tܸk,66 \:s0o5{} V6g'2xg#Eu`X-H|<Y0L_;[ ~b} ubKQ(8!N Bu+ `ܔŷ4.2b[83R߉l )DOHEa671ŶيY$sc5W\Z0Mq֫?kPP* H3>:Z JJ)n 53XeTFҏip^# Y)LJ¿Q wu: ZRPӷ ]iN" p&֯։j1 ˒ju}Mbls1x ekPcrFK2I*^d0%֢_ycUfhS"d]#͟{Nmng!ZsJj6V'vIIXkl3d'PC nu$:'DwΉ穈 eWw5Ӎ5.(g\ܱ`d&RRd_XK]'tL u79f9C鋪EQ!wJKR==jTk:ۑ-8#Yw?ghAzB(ȫPWF|{ ˹FY{+C{i>9s̗=A ZFWf2j]:_eeeq*_!mi {5.0khyay-ݾ^cDZ-՛Ձ;F~&dJ ZRBUiWX6N|xlqCzchRfVx,a18_+O8Q]NV`f>ʈmONե.S}U[*|Yg:j=_9?+kǧ=k>o~F_ݝF$ RoR7 4o + "gU i]ѩ,"Jgx5IlqJdR`yR==b6\MƍlBY:7B@i@ t>^2:[w}ǢS 'ɬ,D!Mř'K+OOʢ=PC#^Z'V:N L7sC7A.uc\O??!>肚=B Odύ _d"hEI-e~rBpp~Ĺ3WmO[)#<+kod\I2oD$nNӟeWFp[Yb'n[aWxlg?"7B\#8 e'5LaxQu|ܞ_\ I9tpΙUNuXMQ%h5q$9ثb!nLµYVHr ^ōx1ZȝƃvVJQIFPw; }bnݩ r|*=«51k5cUL}=e#y*e~R^BDX (ss!uhZ)LiQ5}1B|8k9"sB Z6^x'Bn"vgv}'] 0@BDd= HBmnn^Qؑ,iG܋y^(*Z28sH: 6dUQrTgeATQ~-}Lҏͯ9<?3zv$gq~ljX7? (=ϳ2J2:ҫ&QO*nW" 5)cUI_e윥~1q/ͱ#)#d 䄟! DYd.Vu;Y\/#)̣ݙ?=N8iعT!)Ƹg=OvQd'iT=+mx+gܾ|S[3GCpd 0T"0|a(=Ni&.0ˊ@}}B`~|cz aY1͍$ *1Q;CLݴ ,)( {5wrj^hpuJ4b!pu fBO]pRT}e?5 "vu*/!V]TgD87aU]PV[tYa;bZ-_wtqs >r#{R,/Jm} ߫R*!Kv|%]]*?Bv/>ZdP;=|-v:nqȋed]| @$'6B# t"̈y['لqc>=YM'kCyէ_g7muHOnU.Eiߵ=DϕK^Յ0zlWyXg=IYYR Y׮X]f /=*Gw닖q*j"){ⷼĝF.E9WDiV/Y571qUFi2u$CAj2Q1Q͚鱨N7^Ii~b)㜝gݔB<4P-&_W <.ʛ:Nؖ9&Y)s* -\eΥm?2ܱ\Gzqj/jՀ&\&L&`&X&t&X&h&XV<֟Qfr'w'7_I깠G,'i,GߕI Q+qwїGt5–{(pB Q*/JXK߂nNe!DPDjHG31|( B`P uA.rd͌@ͬDc5/Fm;8ydHKU{ESA$jAfɲ]TʪCd>t>i=V9nA|)kb=By`` Vaa{Q ݩ"&inݰPeIP<0${_d.3n9g|;x<Ϥ͆WQ]Gu*8γT8#&-@EnS!ʼn|WqEqW٫ly'ձ6Jp48el3c<@uׇh|);v*ш|8J 0a@ZA?.(}OuC.Rn%F_dLON?]ݜ%oN6w/¾A yD=am*PЦB:tggzC`zvUb߃y2g JKnzl4aAsAy 5/Ca*F_f-֟0vB܌3¸b-{QK0zDME99ɻ?Ǎ@BZ*$3a{gu>Rw߸\T`2On<⥊RcQυg;1)4";(Tϻ!0*RPE.;G]G˕viIsFIvB$ nz.!CtrGSœ(tV,cfxKZFE婃=: !,oJ-m)hKG[ 7Rіh-m)hKF[ 8Rі8+AfY`s0ğΈfUTˍ+"}H! IeopYVaBlq!k8ZLB܄ {HPIY>ľ*Q~8[7͈!lm6Snh!)\&/ yh7ߒ{Cڹ#4> ; Vw:u([_O:#$tc#X_;gLKU'[ 6#~Axܙ2NY0QfǏd&4]Nmw6^ȺfDUedmkM3(T 48 v5\K6' ]\P$x7^1tމD. fw z=3/C=Ox8U+c=h*Meo ZUY,4Π<&?ō@7i7i ФMZm^Z+a3b ҙ\*Y}3 1gtJiT/xI1OEHY!-k8; "tv]]Ȏ}Yה,HЍ>P!֫UIzOd:aw3Pq)cVJ,HӠXA=KeU2ɻ@!|  v}^krH*E@|qsVD/;]peZtv)d) )UJ \7')Z":l ZKaf+^XBl4H}A=81ϳ8ZY/1CMN){/ItpM^"lLJtl_p.]gXp</~ٓ,{~ٓ˞zٓ˞`ٓ˞fٓ˞hQ,JREI/JpQ_$$a% (IEI/JREI (IA% (I%)Ȣ$X_}% (ٓ @@S|Qz_^$$%)Ȣ$Y$$Z$'\Q,RV&Jߟ~~77 K6,V% X9oh{fw& ƻ`PA<, U*b-%Ee& 4_D13<[!7lUYfebB E坾zXX)$fyQ./`xdlY}B`! 1QABC  D! 9QAF ['# :oXW2 jk ˚*,ͷ͜BUOMN/$&ӓ(γlwDCQ@Ca5:PCa3:j$+$Xvyk}$^4%͢'Q.;A OyKg4ěM7o?HDTJO䉑ofR|L`Y);r0!WO M*nQ[n>3783(Lg 88S jp3)Lg :8S~pr3l4A|!v{nĀAy|^Pqv}h{m= "`h|ng|ш_oe\bV xZ/#Mw {>7$B%~-QWP Fup5p>k!֧lkߖiA~iT1@,Oc&mmm @20ߡ6WȮNyVZ'ć; ݙ+v&dm9<yVZrBxRqkzz3ͩ??:F7装XA5J5ũGV x7a ' BiQPFC=T:mVFY";@ՍMH=,=3 6;O=Ǥ=H E1!%g8}Vnr+dI6<15j]R"#OF_keR2h]/sin! k x/bL~M}Khrl-ŝ(w9>xYk'OrQ 6s " N!$$Cag R`8K3"C)L)LB)L)LB)L)L)L)LB)L)L3A 93A 6\W_ݷGI;Y$}4BsUQ 47gH&=4N,1޵ ޵)@&xצ]]Btn,"հWyZ݃k]ۍ?D\/2fٲ[?e-U\/ ȶ޺0f~zZY_|Z;}zZ>^-qmu!h}틓oax2362>mP=-Zσ-Ap}og|5 .ŏxBXAk%͋d䊑_lK/fn52>̫9J+\H(>9G0 wW`.6B@ L?U[%uϫA8Ӽ8 eۣl.)YT$C/ӌ~,W`$l,]jg#@ω!x$tǤ@a?9tﵞߩFu.nB8#=[nX9 S&9pM;{ؓ>~A u~tuH|07|ڃΏT6UV*?D)~z뚍DY,amV-8Ku޻1H:J^Y35O<$s;| Ez F:Yn?" B؉Fzvґ 1L fxh6a6|._?DD(8K7O- nO$uI#/w;+W2fV8dQ1Oy-XIfu-h$Ӆi&żJhp=w-ağ%=<ɩ|']=kT$rB(gJ# f@p")ԀHD : RVl`(`E!+ǻK.٥qx#_z8 !O2bjp5"V [7@63V؂!دcvx/`> pwk;=Ԙ"vU҉c'8d[b>(o'ŮmS ЦA/%DT5EbE͵r-Sϙ=:$%ft fudKHЖJؖ=w|[hE6?Yo6m5W8Ƴ>, ?H' T8c h&Sl: Q&JsS2yRFxA:{N J^-PeӚ" [Ba7/,) 8!3Q&s;̒HMF Z*?/7Ѻb ,WO ]^ TI&cp*s ]Q, .V!H% `AOKlV;:'q,' `I #sEQ#skOVN;7ΥQ.kz6@)(OQУ<)(OFy 5z'(OAFyBf< ?SQ}L/[$;/-%;';gSHřxJ6ۜIL@08PCA:8MտZɩ,Ϧ{yZcQ>ĊZb: TN5bGIgVbIJ{jpbg V$jf {e֡ !?~10}ӱD 9]$sL"Jo`,^fm000V[n%)VZI n%)pVZntpB\zy$u Y3ӈ_ǻV{fQOEهJB8Z2i(*  ageQ2, sjбfG5h4z7z7!{7az7AzvgyqϓKRQ8wE>D*SJǕVm}eIsudvOCpt)wifCnӳ3Hlc(PUS>M8K_`u͓oe!h1m}hx4Y>ۇlS ž+eTEey:uNE0-ߧ^ ,T?J{ 'zt&i V]y31ϳM Z5U64_Ԩ}B7mDy-P )\0h.}_mz= GJAgoڽ3) JI(bUΖ$wzgWߟ3 D0pUmk=9N ~NLpΥq¾=rJ(SBxd` PhOyA)N qJԥ?,0'%`|A=6hpIn~KJXp7_%tllx(w? I`;\ŕvmLA<2[0L/ kЉai`Q]732@s(Aq rE{S˖ˋ@bKuޖ:M#]ᰫĴ7k8#:ävvT'J# cV=j^aBiU ҦF'^iDa`tcF;RҾbb1'kmjAh9Bцs70Dt#bFhd9(vbh7׮=oݡs@>\5i_QMfڀ7/^~&ԍ͇CߦS&i!gX uaRYR@ ]a ~Q4GWT*!]Nڡh] TUuRwss\ˣ?~z{Dw{}nn47UӇ2oh#y~{tpr-aQܓu/ Aϛ >`4ݿ [AF͟E\{ O6_8pYj5j[QԟP*y^'E>topi^eftoT`{Ϊy-aPoQK(,סxawEIm5+ѣH0vv^/S%&%tw}r_h 5a҄Q0F2a]p 6p™J:J +#6)g*sy)øqwѪNF)܋&(퇘\H>Y+tpA߂tPzXwqVot'A0!\y&YB PF!_)a4{Q(G̞RJʇr8{:?R&=j wAՓ]C[ }jI]p M D+uG{S~Po6ͧGm6lUO^;rHū5ȡ戛tIzn &@%*pS^_|{l%Hs&慠\@81t@YqTWu[$=?щGzˑEą*KJS7xvr뤃 aupz)0(cPI^ ZS؀gIϤ݇C}p} &q\e㑅IBI2A}g7n2M03JZ-]O.l>}0w,lȺ]A5H2Zx&Q\,}#| DTh1 U规駞, Fd.BZ{z@4OVN5+U0b(x!RB01zdQb̄&ɼtVʎac|Z'\te o6l뎍luv:gyyМ{ Ob}3.*'@; {:=LPgT !K?٫='i)6 M(hBG&tфУ GB&Mg} фB&+٫n =fQD3u5%MHo<ETK+RHݰ>yYeW4aչiWs<|[ Wc ,h3SMmlqW=n,PЇ< E՟Z/$gNZk&{7lxJ&HCb=.;)b_K'ϳ'c*]uxU,t@GeW_,ҿ%Y++#be>+jfb =aXK'\K'hK'dK'\K'lK'pK2 Un͘pg1 $8=Y݊f7֜QVz'WjmzmaŃY鋉w1?%lv\1k舷>?\~/URKXNQg=}@'?~/s-hq7UL7J3 6V[{01R,dhH~aRFcFA:!{k9AouCjf!o1`c(H =78R3zVt\,sC/jd/xKH,DyW+[=NǬCX=K@VGě ]oMX8ܷmLއX+68ġp}>XÉ_+ގ 7bKOt)eEAhf["ChC,4 : &? Ww'Bc/up W/,Y<;8LyHˏoctgjz~3rzs2 my۷w ~ևN{M"wwr/}:LJ]k``,*Ewi S{IGBt +D QX+D2 t$ FN⸰w' lca}}pΚ;KuV0f~ }a_sgT:Ji:BnY%C~oHUmŞ=n4KSJA\ y:;̠< @ ]딀  BA5`F,̩+k Dfu>:'Ə8&XSVIiC6YW4"U^r" ic:|H]< !!C\ƒ8yBChy{OF:xPxDPR (, v{jLx $x~P6 LL~w8?ck`>ĵ:Sa=[=]',]"KV ݙM(uk7F08~go vw} 2x]j+</[r4w؆{RYAnƨ6}'}9l5DC2yp73A"q/as%]'|Ef<o|gVu . ۲ ٲ ղ L<+&i2Q_8R[BQh}%$c&;fV4ZJzg"+nyŒc8qx'&SlzpۻݫTg;h\梁~NJ[F^HWv&1J|( |vbˢj xvq}2Z }FCCήQ5 b>EKY~:N}$X3F~dt@^acx<@6~y\ t x;Q t =YȌЁ-U-9 ny9}FBEABT}_ooƣ>;y8 [eϨ4PFe׬r"n q!$ $iM߀r@}rRz+mc+#܉?f1-_fƬL9Tbh\17 s_3y&S|'~-^yY?z-`eO>ϞWhLƒV1L;|83FH3FP3FH3߽G1Bٙ$yf{1,ޱt֟WL ye!OT-);r"p>dL}ya$@v?q36޺xGҦןf\xMd(|ZY"덢%_c#u'hb֜qWY_gEDKI[{iBM5j:::Έ/ &::::3h[& ddve"쉘bѝ. ]T>#t8eSZ'49Q'$]Vw@eY O0qt`d|gؔ6pH˞=klFKb(vlT7^J>,YȢQ /o[$xeye}~9ɣWU*CJ/D_oJu*;5(uTP l:?|ge8xf"IKQLލ"[_S+jVO ]Nra# MKDZpDnsgRF ʳl w?HŻ~6V;9fr?7>p9<{PGq0h[k`E @+ ` 14ƻA{lFMԝəaȍ(#T 8[^D37[ Bέ3+/,NDD1S"Àm>o>m>o>m>m>m>m>(}mu_@/}'ss,٘Ļ~#0DY'auLY+eB4xL&qLv\Y'b5`]'ʏO忓]2r'ݶ))WY=9:Swm8,q4sǕ=;Ԫ+>2zH } 5 3y:cֿѥB]@^,[tlIsNվZiLjtKI`0}FugrU|T@_ZlPQPݘWPhqvw&!!!!!;B&[~WIص9d,3bVYJ(zv'JEՈxWA8'=d,_V+Qx]D𬵱~⓹ h 32ѓtSpXBGŒC?5K 1Ƅ2b1D +]lE8IF>%i#M9Ewju>'+NM4By5{lJ]*b'h}-`eB4Oea.ѽx*G;U΀=B#PWu+u](r)Yp.KY[ f1 KMol+-ߵ"٫1)LǤoB ѲB =w*oKcMtͤo![q;bl«=\{tawtb10CJ'@x?Mw x֤:#i3%Bڝ, S)J]( Ϭ̪f2;Ʒy~~)뷞NNml9լ~Z製ig2.jboݾa 80!kkf-`9mw讙@wG_)u6)D⤊;Ӌar|Өd [НśWeHZ4fxO4?;Y>SesO̥Q6u P:NҊqz*}E`vj.SU}lTqvCMŤIŪ?a"Nh?=  ) S:A+4cx;ixdX {jJ^iHs<3*T_X/B 4ȲnMTwҎB @rDr!y;>\])gS iJ3 wv>a`QLu3Y$yB(>DXY}Jʈq2VF1L^>u9ȋE)Bv.`R鎓llGnzߛ4ɉmK;iH?ޞh@$\b4?ȀhP#UxMAX# N#q4{y6]˚E3w{ {JFEe>n(q}؍QٳBͥN@ֳ/S76ؾQ(w @g6Lo8.[!^[rdbݹ ͞gQnn4zCs\ C^]cPDLl/"_ĩ⣜qE;2֗Ld;bޓ%(鳬 7 `EԀD J<YQF n4[$ۧM4vdzZM5jFLٸŚ+g9l C6m,Gw!M0)H$d~ͣ]OSН46.޻9q=fS{/G)7ki@-dkMo_Wac7a`VHʝEqU#3p=ħܱ¾nVeD_w\۳)^EE :U-"-"-"-tcUFv[\>~?ƝmTm֍Q޷7Z̚ė:(b'{ߩۙfuwЗCέ.`[>ϙ$MI_Ts(2T4nZKNp4}{O :-D_ f+][^>m* vFh-bQ\u/aR7F80Jzq[ B6B6™666B66˜6666B66˜Vpc g[aw6͟LMOn˖]Q_JN4~y01o;C|ntHeyu0¾ToM00rғy5)wjiWOe4v Te[܏@4Os;J-@y9-&7ӷV;!L͆^#4MFlyk,28!)Sl p[~44|͐ `): 7 `)0f˜i a)VruQN8 Xg" Fs7s_-0vV:eЫB=~GQYA fJxY]2Wm l_G[7xA3zߤwm6$$"S7ʬspC R?]PDw"?)3¿Ι($7dA"*U[B r\h *{x$8- .B%:$6&~γXjgTkw-̈́2QQ,zgk䀵z)Oս!Z߾¼u>Ґr+3 C+TwTa8gA0y ފ!ݖϢh\8R(pk!Ɛ"Y Os!!VynWnRkpff+1O"1+S̯6l1b!A{/Ù[E  el +obN'{UVd>}Yk&~F$g;͑[Tjr&fw >yB81v癠;τy&3w)3y&3w)3yބw7;6 Ciy>v[m!wsyn3;|AwۧE<;p$A[6ؠ;-xyCydCn y;-|<[ y9gyAȝ )γ G w[2z繍ݵPe\ yEP ]qmbq*2yJF܃ L+1k]ŲMA6x8ã./n3ЗYN~5R`CH !2RCCPa3j&cB]o yc7gpt(7Š0FzcZ' =zUB*T5T|AEogHVLlC0wH"S"n3Cb2QTFTp7}MB1[L3߳\EyXFw=;#6dAB1D~', a n)٧ & .SOXOhO~lqmB?B2sʻ"ʓ%7yM*؁ٷg1DfHj)R'TƝ嫐oghؗ;RӟgPaU|S-pq`0TEӻIQg=|J}y ng%m&AXx1(F'l~ZQ//%'zy_^܉bh/NOhU2x]xoÓ!@\OU^ ;DC!ųrMN{Dw YH & LLJSfiD`BJ{I֊ŗepЍF⅘"OӓUg\y j'pBgp;s MiÏiOB`!MD=?! c 1oqR{dE*f7ެ,/وg${&5*T5k{fl@$ E7(F;O^^(|ɇ҂mtzntQ. Ea\\ Rȷa6(F0]totQ؍. E6(F`]xmtCntQ. E6(F]tntQ. E6(F"F ]]j]nmtQ. E. Eᶠ(Ȟ] Qv4}slTFӦ1`'W4Bo`p[)sb13B?B?B?B?B?B- wu{=!־8OIp3IB6PA2l̬nl;"xalb-:x1!e FE!\o (Ln2)_fAf[##]^XYiAD05mySžqw"7+[;YЎϛ΢`ehזN|Ƃ>.-Km^$[S; @Ԅ؄pzVIII[z/( Փ v'Q44uOH pe.ߒS v|;5тpNl\ex_B׉Ōq}# dzp~?Cxٙxtjڙ Zhc91ZZR kIXkٽP&HkIaejd-dK_}@0{O7|, R~u>i-dHJ̓( a|91mSmSmSM}W!;31WkXv5$g_g7t""D]+$[Iy4x^P)śKR&}Nٹ1cxN3]q:inEGzQXׄrJnU1?-pFz#Hޢ*N]bYd$m4ZDBrJ qSb@#MC=YO^b9d`R (@յHEnŧ]o77^Rol֟0PDs5N5 ۑGHP<jz.鋲'mMyQ䅳{mq&U"_eO-wz UdoD <YbR)x5):V*sV4zg=MB^(o',v-vhFE[XL]New kL𝇎yHyXg[b,&t/yu֙qW dSCm9BٴZf6]gT=ک0>+^Wu@*ʾ3SspOOB'&uv79I=SÆ&~H;,ep$BwE>DIs`4VWu&Sx9[tPءEѓ(O?:饰az8^ mzaz`zgzYiAܸA \/IDu `%;ao7t'z )l]G~Vb^?h1g;,nJu/Jd^r}ex'κzEk^t浃z|eq*º${$-#h-3̟4lMt!t[>y :ԃog,7XMk >&E!e}u!I0sL])"Rk=Mخv4Q4`| ~5XNrlg8%q|b/a^+y_2RAWls:%0gGѤcq}9VeIVHUKl$panN5 Q P%Y,jAhPgafa™0: p&0 n( &0Do+o k jOX{:p?.*`6Bx֢Yu.{Xn_y`g_ՠ=}yܞݭ?ƎƏr#ywœ\rW$e6VPY \EY!WZ(H ŜFT*BQUnU!y^opJ,@xtk@Gt$k@Gtk@mI&/<8`,"r5Q(^\rC^P 79nEeo`Q{GRUЫetF^#b#< f")Ţ0Y, e(Ţ`Z,:rM{NTዄt=)Fjh48hAEA>J!s-V`g4JIL޶D;H! k+\cδoLn?;q8 "9%ՇLjpK';,̮T~D-E3ڝdߦ:hz  6(TX/:Kl>{r[WZ_}1vg `gcfRVCA[ l5SQ,:W~n>-sB` K֪}~rϕ1z h4 6)hۤcM 6hy+pkP,$vsn62w0;^ w(}w mUbzqoBBV;c.vð(sEJ <6Σ8 'BASoafa!ceFqF !hAQ=I}VaNs ᅢ/LǨ^:JN?5Mv^7VI,7DZYPO>u"a58CDC=sD & 0H&=waQܣhCh&mhbp~ϤY _5K!hv7#0Ϊľ8s Z${' O?Jc?HHG fNwnbf> ܓkvU!; ){x:]nǺK"Ҿ@d[u^:/r2d4GM|wc~me T0uc??ҳϢGGxl90of?k~F=hmԝ';jZJ}];öik ^Ӆ9zO$chN>tmo9zzqv: |#p &|&[S4`4*_1@ J!3PVPM :2X8`< 2PAR>@> @! 1Py@J}ӗID"rrqn&aŇ'>;>ه爞݌n!ZRy"SFXn|cHaAamTl.Q&BֹY5WWt-mdav'Zh}j>~T+΀ꛎ[kEA4`?Eܗ#Tj+J}}3tf7F;<B+\6}~'b*!UQ, *›E CAk[TQ˺B_% ,5 חL9ay KPo0ȠuV펥lFkugJs߳te*_!) f1`Nߒ8q4 QpGQXGh KD.!:#Dq討Ўv(#}ە;Ų8ˋУd|'ٞH-~!QY_7vvZx6xآX&w'7Ն$)/[:xB6*vNte7J.1J(I'을u_O[\eTFugiEe-_ =Ÿm p? Ö*Tm3ػv 23]I^?u%׿ _; `XaJp ֶ&?Yܾ iwY`g1K꼜`fqlfZ@} `i2Z]ht-O5ߎ&ZxpJo cR}L#g{Wu5b>ڷ'4Kʌ C N^4.i-OrFEz#.1|e2@l`r ܄LXշ 6 d=lMl0MP Cv:6tqf69N |F;y!A{0C>hopNByA{{ +6htƖw=A˸Z6㰣J=#cx#cDʍewt,MxΉ Aq8} pk߱@">BT=Ӄ0eTi;Y̤dK%oCzf~@Iz&{&완gJknWIy9%07R=7qsPTK97?nq"}s"g&ҳ/pv`ŷĨsXvʅ:,+"ҿYP rXz[A'wK+BoJl -۩-bܽx*nk.h&{^>J{S֎Z ]ls,qK$M"T,Vr$7jp"< Ny2k07=^G򕽼|kI5'WנUΗGE2jUs%EJa k+޽t}Rb@ES`RZHEINkiҀoVe 0Brs.:1bȠԸ)x ";hW$*h=Vs )R?DOPn,)(ub.'x"5Q\MaL޳T93t8ٓLn>igZF#<;?SAZjf\ʤ܆u/!#vfg6NR'JZFbפ\?+(u%&zwى 7pקP|U$!c5*C8d+Mc)Z{;R4svBa:zhY?MLJ<[dRUJxOtO٥k?}'&ٰ+58QE z"ߒ;TT& 4&z&jVb{()jd=w&P]ŋN U%24ŹVk(Z; +;gg-8"-nDa&R ͏'1?$j~H0a @B 5V8^歷mA2Ai;mONNm>99blcFOe?3iW?(%Gjl9#zi%Tj<cr \_/x,bk=i8([LU?}LKc߹f& փqv|3WczUT&o`iw/Z$ rMj9O3'1:\tw‡J}!%@GRߜ[݉l41h q Hv\== >aIӮwL寝1o`$S݀6 Q%7TF<9OڲX|YYyn<꾨!yuN0pxy;3OCq1:&Kzj"W"MX3EP3EP3P`T)BGdggggg٫Q3qIQc1Wc$ğOZg"[<`nbzXXf>@3r[[؏Sʣqa+-57[Xcy {o0(Ŷ 7-8 `c`e_kFtW.uXf@:p;fDgdb k@ |׸^m09H="9B=t; p11s4Z(0s} >#߀"{|0O0j}32ܐ+/9IScd-aꅮuƾxQdG}nc;5`1H` Ӓ_.Cȗ%~:- e߷73-y-Aq:fhLG̃6fl"P ۃՄSΣNlP#$eEI̊%+!xSMBLuxE1$fITLk~9TʿnK2RE]WJ4ElTY)2@z1;]1D[ ʜUf) z|DӞi|z6 ȇ6Bδtaߒ(U_$'R"l)쭗"J&j-:KGԫkb.'Y82j-koΒe&q(~?ePϢ0;Acvt-a_b;AB晵Գ6Zhn!F=WcrVoF([z43uv#7Nk|tqҘ&\Y Wք+)oX8D׸(ꦠ6c7u쌤8zvpQ~PǜvCf!=g-K߂PmIDw w wq4wdwrgD"+]:29d2#!R쥂{X!iw v|XYb/%|&Zl4.UFT η\"|F;v־tώbJ՛/ $ ;pnf8nru<q;c$Hi\+0ʇbj &g۪~O'<Ͼ} jp4: C۳}u;lnPUᅷpJS04yPL-A(\b 6Q:+ ֧bO9'tw3,Z0@$ZA;AtT5nfz3/vON> Z.=f>{oׂm(T>OZ`buscuS'+4^ɏnNu :jSӇo@;E۪?jQR@_КdVgtG7\6|[۔f;";JxFq6ƅzٺsW$@‰q5N@pa<8 XH;@@;0I# $IHxAItBIRhmIIAzGIbCn2 #<04bQf/d~@^OlCcmW߻^*Z?YߩF|ټSva&gj9n27_`f(, Gd^ALWTmb G$ہ 1]&?q3ߣ+?#mndWz$s5 5)B iMevU?wh;?mi8ȯEeRp7(.R DQWx0!̋dL(!SnL63 X%Y ׹BׅXF5i;SlfUWk+[3ce9Y,LF),.-p|~ 8* cfX^(wím-Vow~7*}#rg&=N rcM$AeojnxZ{*F;ҰQf MonN23`,3?`gy~I'gyzI23OyzN7V8rI2B~Mg8b=9'I̠)׆ؒĖ[ؒ֟rIx2)Q^H7WoH{һߥ$AōPDsbyG[HdLj ,>]g4h5U`u~[r'E2PEH6Px&ljit$HёL#FwX۝ߗ'"cŅJU؈v|@zj:^lyQ78(p+N~ L7(gOTj_rj3U$-.3ɞRcb'<3'_ `Z^ VIyw7 ιߟwz-_~k cT_$/Ǧ[e%HaSn/z_16a*!!!ΉaSF4(Cnm!x}=7WJ&|2CnK 0wf'O[3#H)]oG;!z9׋Uequ;O6Cg[g)ȳ 58Uqڎ0*v2"QA*uG\ GHo5]Hߥ*ϿE*U!ރ`g 3#Bi\6[=i15rfVӅGw_A{13(ԓ0,,3gtG;Zc !EMB.ܮk6 .ջLJB\w4'lk]@"<.*P|-b>@xJ[b| cg7&8e ~Z5Q7IV*#vESJRoY@|,ȞQ$^ً̞/2jؽFLʽ6Jp I*:"9[ERdM)l *U$lHVmG7q4"պ}btg+kR PgppO=ƈZ-&'&҆3/>ɍ,'`$\vCyG0nՓ*kBMϤW73( Cbdɴ CV4Ӯi$UQ7uOSɏ5/8+,MGEqlƍFe&Ƥ1K 9b9U|)J+uI*%T4ORلp *Cѳ(U=X;hVV?W+k"Eչtí]˽H(dk2OE$rM=/vsT+^Yfd%Sq~7qa$TMdi-Q~ l/`Z@PC@$%s:9;|}{<,|0ju&Nv*Ya([u& 4l$I=X{\g'x9#wQNVRjq'-:}x5I= zXڗ#G\lV>b2^QWuGy&ώ5p64)hRkRnR=;_i]T&|͋7ng7,huyW?Խ|d*qB}EFɵگ i9EP'jsn8qݱH4M$;#R&%@$g9CWϪP\-XLݫ*=`ʵǽ8pęi$E'GHf!qdGHh!qGHl!qdG61J3)A$ٔ(ê߿WAVx0C+dl| |Ơ Ԏ9?df03|uC X؈Q~-ٵ\{jW&cvtuks(FZ'0K,<Y_H#DyT+#PWgm/ʑC7&Q7F*$INaHfZF3%:LgJ$4S"gJ$1S" ͔HhDB3%)L3%)zDb3%)D&e$1S" ΔHlD3%)<̔l6Ydr1|+w&BR73ynlex/B3Z; hnR(J!1FpFpFr-t $;lHΠAlm䱳<ϞEUx'xUI+!uz1(#]䷹'Vx ]h?z ~eNo&Ql@idԨz~Veh ei,IY3taHbFd,Y3$`dIڌ[\ s& l'2-ʓL#SIYoKvy'j5YU+b7JETʷMJ2Qy9ҳ 5f_$+%>G י3sJ{\Ǒ} mUXBAn;;wgcXIBc%$>VXIrc%$7VXIRc% $8V J+Ib^ 1E>[! $0*P*UrC.k[E}fL<*vFG8獫R$b@KReP{Ϯjrz_ٜ`'Oae`wa9K}D9axddHơoxXs75yͱ/v @0B| "t\ɚi/,E)zw-"(0b:lĜ+3-Ӷ(&:h蠛eYiqh@sus>譔 }FYCz!#<.#=)we2"]!xԷ Dͪ'ѷ۞wsGW-6QQe41slF ]L]ƌpB{BXDu]>G P6Ƙp405x;R lGLnH/2‚&Eˢ{n|[a쌾ƂI(ѲwpCdzߺPеc2.B=g6}@vx>m˛a8?fŃ{%e;=TI~ 7'ka4>$aY{|fHZ־9d,+ YVٍfNnO61dDEB {8 w3@/{(͉ɓ\FH劌|]KMЯ_&@HEeS;v#|!ޛ![!nBe7N224,=g#{ύ]ՅzN2l2&t1< Ie4ow7_.oT|+wj/k9erNVMP߄ Dl@":מbAמ2|۹k_ʄ8NE^PJE \rWGA?vm?p[Ϗ t~,֎*N*]>@'(Y57~=W)q~icTf6YYvV %묹ێQ(z+1vq*0f.&?F|gףLJݓ#߿Ue_^WX xw;8*ix`ukL2HݟM..e;M'CtZBٻ),Mt" dǞ&y L$o I) y7 1?&U)["Z9Gj/ >IJ 'BO1|?Z{Su[T㤵?qq.vN5#}{]"].wg@PfkHP|<8;@㘆-2q<}u#w N!(3C@p3@r=7cƴڝC"=t](OS %I{4;< ة Ǐl}j6ښ?n)8?9Iiٝ0\w(G48SL9uR ![ζəCXcaLCj)Mmce[EwX@!1cԫW78xI!HPC_C)T'@Fݓ0|ɑ%W0Mwu{m|.a>۟{IQ\&Yw $݌tu"J7wkG3m&X}w ;=^ 8;';q:"+%Bw]ApPdgo} m# AHhNF guId!$FA?|!۶ՙoPI3*>_7e<4jʨ}tǶ`)I=uG.PiKQq^ T}MI^&75Һw\1QͶױgj%#ts,,[k@n{O㇌Ɲ~Nse,IbK5f7/B1r ߪ*0]2J7gIJyזb _̖)QͻZͭ+*雷&vV{Xw,jB߃AlVΨ,1QvǣΝvC4=MZ?]9/vP= "~ {u~8/S{S 31[V@ݛ$wf4F}|&MMMMr;$ '$M&z&QEݙW!D|ENTdnvbyC+1'JתxSk_"&WDRZ \70JU{5ϋFoN+MpF\J pT7"SzL<67|$7Gk&3;%>&<ʪkw4B>?+{xw;Z:Xƌ ~bcfywg?$ٍH72SdZ :·M_qv>ݟ4IVvŕnOZWO>u@6.C Efy{=ӳq w( PS`aD| nk;I3=u^&e{⻌oC5]6REL8}փ@>OIM@^U*Փ K2sU ԧks_FA oUI9PPrՓj-}73MfR;@p^aNz71bV4Ss"#ƿS0VIf໲MCJ^I8{wvsdj΁ O:3 9/ަHr$H/VOs -u=QOR׎0 ͖ɳ{3&Giݗ};/tiuX#>IdU.A#YϿAG3)L4\W /h/-(YV3-UT͐=U3J3=_:/]alkkNR=*u3M<5ӇȄEDkdY&M|95"Kȏۭ\PݭZxf0z &K{xYơ:BY(EqiwnZ8՞U"p/I=nfIUa&| +Bu `_,nM]oOZ(WV&(> --~ Hf ĖHj $Hx ,?F\@>rHh Ė9,.-ɖHb Y)BKp^#1X#%8^nb---o$H"k|$G"k|$GR p_L$\6F G5>\#8/&3k|$G5>[#5>Z#E8®&3pͭQ7Fln1S*=<Ϟ4*G^UHb#[4WoKnK$Ӗݖݖܖ2Ӯ9Lj76hΓ./fwԻ+-h _;Tn[iLM(=pO߻͡_fP/l20B ʡyPCu 9 9 9pc:g0A9S ʨιٹ܃(<o3H <_FEw~~(Iizsv&|]^ 9NFwW`µ(տɌjl'ȉks} ZAS|:vJ`D[6d3MV  A&t9 y,#`ÓNA~?(h?s_|t2H'tQVo٬zśw~"R7G. Z +'OC$|Fʅy+pSzNk`$l`YF5oʱHe91zVOC M! Z'!DDͤ99!D̓ 2$|H3ĀDIbH$!1mx>A+1=l~+gv{,/̙*.!peJ] `6qTEtg"]@gwP<%~'V+˰臢,;zt|cǗ`$K;1bF|UӟeD̏(UBV~{֓М 1ɓ|b@ml0ŧ{bP|lsXcZAZڙt]fN3|;[l6/V{OyFT0B]V N{L+ss:I0Bsb* ER-Hfݘ6%@3m R8n8M~[cK=Ի=GTArR1!fs sg$ w'wN Mv7(qZ 9iIa?8bm\$g$4w"43$g$<=#IMHdzwQ$g$J0#lݫ-.Dw-($&@H7d݄׬pAnI $&4I&sqJ9/m(h8)}c A9r1lW?X9Ө(i=*JAͬ~9O$[Kn&je Ϗ$x9I&B5HW8/>'۴ l&V`{3`д>ndDϞY) CИJmE п>%l}K3 TXM$➒{J"顁c=%!ӽ^{JR) $垒{J2 V)k㷂Zj6!AuO`Pϣ,G E5/J7KCIA ޽zXntK 8RHċ"a/D({mb& hb>[8ZΑHg#aD(rH̍ P1EbnčQjOԍ"7*1s:/vהh=(7q06OswDτ7aby$#)RGx)LĽ~ 琀` Q`?& v>&a8 Dž0N!a &ph(%VNá &։?Y&COxcؔi A  ٿ!igcC7j oipaŬ0ͨb\a,6W8c2GAq~>7 cM`'@m lm%TVh=Z0֮C$}0&Z%p׬Qޱ4H9 FczF6FcOsxvppv؄/8 ͂Icv  T`! lxS8d#`9zr5vs=Pym(VQQ Z}k9D3Hf:zT~  <="%9%Q2<4jV02 Edk͵yZC0<$3>*&7> !1%/L ?>0ko "388“.^c䗄'$2rLoO/pXj8it3y=%sDK8L+*U2|! d? .UT\?yϒi{=qH/ԳsyЌO :b}߿$P3clF6Q DĤl am am m \'$BxBpEb^ BeqrzFa2*z!tm՗=ƈ 3 v.DhKj$'kf]fmMڞt1`3ӳ d33GuSӎtTDY>UȋDyb j exSnn20U|+ Lu(?E>͓*I߀&[P\ ~| <ޔӪ33ƒ+gyGݻr{ t/N# +e+ҩyjjdT(˳U^ѧU3k[hN.Jw7ssyeq }Y4?_yO{[loŤJdQJ<u(Pԋo.y/;(oI/QCeL&P]9d 9Ki}NၐKBѼH֡qIOF=dz -%% Nd 0C fb%g@&6 5s .qpIcLlT/rF(iz95*.8;);`:HP֣ijF7@S;kr ]ݓ)Hj:LqwHHze^_85OXb-`?XWюf@?X=rD'gx,& 1dYaϟOUȒoTݱE>W+K ` ,BMuC̭;rw_pz{v%|O1>}9(s^ܭK&9$SЊ敻8!a=p;棏Kaf9+WPu fޫT'*oA9b᭣?|#ޅDoozX>U&9I9EQR*xPQF~xSU ` ,'ZdR;F~}ͭbXO=,̽bo@iۭ q#zn!6aHAUv_2&QbQ2tMD@/f͉r#`uoA===R]\W33~=U(xk}rWJ'Yd$yȆ_e˱ & ׌ Z ;~vקU1QOȞu5 I(7Iz5n)Wv^u{JyYb}]'=֕m x_4n~18'*CY[a`} ]PBAtN9TK$zZ6wt3*Y!XϺעͳ/Nt+Bw|FNI+" fm^VVy׵juyc~rySXψV mC|upQB(Jx6YyHCOL]fdoz!g*Mhb prQ^ϗQ"e*rTi|S]*K7̛\qޡΖ3wRbObD] Z,%w|uC'Z ẃ,BY;wU$%!_,J5/D90hoXNDUaL:exNޤ74M:IxÛt&,I'oi›t&I7tM:QxN$&74M:MxNޤӄ7dM:m1E 7]lx3H o ›t&&I o›t&(I' oҩ›t&7I>IMoxxNl.xB=]t {#h:a/T Bl"bX1Cs[?IkT/(| '? Hm$g_sagR|-9}V fQ6d&4o-@Vޠir[ **f-E=*:^3voB̩:& Z"2.`a~-,TOshFi5[& {Qiʴչ 1w_{fᜌI'ωDW#K-wZ4BRa + nH>} 1p7&cH>}Xj%4Ur,V=nˁY᝻4x^B=GUZ^guㄝ/bؤ:jΏrm=jf{w5T:_zfl@Ӈ'O?0oe) dx HQbl[ɾP'vORFxl<:)/~ p.610#D#]s.bJ ! " V+\Wc^^==ȍ /IYR&Qډx#8ˬ,ބXU zx[ˀ{$ m(L {jn 9AvIٍ <+D7ݸ7<|ew C/dnN(ϚTd23×*j1OMhΚΧGOs9l6 L&c؋zaC.n}Pk`.JeXx_J\G]"yz3LBO|([T^V+&0 oN>4ӸAlx;B=ioDӛ ?9`$yegqq"_/zˢ_w#H>Džjm]*&VDY,B:oǕp3Sޮ/d`sl ՜\_Qlq2Њ^~[8ǂZgsڿ;rxJ90{쪃n" .Jq ,(.Lñ g`ٔI-yɯfx3Fcpu~U?'g矯o/DSd`B*IMj5B,s [/)4}U\{ZH$aP$7')< MIr OrSx:“>LI)< N="A"sB“$7')<ͬI*X@'“N0')< MDSx??')KfOXnK*8EJsòjI)}I2 9j^=[sz@z% I xżmPi2系(ȤJzP)7Qfδ%HE=/rʡC̓rwhf9w€yVF_&[E0ѾF7hݤ3"I vW'P׈D͋< e!i;л $.τ=:{U՛=ZUَ`+raP'm3'7ۥJU.IB!?GO9Jc uF(%mp$$P_pe&)\$jHYbl{wfJH4zkxP4}|iE)@v2KZ4XɊ*ry="/$&5ĩ`2#;[9_X =f0ku<Ug44aBMR$T35ϳ8%3G42g?XQ"հYZ U츭qEyVIӫBc"=I0|KfyDzMs(/"5% GRYB 4MH$D)B$DHtt$:Q:#X:ɧ#)ґDHtt$:A: ґH.ґH4ӑH4ӑH$DґH,$ӑH2$ӑH4DӑH6NDH$DH$DHtt$:Q:$NDH$DH$DH$DrH$DrH('|"'|d>uw0Ot':Y4OH03H2)pF%DO$D'|Sd>X f>` f>`If>pf>|擋|"'|Sd>`g>uϫRBiʍ>7XLT6SWг@u0m80`mDp?n<_=Տf~#23z|=jM T8Pe܀v_ne&+jyjm8<>|/\~~>vq'Ws8*`ΰEGʂ(7{CywkŮRI,yyӗ@ԍLU}zjZw(Q.D$ңIG׊u]򰌯T =ߝh~ErŗEw;7eVMa9j];Ƀi:pƎ˓jSq}y E"YJE:H0jJ+Xl~o#"@ѨH=N}ٽx|CN罽~̴֨yփlFD)va*ݞjGYff@#c,Tnk *{?h fdF=LmgO~+n(yC|= bR%1$CdO"̺ vHO{};śjMt{Pb n.<өHfo\8YTy)x <QqZGtx*@yH_ݬX 2`?7O[:%Np|2HG(̊ xgOZi^QC?n, ݛ"'}V <}1r \d3L;'|[AJah}sG1J> s;sa(lf ™C̥5hT/y6 V%v(!xND-(˳U^ѧ/Lf&oo6T,Ob6g_o'yERJJ0I#LBLTRIZ54pZD7Rd @NY2>Q<캟o&\YizhP]%t6qXN6R5FU6;hKOF+sig6O,P~ץvLY U+$mn EB0",α"Hx4Ndt7WYbdb($Sv½J205@] $敐WyA&qņi);KҪmfE#YD[qZ{ NP+zο8Y7*q{ftwBw$=GA=:rMqAw lҎ9zܾVE:kfPfIZsfg\_Y;r8s^$YuBd4/Ph?W!P /7U^s?<;Jx *UU$`joHVVqnm6ʢ.㽚EܭyL?>!>Ew:Kn?~VQyW}XGk>nh&i&?3Be|?s2)&$ciGFLs [Н_qWyu'^*Je J%݄?&7Lʪ0X2/u3s4iVF,^Q|0NRV(g]}֐xsv`XfK.E8nE@5z l/jGcAT'Q$kIגT%^KRz- Z$kUl݈lr룮sG|eZѼuo^<o(Ei͕l0OT)O&&yln%qk.{L.U}`!XYޱ z +zgg.#0Z?`T4&E"ҡ)XZx6$ 8hn:=˒{39+J%:g6X*eAH(h)H 685G$$rvypp}w;9]>H=G d ŤgbwQuA ycR't`7 aZ;8_n']KV+~=8wyq0r/ ! X z*#F"ġ 8O{|>><(Fe$jcEzǰ2줪iެgS=OdcX%IF7^kY n%QBȂ 5zQ䟲qS<ܸ]nfpCtoD# g$7/_BgxI[-%&GVF)<֜`qSл闛[*[f~y"K؎m }) N#Q`!7pz##^A{{p;!Z6WeU1TQ2uKa$[8˘!.v^(DZkn_1"؇B?+z"]J"OIvey<'0\)z)JZ=ٽI> {;>&W&ʤ'ߜNѩ>:g'mks8`S8tN:߹'=I's8gwUy2Npi(n34Fu,\JW:A)NRug%V[ez^Iy '{#Gv|63*BBH`K DzVh W瀣(NY`qk&$L;7ᜢypDǎ8X| %ѸP`AǽaerXa=I2>X[+PbzPau49'uCX/.Bl% C: CI:IHɁ>!3̾0P޷ɑDz;';ЇԡL}kP@X+zT!Z4 (X$Z퐟(~[ @G栆W_ɏoEkظ3x8˙OYuGA l-8N z3ɗoʼn0`%pcV/`GjíTxLZrfJվ{^'+oX\XBޕg 5VOf3Y-}s^Lfz}n"YgE CQnW4; ;Yˈ Or)n?Ao?b!6L_{fl@oV22 g,E_M*#J׶MCsNL 9K7aQWE 'SIJ,l"§8jLefMƹ&#uhF8B8(Z7Mkqv߲0KWBljrz/nqPI{pYUсI6pUhq)c .9<o/r n`\,oE yW ITI_`o.y%~Q<{N;7mXRB(o=ecԿAx\Z!2Eq { N9զ S<ˈ:%i i}8LC05 $SkkkfnO>.X#k2mERC~EfT]`4O$}(I* uLo/لau7CySi㼘ޜ'©^/ەЂ`Q䘙m 5{|0nqiŊ2\-fSδ} y?Ǯ*i~N)m$m>H[&)L!gَ2ž;6e)MQ.`1 i1 k1Ib<$V Nr9X(˳U^ѧGof?o_Xۉ~[l_)od)NKoC#'V#z+*UyCQ/*v Z@W0n~wڿ>Ey 1@uVg,VCY>g M}q?eO8I{p@3 1"z9&o[sMZRZzd/ p/ Xrof?zb \}rV `MevDzΌaOW@B.ɺ$" "F=7{PߙO[TQq ӝhd̞]žD*i;֟<T|w9wgmZ]Yi/iZtR?}`Κ{wLwتHʷ_?2w_-p۟K)hh5NhGfeTbͦw (W$I/oA#EQ/t_l'7|M(^(H<[ɏvI:%IVd? ԫv/P3Tߴo-~TzBWG\lebj=o[p^뛈q &n"0 h`2&lǂwΥc5z1R'2`FFFFFFAL^ bv!{;'홉2Zq|%tl~u(8._O>/fJP|sI9y¿6o#ЖI*@X5,^E]JI9{ $ 82=壘rT>L1G$|qLG= NrLGDRU_+_ً*JO2ߓ<Jh籚H8-r&n;d#48އbxUy,N'}${O[ N?">iKy>ç2̓,U=owO'|gm?@HvvJ؜"fF7.Jm"L .B"6ZH-'"Й=msP#\a%D(S6HHy: cΈEbw̅,`](s'̴P/3øW|v6h `xfԜEGC?sx=H&7GB ff*9lO7߃C_h=.%X4+fP/өZp)>z :^_f:O2-ADU1~ƨF4*XδzJQ\'I=>7=Zv$Vt$6UI+sAzz5#۵8~7ֽ2ݭIyPq룻uψͨ ]_=W-Ξ!Z {~~㏴s2Wз?@[/Ł{}%>{wu1*}L[x H&!J.u567+i* VB:%0*6r=ӯ2;Nw}y'ߖIٷ+)M?IB!'=F=$k5ۿo˝dsiN4{>iq<"t$"4g-Y9XEήI6oܓ?e,R!2;/v"NzS\ҴӃcmA|{n&:ߌvgH;Tɼgw[d9;gh,v}}Cc$Ǝt Y#LAviZwjDLG һGhYY#X9Sq OziLۛeLWz0n1Qy s,a3-2t,xny79AZ'̑Eh\ 2Ȃ΂o51H_)HiLϞK|^g/XoVou3u p; @Ȟ@ E[+kF o>b W2H"nAD)BܛlwdgK>D{e?D .}3$I`{ K#R`3lce$lpq%nBm"gkHk23L&3*l _q`pjc*/}_1:pur*'MtIl<^ C9낥W@UG@vΫȣ}R/lNof6Kpi*q1ϟ:ϋL VjUe&;^&/YdI7GIfNШ̞ψEzW s\epËT;fq(I#ZΖz8[n׈Q -HBes Е7nch\}iSUo e|L3hs^4zc;8NQߡ]j^~Հ hZk8JUj3(aԳAIaW0z(yΫ'}ngd2̕^f |=Fkj/¼yU1A:͢TѽZz3uv)( $g3oIK|ns\'( Ds{<B7̻.?D("KEUI.)#E:H޸Yƃ[WnIrg[lIp% ϖ>[mIp;%#w6$~+mzXb]c?6q^ܽW5|d' -v5Zs\/{g*!J(W=Qi 0rhUT6ng-:{] ۴H23˶I$X]Y|N 9cWM:8Aֹ33 0PW;&VR.{8딿FgF(>)&p'>^U7`Զj[ZdVڧ6jjpzgbH!y!$= a~: C< CHhBB<$!$7!yCHlB3- ahlo?OҒŏd8%GⷚvJlw;dd솠|1oVITor^0IT>/'Tۊ&Na3ڊ,-m˟iH^/0:7ܹ(xM2/):fctV6iswEvW79fmC"jK^)ޫ[y!"nÈ9bNNJb ?I?wOF_QrݴZGY{\i),Jf!:{|W *dQ@:d{jI-*DS֜9>v e0e^.`Wϡ{47j}jW0у5vT8)x\(pvH!Cb8;$쐄C;;$쐜Cr8;$'0I9;vvH!Agn[lvZv1M)bB*/ь4#=|~VR.3T󎰤LYFcQ Xg@Z~LY99 XL{De|zNb"ca l(qyH!D\qyH!a\ryH!1ǟ]I BvyH!A.jUec:muEB2{ʣ">#J LV B|?UfHLҜ 6#%۹ gKJ9{?U{Ty?-q9qGXwMH[C !=GUZNdUFQ}ZAZWI24'l󟙙MUY#L/)\i(w@`" gΐS-_zdUKgcrZ9trUgscK퀞_t_N2N WznWO W&vUl@wJ$9/u1*U륹Z=/r_gS1_Hת Ɓ6ҩݕ]4ǁLufw^M~966Da}eMmpҞK;vD;'+Dk;ԓEQo[DZ+5~H!$՛S[ڹ*==)cu.e"JQ2Y?!-EEҴH6lAlfv2&%Q?!E}$$}Mү+wؕZ1) ^'? ?I-ɓJо#KPj{j54T^ign$~anE5]NgίZqF 3v .s=u-Hg<Q /g.*\,Σ"nb&jc Fg IsXb(VEY <*AMgeoܵ.q_|Ycš\i 1z_TM-c@{EyחVCګY 087F+ ʦ7y$>{.Ua3a#7NdAUaoHLVfYBN 6'K=vz5J3ClzߓP-$zzM'dM 5'$0'/CI4'{BNC[&1'$4'=fzO=MI`zaF@ʧG^J**Y uWkvvo{ym5_>N=nmF3XQoECGGGGGMj|=4Kr9v3#vEir/5Z,6|`-yRkW=ɎܨE4flZOU'ɌEO8)ڃvne|JT fP{4GT $Ⳋb–+ٲ̕ V}P*~N-Q*v~P3YiZ- M_U:>ۄ@d VqI'[WTw({H !Xa:A8OoBCH %.CH A#1x[,qd$aH "1N.N&Z9bd4`?N37Ҥ䋍o;!`@^w?W̘43)$N?߫UD$o脆7 7Lpg!õ/'0\w7K{_9N`L'c8 HKy><'_3S0CzOGB3 =·y쌠(Ψ8;K=˃JǫD.]$2tECB]$=te[#~M@CWxH]+o4N34 YWIgDjj3)`}U 3gZ7rEgh瓾ENjWmϿ◇5Pwh, e7/2ve^Q;O'%*( RLʄ /_1de /ynf$eo(O/ڥ%CN22P<_@q2e˄})|0yWƹ`'kGՓ4#l 7Cֈ2cIq]/_9yC~tGa8' 7QP*D`!u[FozmWx`uǃe xU{aFBI3bx-C5 >YAюGY?4h益3hG;BvB3bF]<^uhGγGy9&a59;|}{mCs"|{yױJCr"r"rnYߛu?j?>(T6ODw.M>7ON{ֶ Zcٓ ~1^Ũim 3*:-!ȟTA|%kcUH?fQ[6Eg6M];W&qRP9ww4ū4ns~@gΤ{+ŷ?guI}F42)ZLJ9tlzyF/b , K-|ҔY`SPMA :%pSPNA 8%PSP 7%SPMA 7%SPNA 3%gK2%SP:0.p J)64nvK-pI'矄rI'a[ kjܜiϷCusE(z THԋve>鿹{~Nn7EGOrw&aqԇ6A ~'QJRlnj*N*ӿ77WֽFoGOh}<$-u4Y`gi5=[!*g} Z9 经"=G{GE]{NBTEgh1DRV_ td'&Gj-!OZ|iq|ҘpSuYո]@0+S,*o8xͤ{&?JRs5tH:h{sH9r%mmm!m!m!m!m!mmB`~c;ܬ"V&X%}}.mϴKVJ{l>ӇYt/V[A4.mTS't{$\_n -sW&\ # "ѕO6B p йa?F[B[DtfT@q;Pe_^W/f~$M;`M⻳@1ӓPL@88y<0@=lÁ CKCaG,U|Ef90sP@9`!cH g=UW5`ؤ)?ȜQvf 3#q H`%96趇Qw'Ei OAB'p' &@M`%sڡlcQWB/s)?)byD τ@hzT=lo8Ⱝ4Ѓv|p װc_B9lG}Y 4(oFjTjcG @w|~Uޠ9'G*,BG#Pʠq/j|1r,}1F&zs;͊Qwp<;#dZ,n}\ZL Ike {; 䇭系7|6H sf6+st֯3/U C}0ZF-ߘO$]D^WQl L $1۽XOڼ ׼ ۼ ּ8U?;ޓ7]je֞hq$4$"x' (Ydo;Ncv\Om6JM6zU f1ڔ ՍnBgiʪ (RljwMs|l@㼨O#7Ӫ3l>uU|a]cͧ7Du3'UQ  v_}H_ԓ1L%뿓UƣWDAgUG/(r /#Zv2tyr\>C>W>"UC K8B2xGm36(9`aů%yK1tMR;)hvv |€,'Nd]@5,Plnb9W/ݫq@^owf%eoz az90 M|y$$$!$d?5Q=n9\?d4+ `>&*>$z{,6<5>[/8LkFp}1" ^or<aưacCyb ~XIbTW<.wr}wA|X׽{1!`~X624F4BQ.6I.V]rC5;<%͝lU^<{NWNEKt$Xb^Ltv"}]|K:E_(amf L%qoѭPzB͛PͻN: P]1u\*F+B`e].Tgp@iSa@.ze{"Õa&>Dst(iIM4eÑM+m6SΫ42ɪf^#??7g xTmdr]KvkL.){4{V6{oآwa չK{30_nO~&mv0?rse CF(IޛV4g10ɳVw+0I({=d݌ piv? qa^aOB8z9 ][7,9$sHPP'aCB9tw 9T|V3?.l7':IFx@懷3ww]+UTxo=<_.g;کyDGe|z4ZA ~ϹJUd֧R+2sV!GX$Ios9mη߬>C6o3H($5?Rg>/ Lռl%[OxEK[lexUhAC{Kuu՛&%heߧU #D 5OVQ:͓|t6ax>A|+"wQPkFx=0ĎcGjƎ;a4"M"wp^ o67Io_Ao3kI-?n"I`&Y*wKϞUQ&\ەZp9Jpd*I̷ZKVu,JbmMNɳm+bId%+]Y^6,/%^\s(kOkUe7He98jSz:NgyP̊#t?DF{?,HϢYt?+t(guIPE~2! \N~;uE}6U^"j2_T"{,8UZ@gRWC^Q&k) ;AX;ѝJa ,(9Ocď >ɞƞJg#pQd 6prH7Y]u[hlOag/cTUoEG~138cOo S*|Uqx,'B?֙֙֙d3IYZ<:q֙֙֙ٓQ췵!("l#6EUZ&BQ9Y+mA*b"Q4{nq_"m=sbH\ssQF?Wc}yQVN3Ay/_ZOWr˻(ʻ)z xFXFJ[p[p[p[pH/i}nyEx|R,4RFEgwn8^2ĭU> zW8Lֶ c{\-Q)``dDumZ=o7Z3(PO`@ĮI̍rU;CCF>o8zBH3K^̘]n\O͙(+x Ł=!#bzB]g/R=ll@ke7##N_PbRVH J[K*lI@2O3:+vFJnB7$,v |Q罗r}~g 0$ve>LpU={t(]NPwǮ7#6#,av} ~) Yx0dzidh6w,b{~g+c_GB "ر{-88!4Hm%DmvM%,SY TP,g<F8&]޵j=4D^9`vC"p# wwCv98{კw İ,77`ς$.=Hj+]^#?,[cr W ȗ!l] Z~`v^N0 /0rWZ۞cOvVN o_x<}%](>}oLsUiyge)9|e 5iG$U(F-u,G["*BWVk sj:JzR=c pX5t*H'1tH&Ne&dM I@csm 3TAM׳4z'[z'I0+gbTS$HrMDˆ2N\s秅;s;/' \MqfrMn'(1XQ$;'+ \ϽPvYГ^tQg@2/=^` ,A$'~Ug*@_ĚC|~ZصcAɺCq"?;LB$nApP! Yw s7Hh6~`wmأ6br>ENށUNCZLگaNxopRV"(/_MưLFv$ $q+ǹՠqQesOڄ&JgVQuz\K7y|NSpfN 6&]\( B7bXJ*Y8HYu'Aw|FHؔ!c`lPt1zkD/ Js{ X1QLYG8nyYWjGRswa3I3}*a1.FMG!6@{0 Y~ 1- M%z KnA\pxHC u-Lxs\ }.&?Ձ >Ɓ 0N=gw32uȢnF=tt+yNÆTW;!T`&Ҧ9-dl'˨C3-l[B!$: 8߬#wg&edSG7K462֘|+-we`*1}gEȣK3 Ӷ[f4\f&B,z$U~VۓLܾ5N}|DQq{ ?Jdܞ$ۓd<1:nO=ۓPܞdۓdܞ$'lܞq{2nO. ۓDܞ$ۓHXЫ0nOȸ=  >@и=$'=$S'ۓ@`k$'Ѹ=!8nOи=!S3E<9rX z2΋UEqzjm&k^w?!#m3*It5IZO~Y̽Ϝ$֢ȋLռlI,φq~YU*M^TR.zw" lI y2w:K}g__ZVֹi\|=Lғ$KVU6+Uϐ-uG}PZ/Ls@pTMۅ$T[ :Jg)w#3Y#e,` 9f%K,I `Ib%w0b%K,aX`k>U] ?#XD"e7C:ç]oa^M(M,v;tʩ{10is-3_U['jv=0G$_cP1@wF@ec#T ۝Q0O/FuIA  6A;3QJ2oeqfZ[Q >M@İUI6l4(F,y*pQk8Ī9]@ڷFWi$|?Hy1(qp W$;>)DhY2z 1j$ҜI9Ds&PnA2 {D;5PCvs|u1r oTl󥟩j^td#`IFC7u䭸@$qbYZǺh)DS?rϵ ףlh;FT"׏(ޝZ*mmOˤs=^p>\ڨt7{H|s. IIE&UQp$dejL\oiH߮ N7s2n'acjxwk?ıHr?']$d]$. \SO{Hzn>eApUw4Z38:q ~E>ҶIsD_h-<+.eDB,F%9C`d .ܞ8$JK\T@3$apͽEE=gyQޚwB$qnCusQ+B[5\E:3121 2 z -H{@ t p AB݃#[BGvYW9br4,P_/EW ѫjihܨaXYZƉ,a8vu==j27 c,IDVɰcL:ӿKz6[$xſ M\JN~|-Q|֖?<^gegP\Ơ% F=!G5pj'8k/d2E VFVFVFVw[B#5˕**.RØl Y-*>)-M2J/?"K`EP+;6zk9C}6u1`k;gnvԧ4&~]0qFzlǷqzZ5h?8ϳdѕWI r"`8WϪPY) -Mq%'CyUߪgFǯ~՞X|\b1_c˷:|Үd# ܄+qB.8N4#JaXyZ]_Je2N͢TF*sSG`*0}>io &WɋzҚݺ2Oȫ5PiDg5 0"I=?2W|d*~Ee#AJ;Hbѵ[yt_#"}J/Q~ g.ψ)} G0UYEig"=(b(g矯o/<t3 "݌pcqy"cr&!(VYS?f ᠚FFNY#詐s"^Fu5ϳ8Y򻚩#aZ%+\S;l_HI8.!GBVj-_bg /ea,~ID e7+U2IG0r.8y~6U]&e|uyv |-~3RH6]_)jmN[?3bDfm3U~ |R6Z=%LGh5w጗b6L\g+aU&"ǩ%DO n횀ww1xBsW1(ܻ)׳o&lN ǖP7YN .{G05+gդt67BMDg"XnPMudTσMg'5tlrn1p}2Gt.z{|;:z¯jrjw:xTlҮH;<۝0ȼi+"KjreȞ>UE~AͧGi{FG:{$֧fVYҰr7:4]ƅ0~uq9T:C>]ѝa3v@ >Aą-s)A3ߙ4lǬ[3`pyNr}jG>vv=Sƻj4'_fw{u W*W:U./r SY:8rzw'^qv VQ?\N6g~KhގI1a$1{6I^\t\>d5'Mc֓=pqpyXV=Q{ZPq{{cg 0l2j+jIWy=rX1Q<ń"Q+LWcyr~y3?&΃̿`F?P,wÄIT|W;ts0D='}(A׮c7LϗI3k:S\lT;7 fGƣ@g`mw4'e>ay\w ÔFCeyB(ʢ< Ĺ5iôȟ]m:S4\ckN5Lf𩮢s{q7^0P\gq#ɚWzΘkR."nQNؔ`D Ȥ~~cYUg桫EH@,Ho kdwsJ$7j^VB1HNOYRigܕkϗGޒ=ͧUwB|?ChZs]Y4ЂsyUJɖUXN5ӉTIFbrnr[GJW|@69Kc%@-? "i07+\P'`)&^Odd2ͧU/QhEBȟ] ٣&l_UUVwdqs9IWވE.7;]|3d{0%c SY'~"}m>켨k!-Y+<պ&9m@ u;-6 _ME TKkX|=3j2OJDWƞG. 7 Pr{N '˔Hwo䡗^%w%tvH$VNC/fr:Ą;,n/wUίEPNJFUHgb{ԉ ; O!ېƬ KVZ%`-kB$gHb-;>J0壀0ô&فib3ԶKB= &FysMP &dE%.t1)*alIeFe\D]nI.M>饤36f# &Y{dbߗ2YUʒҵj\c8[tCsįiɀATA T4 z1i6֒D0TMi ,_K2+-J#]&ӠG+t#}AiV^.&FMM#^=IujzLuU(2|[ĈJO&%iʵXPJ&^ VT7˩nGt)ghzZO=b"1X=3XKBc!?Bl!]*csq`n2&诣cޣ*,]&5<(+VVu{M}{MKyS0QO33M*_V-&Sv($s h- Y.Ov!vXɦ}"6|ah0iqTLEU?K Y}RO<[C͖zRpϖ@>l6ղrl[/a FeOVhʞJ]?l&=XOSBcҾVhʞJ-TD8ez?/U$cgYkyh᧮wri{/UoyY-i3zR'WgWyZS^r9{n-=;FӂyoKfſ.66ֶ3+#21%0G}"49r;v0<2=y覚&ol۳iF 4gq?*f+ouWfYU 5/Vȇ޿*x * tȶ*j㜺{.NO7OғS/TX.s8mƇԱoc }U#]J 6QNzH4ET&_"6~ZV,yYY;8t(nȴx!p4/޵Wݥ?(y`9:UɣYP)> ؍:w5L K7nɉ;pv`̏+CeTiXu{" 9{{S0]Ĩ?U f|Mjґ Gl[[H\M1ۋӀ-;P[`}W$23Thʫe`Ͼ!Ou?dNI-p!DP#̤ÿh&} U<]ho˽ϲ7TCA"$4p :K1,w0*!%'_ Sge"1vu&[ U@ϔ_hAIw 1aQj *{W뙲mB#B=hГX-8 E!w|`Nśb~BA擃/,Á:0c<I[Wiv|J!J'j{`þwOY;b0 j'U7媘?sMux)sU„=x Óuɑޕl%oDԪCEy}*+4 \3@Dz(VM y"*5L#(i*,]z1ǫO't=i M/|+'aWc5sRO/D'^*zs?ޤHݬ%{̫x>Je؏6C-u^VzP̝$Avmi:Xy:l{ 01``l8lKt]FM{ C`j mvCܘ~Gȳb-)b =kշǗ|}U2Rd21 `Bá EUU|pԘ{>aP@cVV* h7U^ JYUý@C`P|u(mgCI;%!fbPRVWIN2)oev|uNMigFL6zk$L}MVWN:= O=BLBva^gG}_.Bp2 ȿfloAүE$ByѻI$5~q>!eRg ډ8Cgr N~}cOZ~x|M97ƻb;V{ p^ GvLGZZf^-I degC DPf N@NiE=r7+Wb^$=bJ|)^$MyR<څsR~{':D7HaS-G]3ծ39zʼnVSKoR А2ݛ ڏd' fĜTϾH w?7U1/P4@` Y 1(\+eqꣳ+7VSQ$eshtuZnj:@Ź~rk8*.:(k K!U&5)%[kas$%'S`|r8c7]{N)yaVO Va(^Fp.ބӈMF%ΟV*jNKuXHSɝj"^KX3(Ug7*>:# _"IMp܁tc%(t[uJٷV 9uSs֥a?x*JY6X^ Vj4誇`B 5n2/ 7aP20#o#3ʲvpQjtD6)duYNEiiD4U9] ,ՑլAЊMiPĂi,N٤ o;#jqPL? @R&Z0z((D#Abi*4&}:U͒ r~XU!É]unn]'d7ggwv^q(頌o+O~65 ʼ;2w|_+.\~6̢e'MPl:1 RV؍9sV4Xh g)ңe Bs z7ɿ=UR_ʹL.yES=e<楀3r?k4=wLj.Ŝ>j9h4pOVjlBk|kI]:q(Ɖ0hUU/Dl F4Xl)&4s̆LjuReXxB05Ԟbx,]s<Uz^[yoiȲ[ṕ쐰~yvhأ?-تpNI՚ڥ)7 ODT id!u\a")vBu=K0Qjz0;m'4;R;fiH@m@@k5G<Ȟ'D.bOh4tWJۚhm5}t_TdERS 6 B`=9߸DQ]f^Pe+j*&oE8!]N1,!r ܠR uah:,5o; X9g’qZNၩvyFNy$X&jh>I)wǑ('Y- ~V'Wy*4g]PO5I_TAVFq~\TE ջY sjQE"Yʔ**mU2My*iJ@Ȧͬi(z)G~(օ8RS~/ݗ"F <vTՀ{Lb_|ƉAiMdB/L>.8hjHKd3WOfgUcXm< KZ}CNIebv3| 65-ze1!Y=~x(5z0Ob{s]e9j@m]v`ֻA7)LFŴ<A!yäPzLj:(SGowW( iR)I I=Lg)L.+V XIp$pTk"ֳ߽7yTU|ٜ6$GҀkd'kZҀa^?\pBȄpdI adMaJhide(s1N hEq~ᓁN|fb$Ob4x2:G|ɔSNr1Wӫ{{B́ɷIgM!+EpIȫkDW^J cN.#A@@TO#H<H/B47&,9^a@_*,ٶ[q??ZfWap1;AV)^.i@FՄHDW[j_0&W3Shr4=&3d䌼&:!88nW;BZuBݷ=487IgbݘۘvAoWO/RzBj(S 18LAb;2Nb>D2eܥq'kL crɞI?zoB9/YKA^/DT`O m=`3JGi8'LKp%tbQ-VX=֒(v2 ęyM V? WwGnL7v}&1:IYwlUӛMFje&039JgSd[nSF-QoRgeV遼M`.#ssi1ziݽx4:-җS/-T5aƢ*y:r/EIQxZQOoŻ8? dB@&op2= vZYUD츋rQ<0/fZ$ZX|pܤP*,<9cWQiEDkdxXB|_ƭ&BzgwEe!*˫.ș-y*@ڴ8su>'˫It[={bF3%ns\Mw@HJAM廉ĦwZD[vy}?BFc-YYqg{{_VAB?sj2!o1oR ]4LJ!VuF%%ϙm^Wb I>`N51tb+q7/58e:(Gg nU(i-Ʌ FN通0h:Hu^khkJO1oJ:SO  v}q~$)8sQu0,G/v5<աH8e!W[92M {w93*ԯDx  m[n+ͣm@kI<ʿl)qƃh5pce![h.>zw& v̘ AFy%l<=\ia(f>T4C@o0L?QZ0s18@tNiq\S鄷J"q2|-F gʱGpσyy(xU7kSMIsKxfN:]6t=Vj\}gcg( W.[/\{7fYI\k1u ?US)5^}Oi:nL614+řFa>D_Bn`RT(>?;jd'"=9P}k 1N1G11&'_d_ˆWϠOP 'cl3IbK I?v l41vF;_HkjQm8Ɂd "_-d ;A6[l#mSLDrObm͞\M-DHD l՜Qy)mhUg)d֔/Xw<2f'~8rrO`xIe i8:I. FlyjFmJ?dWvU =rSiE~GP Ĥ30eA  I 5;[[_j1MU>\'τb'!,*m,}Wjd]=Ei3D⮪d*b.;Tϡ|r;ֵ_ҙ&_J;90'Sy|ǚŔK5_&R잍G O:1P(q)5>JK{<߯'sUl u?Nr'!ژO8xJkO"8zlɼkYy:rf϶[]Tnbn0ra vlO ܷn֓NΉw@O [#ucAsIixrΥ]8t$ { o-Ѽk7K)D8Z-&~=8:GϖC)ք;]sx._f+|YPQ|i 9)j]rM"|%^rIZLnBuy\~NutU`BLWOhiL r5}!WϫrL@IՄ8͓H(\2#e n`Ob8Ҝxԩ'Pi@fߝx9h'Bӣ@ZL{Ѻ^0|O.L˺[y/?r$Q)!c4m֤`=?8uNߝum21R`&δ z$`R4 W@6)/$)p3r@:)sx4~z 8tO^3!S?tab&%]ɅrĖxS*hܔюC|MDڒ'}:'!Ԇ\gK01JZ"qm$ l:bڨ2`8Nk/ĻLbM!DS8F7]#r1cP8?MUN>֓fJOD=r9CC@u>OR"5>@pRF'1N4S~xNdTiv4™)-~r O^>v{; Nz*PQ4|;(aԍ=6|غQBt8kCrzUxM.YM!-ZD$])yq2P܍dPn*! |va)h)Iޱ&(_f5"j|b+Rگ˿$߆zro~u1)'!5ow~#$1Ljk%UBS2\0DleY2Iv!!Ϲi6J65F ZdK"I+!LN";xv'(!ڱT9Rwl%O)tc%׀'UgfsHm4efPN#9U{!wqcRG 3'Ah,it! @XS㤗&pIiݤ-i$IT gϋku~+ӽΦ|_~gT`h4ِjw~:%._O@/biI0SylU&}p֖bHħOӧjHx 6=QCw >y`11۸t"k4!$ԩ$t]l*g*6 V4#2 !0sI_eju<`6M^*U,ħ@ٝxKr*tPsJ􂕐RMj S6֟ժ'EQ--%ű_$-eAxsn97SiGgS2ct$ji~aelTπՐX ~^&JϘū#rcǜ aYf J(7,ʚz\sog$g]=ow}7,ĈY,C~;~N(2s(vVYžY7 6r5?Gk*+@zP_Έ+*W£^Ь䱄g ,3fq[=zY RuTW,ޑ  ƹaoz hN6ÁkxA>HJSW#w"mdwZ٨8i È2- yJc$;@Ij]qZֺ@Z黖G5e 8AʝHE0DCοGQ4V"yT*wkAx]׻bw ||wwi-7@m ˋ؆0bؠq0^K {4j_%uy+_U Xb#Hlm$;\o#&x0F0? mY^~cSg/}̰ĶVl}k|k#ܳę3O5#@ԮUŦ !1Zm @)<2ijcb;4< DS Qɪ<drl7*b TݕR0-r#kp QZ\+P]n(яBzWX:~꺞4'ҵ m$ʶA{?u`3xF,ñ$WH'*FQ@fM1H@b&1"hb<(߁0L:yL&tlAe#DtX< >%ƘMwikFwqj> I*x{7gGmj`[]>Dn ld9Y4LϾ+w|B:W]P# ˖xJu^=Ho Y: a |"op>7ctN&wwD^|M&ҟA/?BY$@H`!֯-&DܯF׌L K vhW= jrO_N,DB -Β G7 udp: s2{l0B읟a^ڜ1I| %#^M&<9!\iNne/64 SqUް8# fG`0^jT;pmB|߇gEa .X?}Ftll#*$='"st==Q)\Jd=BM34S_z2j5)= @˙ľ͘^AqNF?A\C= 5_)+ڃ<ԓ=Ufc²Or9OE!"%{]ODd&رB>ņV$ N -=Y,&LՓ78G8$z38-u!-6:ŇdHJA7$#2 E%{",yҺx%їoPDK}sRhN^!C AdW`^Jcc,1U$ #8kf#?Jym3g"pKxP0GO<-:~޼DBOwu(kF&)ÓY ʒ)\>]T}鉃j ('"0l L vI-\*TTd(bؘB"N:hbm0T*}ydFceTᲇ(M[),'/v}k1T#f?8G퐤c1#qo{@ľ<@_nۀj!"K2 H̱9Hغ0LG5FGֽ?EfҴQp)BN 34-nJXpxE0Iޣ Nՙ~<,vL&:v9eb_Uު)&?263[,[ ٬t!2Vwf'^IXq48Ħ_Zn%<\W@Dn.q*Mxъ84"/^"!7ucO뎳6p jOS 2N)1y"fS^o߸`6?6;0?M\4&>^ l!BkcXv!+ / D  ZO?Fgb k+89s\֒I8O&nO ݸؽCsA.Q )v+(4KzZn %#,]J4Ph0$19. HX7 t Q<#n{Б~=0c|D 2~aKSwߐ4܉De0LMŽ,~@uVP8+(7 a K-Ċ8WuH9CN2f{qO}4SK$YGx:wf I/2=9"s}!YcxcQik.fp!K;˧qA= E#fH_!Kh`Q!6fi%;}qIS( ?0}`Xb)|!SOǃGO@Cr͎B\_!'}6ԑ_As*q_R >.ݣ.YBI{}T(Nqjz;U1NUs|_+d# <-?W\@߅?| 1lr`f 1>7 &Mo9ltDnL!Wwf:J`8"2 u7*y+IcԐStK/ 4Q&KrÙ+B{޽suv'34l1.l5\rMrߛdmWfQ*? ׸#޵qT|ߏ{2pgDIxGOvF\1p7ݓ+ɹD6\B?Ъ^ab_l5PaB|FTud~Nr7!올{2V|bGXo C&VE8[?pp<+ҝw |^>fǸL $/j@J!V,@pt+nlc8q 5@ς344!Yc2dDDU|v kCX1!YYQ3r %rw sX~E>{bB^gs sKͬW BH\#ü\yzFszݍI K{nN7{V qD|=39".4Ww0\qA/ uyrGD_d˦ N..:ա<gbӐ{+8(gdt;ݓ&"tPsȔ&}geYďQSeWW$r~ h=HLx*+a 1b \7O%f{} 88x`fת bs q3=2G? ="QPI@ƥ.s§GtLvQ0( ~=2IΈFʱoڑY&*3>U`L#QkH8vtУS!b\N ikE/B" 10 (w:8M}`aee~ 8hDhWU!B7rs%/ e#;T.[ 6#ՃߎRǤ١B *!?b??Q>~⒉JS?& . tL\J['yX?3ahN˪#AaG!w9-ÂŇŰ֎> %7lFb usƅ} c 2%4_W[rL8+N_G6&[ԥ)XŖ܋K3 ‡׵ga׵J<}RA&Y~/)9^sF\DGy&؟+β챯9{vjl<5{s)8$047,?a`|Ae Ӻ.B&q_ 5؍10G0у!+PgD{Y攙1i_s,|XSD Ƽs@9ap?̏^ܯ<1DZW"8$ԫWn_]pշ%૔OJHR4d|q}@mc2 XhJc,T`=[70/4:5+."t J]aFdpD<_"gd0/||ݞ)_FMW0:*{[3&UJFt M)ԓ^#^r̽Uz#7Mz>dQxQ%Xa1 _(@hL*N4UE`=etḎbG/+q:y|_{eyr Ӥ'# p1M_rc'obvJiC)̂=zɥPaX@1'82QF*ݿу5_pjf{,"clax!uX ).&(1 /phqܥEz} WS*!XNd9cJqrc%,?eEǕ(eE/"x|l |U^ծ~4wgI[^cT&S6gԂe`ǤJgd6gw8Y=|1ʸ_N:`µ&A6yl^}0O?&ޛa}ݾ钍徚B;ZQl/䐸6vvee\ѿ1MUW+uD&Hv>/V]mꇼ:Ӷ9yK5=;x1x/\hȎE6^H5 hȎ!=> W33%6y]>Ύ/zrכ7wofdDP0[l_;9>_goN.߃~euv{߹3i]cXZ1=3="KuR|tg:< B=)"= 6_6$(FsfJd=t `&8)_!(\pр7}ņ4F".F/Ķ4(e#Jg(ߟj6y蛛 -Cɋ*l  Urdzӝ7F5p{#qA}$1] ]pwT z ee@)vWMb#/[تߡ$LE9 _qdMeLyV.2H%WHWˊЛ,*z!vH /Vpw6ab1l9sVjl͞xq D6IѥTc(%֞OuA:ϧ0aoQAT}г|Gj.3v1\Gd`frifWbBX(3Fީ_Уk>;xuW_@]+Xr,c}v+zh "fT_2ґ 7uSN@fGiU$DlLkqa2Ha*hO(@ ,;RZ -}l|n&hMJPy<;"$9٢B*7Ůs] X5 `_RG\aІDI^9k)-:d W6Aoj= } Wҙ=/k49QGPHv# CeEr x>%$?!me̤>dL̔qV97L;ɦ)=s< 3W|D@'MPd~pKKC5f_ I ~.%0i"x|_{E-p> GKUi,6ꬩM'ZBOĝn%uH깎9ijMڐhwIBpMT|ߣ/Q157Cf?ToCz"DK+\:o}W|庮oz!#eV?c]|Ji>Tĝ#SjwJ]VߞczW,$)[:$ ^ezJI5 4$*8$ؓn\q]ˍ֏=x%0k0fhZD}/}tr'1֯'wÄ8z(.σyl#m9;wmj}%EEmO2)̥i{Z?y8@H-(An,nrh"1hV'F $W]pn BU?)J(٣Hz8шߐ<2PrM2R"Eni 鿈}}'s-Xٝ:c ZXo#ȶrѸoi#^e[iuroZV8M/ufBʇbEzB(i~!Ma$Ke /oݐFJ5jOݘrgp ެ EO c+d@jw YV OwV 7|u)Rw\3YZ:P f;8>@Qsݾ+_t%dc^? еŹS厇/ P%D!k@7BZ1SwUFa*>Z*˖",EŹB8Ȼa@L.[A"8z_J%ZR-ĢFͫbOё_+V̧p>yKcfL:P~'cCah%^n>c -uT"|G!-P+7: ܈Á龪|.*.3 4v:>?-ےXViѦDkIcjK0TIA'$G l%up@G'qY3'kFEaՁwO,t,ʯ/e|U~Tং:9 lxiv<vt g$a2b!A_5X"gC(|=,*[_5ZCJ-H6d!źPy,бh ]3 $^.c`(khqڂy ɫ;fAϝ;tC4KS>w Pn2/A)Fɗ%j/$oYum~JA`wJKVy]mG #bپ,?֫_ai;*Գ L$R p(q1r/׶KFfN"]v_MDӄ$!4#ں- m+|M"uf^FF #-܊/[,CPl[3!%_ߗè< 6jxj{䪿NjoBfHz_gg0V.lav8qBeEkGmğ37RM1/m-Qa ސƈEvtFzZȓ(Tp$UlCRU>B2Hɩ]](os-dBD\ i1K眉;:-H +X 5=L^,U3$IFG #1S#EI:Ԫ,V]_]]}{-uaL0*֙8;_Zrm }KALr[Pb_}Xh6X ?k晛#B[I+@I-cxc.b*cPxY-2}+u]pEoX <_*qg-*rQPUQ5>5"hZ8oKxȂy r_%"jgяئOˍxIzB|aQԽuv,imBr'?ʵrBݸ\~oH+o -`6Ʋ.N" PN!.ZaR*)}[cuWY99mr2"wA5c{=?S4[+?X&]qF{l߯n`@7ŎZ}lU?I'1 "sC %V@1'Cc3ְWNV}sna ^˵DF;|p?FP3-FʼsRjl!WNYAWr^f2C.-6_V-,-} *}MtSoV?0=#L>âXYpz*/&<4 tƒI Ma ݙĘ5܇\-+J,C! =/]P2Pl{BrロgfV;Z9y[6Ղww9qB3HP E  /JŠ_Dog:|4uQ}3x7D?P g'U^ 1!Pq6:(NM!Zs2'v0kЏu`-vBz rb(!!Y)AAkEMUJ *3rF:@4`шu./&uDeÝa=^d[XP|q5`+[PMc4{ c7|jڗ-hߌznFIm3Qd )7]%퐽[cEK}y؂Oek*s+ |;([ᾇn6TyQ6$WxA^mMJ"*<<-~D(T;  w4"xw0"ý]lc{U 56Bնt1`&@ȣJ1^aW޹ GqObn٨}Hm])ӀܔbngzpxhSSˊ+7J&mE%**'@Fpa3;Qcd|s?IXSx9= fwC~r_;j0}RYVR/ްF\?S+HA-a:x4Jc K5xE<6JJ 3O ud]۝j_iNdQSJVK_1@H"1h)08(:X'7<5e\-YԑC,C(C*W7aTTb%/S٦M^kb!#M1(iCؚ솬6d&gbB1cRԲF"5:7diXRQQ vS[&vKzM@  !kL!0 f"b5*n6+XТS l{WSpd@_D\3⎇#p"C, lq'PǼm{HoI6*c1 6neʲfAXjx2yyn{Oz rD>iz{w=Jc&,6BwQҗ (PPT-!\ D1ސ&L~Edx,wYˊUM: F*GQyF cxjh`|Q.s㠬S s?>(LE@ ZԻjO±3k߃v@0ڌ-ܿ x(fQ`jw]1N}QR\EUan1+M*Q/h, &*݌"xI| pHawdnv f9*Ʋ9 ^a=E@?hؕ_Vr,g{-> 26A !|*m7aMHXZUIM /x޲MoWuGEd0Б?mO,T{F>趲R@PZthG?PՏ#7/ xpԢӱjz+I_xȏHf^Qb̂uVnuYE帇|g7?.,I͓q }-&ݛvU>:WE I7:ŧwY-JgG@:̄x25 8i3ј'78:RHt';ŕnք;bxA9f-񤮒 15'YTG|s/O$TvXnL;d ~ZD:Ll8Fs>N71_]K1 fG3u@ޕs02/AY2s#>; F̙/Ξ  $f W |ㄘCA$9%l%F̡ `29'i A9S mGh?x6mpu7xОŦKWPxԚ+!uq'c!B@X5) |AU5iPa@XL$*UR#ɒ@9I$@H (@CI#Qa%4gy3h[؇YI7Xq5N2zON8{$f9Xqg*Q}#]G oj=1@4ro* q )!\}:HŹڅe,Wrdw1rU+Zv(_~*GrC.B2 2rzڑ%2I=ٮ閆z%d^KSC]7%3fPS(85`ٖӼ2d6OG=ڶt*:(2Ŭ|iABA k> FXrg̓l$"6fz h}9,@q~#u)#.y@)0{HCJ @ękF'W_̏ةg ʥܹ@,2wlN(TРدU&|=g(MҲ{y;JqvT$v.T]Dwx!8c!MB\ qF(M񪨥hVvB y+*`E5`BhN(a?fRMEЫeq?V!cz-m]FHʓN3՛ͼ\yT[Vz'bG<k+r aa˟kU+8,F$q )poE˿ Ѫ; ,r8X(691mUVdE 2%LLUnEaWeu)e^a~)lػrJׯR(g_(>L"{ P(nF_e!~s)BSHU./ j K;x;Q_dA5`Mg} 7 tjrJ(iqZā|CK1^)vFI`JC'[uBO,2!n)1c($s4`3Gr|_+-XNJG)uW(\oHtb/NC*uU.7j%[iH No%s[ xܭW,OV2&penas$ۀUL8}NJ|۷{jH,Dp.TجdܪL8W]{<߁|/rOVխE~~>\&י}LqO('hc_$DQOQUTq5R?F+غVHjC@J/>RY-yX<Ɋ:Rӑc$X=LjȜ@؎8j誶٦V|!kd#Tϳb1N Um&ۉ]~׎5_h;)ACv(p~#tVRAsMd}qfbtwbQn~ ܥpk:FѨNWkcmvuNcK?m'4R,R eP54f:"!*́ d$)DOt4ge1P>^@:@ b-3$%h S{_I~舕h~!lt#qRb[hM|}z~'>S}eEW-- Do6i| + ) @>Rg^S҈RlHP.["EsqHQ҈wBy(Q2rp-5! RrZZB\DSJh< )-@M $׵CDy*ZPf7.L'x>TJ4f0seAEMVC*f%ZRÅ 2ZF:חo6K'qR@LE`14$Wc3`DS'|^ pmQ\DS̲ݾ"`z:=4 q_LCOIMNKؐ@-#T!L=.j( ׮$}?+{$АRWɈiiIj !+ ![ UYܕl| GSö=զ3c CN2o.9xsHh Y?Sc- Mi!)—AXg|+RJ5!?IOoj;`PID\΁3\.m4ޑS8N,R.NqV,R>8䁒api3Jo vϚ2P~PɃ)N:@oo2wy 0PZSYh(2,J#6q&#s͛f"<@ypoi?N` uaoJoӡp]_衿]T骀>qWn9a1Fa(xS> Vd$'#:>X~ p縒.!($ WLd=]70qjM'!(7 YNc}8ۅ6"!N"3k KٖUfےv$}OJh+ w zj(x@HFw[%s4#_9(a5<9]fwY-GXBNne~Ȗ+#+F HՑIш71a=V 14HkUk<\>~Uԏ@v)֓I`g9rEd5жfLLՐF'7QSNdV)ā\Iŵ~ GOҒ"d%Bjii)G%M簓C%~Z/䌃1wur&_9Y)@fy-m؋l†2\~`|dQNJ#`c8@{Tűz"GC kᵙnݑYA~'#c _j<Pu,\[#(2 Uũ&!uJR %dZBA`ͻ?Ef S1~L}7PD&JA%Uhzg0;1ƻlU \Fdxwls=-NFQ?βK%Lsf:?} iGQRJMN4h0έ%iQ>hH5 hGNLrrߨFiD;6MNI4SPR>ىt?y6|>saVtZT&ƀDWetvy˳|Ul`Xw;#ڥukotV{Є6IՓKG^}τ,ÛE!n#Ŧ]ɑɁR6 8?jbF-ebYGDRb|4^xa'-{"ra~0?ThP7r@Kw˫X_tz}8Y^:\7.wϡjFO -ҡxރP1޵OvNQ2C53>$M쬤[i%?88c^^ t:^d]YVT}|0SGȾbS<˽([60I6b-J`#Sμ6~e~)8k#\쏷>xRC"*჊5[ę BS줰wzk;ѲEcES7&m 3gIgIMO02{#D]դ'a9 (Npdg&yԓ!t_ʵ_Fg7#ֆAðo |PN'<-1P!x皥.Ovkw);q| ^ќC=4߅>ɣD:)OCR£F*Octw& O:{<Fj7`N`"N0Xڸbs_}id;=-䍱+z5:6J;MN$%80N嘕 ~ߕ"nU1UlmoC74Bm@?N4Ӟ YC5cRTȒx] ԟ,u ߓ.NJ?B? A0k,T‰Or^Tn6eʣ㤐o^Ddχ }4;OAЅ`^dHhwI,07) ^_\葩ZB9AwZn~{Zd])ySGh m)Lڥƺgux*Ju6^g'q>Tٓk,?7y iMO*/)ЄXq}!(44K@$B\B~V"c.2Z1 . }ɤ!QR2)&`&@=oBncRo*؉*ƅBo5HKK;j2_$&(.w &mlE `˚ TnCVŔ^Mb@j abA@f:vKŜZ!@YYW!v0y㏎WFXWmDTxINf@;*yMH.3^1FVϾMItSb㔓txcd͠H3R8~IE6@ک6X>wk?\#6.G8MQ+͝oy1X:1gqbjg1ٵ7I6:ǭ%Bìh'7nŌv؞*ev$+Aue!tTGq0E#]O 88,I"H&zS۬2pqy>^zSf(р1P՗Y.87P6Q|HwZ͗ΐ SI'u5\琑jk`x!`^2r"P;&bV &N8/۬~l*ʥZsSxmu 7; 8)n*Н!+~W/*q(n='bv-J_/nˋ)2mG O$UhhYrhmA:bk/GgqR]WAZB(;Oѵ*;!a!J{B-`5wwbS&I:.* F!!i D Y|E`(z e-7>^'Fnl  x Nx+Qγuzc@S)>F/^0Dq]g1 5 HVFCGѱ昕 H3 l-r!b\HjW_*V`>r1īw`m HĬppBY`)R!^cQI'+-|H-{s#UxS-g+45v*FBCz0(-ўlr]9$(m]V-sFCI6PyFYf|`9k9t(t~AP`-BjgkSԑkG,wvҘਸ਼C!J#nO@JbYa@ѺMNQ q֒8$ӐFgcᮾaذԑB:$XZ(6nqQZJ_$W_l(^2`lѸ.v$z8pN!-[H1 NѸd^Ujhc+\f¶; df"q:{ -m{fjӁ10. a1k}c7YQ[VoY@AamNu˛"`b ՗f83W)@fh+o&9V>فA{(6/J89uZVi$=ܣ4DJj4=ʅݚ"u追uaC{U|-4nZ/r-nq6BܗL2)?1k$9Qa86Bl 믩nttTK93 x7N![ F-ao.7Bu{N? jx[V,_vUs㞋A P~$zgI;gr/j6 ό6y8@ TLʨט5&IzsL\|P1qWý"h( dy2B-N y2" UJM9BIgʯ洡܅&K8`,j:!o+XUVK׸swD&FGՇ+>R4Q(W_#-|f*%g1 *l7M^ƋtLՈY&c!?WMd ^D`I818XZfa""L*-,4֩1?TC%:B+;Xd@S\FS̲ݾ"zJ=Dq_PCO I$MNKؐP-#!XAD,#T ) SX5T8޷]khj:bUrjBJ؈iQ+_߯e@|&9D L!*}y)!SFcj!3-qM霂װ%p=`bjaZFjDJuI\XƣMiHij!yr@CJ PA[#tuq +%`z/G˜ fQSMs'\jdCI%v!~weYWtbC LEO %4إ $aIcOu0$<͠I mVmqX!PD'|h] o[dq3>S9CݰPnZl|*uԞoqEu#_W7T`21\;`9JEt*' 5ycdȧL*k]iˈMˀ ݐD9eQ@5g`s14@ 6,x/FAr\:4`XΦ+hρ>RٽԄv* F IU&R`ER'Rj@w+S͖6P'S늄4uX?TUYnnѵy^SGp_+`x^I6<*#~djq/Q BlC*{Vg\9̡(^ `.U L@( 4dгNU .F20et؆-˶A9[|bl$Jc 6Ufx(w'Ps(v4-؞k)>B!wdzdy.VHˡ3j!‰fwWʢ,ʎ:j~ (mpQ%:ܔ]Ls@$oHc4mИ7i7 r_םu_M'PB@G&D9LOF>_e+n !f":kn7o3Z鸮yJu~`uȑ[Q!ħ^ԅ NTaUKBD]]z)&mӇoiX)CLI7 + Bs0T0px!JrX.v+X$.{ b'MmYmē0eAg8A(A'}axCtd{|U5:  z㸡7UGfC*B{ 8:*rdIfmbAڔ!Ǵs5#n.7[e\6*ih?&Ve_R -(y+YX{K/eGB/y|勿E\Ǎ(Ohk#TTN?/Rw/~O[,'Iя߿oϗ_7omPr^*w,7jmZ"`6/~/ 2){~sޒ/}̧;݉wdW(?:ԫ;ލA:Y8N>:~bFgXAZBh<^čڱM`+Es]y{0rCF~3\}8@F7 c]#q8EPr$DxA,HH,L?IM.u(i"bh|lCfX3>v6ȁ A*}>c~`>N{PKp?uoXoï&X'o>^cL> mS%|%\A #Ȝ{f"ǝ+1[BK8 O "!(c/|38{!1/WhE<^~ק3sH0j.G8p?|'fxk2~VNK`ۊTV [w93|>C()^A2&Xl^wT} -ӳ8D/_3˓zYb+k!QĢ"Lٓa :wdw}ݻ6,@, BH[ݨwpG[@q}rDqy_f@ RU,n&{MCBߦ͡6oP)ЂY}dfbۯ BvB B0o?~*p?4̺`:OfW(K? [We3boÞ0}Hp8NP ͠e rj;93,̶h~CFV&*KĦ=TKe S\`O%ArqW_O-\B28jz .>s)K3 Kfٳ+E p0AI-P!렲x/+j}Lڨ ^+CpJ穓r ] * 3uީs2SjUYuF,'9ᥜG_)rX7xҷHM{|~8(̍{NRWW 4tk]q ˬ x"Njwڹ9L!ARjr11SWb,~;1])dZ'_&@Rρ Ji(u1C tr`n }8RR7$Ė`P!v).3\ @04*>$rېq&t9ˢ8=J2d)Rvg+Ǐ)VwsK2lrq8?3*]%ɜ4|1bFhtܰ A|O( _=r 0tƉ?}) Ƞl:H^QmXC5M:2=_y5PqܺF0B-UApNe'vC =srNfXbc$q`rE1 )'FCM_CӗFV2o2t7 w~:%8n7K!G5ߟjeAgY+'b4Ѳi.iZ&Oszڸ{0CM6>⼼+'.VeGE{ ? K!|cEZ 9 /$1o bK v:.;t`O:?Ӵ#rGR.P`gy C*KNeёp'kQ=X$.Q8Yޮr6$tti+90%l7]H.x*eCF#&&LG7xa@Xs \m,LG[$>JN.+f_ 9e gfX<B<*j)92{xZp^B:9]_phtFHлn,knG!T,Kjĕrb'LЋng 8ms(x+*IGqsp}/vM!<֫_u6XO Isn,aP:54o*>=Sלˈ?N/:"Z'ERme{A:w0A:j;8K y1KVdx0n ׏7+(Jݳ8 X  ,vď7kҞk +ddH5=Qgo1s -Xڟ 28:-ziqJ;Бx|=7bKE: sɟn*MWN"eE%AQv]_2+qmvL/^A9ֹl[W_މsמ8[t(|e0je(j8\7꩘+oĉٲ4\"hBvU@54cn0j*h\.(:k"gSvvP8f,4̜{*!X͆D u9fGUi1glu>EX{%lbSaEes#Ɏ,4;Mb진ћoeiięh*#q\Wf+F),,ҧܴl:8^"5=Lzgu:o$' qSpmGцMfQ}k!KgxfI/ͥ2X E|gۗӐYᱪAIs).WtԀe=᚛eIE6dJ 0`F'v-*#"MNgܤ`jBъw.FVN &C!A0ƌ7jУnV94|8ۖUd]~0Ҽx5tz..Œ34HjEW=w7'fŢ/jů1B:(mxp?>u.|LD.A^NZn猋2F*sga\PJAC-7hB^GfsH0`DlF.m 2djסs]VZ?'p#s\d-b I1jej'LJ([X{YISl@Ko}IWUez0Z,kTsh7"Ypd׵m%J#f@_Awи1'8AZa'" 5n\V;oG[NaHX7`DvBM5郹E+EEVf{"0/ޡ,cd\ luE'v7Yrtv[UjK쫪ރ"{EHvؾ d1J5q]Px"rnn.@կ!tu»sDljku.c',EoA ?G}V>Dv x#0#!3*#XT}_Qfl!qׄ#3"é<(89懥kqX/@BMUE+, #!z*rؐBQ:׾>ΰ 2y sPuX.Oe"4ovAa;®^D#K3;Uz&K.;ϡZrZ?B=>;hEpۘ3+bKfhZC2+>:7_:\@F$Ƕ}mՅDB۵S)@ۣ~UԏemtYH)WH LEY{\7gwr>&\:fύsƗka0ݕ23)cmu0D Nߪ`(&/D'ki=0^:w@.?3DTŭ ,o#j_>)v}^_obk}^'Lq8v ɖ00=v};+ca\ʉB֩uPfj! Ikv,hR>5MĴ ຢWQI9Ҫf:]Q 9`)ד rѫWh_9NotGԜp ƆYNbq})K4 pىGLfgc?:[GYN9XwHh .\aG 0eSD mrI~n]."j{n,m@BWI:S2:@GgeTB]'~qT0xVw2.FSS'U9V@lބ[!rǿbOmSNb[t(Zk`lrJgF}8w+v-5rr&PCb02m|M,%!&kt}@^z >^s֯N?xuDﴫ Y Nu^ua(P5roIFn8X%RQn՗D,+}|_C7CXvXS BB&8S+mSq\p?³]+΀O17))P{s674~dwb/"th]1-VM0l~wwm֢NG2$(Moľ,m4^!]loXpJe5~w&2{/Ȍ.'A79z2׈MP F k0ѷ]~ױsmC*nx.C-{k ϫb7hVb ,qjd;ketI^:MWT9tPhi$_WK: q9z}j¼p0_P$ȝug5M% ށ HW~P_RO3sΨRĹZ 9p9 wI.}{xeȴ %a9Cچ Bm =By,br֖b^l- \ٙ [PZ4xܸssߋtn\U(v_WJI{C!Хާa"ptzX1l[Dde fjD=|`Wk9tl)ǘ}'uca2!/9_]Zz_'p*7cgSvA>,c>~է7̰-Jf';2kVbD .E6Rg;hU!{#ݬm4*EcV݈IM'S&$b]ĝM9C=9d ʕچ)6_=^hct?{БFb]Ұ{M]MzVȞ'UE8ϲ*IChE23r_cZ372YͰMjF*I\wMuO;\mfm^;_m&J;âsWe5L+Mz'[感b8,畾!6S-#CnODN\Mn zԻg/W_ޕ142q[Gǝ+ 5!0=7!!t_Uf vUrBxEqJ+.΋z[%禸#*lhtU;zu~آ'C%y<[ ;Bs0~kW'WAfr[2vdRO5R kz:nP)OAWGۯ+&PM$*qh抁d;xP%DPoud0d&0gEuB z'QN̑%$yڱX!jpv`V,dS3no*p[D9ʦ ]ghS=ʏ}' 4v< 3p-2O-ͳ V*pek[zdYObsDlgk>kWo-GЙ/;C^L9"xxvt `j'qeh{߲vxv)QrNJ~ te;ى'<w>ͯ3&g>;5:ɕwqq`\BVbߌ;~e0 ߢuorУnvǾDy}"HnK*\NV当q3 pݯmp]oM\f\=CzQ=9r41PӸqcͤK'ۭ8 a]&SDNmŎ8'#Kx*3xɾ/dj-7GoEhG9/u}Z/G t$MWs7 yp<(r9o׻.C(e .'G2/9l"W?Q}E7a.B.e*R4i5>prAb`1Ɂ􍝷M7;̂,$gWZdp줁Y*j8~KpPsFV21~`"O~ce4SWi]g1[fEY$;0Hz7Ds87f7QHL|?>;w:Ρ n;2VA knVsnlwNVWުIv;j=S-]SN.? q,r4wK0 oy*¬L.#u'dwEn)lqOtdӛQ!;!8'!cX"T".J߼E 0wKHnHmȗX8(+jUt teĭ8.Vx]V{iD$yYdճcA=7֯ PQ.؟Z|9KokZpT5aƨqW;ih k:͚Y]$cwSG;,$ VbcQCMȽm@ >??m~|xn҃WUMgf.(~Yc+KYdm}uL6ȷ8~Ĩ<,XwPA'{&agG&d {6#dh%cy8lyr*3# (a8WMZn:{MxsqԜ”{t[ r,f:/PkG$$a-Cr%T uEBh&mP>Xq"A:KM,Whg. /Gh.qDϡ]}CsxcQ1x`7Ot$˒Rm`!@-چ4BUhGi 뤰B7}fEFי7Pw[Mx4qm Q׻G跭 N3͐F/;4]hRo;uʤ\O;;cΠT n֯+e0s(v|JG xl0tU!f[dԷɁ6Yv FEG~wm>ߐ"l}S-ϲlL Ro= sɉLP({Z=ow%FsӸHhʽglNrݫ\ִ$cJ}U;?gIYd{mɿ5:g$e>5Qi'ʆWl|E$Wq 9yTNܤ8uvNGt*E:;oPB9$9e_>݇nhfsqOҐ@pˡZ>p'j ŦEN-Q͊ y4|,''`pUx;ְcQXZ ;`k1 qz 9_*p`r.n(uϔ;s,є zp"g7S:e"c\sPbLd\׭$yv-2(q'6s_N P|5#̀+h<Ѧ=HG~ ~BH>+5LoH^| ֶB$"K#a[ߜ<=. uNܰ2}d 0Mdl}ed2>9ǽ$1}+v] @ qi,)ib9@${`xؚ}ׂ lWnr#NVN>ގx!UP|_2 {pj)ﮉÝཆaXTTWpHTns^TN(#fm8ݍ'~-HA%0ã z&æqzW~}Pz?+o`*$_ #(HKSmU&Λ$xOz"QةAc"y^bV Gwus߇dGoﯿ=;0pP=ZNb4_K2|bVb<+' j +!%)":]\n nM)ܤ&]دmڨ/3 1dk1bMV:(} @c:/}L1mB)tvQqZج7:~ƓG|n>s$ Pm@ڲ^T-{j;*&V:!p*{*+ML t|%θ #:8Laދ LPׁ$/gGU>1`h 4IpM Iˠd $yMZg侱XFn)dÉlgdaD+kEF \zq?z5E- }W4pH_v̨0ٖwBV'}t ,2XÝyDz*DـgrdquT|qB  8:bf~?P/?1N?s2%_!; yV*'zPk(+E~vg Fh/^nLL&MS.<>ם(bsB]&* .|N宴y铿XT]W.7f oȽK,?&ϫ\wfmqL%~`+bb-a9n%};bЋn"c:Տw+ޤG#z;LN<%--;=hMji}eN\;bEad.&p\w׻l Wuڜvjݩtv(& udΞdzL`=(a[_D^Rj@;:0U.-0k8;lll!̪=ˇ}TedӮQJRIg>Ia=P5m>s2"L` ۩K $P'|9tU9[Ðc'\d!߷@7 HCuk)*px]-?]erf-hfL ~G].a"o]*;zC 9Al % gۃ8*Y7:'$(ȏٴ#3s;Sl)O4mN ZSiLZ U%(&Z8]%󛻳{lF<~DW9guQ4H=?#aQ!`&&8KH>2~[, .ZKق$r/BrΈnad:ܛp_Gx=hg't9§#/Ά|Y+E$-WEDS~h-kiA#;hYZTΣgviMqB Ng?ym Q>s"'_$3 Jo(,ȉf.@E ;ut7}=afì>dO(̀&f-sJ^pVK#h+|D40jC;fڍ{h#Ӭ6=k$UrSM-!B8< B#h/6q^*4|I,36^n`}98l[C >p 3p=6dٮm68Ae$$mcjO/eY?gѾG:-ԃvٱ؜LϺKLr-A3pI `BFB밷 Ճ `⁺\4.E_(A_. w-R# \;qDT by|{E@?D?{~N:`F[>!^6!xesŹ⯾ܖxji& I8Me$ڬ@X\:&}ϩMY=fu2cVR0^f 3ޯI_e5UY.ou,$.iCm5R}i˪lS V.Usw,tHafDKZMbe<=7?3H4*?!i?bg"1=Nm G.(5T$`_VQFOFղΨNE#yr!$䁒!͇'}PF"6+Ъ=x!(e9YzܓH 娉o:jB,*'k L}خm Cy_9(6aQe>nmNMc %e>yrLHm%: l$Xqϲ|ȋb{G$$ZPs,Pz܆ߕNj86~ġ'sH c !5evwrWB"S0 (VY^CI 6o KH /i2;'lo8n=]<4l6 ϬΥr#&٦CXuF(>^10ۨWc $S>UV]]ʯ{U,˸ob훙atȽh9.nm+&K' ?(=&C,>设\lu t+xZh01(q`Ljo;j g`K#rsߡܠ2$dLn:d);He&A`wL.{(މHȂƻ\E,,ޤm Wb[qwt C,Rer6ab $!&t[`63DBy(t6aaa5}ѐ谚_y([\jK a理LdQ4@887csmV>o4H!N'rqVۈ;IF襲8oYW2RwV IUBW4uՑ{ cA xA0Z%ILZ(dxt@ic ;Nli.g|w.L DDpKqRQZc@O0! kb`#ȃD?i@U7`?ݯaos-ϮmenYA8od3Xmv-:ZAT_B\nSnJ 81K3/ecU{UA]n]=z\?o溮M*x\XF7O,O, ɉì US q 4l={s%K]fpt B yZĔ\]sQWjhN:62Vg(@[DAnd`QobH}gR/r|Mm4#Y\aֈZ07 {ҎH%ҲpʳZ<6C$v!PnJkrEU nsO$kۈcM9/y_9R zjnpfCcLۜbf:d8FZ"&J~ Ɉi* ]z\h8u%2eG >t**w'SЉNa('Ap y |1[`RIFV|s,rT'qVp.Vz>|)F+NM1u^;61ɔe'N襛Ó#N2 -m`YUeL{\CBVED--νa5p]'URDP}GNv;蛛 {\pbr y.BxĵOHuU(2m%.hUf] PʵB.jah7yt74dD0d)P`Y-Öމ]$s_'J-Ӧ~p<-zn`ȫ/Dh/ͷN!޿nbŮ&i佋"| `tp)mļi빢b`᪩Bzĕu]lL3{d.ne=Gr*$a7PܵIiPHJzucT),xr9ϢԱR 薃]ev-;x#V*UE=Bûr+~*lҷ3xoT"x2D: *jhA2{υEǁNi6 `;Ooe&E6!cfR&,@lmhx6|@T{6&,/amniC;w*vGo@@wQEhYuw\ G|Ǣt 1p3{)бQ \nh1@r^/Sw7Qώ﷧ GY10t s `Io6Shd[kb"6 V{B[c{6xW.M(l!l>"pLBk¯uŬXf[w-he5{̻V/>']P g ?fqpͤ ^53Eg8:(@X;720;);بMm>w )YfgTQN<|V~rCsSZ)u{ 礕!jJٮ8_2" }UD.3 Th9ڊ,Ro*5(AfkP-քTj b %xo icpѳ=/7;H3)g$Y\ D냉BSmhn?2ѵ\!jFѶ2A_f{'>},9n(vxؾ@y6 Vb X9 DqVMsNyl\xC=j P3zK]r_6Dt@ehW_,?t?1(KqcŒR-uo ߌB [+~$\G=p;e&WbniZPu 9WlV}w| EZ\EMSNN[#Z:X =U6ηF`Z8GaQP c" [3FaIL9 1Kp)qNӛͣrXp!C[\aR!ϓgʝRF(ݪ4E+;)n5=|voPw =\%^S t O }n7Pd!nKJֵͧ/QD"vXsmya7az7ߜqܤk nE7@kb TӁNU!F7ueWw+^)Lmq㹉8}N+|<= h~>?"vܖ'vq?܎Q\V(`EЄG9A~*xCI!\PKӍLnV 9gg5Prg)HO4{ȴd1q[S $`Arx<ںXY{3.8P.)P^Vr[0˸f _ j;WzZ^3RAMNbM64_w_ߗZKc )⢟ *\wgQEH# |'dfƬ4)-ႁX'zYq@Ul8U d&6݊ihj2}U0 =>'q49/bCP ,Btp梁=/V9mHBdreKFM{Uy!vPeR@69 N$Esw%PgJ)h'o.dbۇʞhEkҥ?/H$)Ez1T1SP.ux<|Ѧ~>ϒ0NDfQS x~wď2Lefxi oȓU Vmme29@ sAkˢ7F.riB.Qj$һcw7~B>DD '-u=A`D]SI?g(<۽~a )>ҳ3\ȋƇI;isOtb6;x+ u½͆ݸXi'3y Mg# hO-]:3ȹ4WU4Mɾ& Cἳ `|qY:VC4ZbA bnḤ`"%S8eD)IEtl1Ξ1I9N!9y) /`c,8#P-PU v_tpƕMz{}FtDVڙh2IվKʷK:ah3وN7$B^ZI?uPC SZy])B řPQ(տɴpxo}^䫅eGx׃ ۅ)A%F ð [:v6BȰzV%f#[bB O*܁; ( t>bӷMٖ-7᧧ANnWJH .P̅ߥ*e΂X+ДƩm0Wǧo/߿Ȍ]YI0s7۟[1.G2xbþ) ?nKtpp5eSBz2[~_z@ B]Kj8 &pL8`Q0q."Gźs?j*͵_3*eaC3D.&u*D \zjr6:$/|],澷l1i(CvR?Pq`5NW˜r݃ T Ja V/Q6"&s [[w֧-\ޑ9F565Jv~ߕ*3V!c,ILĝ_ d\3|.QrMpC^]&=G|"{y{Z9 g^PxS^U;|87Pp& B]v57tpr]̊A-!;f v^Wvbt&~e_ބP^@r5b}0UEC Wn_tË LȊ?q {s*O0צmK]C-@ E%E*ytJYewQH3qPN,hI4S'JhZ_T}f@bNf0Wݙ$ wb}sĹ 2 _אJ4ZTLO"H}u+;f:!)AE!{>'ԭbA\4߳|cWn @li jY|LU=-^)×QWhx <*!;M ZZ7 )]D9nRtD- 9W8OVf_]"?h,r 4 ulqhmjH0|oNZVqƀjii e 圳i` F"=Т&i![S5 r]^ 'p-B) t7jQS\TfqW՛oվFsb':7ˈ?<͈%&̜5x&xqZm܉[,soo:TA,t詁ʍ&١TNL' vvnlp:m}ͿsU<^uhZW ^|`XndMDb= j\E^f)>v4 ~]8먛r1T'Tܷ›H|2"b_(>tW"9%y]lTCv幣q7)hFR`P;f%D$J Nj!:NYFb:r,ʀ (әd!,I3(QY|AV4S6NTvEN8W+}oU1 lG栚3:hpY c) :ɛ]Nji=dO"$%5\cэ߱byq/,2C[TSgAM,v@ w0v@ ֘;"!~-$0 5J6[?]jum/nˋ)m#O1YBp?)B#_|YMp,Mrv֫#L֙i9;b( Yc녲9G/pGc-FB=n1˹pMZ裸' Jm<K*EY'MaM5 v[h)>O|Z:S/Դ :]1v 0Hb&78c>C&OԌ/m"Q=8(esFe#FcK*' AEqǾFs&ᆖ@{_͎TZ_jhGixvȫ& Qf :"Rb)!%~q[H˘3TK[[c(pڃ*| $-t+@K`NEC܊D: ]qÛ:Ixy[ hO;kCK2 Bw e >]G@^#;锝HpM,tKW05yvav1Xt^[ au:PwƗk>ճ/t.ʒJvϚZT&+3"j?q @{nW @D ,`7f Qڋ*:[a+Qe cCϳzuRUiC!+׶ ZFլ| O*g" F,! YS<࢐=>V]w H7?m:[M Gj!%M{ly Be\#LoAS$C%Bu>;^\a 07%w!6\lVӽP@饽g/(1Ebm@g!{=j-g10NJkAye7=p|okqNW> #\GU=kQX׳2= r={H;u1C{jo@a=Jq7ێ?c5sf QaC?d*Oվ%SklP(Ohg ԫ,wm]ÜwQ,u'H쵭H D8$UɡF.FzQF]:#y]=9nV*u@ FuBG&tCjXk )2j!@jFu􊵡cMuZ?~jD{^ʕjjt e[VbSX+-zT|]-ک9Cw%@$;IS%v!pN(xB+(ƕ.ب""9iAi.HKU wBA#ȋ*74ſ"S( l=ǙumE9>sB#nfY"eA"խ@=o6eVc].7rBIʔYv?%|QlVD77K^kYB{w}J8+~? 'ƗfGOJ0@1#-[ntfRWL_A;F2;<~sT ga M X9D?(.4bu#$QUm$l F`~Xe-ثh_If<&W5sDVUqMwԫe-ۜin5BH^cq|niQO:9M2ߺN3S\%_kW>Y]x:B۠ƈKClGx#wiX%W_c ޴t\mvVc=W"ś<v͡&A4˷△iY&WtU >Lf"qv[TCPAݐ!YEH2 h}q}{SWKིߴkf]:7$M(se >%G[c<ї}X\|<ՂnJ`%.LqN=îAʋC=.*/aauym Rr b6}@{Ǹ]ysGHYHqծ|q;Ȯ2>"aFnjAG-]4Ƹ7z7?2#hG_w/^lbc rO8z.v[$R\+Rѩ7LEt&S1?HXTK^enJ =?6jMӛ1©* cH e9h# IS6j$XC~&!u0 z&Cul" \ ]JL$ ^~~';s\E'FS,_VIX)3¢+:J"^aY̙*DcT<nzl G3eIhې;?#3QYzG- 2)LەA\C@@< 赸ɶhoR0޸x_|an,F6ZuBr3P,Իأ8+XELW}Z兎{ӝom6V>__nJ6f[}6+u8NkKZ 'Bg)x?\EP]GE(x($Ci;;JWe.;|SN#sS3˻E:ztE\.ŧ,7iXk}yV9ʻ<`ֆPmo_?]y;EiHϩ˱֯};O뷶y‹2x0VUX=|a}1;r$H?Lr%vKtJFC$&7jdUXq"FYN(PK)4&Q~sNVĮ9BuW"s͢%P?*ߐ#J #DPZ nmk_ tFtM}!Bc}oVܨC.ۭg#"T[ҡFۂ|~T92'b^Bq͟,]8p YJF8*ۭӪ >@jtN-Bجes2䄫h"0=ZCLor N [M\v =IH*QDt Kl0sxQMbf`U)<"s'@/!{Zt޳W'|@wC59`U~jM`Ft< Fk(wr`v V?~›PIMJd!#ο Bf kB EG =ߐPNn\&u_iE SC"Z;6=joA:~l[VCSLY9~'qDu'nO>̿T]uvgRl8C^_f8BΒdަJ4]up*SωZ+mҥQ*([%PKtACFUiT[csD?Six( KWt9|v<.X uČ9u/0a'A,Lǁ;DnV9\5U`i",jw/\4bkeRwCqs q00DQ1eV.u_Wo?trnҮ|]?gq'u).EJN `Bd1,xW׷`pQ".sUHPFМVjxhQg{k~,3]f宑mv~usrzfӸpS?ǝzvn~>8cKj;:<[P/եV/܎Czc~Oծ_X\> ih=0 h8*g?`Vhn6ɿU'T)׸ v533iS $Yt+_fWeyZ899~wOWbz{UnNnn?cĵ^8!{z47 yO }_Opxyqq6?W;p$uz/  ٹ}L:Ai I?%E)΄m~-,GTm]Z|sEm*ԣJf@DZ ~$O+ۃS(r> ?|IŏUC|ZB] J|I'_zzh9vBUpC[O{Wڄk_J'τi }%yL^1P]StYs$#V Gǫ-0wot8+7;x{bȝ/fttL*(hNkMso}O=kpX顓>H[g`U\'D $g97 ( dn ^#r^fm8sH"a=HXri*Z vRMHPTIQyO !!&^ȣ*ޮ8[XS So2yidAWF#GtU÷9OkJtv*.M';վxt^ 3N/-rCJot#M'}LXg)wZ!/ɔd*z ""AYL=lRzuhP9R!cγ*<4@ U"}}ߑR^)rןU5e̋}a2/0jM57UPd^^ZiNYh_Uąz_bgxLó!hH?Noiniэ^(y輲yeI! S-ǀX(64x"eh%aJ .*̋7xTE~nA(!(ZNKH9DІÂh`φ "Y 7Rh xm$i`g"z uůbxH5^߈zT;0+(T Gs.nJΧT#7N-*xڿkI.c!'SO}˜ &yRIP_:IS*mxh zOe~Šj[B-wz`}hC.s= _~PeաJ &irSԫSºQWj]ĕ.2Ys6S\TnӛkCx+dvLJN>w/:1bZ1Q[ ۞L MkYJE`)$?iB?ݬp2 k֣m0jC}fjpDGj#_:ͬH r~@H< 86`&?rg -U }8@KʍmYJVm@3sY(5n,:^|v-I8k-As?_:K6"i^xȵ7D(:1:Mui&c zY?3\j?bDb׹dѣ 1El]>/]I(i.R-8"mG~ :%e'82O3=88>6q#q6ITem GvLjLRDMؖU_^#38f %FnHc$\FZU@*3֍+zmhdc5^l)tVq`)q:oHiX<&BRitNGE2>H-D$8}֠EPE`HЧPy71jgMeiqJgT@RC:V3$)'5epR6V678C6;do Wv,[6"@ʢI`ELzd*?[7vN 6h Z)bM1@BpZga o/S]Jg[˘TߦeE8EFwGđo]ejej]xjD@G!edZC}+#T/e(!Q݁-^ByUW|]ϯ^|jf7R-ʾL fMcЋJCkaCwW^/5#]r $u7sC|-Ę?$3T>vB5㷯v{RW6v bNÉާ/q=o2p)O4Z24T_`8 O߯O.M]Vrk~hM0CJ 7ӈF^XEi=:an"X'$tb>C`7|zT#:K7yr'ǘvtд_ZPgnkűYt"D \'ZD7Ke \kR !ElGANgrrb̶fDۥڬ%#7e${'g9n,z/6 : uۛՕY4_&woWxt ΪHvfVpnN,Zm*In6*me<"QQsŴ26QmD<M'LD<b /OLKH*ӫIn_K*[Z£\KFՠi zJH9CVf싒i|DQb6_$j6S| -!QyikgIأCKP2R".o*Y>/-($0 %C>7s&%3"1,A*x)FC‡QHk$(y7biWB& ;X'dp*@y'1L|To,/fd-)fЌ!h$ |'8pi' uHvRG2P}7Wڊ[b(1Opz_#6-#rw‘Z&%pD{࿣DH8ۍtK9#fB+|'/8Kٱ]BXJ;~'VnoѪqI|ju)aε,\Y_>}brt"8~.=a@Ӆ+VJecKBU{Z*jm-M9TLM܄]9l.3hڂ@,mDqHR@pSRQ aXZ,@I*fVYc¢ٮvEx i4I]_l0ov2^N,,Mu5W hF};Ki0Gm/r nF_3y6T  ses*j`ze=wu%#d4X˪I A34+5 3ASSpL Ƙ,x/>ԈPލ(N#6h'aQ|0;U$T٪FoTQ>U:{Tύ4hX=wm"`Uֳ2Ѫ q ђ橰~J;x h&@cS7{oP%0^՝.ْ!fmau8 ps2ErBd0 Q-1{ʁX4 ?FʪɐBͩY|z[0F:BhffۀP L塗^Xӥ~Gx3ء>}Ja]|w2Xҥ{&)*)ZojW|a<+ܑTSCMz_É33*Qxd.j'&Y[puD8?~bwӐF dDSP *v ~o 8JRbe+VZIOu[: k+f#lM!O&l߭,&m4 a8U'68`gĝݐFRgAkNHq5#!(Y ?Ch]b# LB/Q8~(|(A}mҭBdRskNս` {~Qꟼm& ,OHY8ӎc}9J54SiʜFq n,fP+ Nʏ` Mzy0H6IgGCuM@T6Of҉fr $cc2k)X TWkRWpD突)}YU_oHu'@C+ 𑬊,}J*]c0dH{VjS}9RYU*~Fh:GLVP,lO~#ې[1$X܈Fj= xѲ:SUZK6"دĊKͳV~S"S[$R!OM!3^wX$Qk+[kNak(f W CA:gO .UWlA4M$bQwBQU(s&^)"8Ї߈b4}08/PgLjTF*j ~U G‚@}&@GʷDp(h"PHtQV4hȷoeQJa"8{|X~ĪG eǪ>W*m_FXph:q]3.h݊|ڝpc3X w@b I)x<,DfEXJD]"2Ch!Z QW*b&2;AζO!qbC,^vVƤ>4APAPz(^+W{(Fy@桑(:4F=JEgg'ͨC~Lr C-cRM?Ao@Q="q4jt,F!i(xex=8jVC$%M A6FD[xIjxICZ6& Xr\kз꛻jn֨a|l_K6{ Uhxu@5wW~lW{iDP-8@ 3G3h'-6$  rWR%4)E*)oKHBv^E!Qi 8Z9꿆4BcSEm;qLYj\dPev6(VjYRrAhGKS±j&Ԧ0 3i]¶@ $`xUR nN<5a=:FlbN\_ X)Ծgto7.l-.P^-hd-zTX#D:y!\_Spdfӻ_J؋ׁLlWo~]'v+N4/kj;< l㳟,੆h⛷ꉑu$; {0{lRC9v;_2hY֋(Mncj4嵭4qx}BNfM*hN|!|M)Q *ԝ,(ܸߚᣜ*e'd$7Ȍ L2OE\lpb& }_KH7/f͟a Y $_clBZ*Emfr2"*L}2P wk# eCPMv1]঵R*FrfM9yXe "9&G!6 2J`Ekܬ#@m L\TuZF>hn@.eyEMT28[T΅y4W;XJ5q Od] Ǝu=,V".k=c_`WM c\(]_ ;Ae&!U+:,&o j9{t2WpQ@c?%ehiQwÌ++3"oqΫfR1.Nf^`xs2I-*l.A\ޝB J& Á(i\,ion oXjv C*0 7mtO9#kh7X5@pp+ט++(DyRy]>Xo5YUj*<0AZ-j󿎵u! ׵BY&CZ7|PC"QZ6]Xz F3O+T&"+ !chIYJ{fy)զIS#_{J*2q,V a  D_R# hیqi(˗2Oiq|;*8ns+,](2ݛOnIYC;>{:u Z?:mzi{hj8>Y:atQ/oI R]Kq-MR>Tj&eEYC&KbV{AXl2g^:j8OKI@(y4eV$ @}&loiVCe%ӄ gK#܁M/3KuyV"6Zs6+cxTv;ف{ZfL-Og0mwpF%R/RuXh>ϓ^G/W zx֝TͭL' 3ͪiJO~՛:Wp>H-RSPח"Ϥĺ htBfm)8*Mz54H-ZB܀ߤ~mOQp,ݳՍPF<@;E4wjZF:#Q20_BJ5тd`>l!79~ e +7^eP_ K맇H1'`Kkf}K? Q٣b{bXV}N%G5f~ԣ݌V=d#))f 0G)-tB7@h}HCLǮH$QRf jme#ʷ@#zmꞵ'S}T|Zꅘv^7\$g!o\q' 6AfSbicwr!,D: 2Iebэh|2XaѹHnQ)EO'$pѠ$KLa6Bx$L]>SSNPۊ#Ueڞ!P-e׷_#\*c@9B3(;wnEC< &`y}>}5+",L6{?{2pʣWvoxCCx_鶒^78qoSUSe5c6JuO"\4dmOqt:i6Ent_Ei)KFkEک֍mY.]R4) `yR ح. ¸TjIyu*OX#hI^[1]H(ن;WʀIX YNM-QGׂUJ} ʌND ފ fٳ't7T]bDr^j_YZJO-"h:/΢ &1X0*D6 dsovIt d [}cqC({6223B8n"504Cμ";JoiRuY T$϶ԇ*?\.mkSPdC0^g?Lîp(?_#e+ٯγi'ۺL2)`Qo6p&|[+il!WUp ܯAvU/^5MZg1 17/|Q# BƏa?:,(g=sXi>J1OyZ%ЗѠ918_n2}Js$=]/pj[#h| Ν&a8k" ,d͔"'/>H$n}]qŴP$aYؗD1 #ۖoӽE5;Vǹ-B^6v+1]E>0YNٴ5"<0K5r3BVʛaH p qRd5ȣuc!{Nh1E=ZBnYճbrXd󒓤#D]-Ѽf욿Lt H!ͧ'zeb+ YwveFFwΦDдY<5za#4R% Xv:ܐYS D62uѻcDcoQZDԀk2{ĭcZ0#SA rYiLJ2g L"[NV7a脤'HLrQ֙`` LU{j \'m-=xLe؝8c,wJk8(A#G_g"sa %I @25d(];9" `{K1_l˪;!YwIj( {eمTB='\G&!R9j3RqkOd༔Χ8B$RZ,5HCtl.0ʪ¶ 'iP#Â\bD rS6. 8cxmb0byNy6#X.-bw~wt>žȪL8VsZ,VI0ƭ,Z)u h¦D$i #2<̳ZO͉9&g!. IٰM :eꉽT]޻AdHY-\#oҥXcSqjH] #E?'ddl,)a<L~_IqF~jƏD 5Y7eh hL#S<zd=U ¢J&\>%EY乸f='1 Wr\ߞ>0nJMڢ9`ͩ1J 4@xyWzl$BYo?Ue*D8ۭ)R,8f T@'$Xލ"ɫ12ylIUA&GЯ|Ry֊?W+~w-*N`HSZ:Ԉ>xh pH!]ltƘ8)'/aѶJ6M7eզdAJGCkX}uWc6Яq8+[TK;Mmv󯾮_`k0QMطrv44,b-MF 49ut 1>C'#c@+ 8fn4 d=HӲ>ՋcܒWY*d٫]#@x_q`j;(" _WI +XfR]rvWf>p @RAƸo:yKܺF yH/KzWf}T;BUm('Aq,IsAdA6C*#<~ xb"Jhh|k XLIz+͐E/\!kWx´ӱzR?X+!i'WٕCz^Vo.Noo[X^}|jSNex%&$?8η}Q&-k;ܐ?9X6|z}^IJxde\W(W/ Pz_q,Ii*_$k:OTʿ"<"XCtݚAٻ"wnZtOHh0Rf|!fyg&FB& ;(Ʋ+O6(V[5X(LȉKz B4hz.S̢ caWe!}?obNBj}ɶVcNeBy\BuKxKT'ZdIifag":beZQ NnKWZzfp#ְ="XϚrmCsٌ-?m80sPۆʪ}fB]O.KwlUh^@oXacl]nP&ٮTyoHYT^gejR.hTf'3OmVNB<$(!HNa6рp;>&_h72}Y xճ3@#s'Qn.qyvi۫1yev\UM(I=kUw,{G)z@LҺry:x,1TR]{]hxZc[EV,eA&8 al"HVLGDVs&'Å+!Mk U%RUkqˑy0i'B3>j٣ӊ- ,]/Eg:^adB/yfF7y8dT6g`TIpz}w:Kjl%)_hZAl"sIO!w,'58"j / u= G{ }Jׯ rS͵RMp!PG_Ed;̉=kSc&'g_.l֟> <0lkzrE+L7e(VI8X<٘=ӡLB)%zބbK4i 8L~)Ԯ9I%?09*lȈ4! gЏ>:S̤]^&*|9#~Kwmb^0꿽)AX& iߦje? Z]o3˓c G迮J)^K CC8f hezgκoщT4Kb q")>ׅ2[d`:ˋ ! l/2W5PJ HfB7$^x,:Py .S )en/ ; Q [#ԖP/_}Ջ wr076BXN7u2?y՚L, $}DjxEGY5aPm|9/ NCI BxYE&Af>v2*83htѮ;o*_WoH9X>ΒJ G-+;lwѕ n"o*[PA+Wzִr|9,|0M$<80˜uOUU$&Q=Y6Gtc :*j#_v&AZY|p).- u&EX%sxժE34MlyO=:'Pވ: a9Zx:1 9hee6+щ99^UpŬx`QKJ?Gs^Pm͠yJJ^:RZة=o7T}Z%ٺ$8Fd[ .dMUH.' ̜86CC)Xx;[^=Gyw=[ahٿpt?.$C$&Gj%T%H+ʻZԶߦVԪ/DƩWјT=뤕S[~]]l Tn⅗[SMyjJR- ]U@-leWA5n"!Q+z-B4n&Bvjp5,,BMĒi[CtG V:b#Q֞᪭iǑ\!,߀|1֝qXXҢIJ8R߁q$DWl8<F+שV#7#߃[VS`F~Xgcd@X<zHT^sI*Y^YeP^s˛{..B8@/Q΋*5LZLYbs1-x㶑7y\YeY_zTQ8_dj\ޮ|Z0Yʅ }#47 [Pjﭕ20qR o_ {W hz4Laob~D9e=EcHƴVzu?G0i# qWA0T; Q,ro9hYf1;;bq]%E8JYuΖ,*-;8g}VzZ4FaYf-*A&˱x뽝~T GؒZh2VKc"( Dr hYO@QB#Chkډc o@[iV:*b,[Z+ԀxMje7Oji--Gh#u(m7hk#ܑZwVaNk8ñ+ GE Fvr$>Iaexxo@՗`TΥ U4Z'GdiP5;̕Pՙ2*IxlC!8 uVZlD~`jYkae2,/ZPg&ZYN-kI47ӈFj3PCc!f9HAӢȋ7(N$a,?g"BP&[~۫Yg6ռo(2~SC,(꒵J5+;H?i%?UI s$WЎS_p`5mRw6ULt&)H:y/_ZTPnwnȫS֢R?PPMk 2 :neDWٳ:IٓxtM<>lĻOeFPD M:XkQ5~11>"2(G_bl3޴ptƒEى|~h:p]N\>ڭЦ ӊ{hjH/_|..LuxaMqV7؈N>Wj8(x*ۧ_~Rݓ.jbkj|#lQRĘo|Wvb!gbz_ EGa*S`8VðBYv r֣OPp_gSDoQ򂨐*Y3J0C[ڒ}U/%ȵlU*sBT=Wv* '(hDp]YYEE#b$*bd]z~-ezٶ5w#m/6 4U,", ij@1[;zfYMRd8E";~A; GUg:-myo's3JmWŊEX$Zň.I*F 'F4;:'*IgҠpHBeqx,ӵZSGntSL=PGvzޖ y ;SOmԤU.ekNԐZ;kL[p̐қp]Z2L2wAcMP-p8BHx`} dv``\ }no@x)%ϒE4%F?f\k !,_f/vZœZ]v#%uK))loyu0Pd/Ui_viD߉galW๳x i40"h{}Ƣh/}h|{&)^tB!#Q"nEXe D=zw"Xnv" V!YZ*TyGƖ8 Ugrڣ*<@;0sX9]EK'(U^at]jL+A  f(NMÈ7rY&Mz_o M}nض@KT?*N]aZ8QD+.;W)}zyOAp2d%-WR'P& bc{0͍v +HL/yVbpW]á|n N/pkTOߏqR:fK$Y6dupcE)H[[VK0ZqJE3x*yxx`W~7Twi~*Q/\U/np _>c6ke 2d!xd1X-3\k3StdE| !ˢmZ j9"\tu6"򡖆~]͗icJx̢`)ō݈"4ΥS㾠T,QaoU* m"K𷧒)\hcY`|SA޼?Gb[6[=gN2#Cus61Đ`ݦAbLYuu?K9r$¡SVvR&P2K,Zpttb%-̼*KHUAL5ȪUK9KxngJijʷu 5xW ?\` {1^G'|þtb'NGd4أ]jn2e.\1>v6;懸e&&Z"i&{.5M}ú}\T!*EOHjbxjtLB쫀uOzVE@m;aDlG#D[o6mqV۳(}-2rŸ+? p.R<$/_з;;,tr|}jI* q/7hQ$,jxΒ A1djk. E2͒$  !H @@ذVwG*&`p/}ބQ. Dw!Bظf)㑷 `k'FjV>Rxrk$nfR: ꃸ8}DzD7y;9Y5 >˛۬ ˻#f:".)+ عjK&k܈(:{q}^((x"mjf96`/aM ט8fG:pVQ츎FQ**ױ)|u4AuѤ*ڸrZefV-j*w_}Mfߦ_}E=W_y^[:^V3J[91WR\(c(.ϕ +UM^WS/C{ >e%ňeuET}% LWpAk#}uUǯ6?MTi ZY\Vu% L3ҫrVəOSPB&j8Od;=+B8Ȏ.gelD%>KPa}Jf 04CH|4CvL@qۆY ,ٮp`NWjq+rY .1P'[.8|0LޱX^Q,4,wa bQeD ߽Jr)nYh4Mn]piDEkف!d6oE_:K\:'٥-$ @[w wqc!IAlD.jE_ jL2ïi O>S1^h S:{ґu5 C2{kP,;)zm0Gt2 vAf*(U"p=bai=Frk0RUch,Ņ|z5JAK0{$ ǫuVC_M"/t`wF}q$7eWXW(պȔQ\\"ۚ/ʱs#_1zE$o@ GʄE+sh}W{!IU|VpJ"_,[dqB_T{% hcBtWh٣q 95r0~=!.–J*k8 x(e'dbɎПS6wLmlI600]Ȅ1k%ܶ[ Srpw(d"SWpP 7i_ J2q,^A~y= /_^pۧY^Kԝz.' 1| ?V>__nJ6f[_d^Ecή4=CkDCwW^3#d[(6 p0I-CO-;d'yMoU]"I Syx8S C q?86NL%u 6dtu~߯O.M]Vr"S?ܧbXزe~ d7Ȣ4fQ/T xׇԚNwtO0H4R'ҭn9_"x^"VNdҍJ79H RDDY`K/HTb_eky!h5DW`nt[Ak: /VZ37','BtZ([̶W&~?Tu~ϰӍcd,,õdfjֳ r'ދ 89P#nw{s͢2Kͷ&hQR -ю \u ĪHvLXnr3!RE\#`YxtaG.l6s5UX?ZS)lm0<+KFj?-RRoԊB"/F y8w[$Rޤk8|x !x69Ta[G-@Tc}b&yl}EƁuH{E+W+mg唤c5+؉x]|k 9V?R#51.A4ƾaHcpOGkR$Fq:!w G`&+)"'ځhG Em&ù*Q-b"W\JEOr)#PS0&:<˛j!MeeU"J4`e[\֯&Wp(@~Rtb!7z|x(DGRQsŴ26QmD<M5D<b-OL7#HluFn_K _w ?V5AZ¨JlHi 1R| M1#/GH9}:W~ 2%%( 2F̀֞k;9$д42&_@{O1d/H,UbIs~2LT;bgHh*!θ^waB 涨UM7e5N+3A62ho6gEndo %e#'վ h9ўz%e#}%A)ɣl4-IlT% ZBh R|G7z5N+c%()& HR".o*Y>/-(H:dS!^9jZSc m#!CǨ]P./EKB?K#BRV tGL:3Bo |$϶sm&>*dy\7w&Dl dcSB̧"6:Ǡw_#BI)2w‘Z?^NA:&%Id <8iu#Qq.bi9RpEGFgz Я`߇\4Ua;qrgbOwoU0nS<^ž^HǣX.QB8B"\5±j/ aI9+ ,pӢP1'-pfʡr;e,u0wق0(&Z ȣnUJP@ )f'ٻb@$ϮUN=N;s-xh-8JSs"2>iY7 9:K Q5i 8 POL|G1˔31\71&&3x5gtވ^ 06&b㬖JpJSEBYyTZaZ?H-0V!ec p%(hH|jBkP q~+8uGK_#0.q|T0@益5]Z} 2bLn*oM~=C|!L|7}'F) l*e;}N5k'Gnm2Lu I2tjC!G_bRUm;2X'$e)1Q3}"c,(TxJ'O eRzX[rpӉEyhu\lh:P'`48 ¦ORd {r/Y9ibNn<CTFh$0DE).S<^u@·U )F(<|Kw Erٱ x2 hOO>z`̴AN"Y$ݵEEcq0ۛ6V )E52 f}lyg<O^o ',]iٵX8%b4LR87`3u'G_0&v=z«o+.4ϒSZYM1L6gH)c(?E!3^wX$ׅ$,ϠFj=R i~#RtSl #-FP<_#31ꯊVyn} /}#KTi hW~Un G8@}&*'/\#%(N%flҿ=RF 8\*%NjGUF=CQGr@H4 aB($@V4hȷj™6Lmy(4 ~~Uo|shhq]h݊|@>IviN8VLL Mnqv2,-,5tPx*D㉮{&(G¶ZD&2~ ߸-R 4*aln1.OhkG4`qheLC|MxcD>,vxcԣtv&J{bVj 7DŽ!'"K$^/Dht0d`ǂID+F)P] œ @h,ZxIix}E(ݐ:ijQCf{O@>^}sI#[tOV$Р奎OZx*$T8&u}Ո: Wx.Nw?6.YCl-PUvkDta@x7r!<0S-FO!NSO,MxދiUvb^Bb)i8ϣ,)$@}loiVj6e%ă ,1 $ʚXfF Nv`3p ?˶eZT*՟?m*5{Ru8N{=sW\ͤMPխ;^XlfTx`.i'ipJE ޥk{tCX/'~FS! 6{taoW4XF!$%B Ii壈.=M7K}0R9JlAM X6"C| Qd3 V-<ӒP/\s!"9WTg"$76AF_biCVwr!,D:!*Iebэh,+\L $7&J)M! NA &\h.zf>83uLM9ATo+TyXj{~bB~uƫUemS%8i~'J1aqo]F# S)3(;w50]#F^ Ae{?PWv'J G(h^ؠ.Pm9E䟗2}HTTZ!rDhg:{ @qt-T8#4Z4^LmcuR,r`p,u"I-,czNrL/\e`v!@y Һw̷7NH`]Cܤ”q=^_kEKh%4A|qw6 2уƅN'<w Z ǮN t;R.}\#/rܼ9b~'$^/ i~1D8 6s8GNJHw 3/:onӆpPp̷E<B Mu-0wJ¡x~U٦f:ϞһZ*Bl2ɤEuyEKm l\W2+%@8Ȯ pš۫O"Y|&!_oo=kC9d.9Kw^4Ľt\0=IoFNpJ59XL]Q69K6j%`g<O?y7ŀ"tSMHòL7w?obйշ-B` &kvcms6("|d|wDɲ.&Tf9i?~FIbF.P(T(/CT!,DMXަSF#3 LAd`<$,C'7|tM8mYuA8=1qs)TNžX4[_0!EbQx$6Gu#UI6Q#Unzw{Uu= c#pQt"ȱ;+[âl9Fѐ a"3, ,đaZ6.GG B81@>#y I*x+BHG#|_@Yr-` =R&Rl&=q]&KDʮ^"8ʳJx{aغΩ6-2ΈԴKʗ%7}U/gugQM]ӂ}lEbZ1gBA}h4 FҸ"m8yH9v$Lc MƧm˴TJ470/m-?#W*󯳮\IOV-jrȎsd$L\s} XdFqQ8']UB/6ڏT;=3pth-pHY-\I07I)yhc f;-d3Cy}w} hS7y.l)|WxzrG(# ܬCa0 a\",,B"2uȞ,BelF%hFMr}{r¸)E7iv 7x(E;)Bx7z6#DuBd!̷*DzAj"AG3TPpCC*c.FU͒ٶp4W Gk W(uRBEu ~ ]'0F)ɾWi 0쁓 pov+M`ҒONZ ~IФ:;b /5ɫZט蔕FЫT[8<81*֮ @(t)d&98qgIP-g':}X:BL@1: chX%@=yHl&cB%76PzeGS;!T4]Q&4Kq T"!*6# 8%Jsrk=^tB(hsIXbB8bGJ#5 cU=A$(GSʣ+j?m h,g4KbcE CtMN̢[~pp㠨eUʕ.'6GJb;Y*` M7CYOslWA,-ϛu-9)ŬK;3iIi ՈW4`h^‹ϊ).'L)kfj802VtYJN-aDZ"ROuif*oxFSJt\0=Im;i,d0`Kʣ9o8EA273T<@ŦG@.dv /.]E&5UnԂǞ!.0{𖛰&!`35 cb\QyF^G~^NP§0Z?xAĖȹkB{Q|#Q\h>I8]4G1OJS Dj ka:ye1J s4av^ĿՂگ{-)tڡvaJq}!>LTv t4ѣB`|{tA'."|W=Oqj-Viݥ#ˣ_DZLR aJʷQ{@~bf{=#ҡ ۊbIV[7)&pnG!;x3.gcyԋv%]Zj;lL>.۶|VE{{&m]PU9GzW1n&.'mA@%|}U/ C赊 ^bȦAP"'ڇ͗fˉ" үL,7/TH5W]pGX- FI>E7~Yr0p]tD: \G'βt1{Q`~< $| g=uF/ LCl#}ke(c(u~^^|?x|˶Y~wNRn׻{i+STJiCtTVk;X$X<٘ӡLBfބbKhՎ*(AhΠ1cF5h~H ҺBұײ*ZM+0gD U ֖ !4@pi06b|bA&\Z IG(>]UA 0Vg acI<#!6EBy2g;&&o֮g+6سб$ ;pRrGD†0ù:x b׶Q$uԔǩ2#AmA'%*GZF VlY16k-x ZyGEXNv=  e༨RƽɤU\EA,-V)8w;Gzg\o 7!0%` |gO4-ӂl7 V.N05ӌډuiZz9X g@C!ed k4xS=EcHƴVYRbg(s# uB0T;D Q,l4PܼY>Rd(G)#4s]3JAJG- iòV[:^0Mh疃տX{++xt6ұZeV/T GeQ@,S[$Uj]`=؃j)kƟɣXf[=-aT6[eoFgEL^02-A4Q#SO4$9'>%t%Z$%rOj"B,uej4lw72U;8Bҝ7ȡ =YT^ZמHX#zSȡj,ϯ=(Pi#GRlJh?7dki Z_dVGyis׼tQG좦nȉ=}FH|"rŭr~0Qh1ip; qQ.0 B܄C恦 36CZݺb9M5([V 0@5"AQǒ30 )MYɣXlaGx, Oxa?4\ bK6B8LqCXemK%1FTnQW@Q,|:|4QY:_ʯ/LӼzǟFt}W2,[L?Otuo/x,zvR8=-Wë~ &lßWX{-(78,MF`c)gY^p"V(žȪ{Qg93|8LdeyIWoRFK7 Uu^#\5j?'xű {sl죘(!M22\ژ[}o#6hV~ְ>lQqz@},7wzgI[0=DUz=Cuw|[DEҰ8LG:3u:}[@w]T˳M/ zB#W駾͊H ޖQ8el0e؆N 0|g'λm͑Y 'dOj|`f"^w}O|M|>6ha1:իJ ^mgenM1_?mVAwHR^[a}.p }?$W;AhcCC[_r p8o0vD>o}:V++{_ɢw"K&W-)z/yNx2`T Ȕ*A^! dnbr#haaǨWo~ăs'EKu˨_i$j]l˪/Lp(N־K 0ןV''6| !OeΞ"]Uز)щy >A0 weUf>j28讳8b3WbJQ9r=hAcqw[-"8| "XY,u; !8Kޤ4s-*ݬdA&)ʹtY3a)I(ru+heVV9zѪB:vs39[{U,y뷇yAx\Bx*X_= M{vv@/aXS y~hZN_vI(gt67uBnr?aT*rrO+4S0^ .98?>d×-;0=,ϋ%byoLdzn6VO{V=ū5>,^5SC_ :(@&ˇTFj?`WUf * '`kG[XxUӇ%\9n.syz_z30C pndgNx݄rl=E' U>Cdž4zߦSN8C^X!b`ٰ$hmr=Tj"-'"N`qYKj=Z5l'`f=VBvl}De\ "=B}u~_SJL4Oܖd`_UēyVZLiGu@Ow\vrMA`<0Q ¦W"-ӭZԐUQ;m}7 @s Kd9$@N#W6bZ#{ZSAj¿j277"D!xYe *̏x"BhQPg(ta=îƸHA{̽[OHy}ʅ7$9@o ^S [E}~G17ѯp%XFؕG7ItqkUX7:ᐃ(?kɑ=UXEܓƢ+:2_dzDnbn|UNÛzv9L59%"5"7uL;@Fk1 lYYQLy[o$Xm%~|[GNL엝IpCNĩoMJu8f&04åc9Q>qh?vD8++VbM).챫(-C(`yj32ȝ>@)m+Gz S:!`hw~vgیa̿uҘ +Kʇ썘V FDT2BdRGjQFumz D3z9Zak`϶YhF^a>ٸ'RL2>@/BQy;s=wI{Xumى΅(*]{Az'oZ/rM ꈁGёj]?sv> 4/w| z6>[Qn6ɀVTH.i*w{w:"~$N.TIQ P5\gky49 y^{ cNҙW{M\=Ty PkQrT|ZR*KkgVZZ?y Af wO/Q{YP 0P-`^&<({F/Cjپ%qtPm?f9e"__76dc^Ao&znOr~|4-X);yU+BlP ^V*n+!Yavt2YA6vbll -B]D+K #~ltgKv0jhۓ#0iFF_o!FӠ)n+.ߍ/JGCr=4``Fꍍz]TR%k}??:œ |I$3IYѸG k"ȧq^^.~->D 즎Y3AG`E`>#䡚A'l}n7I)a߮#[rrz`iuͤ ȸD.'G]Am![.8C(^rs_ ZcCrMi˚zb|-c]l*޺у!E& tV ҙȖ vqWR^Y%iTjl{깔a_W#gfۧ$r.$[ @N>tzc#G.;yf#8j4h@#Cw+>r',!k!uZvb(V{cch^v?yi9];f}ӷ)H7ԟ[}8nFJj3ŝfR c^O -6Mf q¾l s^K{43!9>P2\CD z{[>^ai/mv-%n|L 'w朗 [0qnͻӻ4?_岀QdTQOlc k'ОyCuN@%0 (C2^奒~Cɘ҉JUaYY^Ea-b=YΙبTw V qX}e[07NO^4;R"H'? bG'cHy J%}D#VbzD<G#'ޅVS=|DXG#9uy3l`^zR)ᤸٯ3_SO:uܹ1` ѺH;l OBC~]oyE=2n"=حpU= HTڅ[( ! ^ 6ػe}c_/=eZ3 !:K<vE86*#}i(p;kLnz츆r$05sr8 .@Ym|> eeIx ڠc͹0 snv%MeID ̤c>sˢUԁ# Z>a+ɧ_y7DP Jx ]%0 ~J˦#ts FsAhSJFuœz[fu?Y.2Mғ[7}:kg>z T!,#F+qQ,;0`>жR8"^qߥ>L-ٖ6x["cMVO^V;ѓن}Q.<| L NߩCGy{@ܾcf֒NB Z#xG]e"}j8w^>j/dm_4 ċͧ7 5d;rb &h, ֗a{koL|IE&rp T$L:'7fx"q62p'xȭ0Ա^ފ37Lʈ7vAr{!7(a5] vE|w|j^hbL zØu]  3{gU=ߋ(Y$ѰgdW"<%p,j轳tHQ)KHTx(@̨ oP7^sm;G&nz5Jp!?tԿ}fsb9"h?Ipx>>~lvAx0;\[qħ׼ti Q3:Y%/bWKS[1)A)}O{kJhzߏ@I拇tc@8O>qhTӠcz**'xySR#m;"BN|TtJ:7Urn ҚJbU1"]!I&ci=G7!yΤK~mdC/V^ߐvϑ_zTUB^^G NRqP`wO,)>aY7M$L<݀sVpu􉪏:Q#N{L>awy1؝vzx" 9Q89QfT{66QCxZuori _Q#yok2C!ˤugv֫NL?d7ַD/R6vux>O <>Iۋ EOD\eW=e#FS]Kk?죝5<)pސܷ}sw6={pksAdd\} 4)E*6WfBړG?_{/n⡞+˽^đOpI*Уϲ5ܨe[1AO%e'qȾh3)1+F-B~yX=XY~<Ă g2GcN Y$ '%C 6 %a1 vnJ9#r.j{H^1Qga%˛}t'؞/fB~zrOS4[C6{FïAݿYOnP"_*d-R"o +fҬ}-z#)ݨ w V@NGߙ6-یw.B AP"'j8Q-FiT ZJ %rhw/|!cXK0Ws't;<3n=x-2(Jb,.ax_&*_;C}"ngi,B}΀aӺJKE>|׫ p%_۸#/ #G|ŐóԁwH: 8yf.d$ W zmn+q[#<نzh+\Y xr*A?Ocod,7!@>QAhY^O1~{`hfjۗ.ϲm@Rb4.:\g$(QO곧V,Y%y} _2SfAӑJmZMdH}<jkimn!TN;͠(ਂjQ0A0zD7GhWNεP7'YCÎ=_Y;2rQ 2qPfO; /"Rũо!|\9e( G&Rf_Į[4C;H'_<N~N2pz~&6vuETxwЭ_pTD̾JR,h6.8pl^ e^ժI;pgfz=Eԗ ,|~Ko7LdH٘tUaGj\\٣j; ߌH }SAah鎡>;FW.&s/y EI,'VE"D@RN<ƧxuߤEZZWMq﮶3I7_Wyxi[(CB[\Y@Z_428ۂ^b{mfج3P ^W;q9NFGo@K.qT&y BJ-!F_ު c#Ɛ`iC&FUSU$a.A Pl^@EMey_d ~?/hz/6iK䟚lJXӈP:C^c=Œ}6 /G'${@B)v~Tcyå *.XLpЕKF7gn s/Nr~ֆMJʗÄBnXίX iϾu o=kL4Vp|D~]W۷ i˧^8+cȣ@ ݃{[k u>qB ݗOPz!|rkCxѶZa&܅1ƃ&:=Məpkb/ J}tԾ,0$ۛh^ Q+]fs^Tְ@N~$pJG&Nb NTDߢjn?&Oh}:0ZժKLvOwA@⡛x18*{OAb>?=nk^UA<+Z>0wEn@  |L*AЅ]C:d)˽bAqZz~p.gE=U@o񂳓z}=oκWF迉n|hk+ KuɈcTxv mq-I?rZ'ԉC K;l&*@Wu0S~FWޅmkvܾztV#:3K/.Is_d܊%IDe5vWͺ6zh/.0| WԸp:@Y/CMX;sEZ0$I"ȟ 9[RLC\dX*ڳiZ~Wh},Cl/aڰ?[ Mtkljn|ɗ.\ Mu<9%\42ȇaPgxv7Sh6Eο-Gl]4[9؈z4mݹN~bJB@ǽӅ,U UK\#|Jh4Ki35=ȉ/b(7OD%@" /ss I'gOW+RKS3Oxy~s۝>/R|!$*xbnU e=1!N :eu C|o~y_֛8ݮ`.Q)ܖٔϐrtacN +3D[ ȡ xsZԉZ%pOPQQkc gl\"5}:RRxbw#|aC0" ~F9Ixpy~(%%$D&1 >{βi /N(#8(-75棤LQ^F*r1 <ӧ:Iy$+@1{LAQjbQ鈩V ozpaFf2KhAP-V R$M| }ُWkIM-pKrپY [{S g-$QU}pdN=romX=B-yqex׏Ǘl!<e#Uo0}"[tlKIG6y=+:M4RHBY-uM  2o8>ٯ+>?8?;7{Ľ8`/~r2Gynp z:3^U&"ZY _Y2 A_i0B P]F*#-y?N@وe|.-H@٣#O“XLQo(,^0 H{Q۬5i5):0pa@g#ͱ9s hg8ɿ!9J?eD_\h_  w;kv7%"S9>[NCB C H:*>N@wH<@AAUk*r3d*fG:,m sMC]H.f}fV #Wl5{$qhO噱AfER7YM<g 4V7Iz"XR̰[g)I q-. 0e<: !n\`9Ceo|łB.~,b;K=!g|IFl߹p@&΀0GDx_vQf\%긞szJqUu=D?/a(x&j<ӻ|i4p1dKNտ᩷ϖS p=0|ABx[;,¸Wlu6JVTdg_N#iqb^)MN\4p: 2.N :Е񝚪;objW`%~: f+2B`@/swB#Fި 8JpSܿ2+|q$F~;N2/Z5b¸g\ϞiM[!m7?A*Gg_٣vf-{zmQ' 8O|_>>Pkc\mEQ4݉iܯ-{"߽S6G׷!W|"u G GAah]>aR/eSu덅Қ۟|0~_]\v bEoUp/Ra}L.8Bu6OEI+BK$,Y_ uqyzlOa+7˔WjgO}đק2]gb6]rtl@!zs@`gdO"teIChoMw6uEܐZ;kӞl0L`nkVD[AX|DdLϲtGG%++ZuX{a"s\ 8/|싏NM^Kz ʌ}sk4Bڏ@z,Hs#y9ǿ=2ܠ ,_n:UK.|vUyBYo`Q{? BN a,ѥYlJLΌ^2jw*B5]"`EWPnpLS MIVdz^ܴڊ%)"5@n1@赣? {Wָm$fuo/^M?hAvKmq[nU ߚeUD}0}6M(_s,+0|d(f+fLQe@|$벛ɤS;|Zэ,YC҆)DbE# ڎuОćuo+ }Q]#8# UmXt+$CH~N׎Z0?r4=1miq ?%`h$Fǰ:  >_ 5_/VtO/C=x2ZBڛdw SGIɨ!X@~-*ݤA$=6"OitzI} adt$`w Юmu)dm:ZwA */XuV>9dk*Vo yrkhJĐ=]A0% {ZClW-n<]xB({(N'@S%j1Xp` ׋U Eh ͻ8ei: 5зdt9'fAL1-U@9vӒpk_7&,UX}2tTſAYV\_['~??gR>zR N^6R0)ɫ^$ۨ7vKZ 2d6{wPԋWp !Iig',,yF-JecEٱ].-i{j͋]St!qֺFYЌcbtT ? pAPI AȮ {mq=Dѕ-[As܇m=36>Tגixsf>O's42/אLxT?| o;Hqz_Sٸh :kW}yn9O'T x-_ B/ aqf3:ٰ= ,-(Q5;; Ղ1y6.M!1$d2is lgѭn&].;cݍ0ҦvM?Aqk=ΙMꟷ60u}8EzliC-hU'&gmZmՋk/Sϓ(5-ZɸɎ4>T,/˸3ke 9Ϋ߼A{7X)"?'UOƾxJ}.`ͷK* BzA>.6oW/[.Ow=.}ka砜?{;0Z?w,Gܘ7l>7zQ*no_#8OwQO^uuqHuF#fpl w- /2>"˳d?džB@v.hִHln䍕u~ge,^"eʶOR}Ehc[ ?9gނcXH7p_*٣XY^ZZ+?䣊yJ#K\fa&q^[vGSFz-cd~L&=Pj^.3&mtͧ?qO#'>PUW ?ureHurMK&JlY|\\aH{M^z7}扗!,OG/UzXILT~3+/PI _r9 (qhc/XֈGZ:/] ƚ ]y2K<\uLe .l!pf>-^+34HݢA gɢALWG%ճWEyr7[IԶInl@_Ê ~sgy@!Ku=@CGknC" Qp< U VeUwE \(^o E+S.Ojm1{N7*k#M@3iL0 /1 "\Exՙ+IJ _-]IY)mV|JBmM4WÏ~:ƒ0Q kOSb IOvd~<\\k%F #{\q=@s#ügtf>5.ea2u&߯ &gu %:?к!ا \cZtD|22DDMU ;^Fht57hЏiㆌ a=6P/X4roN;6b, "=|?0G];c. & +}~ߕkZW >K4{1B{4H\'\mDܜ!_[NnɓܲGOޠa"b gy>C8!VdqhE='̊Hn'$o !=ʶZaj.ӧr&K ~Rydk!vY?(<6 :j<|x|PRS B\׻n4]gXwG!8@F{}}BN+*0LZ߻L<.MfeǠ:EBB[J?[Ήme>>Hˠߋ,q쁼*d";,(z`}?M#$2Ϟ1Kr_ϭX%\B27BPw#=%zLcr`SX&x.^%dkGPה{)cai8ضE<]R;jԹ5@V/J=W[rVzʥXGQfm#_3o|:v} -ѢENq@$DM\@R\LY̧ԒfFYez3c73@t OHApj' cwG?#^ m҄VViPNPE7gEt{՞:8]Ziv-إm) ȿ#Kybol8\Y ymYeվҮ e(}'dYhl!~] vo{/_;oBlo5H;pl(M @y2K$rܖ5N" ?O.7O /8u3,B]yMMy-wvPv<^Г'{tTVM|WD1UA3^Gm*l $\@B%t1%sw+66F#kme¿w ̼i=WӆgW3-\}kvs,/ǃvXBzV<zn

mxj - to/from maps, XML and JSON

Decode/encode XML to/from map[string]interface{} (or JSON) values, and extract/modify values from maps by key or key-path, including wildcards. mxj supplants the legacy x2j and j2x packages. If you want the old syntax, use mxj/x2j and mxj/j2x packages.

Installation

Using go.mod:
go get github.com/clbanning/mxj/v2@v2.3.2
import "github.com/clbanning/mxj/v2"
... or just vendor the package.

Related Packages

https://github.com/clbanning/checkxml provides functions for validating XML data.

Refactor Encoder - 2020.05.01

Issue #70 highlighted that encoding large maps does not scale well, since the original logic used string appends operations. Using bytes.Buffer results in linear scaling for very large XML docs. (Metrics based on MacBook Pro i7 w/ 16 GB.) Nodes m.XML() time 54809 12.53708ms 109780 32.403183ms 164678 59.826412ms 482598 109.358007ms

Refactor Decoder - 2015.11.15

For over a year I've wanted to refactor the XML-to-map[string]interface{} decoder to make it more performant. I recently took the time to do that, since we were using github.com/clbanning/mxj in a production system that could be deployed on a Raspberry Pi. Now the decoder is comparable to the stdlib JSON-to-map[string]interface{} decoder in terms of its additional processing overhead relative to decoding to a structure value. As shown by: BenchmarkNewMapXml-4 100000 18043 ns/op BenchmarkNewStructXml-4 100000 14892 ns/op BenchmarkNewMapJson-4 300000 4633 ns/op BenchmarkNewStructJson-4 300000 3427 ns/op BenchmarkNewMapXmlBooks-4 20000 82850 ns/op BenchmarkNewStructXmlBooks-4 20000 67822 ns/op BenchmarkNewMapJsonBooks-4 100000 17222 ns/op BenchmarkNewStructJsonBooks-4 100000 15309 ns/op

Notices

2021.02.02: v2.5 - add XmlCheckIsValid toggle to force checking that the encoded XML is valid 2020.12.14: v2.4 - add XMLEscapeCharsDecoder to preserve XML escaped characters in Map values 2020.10.28: v2.3 - add TrimWhiteSpace option 2020.05.01: v2.2 - optimize map to XML encoding for large XML docs. 2019.07.04: v2.0 - remove unnecessary methods - mv.XmlWriterRaw, mv.XmlIndentWriterRaw - for Map and MapSeq. 2019.07.04: Add MapSeq type and move associated functions and methods from Map to MapSeq. 2019.01.21: DecodeSimpleValuesAsMap - decode to map[:map["#text":]] rather than map[:] 2018.04.18: mv.Xml/mv.XmlIndent encodes non-map[string]interface{} map values - map[string]string, map[int]uint, etc. 2018.03.29: mv.Gob/NewMapGob support gob encoding/decoding of Maps. 2018.03.26: Added mxj/x2j-wrapper sub-package for migrating from legacy x2j package. 2017.02.22: LeafNode paths can use ".N" syntax rather than "[N]" for list member indexing. 2017.02.10: SetFieldSeparator changes field separator for args in UpdateValuesForPath, ValuesFor... methods. 2017.02.06: Support XMPP stream processing - HandleXMPPStreamTag(). 2016.11.07: Preserve name space prefix syntax in XmlSeq parser - NewMapXmlSeq(), etc. 2016.06.25: Support overriding default XML attribute prefix, "-", in Map keys - SetAttrPrefix(). 2016.05.26: Support customization of xml.Decoder by exposing CustomDecoder variable. 2016.03.19: Escape invalid chars when encoding XML attribute and element values - XMLEscapeChars(). 2016.03.02: By default decoding XML with float64 and bool value casting will not cast "NaN", "Inf", and "-Inf". To cast them to float64, first set flag with CastNanInf(true). 2016.02.22: New mv.Root(), mv.Elements(), mv.Attributes methods let you examine XML document structure. 2016.02.16: Add CoerceKeysToLower() option to handle tags with mixed capitalization. 2016.02.12: Seek for first xml.StartElement token; only return error if io.EOF is reached first (handles BOM). 2015.12.02: XML decoding/encoding that preserves original structure of document. See NewMapXmlSeq() and mv.XmlSeq() / mv.XmlSeqIndent(). 2015-05-20: New: mv.StringIndentNoTypeInfo(). Also, alphabetically sort map[string]interface{} values by key to prettify output for mv.Xml(), mv.XmlIndent(), mv.StringIndent(), mv.StringIndentNoTypeInfo(). 2014-11-09: IncludeTagSeqNum() adds "_seq" key with XML doc positional information. (NOTE: PreserveXmlList() is similar and will be here soon.) 2014-09-18: inspired by NYTimes fork, added PrependAttrWithHyphen() to allow stripping hyphen from attribute tag. 2014-08-02: AnyXml() and AnyXmlIndent() will try to marshal arbitrary values to XML. 2014-04-28: ValuesForPath() and NewMap() now accept path with indexed array references.

Basic Unmarshal XML to map[string]interface{}

type Map map[string]interface{}
Create a `Map` value, 'mv', from any `map[string]interface{}` value, 'v':
mv := Map(v)
Unmarshal / marshal XML as a `Map` value, 'mv':
mv, err := NewMapXml(xmlValue) // unmarshal
xmlValue, err := mv.Xml()      // marshal
Unmarshal XML from an `io.Reader` as a `Map` value, 'mv':
mv, err := NewMapXmlReader(xmlReader)         // repeated calls, as with an os.File Reader, will process stream
mv, raw, err := NewMapXmlReaderRaw(xmlReader) // 'raw' is the raw XML that was decoded
Marshal `Map` value, 'mv', to an XML Writer (`io.Writer`):
err := mv.XmlWriter(xmlWriter)
raw, err := mv.XmlWriterRaw(xmlWriter) // 'raw' is the raw XML that was written on xmlWriter
Also, for prettified output:
xmlValue, err := mv.XmlIndent(prefix, indent, ...)
err := mv.XmlIndentWriter(xmlWriter, prefix, indent, ...)
raw, err := mv.XmlIndentWriterRaw(xmlWriter, prefix, indent, ...)
Bulk process XML with error handling (note: handlers must return a boolean value):
err := HandleXmlReader(xmlReader, mapHandler(Map), errHandler(error))
err := HandleXmlReaderRaw(xmlReader, mapHandler(Map, []byte), errHandler(error, []byte))
Converting XML to JSON: see Examples for `NewMapXml` and `HandleXmlReader`. There are comparable functions and methods for JSON processing. Arbitrary structure values can be decoded to / encoded from `Map` values:
mv, err := NewMapStruct(structVal)
err := mv.Struct(structPointer)

Extract / modify Map values

To work with XML tag values, JSON or Map key values or structure field values, decode the XML, JSON or structure to a `Map` value, 'mv', or cast a `map[string]interface{}` value to a `Map` value, 'mv', then:
paths := mv.PathsForKey(key)
path := mv.PathForKeyShortest(key)
values, err := mv.ValuesForKey(key, subkeys)
values, err := mv.ValuesForPath(path, subkeys)
count, err := mv.UpdateValuesForPath(newVal, path, subkeys)
Get everything at once, irrespective of path depth:
leafnodes := mv.LeafNodes()
leafvalues := mv.LeafValues()
A new `Map` with whatever keys are desired can be created from the current `Map` and then encoded in XML or JSON. (Note: keys can use dot-notation.)
newMap, err := mv.NewMap("oldKey_1:newKey_1", "oldKey_2:newKey_2", ..., "oldKey_N:newKey_N")
newMap, err := mv.NewMap("oldKey1", "oldKey3", "oldKey5") // a subset of 'mv'; see "examples/partial.go"
newXml, err := newMap.Xml()   // for example
newJson, err := newMap.Json() // ditto

Usage

The package is fairly well [self-documented with examples](http://godoc.org/github.com/clbanning/mxj). Also, the subdirectory "examples" contains a wide range of examples, several taken from golang-nuts discussions.

XML parsing conventions

Using NewMapXml() - Attributes are parsed to `map[string]interface{}` values by prefixing a hyphen, `-`, to the attribute label. (Unless overridden by `PrependAttrWithHyphen(false)` or `SetAttrPrefix()`.) - If the element is a simple element and has attributes, the element value is given the key `#text` for its `map[string]interface{}` representation. (See the 'atomFeedString.xml' test data, below.) - XML comments, directives, and process instructions are ignored. - If CoerceKeysToLower() has been called, then the resultant keys will be lower case. Using NewMapXmlSeq() - Attributes are parsed to `map["#attr"]map[]map[string]interface{}`values where the `` value has "#text" and "#seq" keys - the "#text" key holds the value for ``. - All elements, except for the root, have a "#seq" key. - Comments, directives, and process instructions are unmarshalled into the Map using the keys "#comment", "#directive", and "#procinst", respectively. (See documentation for more specifics.) - Name space syntax is preserved: - `something` parses to `map["ns:key"]interface{}{"something"}` - `xmlns:ns="http://myns.com/ns"` parses to `map["xmlns:ns"]interface{}{"http://myns.com/ns"}` Both - By default, "Nan", "Inf", and "-Inf" values are not cast to float64. If you want them to be cast, set a flag to cast them using CastNanInf(true).

XML encoding conventions

- 'nil' `Map` values, which may represent 'null' JSON values, are encoded as ``. NOTE: the operation is not symmetric as `` elements are decoded as `tag:""` `Map` values, which, then, encode in JSON as `"tag":""` values. - ALSO: there is no guarantee that the encoded XML doc will be the same as the decoded one. (Go randomizes the walk through map[string]interface{} values.) If you plan to re-encode the Map value to XML and want the same sequencing of elements look at NewMapXmlSeq() and mv.XmlSeq() - these try to preserve the element sequencing but with added complexity when working with the Map representation.

Running "go test"

Because there are no guarantees on the sequence map elements are retrieved, the tests have been written for visual verification in most cases. One advantage is that you can easily use the output from running "go test" as examples of calling the various functions and methods.

Motivation

I make extensive use of JSON for messaging and typically unmarshal the messages into `map[string]interface{}` values. This is easily done using `json.Unmarshal` from the standard Go libraries. Unfortunately, many legacy solutions use structured XML messages; in those environments the applications would have to be refactored to interoperate with my components. The better solution is to just provide an alternative HTTP handler that receives XML messages and parses it into a `map[string]interface{}` value and then reuse all the JSON-based code. The Go `xml.Unmarshal()` function does not provide the same option of unmarshaling XML messages into `map[string]interface{}` values. So I wrote a couple of small functions to fill this gap and released them as the x2j package. Over the next year and a half additional features were added, and the companion j2x package was released to address XML encoding of arbitrary JSON and `map[string]interface{}` values. As part of a refactoring of our production system and looking at how we had been using the x2j and j2x packages we found that we rarely performed direct XML-to-JSON or JSON-to_XML conversion and that working with the XML or JSON as `map[string]interface{}` values was the primary value. Thus, everything was refactored into the mxj package. mxj-2.5.5/remove.go000066400000000000000000000013751402172443100141510ustar00rootroot00000000000000package mxj import "strings" // Removes the path. func (mv Map) Remove(path string) error { m := map[string]interface{}(mv) return remove(m, path) } func remove(m interface{}, path string) error { val, err := prevValueByPath(m, path) if err != nil { return err } lastKey := lastKey(path) delete(val, lastKey) return nil } // returns the last key of the path. // lastKey("a.b.c") would had returned "c" func lastKey(path string) string { keys := strings.Split(path, ".") key := keys[len(keys)-1] return key } // returns the path without the last key // parentPath("a.b.c") whould had returned "a.b" func parentPath(path string) string { keys := strings.Split(path, ".") parentPath := strings.Join(keys[0:len(keys)-1], ".") return parentPath } mxj-2.5.5/remove_test.go000066400000000000000000000005051402172443100152020ustar00rootroot00000000000000package mxj import ( "testing" ) func TestRemove(t *testing.T) { m := map[string]interface{}{ "Div": map[string]interface{}{ "Colour": "blue", }, } mv := Map(m) err := mv.Remove("Div.Colour") if err != nil { t.Fatal(err) } if v, _ := mv.Exists("Div.Colour"); v { t.Fatal("removed key still remain") } } mxj-2.5.5/rename.go000066400000000000000000000027651402172443100141270ustar00rootroot00000000000000package mxj import ( "errors" "strings" ) // RenameKey renames a key in a Map. // It works only for nested maps. // It doesn't work for cases when the key is in a list. func (mv Map) RenameKey(path string, newName string) error { var v bool var err error if v, err = mv.Exists(path); err == nil && !v { return errors.New("RenameKey: path not found: " + path) } else if err != nil { return err } if v, err = mv.Exists(parentPath(path) + "." + newName); err == nil && v { return errors.New("RenameKey: key already exists: " + newName) } else if err != nil { return err } m := map[string]interface{}(mv) return renameKey(m, path, newName) } func renameKey(m interface{}, path string, newName string) error { val, err := prevValueByPath(m, path) if err != nil { return err } oldName := lastKey(path) val[newName] = val[oldName] delete(val, oldName) return nil } // returns a value which contains a last key in the path // For example: prevValueByPath("a.b.c", {a{b{c: 3}}}) returns {c: 3} func prevValueByPath(m interface{}, path string) (map[string]interface{}, error) { keys := strings.Split(path, ".") switch mValue := m.(type) { case map[string]interface{}: for key, value := range mValue { if key == keys[0] { if len(keys) == 1 { return mValue, nil } else { // keep looking for the full path to the key return prevValueByPath(value, strings.Join(keys[1:], ".")) } } } } return nil, errors.New("prevValueByPath: didn't find path – " + path) } mxj-2.5.5/rename_test.go000066400000000000000000000015431402172443100151570ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) func TestRenameKey(t *testing.T) { fmt.Println("------------ rename_test.go") m := map[string]interface{}{ "Div": map[string]interface{}{ "Colour": "blue", "Width": "100%", }, } mv := Map(m) err := mv.RenameKey("Div.Colour", "Color") if err != nil { t.Fatal(err) } values, err := mv.ValuesForPath("Div.Color") if len(values) != 1 { t.Fatal("didn't add the new key") } if values[0] != "blue" { t.Fatal("value is changed") } values, err = mv.ValuesForPath("Div.Colour") if len(values) > 0 { t.Fatal("didn't removed the old key") } err = mv.RenameKey("not.existing.path", "newname") if err == nil { t.Fatal("should raise an error on a non existing path") } err = mv.RenameKey("Div.Color", "Width") if err == nil { t.Fatal("should raise an error if the newName already exists") } } mxj-2.5.5/seqnum_test.go000066400000000000000000000015451402172443100152220ustar00rootroot00000000000000// seqnum.go package mxj import ( "fmt" "testing" ) var seqdata1 = []byte(` `) var seqdata2 = []byte(` 1 hello true `) func TestSeqNumHeader(t *testing.T) { fmt.Println("\n---------------- seqnum_test.go ...") } func TestSeqNum(t *testing.T) { IncludeTagSeqNum(true) m, err := NewMapXml(seqdata1, Cast) if err != nil { t.Fatal(err) } fmt.Printf("m1: %#v\n", m) j, _ := m.JsonIndent("", " ") fmt.Println(string(j)) m, err = NewMapXml(seqdata2, Cast) if err != nil { t.Fatal(err) } fmt.Printf("m2: %#v\n", m) j, _ = m.JsonIndent("", " ") fmt.Println(string(j)) IncludeTagSeqNum(false) } mxj-2.5.5/set.go000066400000000000000000000010211402172443100134330ustar00rootroot00000000000000package mxj import ( "strings" ) // Sets the value for the path func (mv Map) SetValueForPath(value interface{}, path string) error { pathAry := strings.Split(path, ".") parentPathAry := pathAry[0 : len(pathAry)-1] parentPath := strings.Join(parentPathAry, ".") val, err := mv.ValueForPath(parentPath) if err != nil { return err } if val == nil { return nil // we just ignore the request if there's no val } key := pathAry[len(pathAry)-1] cVal := val.(map[string]interface{}) cVal[key] = value return nil } mxj-2.5.5/set_test.go000066400000000000000000000014411402172443100145000ustar00rootroot00000000000000package mxj import ( "testing" ) func TestSetValueForPath(t *testing.T) { m := map[string]interface{}{ "Div": map[string]interface{}{ "Colour": "blue", "Font": map[string]interface{}{ "Family": "sans", }, }, } mv := Map(m) // testing setting a new key err := mv.SetValueForPath("big", "Div.Font.Size") if err != nil { t.Fatal(err) } val, err := mv.ValueForPathString("Div.Font.Size") if err != nil { t.Fatal(err) } if val != "big" { t.Fatal("key's value hasn't changed") } // testing setting a new value to en existing key err = mv.SetValueForPath("red", "Div.Colour") if err != nil { t.Fatal(err) } val, err = mv.ValueForPathString("Div.Colour") if err != nil { t.Fatal(err) } if val != "red" { t.Fatal("existig key's value hasn't changed") } } mxj-2.5.5/setfieldsep.go000066400000000000000000000013271402172443100151600ustar00rootroot00000000000000package mxj // Per: https://github.com/clbanning/mxj/issues/37#issuecomment-278651862 var fieldSep string = ":" // SetFieldSeparator changes the default field separator, ":", for the // newVal argument in mv.UpdateValuesForPath and the optional 'subkey' arguments // in mv.ValuesForKey and mv.ValuesForPath. // // E.g., if the newVal value is "http://blah/blah", setting the field separator // to "|" will allow the newVal specification, "|http://blah/blah" to parse // properly. If called with no argument or an empty string value, the field // separator is set to the default, ":". func SetFieldSeparator(s ...string) { if len(s) == 0 || s[0] == "" { fieldSep = ":" // the default return } fieldSep = s[0] } mxj-2.5.5/snakecase_test.go000066400000000000000000000034131402172443100156430ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) func TestStakeCase(t *testing.T) { PrependAttrWithHyphen(true) fmt.Println("\n----------- TestSnakeCase") CoerceKeysToSnakeCase() defer CoerceKeysToSnakeCase() data1 := `something` data2 := `something` m, err := NewMapXml([]byte(data1)) if err != nil { t.Fatal(err) } x, err := m.Xml() if err != nil { t.Fatal(err) } if string(x) != data2 { t.Fatal(string(x), "!=", data2) } // Use-case from: https://github.com/clbanning/mxj/pull/33#issuecomment-273724506 data1 = ` srx100 srx100b srx100b junos JUNOS Software Release [11.2R4.3] ` data2 = ` srx100 srx100b srx100b junos JUNOS Software Release [11.2R4.3] ` ms, err := NewMapXmlSeq([]byte(data1)) if err != nil { t.Fatal(err) } x, err = ms.XmlIndent("", "") if err != nil { t.Fatal(err) } if string(x) != data2 { t.Fatal(string(x), "!=", data2) } } mxj-2.5.5/songtext.xml000066400000000000000000000021731402172443100147170ustar00rootroot00000000000000 help me! Henry was a renegade Didn't like to play it safe One component at a time There's got to be a better way Oh, people came from miles around Searching for a steady job Welcome to the Motor Town Booming like an atom bomb Oh, Henry was the end of the story Then everything went wrong And we'll return it to its former glory But it just takes so long It's going to take a long time It's going to take it, but we'll make it one day It's going to take a long time It's going to take it, but we'll make it one day mxj-2.5.5/strict.go000066400000000000000000000017451402172443100141650ustar00rootroot00000000000000// Copyright 2016 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // strict.go actually addresses setting xml.Decoder attribute // values. This'll let you parse non-standard XML. package mxj import ( "encoding/xml" ) // CustomDecoder can be used to specify xml.Decoder attribute // values, e.g., Strict:false, to be used. By default CustomDecoder // is nil. If CustomeDecoder != nil, then mxj.XmlCharsetReader variable is // ignored and must be set as part of the CustomDecoder value, if needed. // Usage: // mxj.CustomDecoder = &xml.Decoder{Strict:false} var CustomDecoder *xml.Decoder // useCustomDecoder copy over public attributes from customDecoder func useCustomDecoder(d *xml.Decoder) { d.Strict = CustomDecoder.Strict d.AutoClose = CustomDecoder.AutoClose d.Entity = CustomDecoder.Entity d.CharsetReader = CustomDecoder.CharsetReader d.DefaultSpace = CustomDecoder.DefaultSpace } mxj-2.5.5/strict_test.go000066400000000000000000000023111402172443100152120ustar00rootroot00000000000000package mxj import ( "encoding/xml" "fmt" "testing" ) func TestStrictModeXml(t *testing.T) { fmt.Println("----------------- TestStrictModeXml ...") data := []byte(` Bill & Hallett Duc & 123xx E `) CustomDecoder = &xml.Decoder{Strict:false} m, err := NewMapXml(data) if err != nil { t.Fatal(err) } fmt.Println("m:",m) } func TestStrictModeXmlSeq(t *testing.T) { fmt.Println("----------------- TestStrictModeXmlSeq ...") data := []byte(` Bill & Hallett Duc & 123xx E `) CustomDecoder = &xml.Decoder{Strict:false} m, err := NewMapXmlSeq(data) if err != nil { t.Fatal(err) } fmt.Println("m:",m) } func TestStrictModeFail(t *testing.T) { fmt.Println("----------------- TestStrictFail ...") data := []byte(` Bill & Hallett Duc & 123xx E `) CustomDecoder = nil _, err := NewMapXml(data) if err == nil { t.Fatal("error not caught: NewMapXml") } _, err = NewMapXmlSeq(data) if err == nil { t.Fatal("error not caught: NewMapXmlSeq") } fmt.Println("OK") } mxj-2.5.5/struct.go000066400000000000000000000032561402172443100142000ustar00rootroot00000000000000// Copyright 2012-2017 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file package mxj import ( "encoding/json" "errors" "reflect" // "github.com/fatih/structs" ) // Create a new Map value from a structure. Error returned if argument is not a structure. // Only public structure fields are decoded in the Map value. See github.com/fatih/structs#Map // for handling of "structs" tags. // DEPRECATED - import github.com/fatih/structs and cast result of structs.Map to mxj.Map. // import "github.com/fatih/structs" // ... // sm, err := structs.Map() // if err != nil { // // handle error // } // m := mxj.Map(sm) // Alernatively uncomment the old source and import in struct.go. func NewMapStruct(structVal interface{}) (Map, error) { return nil, errors.New("deprecated - see package documentation") /* if !structs.IsStruct(structVal) { return nil, errors.New("NewMapStruct() error: argument is not type Struct") } return structs.Map(structVal), nil */ } // Marshal a map[string]interface{} into a structure referenced by 'structPtr'. Error returned // if argument is not a pointer or if json.Unmarshal returns an error. // json.Unmarshal structure encoding rules are followed to encode public structure fields. func (mv Map) Struct(structPtr interface{}) error { // should check that we're getting a pointer. if reflect.ValueOf(structPtr).Kind() != reflect.Ptr { return errors.New("mv.Struct() error: argument is not type Ptr") } m := map[string]interface{}(mv) j, err := json.Marshal(m) if err != nil { return err } return json.Unmarshal(j, structPtr) } mxj-2.5.5/struct_test.go000066400000000000000000000035711402172443100152370ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) func TestStructHeader(t *testing.T) { fmt.Println("\n---------------- struct_test.go ...") } /* func TestNewMapStruct(t *testing.T) { type str struct { IntVal int `json:"int"` StrVal string `json:"str"` FloatVal float64 `json:"float"` BoolVal bool `json:"bool"` private string } s := str{IntVal: 4, StrVal: "now's the time", FloatVal: 3.14159, BoolVal: true, private: "It's my party"} m, merr := NewMapStruct(s) if merr != nil { t.Fatal("merr:", merr.Error()) } fmt.Printf("NewMapStruct, s: %#v\n", s) fmt.Printf("NewMapStruct, m: %#v\n", m) m, merr = NewMapStruct(s) if merr != nil { t.Fatal("merr:", merr.Error()) } fmt.Printf("NewMapStruct, s: %#v\n", s) fmt.Printf("NewMapStruct, m: %#v\n", m) } func TestNewMapStructError(t *testing.T) { var s string _, merr := NewMapStruct(s) if merr == nil { t.Fatal("NewMapStructError, merr is nil") } fmt.Println("NewMapStructError, merr:", merr.Error()) } */ func TestStruct(t *testing.T) { type str struct { IntVal int `json:"int"` StrVal string `json:"str"` FloatVal float64 `json:"float"` BoolVal bool `json:"bool"` private string } var s str m := Map{"int": 4, "str": "now's the time", "float": 3.14159, "bool": true, "private": "Somewhere over the rainbow"} mverr := m.Struct(&s) if mverr != nil { t.Fatal("mverr:", mverr.Error()) } fmt.Printf("Struct, m: %#v\n", m) fmt.Printf("Struct, s: %#v\n", s) } func TestStructError(t *testing.T) { type str struct { IntVal int `json:"int"` StrVal string `json:"str"` FloatVal float64 `json:"float"` BoolVal bool `json:"bool"` } var s str mv := Map{"int": 4, "str": "now's the time", "float": 3.14159, "bool": true} mverr := mv.Struct(s) if mverr == nil { t.Fatal("StructError, no error returned") } fmt.Println("StructError, mverr:", mverr.Error()) } mxj-2.5.5/structvalue_test.go000066400000000000000000000007541402172443100162740ustar00rootroot00000000000000package mxj import ( "encoding/xml" "fmt" "testing" ) type result struct { XMLName xml.Name `xml:"xml"` Content string `xml:"content"` } func TestStructValue(t *testing.T) { fmt.Println("----------------- structvalue_test.go ...") data, err := Map(map[string]interface{}{ "data": result{Content: "content"}, }).Xml() if err != nil { t.Fatal(err) } if string(data) != "content" { t.Fatal("encoding error:", string(data)) } } mxj-2.5.5/updatevalues.go000066400000000000000000000201051402172443100153460ustar00rootroot00000000000000// Copyright 2012-2014, 2017 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // updatevalues.go - modify a value based on path and possibly sub-keys // TODO(clb): handle simple elements with attributes and NewMapXmlSeq Map values. package mxj import ( "fmt" "strconv" "strings" ) // Update value based on path and possible sub-key values. // A count of the number of values changed and any error are returned. // If the count == 0, then no path (and subkeys) matched. // 'newVal' can be a Map or map[string]interface{} value with a single 'key' that is the key to be modified // or a string value "key:value[:type]" where type is "bool" or "num" to cast the value. // 'path' is dot-notation list of keys to traverse; last key in path can be newVal key // NOTE: 'path' spec does not currently support indexed array references. // 'subkeys' are "key:value[:type]" entries that must match for path node // - For attributes prefix the label with the attribute prefix character, by default a // hyphen, '-', e.g., "-seq:3". (See SetAttrPrefix function.) // - The subkey can be wildcarded - "key:*" - to require that it's there with some value. // - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an // exclusion critera - e.g., "!author:William T. Gaddis". // // NOTES: // 1. Simple elements with attributes need a path terminated as ".#text" to modify the actual value. // 2. Values in Maps created using NewMapXmlSeq are map[string]interface{} values with a "#text" key. // 3. If values in 'newVal' or 'subkeys' args contain ":", use SetFieldSeparator to an unused symbol, // perhaps "|". func (mv Map) UpdateValuesForPath(newVal interface{}, path string, subkeys ...string) (int, error) { m := map[string]interface{}(mv) // extract the subkeys var subKeyMap map[string]interface{} if len(subkeys) > 0 { var err error subKeyMap, err = getSubKeyMap(subkeys...) if err != nil { return 0, err } } // extract key and value from newVal var key string var val interface{} switch newVal.(type) { case map[string]interface{}, Map: switch newVal.(type) { // "fallthrough is not permitted in type switch" (Spec) case Map: newVal = newVal.(Map).Old() } if len(newVal.(map[string]interface{})) != 1 { return 0, fmt.Errorf("newVal map can only have len == 1 - %+v", newVal) } for key, val = range newVal.(map[string]interface{}) { } case string: // split it as a key:value pair ss := strings.Split(newVal.(string), fieldSep) n := len(ss) if n < 2 || n > 3 { return 0, fmt.Errorf("unknown newVal spec - %+v", newVal) } key = ss[0] if n == 2 { val = interface{}(ss[1]) } else if n == 3 { switch ss[2] { case "bool", "boolean": nv, err := strconv.ParseBool(ss[1]) if err != nil { return 0, fmt.Errorf("can't convert newVal to bool - %+v", newVal) } val = interface{}(nv) case "num", "numeric", "float", "int": nv, err := strconv.ParseFloat(ss[1], 64) if err != nil { return 0, fmt.Errorf("can't convert newVal to float64 - %+v", newVal) } val = interface{}(nv) default: return 0, fmt.Errorf("unknown type for newVal value - %+v", newVal) } } default: return 0, fmt.Errorf("invalid newVal type - %+v", newVal) } // parse path keys := strings.Split(path, ".") var count int updateValuesForKeyPath(key, val, m, keys, subKeyMap, &count) return count, nil } // navigate the path func updateValuesForKeyPath(key string, value interface{}, m interface{}, keys []string, subkeys map[string]interface{}, cnt *int) { // ----- at end node: looking at possible node to get 'key' ---- if len(keys) == 1 { updateValue(key, value, m, keys[0], subkeys, cnt) return } // ----- here we are navigating the path thru the penultimate node -------- // key of interest is keys[0] - the next in the path switch keys[0] { case "*": // wildcard - scan all values switch m.(type) { case map[string]interface{}: for _, v := range m.(map[string]interface{}) { updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt) } case []interface{}: for _, v := range m.([]interface{}) { switch v.(type) { // flatten out a list of maps - keys are processed case map[string]interface{}: for _, vv := range v.(map[string]interface{}) { updateValuesForKeyPath(key, value, vv, keys[1:], subkeys, cnt) } default: updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt) } } } default: // key - must be map[string]interface{} switch m.(type) { case map[string]interface{}: if v, ok := m.(map[string]interface{})[keys[0]]; ok { updateValuesForKeyPath(key, value, v, keys[1:], subkeys, cnt) } case []interface{}: // may be buried in list for _, v := range m.([]interface{}) { switch v.(type) { case map[string]interface{}: if vv, ok := v.(map[string]interface{})[keys[0]]; ok { updateValuesForKeyPath(key, value, vv, keys[1:], subkeys, cnt) } } } } } } // change value if key and subkeys are present func updateValue(key string, value interface{}, m interface{}, keys0 string, subkeys map[string]interface{}, cnt *int) { // there are two possible options for the value of 'keys0': map[string]interface, []interface{} // and 'key' is a key in the map or is a key in a map in a list. switch m.(type) { case map[string]interface{}: // gotta have the last key if keys0 == "*" { for k := range m.(map[string]interface{}) { updateValue(key, value, m, k, subkeys, cnt) } return } endVal, _ := m.(map[string]interface{})[keys0] // if newV key is the end of path, replace the value for path-end // may be []interface{} - means replace just an entry w/ subkeys // otherwise replace the keys0 value if subkeys are there // NOTE: this will replace the subkeys, also if key == keys0 { switch endVal.(type) { case map[string]interface{}: if hasSubKeys(m, subkeys) { (m.(map[string]interface{}))[keys0] = value (*cnt)++ } case []interface{}: // without subkeys can't select list member to modify // so key:value spec is it ... if hasSubKeys(m, subkeys) { (m.(map[string]interface{}))[keys0] = value (*cnt)++ break } nv := make([]interface{}, 0) var valmodified bool for _, v := range endVal.([]interface{}) { // check entry subkeys if hasSubKeys(v, subkeys) { // replace v with value nv = append(nv, value) valmodified = true (*cnt)++ continue } nv = append(nv, v) } if valmodified { (m.(map[string]interface{}))[keys0] = interface{}(nv) } default: // anything else is a strict replacement if hasSubKeys(m, subkeys) { (m.(map[string]interface{}))[keys0] = value (*cnt)++ } } return } // so value is for an element of endVal // if endVal is a map then 'key' must be there w/ subkeys // if endVal is a list then 'key' must be in a list member w/ subkeys switch endVal.(type) { case map[string]interface{}: if !hasSubKeys(endVal, subkeys) { return } if _, ok := (endVal.(map[string]interface{}))[key]; ok { (endVal.(map[string]interface{}))[key] = value (*cnt)++ } case []interface{}: // keys0 points to a list, check subkeys for _, v := range endVal.([]interface{}) { // got to be a map so we can replace value for 'key' vv, vok := v.(map[string]interface{}) if !vok { continue } if _, ok := vv[key]; !ok { continue } if !hasSubKeys(vv, subkeys) { continue } vv[key] = value (*cnt)++ } } case []interface{}: // key may be in a list member // don't need to handle keys0 == "*"; we're looking at everything, anyway. for _, v := range m.([]interface{}) { // only map values - we're looking for 'key' mm, ok := v.(map[string]interface{}) if !ok { continue } if _, ok := mm[key]; !ok { continue } if !hasSubKeys(mm, subkeys) { continue } mm[key] = value (*cnt)++ } } // return } mxj-2.5.5/updatevalues_test.go000066400000000000000000000132621402172443100164130ustar00rootroot00000000000000// modifyvalues_test.go - test keyvalues.go methods package mxj import ( "fmt" "testing" ) func TestUVHeader(t *testing.T) { fmt.Println("\n---------------- updatevalues_test.go ...") } func TestUpdateValuesForPath_Author(t *testing.T) { m, merr := NewMapXml(doc1) if merr != nil { t.Fatal("merr:", merr.Error()) } fmt.Println("m:", m) ss, _ := m.ValuesForPath("doc.books.book.author") for _, v := range ss { fmt.Println("v:", v) } fmt.Println("m.UpdateValuesForPath(\"author:NoName\", \"doc.books.book.author\")") n, err := m.UpdateValuesForPath("author:NoName", "doc.books.book.author") if err != nil { t.Fatal("err:", err.Error()) } fmt.Println(n, "updates") ss, _ = m.ValuesForPath("doc.books.book.author") for _, v := range ss { fmt.Println("v:", v) } fmt.Println("m.UpdateValuesForPath(\"author:William Gadddis\", \"doc.books.book.author\", \"title:The Recognitions\")") n, err = m.UpdateValuesForPath("author:William Gadddis", "doc.books.book.author", "title:The Recognitions") o, _ := m.UpdateValuesForPath("author:Austin Tappen Wright", "doc.books.book", "title:Islandia") p, _ := m.UpdateValuesForPath("author:John Hawkes", "doc.books.book", "title:The Beetle Leg") q, _ := m.UpdateValuesForPath("author:T. E. Porter", "doc.books.book", "title:King's Day") if err != nil { t.Fatal("err:", err.Error()) } fmt.Println(n+o+p+q, "updates") ss, _ = m.ValuesForPath("doc.books.book.author") for _, v := range ss { fmt.Println("v:", v) } fmt.Println("m.UpdateValuesForPath(\"author:William T. Gaddis\", \"doc.books.book.*\", \"title:The Recognitions\")") n, _ = m.UpdateValuesForPath("author:William T. Gaddis", "doc.books.book.*", "title:The Recognitions") fmt.Println(n, "updates") ss, _ = m.ValuesForPath("doc.books.book.author") for _, v := range ss { fmt.Println("v:", v) } fmt.Println("m.UpdateValuesForPath(\"title:The Cannibal\", \"doc.books.book.title\", \"author:John Hawkes\")") n, _ = m.UpdateValuesForPath("title:The Cannibal", "doc.books.book.title", "author:John Hawkes") o, _ = m.UpdateValuesForPath("review:A novel on his experiences in WWII.", "doc.books.book.review", "title:The Cannibal") fmt.Println(n+o, "updates") ss, _ = m.ValuesForPath("doc.books.book") for _, v := range ss { fmt.Println("v:", v) } fmt.Println("m.UpdateValuesForPath(\"books:\", \"doc.books\")") n, _ = m.UpdateValuesForPath("books:", "doc.books") fmt.Println(n, "updates") fmt.Println("m:", m) fmt.Println("m.UpdateValuesForPath(mm, \"*\")") mm, _ := NewMapXml(doc1) n, err = m.UpdateValuesForPath(mm, "*") if err != nil { t.Fatal("err:", err.Error()) } fmt.Println(n, "updates") fmt.Println("m:", m) // ---------------------- newDoc var newDoc = []byte(`simple element`) m, merr = NewMapXml(newDoc) if merr != nil { t.Fatal("merr:", merr.Error()) } fmt.Println("\nnewDoc:", string(newDoc)) fmt.Println("m:", m) fmt.Println("m.UpdateValuesForPath(\"#text:maybe not so simple element\", \"tag\")") n, _ = m.UpdateValuesForPath("#text:maybe not so simple element", "tag") fmt.Println("n:", n, "m:", m) fmt.Println("m.UpdateValuesForPath(\"#text:simple element again\", \"*\")") n, _ = m.UpdateValuesForPath("#text:simple element again", "*") fmt.Println("n:", n, "m:", m) /* fmt.Println("UpdateValuesForPath, doc.books.book, title:The Recognitions : NoBook") n, err = m.UpdateValuesForPath("NoBook", "doc.books.book", "title:The Recognitions") if err != nil { t.Fatal("err:", err.Error()) } fmt.Println(n, "updates") ss, _ = m.ValuesForPath("doc.books.book") for _, v := range ss { fmt.Println("v:", v) } fmt.Println("UpdateValuesForPath, doc.books.book.title -seq=3: The Blood Oranges") n, err = m.UpdateValuesForPath("The Blood Oranges", "doc.books.book.title", "-seq:3") if err != nil { t.Fatal("err:", err.Error()) } fmt.Println(n, "updates") ss, _ = m.ValuesForPath("doc.books.book.title") for _, v := range ss { fmt.Println("v:", v) } */ } var authorDoc = []byte(` William Gaddis The Recognitions 1955 A novel that changed the face of American literature. JR 1975 Winner of National Book Award for Fiction. John Hawkes The Cannibal 1949 A novel on his experiences in WWII. The Beetle Leg 1951 A lyrical novel about the construction of Ft. Peck Dam in Montana. The Blood Oranges 1970 Where everyone wants to vacation. `) func TestAuthorDoc(t *testing.T) { m, merr := NewMapXml(authorDoc) if merr != nil { t.Fatal("merr:", merr.Error()) } fmt.Println(m.StringIndent()) fmt.Println("m.UpdateValuesForPath(\"review:National Book Award winner.\", \"*.*.*.*\", \"title:JR\")") n, _ := m.UpdateValuesForPath("review:National Book Award winner.", "*.*.*.*", "title:JR") fmt.Println(n, "updates") ss, _ := m.ValuesForPath("biblio.author", "name:William Gaddis") for _, v := range ss { fmt.Println("v:", v) } fmt.Println("m.UpdateValuesForPath(newVal, path, oldVal)") path := m.PathForKeyShortest("date") v, _ := m.ValuesForPath(path) var counter int for _, vv := range v { oldVal := "date:" + vv.(string) newVal := "date:" + vv.(string) + ":num" n, _ = m.UpdateValuesForPath(newVal, path, oldVal) counter += n } fmt.Println(counter, "updates") fmt.Println(m.StringIndent()) } mxj-2.5.5/x2j-wrapper/000077500000000000000000000000001402172443100145005ustar00rootroot00000000000000mxj-2.5.5/x2j-wrapper/LICENSE000077500000000000000000000027431402172443100155160ustar00rootroot00000000000000Copyright (c) 2012-2016 Charles Banning . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. mxj-2.5.5/x2j-wrapper/README000077500000000000000000000115211402172443100153630ustar00rootroot00000000000000x2j.go - Unmarshal arbitrary XML docs to map[string]interface{} or JSON and extract values (using wildcards, if necessary). NOTICE: 26mar18: This is provided to aid transitioning applications using the "x2j" package to the "mxj" package. USAGE The package is fairly well self-documented. (http://godoc.org/github.com/clbanning/x2j) The one really useful function is: - Unmarshal(doc []byte, v interface{}) error where v is a pointer to a variable of type 'map[string]interface{}', 'string', or any other type supported by xml.Unmarshal(). To retrieve a value for specific tag use: - DocValue(doc, path string, attrs ...string) (interface{},error) - MapValue(m map[string]interface{}, path string, attr map[string]interface{}, recast ...bool) (interface{}, error) The 'path' argument is a period-separated tag hierarchy - also known as dot-notation. It is the program's responsibility to cast the returned value to the proper type; possible types are the normal JSON unmarshaling types: string, float64, bool, []interface, map[string]interface{}. To retrieve all values associated with a tag occurring anywhere in the XML document use: - ValuesForTag(doc, tag string) ([]interface{}, error) - ValuesForKey(m map[string]interface{}, key string) []interface{} Demos: http://play.golang.org/p/m8zP-cpk0O http://play.golang.org/p/cIteTS1iSg http://play.golang.org/p/vd8pMiI21b Returned values should be one of map[string]interface, []interface{}, or string. All the values assocated with a tag-path that may include one or more wildcard characters - '*' - can also be retrieved using: - ValuesFromTagPath(doc, path string, getAttrs ...bool) ([]interface{}, error) - ValuesFromKeyPath(map[string]interface{}, path string, getAttrs ...bool) []interface{} Demos: http://play.golang.org/p/kUQnZ8VuhS http://play.golang.org/p/l1aMHYtz7G NOTE: care should be taken when using "*" at the end of a path - i.e., "books.book.*". See the x2jpath_test.go case on how the wildcard returns all key values and collapses list values; the same message structure can load a []interface{} or a map[string]interface{} (or an interface{}) value for a tag. See the test cases in "x2jpath_test.go" and programs in "example" subdirectory for more. XML PARSING CONVENTIONS - Attributes are parsed to map[string]interface{} values by prefixing a hyphen, '-', to the attribute label. [See https://godoc.org/github.com/clbanning/mxj#SetAttrPrefix for options.] - If the element is a simple element and has attributes, the element value is given the key '#text' for its map[string]interface{} representation. (See the 'atomFeedString.xml' test data, below.) BULK PROCESSING OF MESSAGE FILES Sometime messages may be logged into files for transmission via FTP (e.g.) and subsequent processing. You can use the bulk XML message processor to convert files of XML messages into map[string]interface{} values with custom processing and error handler functions. See the notes and test code for: - XmlMsgsFromFile(fname string, phandler func(map[string]interface{}) bool, ehandler func(error) bool,recast ...bool) error [See https://godoc.org/github.com/clbanning/mxj#HandleXmlReader for general version.] IMPLEMENTATION NOTES Nothing fancy here, just brute force. - Use xml.Decoder to parse the XML doc and build a tree. - Walk the tree and load values into a map[string]interface{} variable, 'm', as appropriate. - Use json.Marshaler to convert 'm' to JSON. As for testing: - Copy an XML doc into 'x2j_test.xml'. - Run "go test" and you'll get a full dump. ("pathTestString.xml" and "atomFeedString.xml" are test data from "read_test.go" in the encoding/xml directory of the standard package library.) MOTIVATION I make extensive use of JSON for messaging and typically unmarshal the messages into map[string]interface{} variables. This is easily done using json.Unmarshal from the standard Go libraries. Unfortunately, many legacy solutions use structured XML messages; in those environments the applications would have to be refitted to interoperate with my components. The better solution is to just provide an alternative HTTP handler that receives XML doc messages and parses it into a map[string]interface{} variable and then reuse all the JSON-based code. The Go xml.Unmarshal() function does not provide the same option of unmarshaling XML messages into map[string]interface{} variables. So I wrote a couple of small functions to fill this gap. Of course, once the XML doc was unmarshal'd into a map[string]interface{} variable it was just a matter of calling json.Marshal() to provide it as a JSON string. Hence 'x2j' rather than just 'x2m'. USES - putting a XML API on our message hub middleware (http://jsonhub.net) - loading XML data into NoSQL database, such as, mongoDB mxj-2.5.5/x2j-wrapper/atomFeedString.xml000077500000000000000000000056531402172443100201510ustar00rootroot00000000000000 Code Review - My issueshttp://codereview.appspot.com/rietveld<>rietveld: an attempt at pubsubhubbub 2009-10-04T01:35:58+00:00email-address-removedurn:md5:134d9179c41f806be79b3a5f7877d19a An attempt at adding pubsubhubbub support to Rietveld. http://code.google.com/p/pubsubhubbub http://code.google.com/p/rietveld/issues/detail?id=155 The server side of the protocol is trivial: 1. add a &lt;link rel=&quot;hub&quot; href=&quot;hub-server&quot;&gt; tag to all feeds that will be pubsubhubbubbed. 2. every time one of those feeds changes, tell the hub with a simple POST request. I have tested this by adding debug prints to a local hub server and checking that the server got the right publish requests. I can&#39;t quite get the server to work, but I think the bug is not in my code. I think that the server expects to be able to grab the feed and see the feed&#39;s actual URL in the link rel=&quot;self&quot;, but the default value for that drops the :port from the URL, and I cannot for the life of me figure out how to get the Atom generator deep inside django not to do that, or even where it is doing that, or even what code is running to generate the Atom feed. (I thought I knew but I added some assert False statements and it kept running!) Ignoring that particular problem, I would appreciate feedback on the right way to get the two values at the top of feeds.py marked NOTE(rsc). rietveld: correct tab handling 2009-10-03T23:02:17+00:00email-address-removedurn:md5:0a2a4f19bb815101f0ba2904aed7c35a This fixes the buggy tab rendering that can be seen at http://codereview.appspot.com/116075/diff/1/2 The fundamental problem was that the tab code was not being told what column the text began in, so it didn&#39;t know where to put the tab stops. Another problem was that some of the code assumed that string byte offsets were the same as column offsets, which is only true if there are no tabs. In the process of fixing this, I cleaned up the arguments to Fold and ExpandTabs and renamed them Break and _ExpandTabs so that I could be sure that I found all the call sites. I also wanted to verify that ExpandTabs was not being used from outside intra_region_diff.py. ` mxj-2.5.5/x2j-wrapper/goofy_test.go000077500000000000000000000020451402172443100172150ustar00rootroot00000000000000package x2j import ( "encoding/json" "fmt" "testing" ) func TestGoofy(t *testing.T) { var doc = `` type goofy struct { S string Sp *string } g := new(goofy) g.S = "Now is the time for" tmp := "all good men to come to" g.Sp = &tmp m, err := DocToMap(doc) if err != nil { fmt.Println("err:",err.Error()) return } m["goofyVal"] = interface{}(g) m["byteVal"] = interface{}([]byte(`the aid of their country`)) m["nilVal"] = interface{}(nil) fmt.Println("\nTestGoofy ... MapToDoc:",m) var v []byte v,err = json.Marshal(m) if err != nil { fmt.Println("err:",err.Error()) } fmt.Println("v:",string(v)) type goofier struct { G *goofy B []byte N *string } gg := new(goofier) gg.G = g gg.B = []byte(`the tree of freedom must periodically be`) gg.N = nil m["goofierVal"] = interface{}(gg) fmt.Println("\nTestGoofier ... MapToDoc:",m) v,err = json.Marshal(m) if err != nil { fmt.Println("err:",err.Error()) } fmt.Println("v:",string(v)) } mxj-2.5.5/x2j-wrapper/pathTestString.xml000077500000000000000000000005461402172443100202150ustar00rootroot00000000000000 1 A B C D <_> E 2 mxj-2.5.5/x2j-wrapper/reader2j.go000077500000000000000000000037411402172443100165350ustar00rootroot00000000000000// Copyright 2012-2018 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // io.Reader --> map[string]interface{} or JSON string // nothing magic - just implements generic Go case package x2j import ( "encoding/json" "io" "github.com/clbanning/mxj" ) // ToMap() - parse a XML io.Reader to a map[string]interface{} func ToMap(rdr io.Reader, recast ...bool) (map[string]interface{}, error) { var r bool if len(recast) == 1 { r = recast[0] } return mxj.NewMapXmlReader(rdr, r) } // ToJson() - parse a XML io.Reader to a JSON string func ToJson(rdr io.Reader, recast ...bool) (string, error) { var r bool if len(recast) == 1 { r = recast[0] } m, merr := mxj.NewMapXmlReader(rdr, r) if m == nil || merr != nil { return "", merr } b, berr := json.Marshal(m) if berr != nil { return "", berr } return string(b), nil } // ToJsonIndent - the pretty form of ReaderToJson func ToJsonIndent(rdr io.Reader, recast ...bool) (string, error) { var r bool if len(recast) == 1 { r = recast[0] } m, merr := mxj.NewMapXmlReader(rdr, r) if m == nil || merr != nil { return "", merr } b, berr := json.MarshalIndent(m, "", " ") if berr != nil { return "", berr } // NOTE: don't have to worry about safe JSON marshaling with json.Marshal, since '<' and '>" are reservedin XML. return string(b), nil } // ReaderValuesFromTagPath - io.Reader version of ValuesFromTagPath() func ReaderValuesFromTagPath(rdr io.Reader, path string, getAttrs ...bool) ([]interface{}, error) { var a bool if len(getAttrs) == 1 { a = getAttrs[0] } m, err := mxj.NewMapXmlReader(rdr) if err != nil { return nil, err } return ValuesFromKeyPath(m, path, a), nil } // ReaderValuesForTag - io.Reader version of ValuesForTag() func ReaderValuesForTag(rdr io.Reader, tag string) ([]interface{}, error) { m, err := mxj.NewMapXmlReader(rdr) if err != nil { return nil, err } return ValuesForKey(m, tag), nil } mxj-2.5.5/x2j-wrapper/reader2j_test.go000077500000000000000000000031411402172443100175660ustar00rootroot00000000000000package x2j import ( "bytes" "fmt" "testing" ) var doc = `barworld` func TestToMap(t *testing.T) { fmt.Println("\nToMap - Read doc:",doc) rdr := bytes.NewBufferString(doc) m,err := ToMap(rdr) if err != nil { fmt.Println("err:",err.Error()) } fmt.Println(WriteMap(m)) } func TestToJson(t *testing.T) { fmt.Println("\nToJson - Read doc:",doc) rdr := bytes.NewBufferString(doc) s,err := ToJson(rdr) if err != nil { fmt.Println("err:",err.Error()) } fmt.Println("json:",s) } func TestToJsonIndent(t *testing.T) { fmt.Println("\nToJsonIndent - Read doc:",doc) rdr := bytes.NewBufferString(doc) s,err := ToJsonIndent(rdr) if err != nil { fmt.Println("err:",err.Error()) } fmt.Println("json:",s) } func TestBulkParser(t *testing.T) { s := doc + `an`+ doc fmt.Println("\nBulkParser (with error) - Read doc:",s) rdr := bytes.NewBufferString(s) err := XmlMsgsFromReader(rdr,phandler,ehandler) if err != nil { fmt.Println("reader terminated:",err.Error()) } } func phandler(m map[string]interface{}) bool { fmt.Println("phandler m:",m) return true } func ehandler(err error) bool { fmt.Println("ehandler err:",err.Error()) return true } func TestBulkParserToJson(t *testing.T) { s := doc + `an`+ doc fmt.Println("\nBulkParser (with error) - Read doc:",s) rdr := bytes.NewBufferString(s) err := XmlMsgsFromReaderAsJson(rdr,phandlerj,ehandler) if err != nil { fmt.Println("reader terminated:",err.Error()) } } func phandlerj(s string) bool { fmt.Println("phandlerj s:",s) return true } mxj-2.5.5/x2j-wrapper/songTextString.xml000077500000000000000000000021731402172443100202320ustar00rootroot00000000000000 help me! Henry was a renegade Didn't like to play it safe One component at a time There's got to be a better way Oh, people came from miles around Searching for a steady job Welcome to the Motor Town Booming like an atom bomb Oh, Henry was the end of the story Then everything went wrong And we'll return it to its former glory But it just takes so long It's going to take a long time It's going to take it, but we'll make it one day It's going to take a long time It's going to take it, but we'll make it one day mxj-2.5.5/x2j-wrapper/x2j.go000077500000000000000000000347521402172443100155500ustar00rootroot00000000000000// Unmarshal arbitrary XML docs to map[string]interface{} or JSON and extract values (using wildcards, if necessary). // Copyright 2012-2018 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file /* Unmarshal dynamic / arbitrary XML docs and extract values (using wildcards, if necessary). THIS IS ONLY PROVIDED TO FACILIATE MIGRATING TO "mxj" PACKAGE FROM "x2j" PACKAGE. NOTICE: 03mar18, package mostly replicates github.com/clbanning/x2j using github.com/clbanning/mxj (Note: there is no concept of Node or Tree; only direct decoding to map[string]interface{}.) One useful function is: - Unmarshal(doc []byte, v interface{}) error where v is a pointer to a variable of type 'map[string]interface{}', 'string', or any other type supported by xml.Unmarshal(). To retrieve a value for specific tag use: - DocValue(doc, path string, attrs ...string) (interface{},error) - MapValue(m map[string]interface{}, path string, attr map[string]interface{}, recast ...bool) (interface{}, error) The 'path' argument is a period-separated tag hierarchy - also known as dot-notation. It is the program's responsibility to cast the returned value to the proper type; possible types are the normal JSON unmarshaling types: string, float64, bool, []interface, map[string]interface{}. To retrieve all values associated with a tag occurring anywhere in the XML document use: - ValuesForTag(doc, tag string) ([]interface{}, error) - ValuesForKey(m map[string]interface{}, key string) []interface{} Demos: http://play.golang.org/p/m8zP-cpk0O http://play.golang.org/p/cIteTS1iSg http://play.golang.org/p/vd8pMiI21b Returned values should be one of map[string]interface, []interface{}, or string. All the values assocated with a tag-path that may include one or more wildcard characters - '*' - can also be retrieved using: - ValuesFromTagPath(doc, path string, getAttrs ...bool) ([]interface{}, error) - ValuesFromKeyPath(map[string]interface{}, path string, getAttrs ...bool) []interface{} Demos: http://play.golang.org/p/kUQnZ8VuhS http://play.golang.org/p/l1aMHYtz7G NOTE: care should be taken when using "*" at the end of a path - i.e., "books.book.*". See the x2jpath_test.go case on how the wildcard returns all key values and collapses list values; the same message structure can load a []interface{} or a map[string]interface{} (or an interface{}) value for a tag. See the test cases in "x2jpath_test.go" and programs in "example" subdirectory for more. XML PARSING CONVENTIONS - Attributes are parsed to map[string]interface{} values by prefixing a hyphen, '-', to the attribute label. - If the element is a simple element and has attributes, the element value is given the key '#text' for its map[string]interface{} representation. (See the 'atomFeedString.xml' test data, below.) io.Reader HANDLING ToMap(), ToJson(), and ToJsonIndent() provide parsing of messages from an io.Reader. If you want to handle a message stream, look at XmlMsgsFromReader(). NON-UTF8 CHARACTER SETS Use the X2jCharsetReader variable to assign io.Reader for alternative character sets. */ package x2j import ( "bytes" "encoding/xml" "errors" "fmt" "io" "strconv" "strings" "github.com/clbanning/mxj" ) // If X2jCharsetReader != nil, it will be used to decode the doc or stream if required // import charset "code.google.com/p/go-charset/charset" // ... // x2j.X2jCharsetReader = charset.NewReader // s, err := x2j.DocToJson(doc) var X2jCharsetReader func(charset string, input io.Reader)(io.Reader, error) // DocToJson - return an XML doc as a JSON string. // If the optional argument 'recast' is 'true', then values will be converted to boolean or float64 if possible. func DocToJson(doc string, recast ...bool) (string, error) { var r bool if len(recast) == 1 { r = recast[0] } m, merr := mxj.NewMapXml([]byte(doc), r) if m == nil || merr != nil { return "", merr } b, berr := m.Json() if berr != nil { return "", berr } // NOTE: don't have to worry about safe JSON marshaling with json.Marshal, since '<' and '>" are reservedin XML. return string(b), nil } // DocToJsonIndent - return an XML doc as a prettified JSON string. // If the optional argument 'recast' is 'true', then values will be converted to boolean or float64 if possible. // Note: recasting is only applied to element values, not attribute values. func DocToJsonIndent(doc string, recast ...bool) (string, error) { var r bool if len(recast) == 1 { r = recast[0] } m, merr := mxj.NewMapXml([]byte(doc), r) if m == nil || merr != nil { return "", merr } b, berr := m.JsonIndent("", " ") if berr != nil { return "", berr } // NOTE: don't have to worry about safe JSON marshaling with json.Marshal, since '<' and '>" are reservedin XML. return string(b), nil } // DocToMap - convert an XML doc into a map[string]interface{}. // (This is analogous to unmarshalling a JSON string to map[string]interface{} using json.Unmarshal().) // If the optional argument 'recast' is 'true', then values will be converted to boolean or float64 if possible. // Note: recasting is only applied to element values, not attribute values. func DocToMap(doc string, recast ...bool) (map[string]interface{}, error) { var r bool if len(recast) == 1 { r = recast[0] } return mxj.NewMapXml([]byte(doc), r) } // WriteMap - dumps the map[string]interface{} for examination. // 'offset' is initial indentation count; typically: WriteMap(m). // NOTE: with XML all element types are 'string'. // But code written as generic for use with maps[string]interface{} values from json.Unmarshal(). // Or it can handle a DocToMap(doc,true) result where values have been recast'd. func WriteMap(m interface{}, offset ...int) string { var indent int if len(offset) == 1 { indent = offset[0] } var s string switch m.(type) { case nil: return "[nil] nil" case string: return "[string] " + m.(string) case float64: return "[float64] " + strconv.FormatFloat(m.(float64), 'e', 2, 64) case bool: return "[bool] " + strconv.FormatBool(m.(bool)) case []interface{}: s += "[[]interface{}]" for i, v := range m.([]interface{}) { s += "\n" for i := 0; i < indent; i++ { s += " " } s += "[item: " + strconv.FormatInt(int64(i), 10) + "]" switch v.(type) { case string, float64, bool: s += "\n" default: // noop } for i := 0; i < indent; i++ { s += " " } s += WriteMap(v, indent+1) } case map[string]interface{}: for k, v := range m.(map[string]interface{}) { s += "\n" for i := 0; i < indent; i++ { s += " " } // s += "[map[string]interface{}] "+k+" :"+WriteMap(v,indent+1) s += k + " :" + WriteMap(v, indent+1) } default: // shouldn't ever be here ... s += fmt.Sprintf("unknown type for: %v", m) } return s } // ------------------------ value extraction from XML doc -------------------------- // DocValue - return a value for a specific tag // 'doc' is a valid XML message. // 'path' is a hierarchy of XML tags, e.g., "doc.name". // 'attrs' is an OPTIONAL list of "name:value" pairs for attributes. // Note: 'recast' is not enabled here. Use DocToMap(), NewAttributeMap(), and MapValue() calls for that. func DocValue(doc, path string, attrs ...string) (interface{}, error) { m, err := mxj.NewMapXml([]byte(doc), false) if err != nil { return nil, err } a, err := NewAttributeMap(attrs...) if err != nil { return nil, err } v, verr := MapValue(m, path, a) if verr != nil { return nil, verr } return v, nil } // MapValue - retrieves value based on walking the map, 'm'. // 'm' is the map value of interest. // 'path' is a period-separated hierarchy of keys in the map. // 'attr' is a map of attribute "name:value" pairs from NewAttributeMap(). May be 'nil'. // If the path can't be traversed, an error is returned. // Note: the optional argument 'r' can be used to coerce attribute values, 'attr', if done so for 'm'. func MapValue(m map[string]interface{}, path string, attr map[string]interface{}, r ...bool) (interface{}, error) { // attribute values may have been recasted during map construction; default is 'false'. if len(r) == 1 && r[0] == true { for k, v := range attr { attr[k] = recast(v.(string), true) } } // parse the path keys := strings.Split(path, ".") // initialize return value to 'm' so a path of "" will work correctly var v interface{} = m var ok bool var okey string var isMap bool = true if keys[0] == "" && len(attr) == 0 { return v, nil } for _, key := range keys { if !isMap { return nil, errors.New("no keys beyond: " + okey) } if v, ok = m[key]; !ok { return nil, errors.New("no key in map: " + key) } else { switch v.(type) { case map[string]interface{}: m = v.(map[string]interface{}) isMap = true default: isMap = false } } // save 'key' for error reporting okey = key } // match attributes; value is "#text" or nil if attr == nil { return v, nil } return hasAttributes(v, attr) } // recast - try to cast string values to bool or float64 func recast(s string, r bool) interface{} { if r { // handle numeric strings ahead of boolean if f, err := strconv.ParseFloat(s, 64); err == nil { return interface{}(f) } // ParseBool treats "1"==true & "0"==false if b, err := strconv.ParseBool(s); err == nil { return interface{}(b) } } return interface{}(s) } // hasAttributes() - interface{} equality works for string, float64, bool func hasAttributes(v interface{}, a map[string]interface{}) (interface{}, error) { switch v.(type) { case []interface{}: // run through all entries looking one with matching attributes for _, vv := range v.([]interface{}) { if vvv, vvverr := hasAttributes(vv, a); vvverr == nil { return vvv, nil } } return nil, errors.New("no list member with matching attributes") case map[string]interface{}: // do all attribute name:value pairs match? nv := v.(map[string]interface{}) for key, val := range a { if vv, ok := nv[key]; !ok { return nil, errors.New("no attribute with name: " + key[1:]) } else if val != vv { return nil, errors.New("no attribute key:value pair: " + fmt.Sprintf("%s:%v", key[1:], val)) } } // they all match; so return value associated with "#text" key. if vv, ok := nv["#text"]; ok { return vv, nil } else { // this happens when another element is value of tag rather than just a string value return nv, nil } } return nil, errors.New("no match for attributes") } // NewAttributeMap() - generate map of attributes=value entries as map["-"+string]string. // 'kv' arguments are "name:value" pairs that appear as attributes, name="value". // If len(kv) == 0, the return is (nil, nil). func NewAttributeMap(kv ...string) (map[string]interface{}, error) { if len(kv) == 0 { return nil, nil } m := make(map[string]interface{}, 0) for _, v := range kv { vv := strings.Split(v, ":") if len(vv) != 2 { return nil, errors.New("attribute not \"name:value\" pair: " + v) } // attributes are stored as keys prepended with hyphen m["-"+vv[0]] = interface{}(vv[1]) } return m, nil } //------------------------- get values for key ---------------------------- // ValuesForTag - return all values in doc associated with 'tag'. // Returns nil if the 'tag' does not occur in the doc. // If there is an error encounted while parsing doc, that is returned. // If you want values 'recast' use DocToMap() and ValuesForKey(). func ValuesForTag(doc, tag string) ([]interface{}, error) { m, err := mxj.NewMapXml([]byte(doc)) if err != nil { return nil, err } return ValuesForKey(m, tag), nil } // ValuesForKey - return all values in map associated with 'key' // Returns nil if the 'key' does not occur in the map func ValuesForKey(m map[string]interface{}, key string) []interface{} { ret := make([]interface{}, 0) hasKey(m, key, &ret) if len(ret) > 0 { return ret } return nil } // hasKey - if the map 'key' exists append it to array // if it doesn't do nothing except scan array and map values func hasKey(iv interface{}, key string, ret *[]interface{}) { switch iv.(type) { case map[string]interface{}: vv := iv.(map[string]interface{}) if v, ok := vv[key]; ok { *ret = append(*ret, v) } for _, v := range iv.(map[string]interface{}) { hasKey(v, key, ret) } case []interface{}: for _, v := range iv.([]interface{}) { hasKey(v, key, ret) } } } // ======== 2013.07.01 - x2j.Unmarshal, wraps xml.Unmarshal ============== // Unmarshal - wraps xml.Unmarshal with handling of map[string]interface{} // and string type variables. // Usage: x2j.Unmarshal(doc,&m) where m of type map[string]interface{} // x2j.Unmarshal(doc,&s) where s of type string (Overrides xml.Unmarshal().) // x2j.Unmarshal(doc,&struct) - passed to xml.Unmarshal() // x2j.Unmarshal(doc,&slice) - passed to xml.Unmarshal() func Unmarshal(doc []byte, v interface{}) error { switch v.(type) { case *map[string]interface{}: m, err := mxj.NewMapXml(doc) vv := *v.(*map[string]interface{}) for k, v := range m { vv[k] = v } return err case *string: s, err := ByteDocToJson(doc) *(v.(*string)) = s return err default: b := bytes.NewBuffer(doc) p := xml.NewDecoder(b) p.CharsetReader = X2jCharsetReader return p.Decode(v) // return xml.Unmarshal(doc, v) } return nil } // ByteDocToJson - return an XML doc as a JSON string. // If the optional argument 'recast' is 'true', then values will be converted to boolean or float64 if possible. func ByteDocToJson(doc []byte, recast ...bool) (string, error) { var r bool if len(recast) == 1 { r = recast[0] } m, merr := mxj.NewMapXml(doc, r) if m == nil || merr != nil { return "", merr } b, berr := m.Json() if berr != nil { return "", berr } // NOTE: don't have to worry about safe JSON marshaling with json.Marshal, since '<' and '>" are reservedin XML. return string(b), nil } // ByteDocToMap - convert an XML doc into a map[string]interface{}. // (This is analogous to unmarshalling a JSON string to map[string]interface{} using json.Unmarshal().) // If the optional argument 'recast' is 'true', then values will be converted to boolean or float64 if possible. // Note: recasting is only applied to element values, not attribute values. func ByteDocToMap(doc []byte, recast ...bool) (map[string]interface{}, error) { var r bool if len(recast) == 1 { r = recast[0] } return mxj.NewMapXml(doc, r) } mxj-2.5.5/x2j-wrapper/x2j_bulk.go000077500000000000000000000071101402172443100165510ustar00rootroot00000000000000// Copyright 2012-2018 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // x2j_bulk.go: Process files with multiple XML messages. // Extends x2m_bulk.go to work with JSON strings rather than map[string]interface{}. package x2j import ( "bytes" "io" "os" "regexp" "github.com/clbanning/mxj" ) // XmlMsgsFromFileAsJson() // 'fname' is name of file // 'phandler' is the JSON string processing handler. Return of 'false' stops further processing. // 'ehandler' is the parsing error handler. Return of 'false' stops further processing and returns error. // Note: phandler() and ehandler() calls are blocking, so reading and processing of messages is serialized. // This means that you can stop reading the file on error or after processing a particular message. // To have reading and handling run concurrently, pass arguments to a go routine in handler and return true. func XmlMsgsFromFileAsJson(fname string, phandler func(string)(bool), ehandler func(error)(bool), recast ...bool) error { var r bool if len(recast) == 1 { r = recast[0] } fi, fierr := os.Stat(fname) if fierr != nil { return fierr } fh, fherr := os.Open(fname) if fherr != nil { return fherr } defer fh.Close() buf := make([]byte,fi.Size()) _, rerr := fh.Read(buf) if rerr != nil { return rerr } doc := string(buf) // xml.Decoder doesn't properly handle whitespace in some doc // see songTextString.xml test case ... reg,_ := regexp.Compile("[ \t\n\r]*<") doc = reg.ReplaceAllString(doc,"<") b := bytes.NewBufferString(doc) for { s, serr := XmlBufferToJson(b,r) if serr != nil && serr != io.EOF { if ok := ehandler(serr); !ok { // caused reader termination return serr } } if s != "" { if ok := phandler(s); !ok { break } } if serr == io.EOF { break } } return nil } // XmlBufferToJson - process XML message from a bytes.Buffer // 'b' is the buffer // Optional argument 'recast' coerces values to float64 or bool where possible. func XmlBufferToJson(b *bytes.Buffer,recast ...bool) (string,error) { var r bool if len(recast) == 1 { r = recast[0] } m, err := mxj.NewMapXmlReader(b, r) // n,err := XmlBufferToTree(b) if err != nil { return "", err } // m := make(map[string]interface{}) // m[n.key] = n.treeToMap(r) j, jerr := m.Json() return string(j), jerr } // ============================= io.Reader version for stream processing ====================== // XmlMsgsFromReaderAsJson() - io.Reader version of XmlMsgsFromFileAsJson // 'rdr' is an io.Reader for an XML message (stream) // 'phandler' is the JSON string processing handler. Return of 'false' stops further processing. // 'ehandler' is the parsing error handler. Return of 'false' stops further processing and returns error. // Note: phandler() and ehandler() calls are blocking, so reading and processing of messages is serialized. // This means that you can stop reading the file on error or after processing a particular message. // To have reading and handling run concurrently, pass arguments to a go routine in handler and return true. func XmlMsgsFromReaderAsJson(rdr io.Reader, phandler func(string)(bool), ehandler func(error)(bool), recast ...bool) error { var r bool if len(recast) == 1 { r = recast[0] } for { s, serr := ToJson(rdr,r) if serr != nil && serr != io.EOF { if ok := ehandler(serr); !ok { // caused reader termination return serr } } if s != "" { if ok := phandler(s); !ok { break } } if serr == io.EOF { break } } return nil } mxj-2.5.5/x2j-wrapper/x2j_findPath.go000077500000000000000000000075141402172443100173610ustar00rootroot00000000000000// x2j_findPath - utility functions to retrieve path to node in dot-notation // Copyright 2012-2018 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file package x2j import ( "strings" "github.com/clbanning/mxj" ) //----------------------------- find all paths to a key -------------------------------- // Want eventually to extract shortest path and call GetValuesAtKeyPath() // This will get all the possible paths. These can be scanned for len(path) and sequence. // Get all paths through the doc (in dot-notation) that terminate with the specified tag. // Results can be used with ValuesAtTagPath() and ValuesFromTagPath(). func PathsForTag(doc string, key string) ([]string, error) { m, err := mxj.NewMapXml([]byte(doc)) if err != nil { return nil, err } ss := PathsForKey(m, key) return ss, nil } // Extract the shortest path from all possible paths - from PathsForTag(). // Paths are strings using dot-notation. func PathForTagShortest(doc string, key string) (string, error) { m, err := mxj.NewMapXml([]byte(doc)) if err != nil { return "", err } s := PathForKeyShortest(m, key) return s, nil } // Get all paths through the doc (in dot-notation) that terminate with the specified tag. // Results can be used with ValuesAtTagPath() and ValuesFromTagPath(). func BytePathsForTag(doc []byte, key string) ([]string, error) { m, err := mxj.NewMapXml(doc) if err != nil { return nil, err } ss := PathsForKey(m, key) return ss, nil } // Extract the shortest path from all possible paths - from PathsForTag(). // Paths are strings using dot-notation. func BytePathForTagShortest(doc []byte, key string) (string, error) { m, err := ByteDocToMap(doc) if err != nil { return "", err } s := PathForKeyShortest(m, key) return s, nil } // Get all paths through the map (in dot-notation) that terminate with the specified key. // Results can be used with ValuesAtKeyPath() and ValuesFromKeyPath(). func PathsForKey(m map[string]interface{}, key string) []string { breadbasket := make(map[string]bool,0) breadcrumb := "" hasKeyPath(breadcrumb, m, key, &breadbasket) if len(breadbasket) == 0 { return nil } // unpack map keys to return res := make([]string,len(breadbasket)) var i int for k,_ := range breadbasket { res[i] = k i++ } return res } // Extract the shortest path from all possible paths - from PathsForKey(). // Paths are strings using dot-notation. func PathForKeyShortest(m map[string]interface{}, key string) string { paths := PathsForKey(m,key) lp := len(paths) if lp == 0 { return "" } if lp == 1 { return paths[0] } shortest := paths[0] shortestLen := len(strings.Split(shortest,".")) for i := 1 ; i < len(paths) ; i++ { vlen := len(strings.Split(paths[i],".")) if vlen < shortestLen { shortest = paths[i] shortestLen = vlen } } return shortest } // hasKeyPath - if the map 'key' exists append it to KeyPath.path and increment KeyPath.depth // This is really just a breadcrumber that saves all trails that hit the prescribed 'key'. func hasKeyPath(crumb string, iv interface{}, key string, basket *map[string]bool) { switch iv.(type) { case map[string]interface{}: vv := iv.(map[string]interface{}) if _, ok := vv[key]; ok { if crumb == "" { crumb = key } else { crumb += "." + key } // *basket = append(*basket, crumb) (*basket)[crumb] = true } // walk on down the path, key could occur again at deeper node for k, v := range vv { // create a new breadcrumb, add the one we're at to the crumb-trail var nbc string if crumb == "" { nbc = k } else { nbc = crumb + "." + k } hasKeyPath(nbc, v, key, basket) } case []interface{}: // crumb-trail doesn't change, pass it on for _, v := range iv.([]interface{}) { hasKeyPath(crumb, v, key, basket) } } } mxj-2.5.5/x2j-wrapper/x2j_test.go000077500000000000000000000214341402172443100166000ustar00rootroot00000000000000package x2j import ( "encoding/json" "fmt" "os" "testing" ) func TestX2j(t *testing.T) { fmt.Println("\n================================ x2j_test.go ...") fmt.Println("\n=================== TestX2j ...") fi, fierr := os.Stat("x2j_test.xml") if fierr != nil { fmt.Println("fierr:",fierr.Error()) return } fh, fherr := os.Open("x2j_test.xml") if fherr != nil { fmt.Println("fherr:",fherr.Error()) return } defer fh.Close() buf := make([]byte,fi.Size()) _, nerr := fh.Read(buf) if nerr != nil { fmt.Println("nerr:",nerr.Error()) return } doc := string(buf) fmt.Println("\nXML doc:\n",doc) // test DocToMap() with recast mm, mmerr := DocToMap(doc,true) if mmerr != nil { println("mmerr:",mmerr.Error()) return } println("\nDocToMap(), recast==true:\n",WriteMap(mm)) // test DocToJsonIndent() with recast s,serr := DocToJsonIndent(doc,true) if serr != nil { fmt.Println("serr:",serr.Error()) } fmt.Println("\nDocToJsonIndent, recast==true:\n",s) } func TestGetValue(t *testing.T) { fmt.Println("\n=================== TestGetValue ...") // test MapValue() doc := `barworld` fmt.Println("\nRead doc:",doc) fmt.Println("Looking for value: entry.vars") mm,mmerr := DocToMap(doc) if mmerr != nil { fmt.Println("merr:",mmerr.Error()) } v,verr := MapValue(mm,"entry.vars",nil) if verr != nil { fmt.Println("verr:",verr.Error()) } else { j, jerr := json.MarshalIndent(v,""," ") if jerr != nil { fmt.Println("jerr:",jerr.Error()) } else { fmt.Println(string(j)) } } fmt.Println("Looking for value: entry.vars.foo2.hello") v,verr = MapValue(mm,"entry.vars.foo2.hello",nil) if verr != nil { fmt.Println("verr:",verr.Error()) } else { fmt.Println(v.(string)) } fmt.Println("Looking with error in path: entry.var") v,verr = MapValue(mm,"entry.var",nil) fmt.Println("verr:",verr.Error()) // test DocValue() fmt.Println("DocValue() for tag path entry.vars") v,verr = DocValue(doc,"entry.vars") if verr != nil { fmt.Println("verr:",verr.Error()) } j,_ := json.MarshalIndent(v,""," ") fmt.Println(string(j)) } func TestGetValueWithAttr(t *testing.T) { fmt.Println("\n=================== TestGetValueWithAttr ...") doc := ` bar world universe ` fmt.Println("\nRead doc:",doc) fmt.Println("Looking for value: entry.vars") mm,mmerr := DocToMap(doc) if mmerr != nil { fmt.Println("merr:",mmerr.Error()) } v,verr := MapValue(mm,"entry.vars",nil) if verr != nil { fmt.Println("verr:",verr.Error()) } else { j, jerr := json.MarshalIndent(v,""," ") if jerr != nil { fmt.Println("jerr:",jerr.Error()) } else { fmt.Println(string(j)) } } fmt.Println("\nMapValue(): Looking for value: entry.vars.foo item=2") a,aerr := NewAttributeMap("item:2") if aerr != nil { fmt.Println("aerr:",aerr.Error()) } v,verr = MapValue(mm,"entry.vars.foo",a) if verr != nil { fmt.Println("verr:",verr.Error()) } else { j, jerr := json.MarshalIndent(v,""," ") if jerr != nil { fmt.Println("jerr:",jerr.Error()) } else { fmt.Println(string(j)) } } fmt.Println("\nMapValue(): Looking for hello item:4") a,_ = NewAttributeMap("item:4") v,verr = MapValue(mm,"hello",a) if verr != nil { fmt.Println("verr:",verr.Error()) } else { j, jerr := json.MarshalIndent(v,""," ") if jerr != nil { fmt.Println("jerr:",jerr.Error()) } else { fmt.Println(string(j)) } } fmt.Println("\nDocValue(): Looking for entry.vars.foo.hello item:4") v,verr = DocValue(doc,"entry.vars.foo.hello","item:4") if verr != nil { fmt.Println("verr:",verr.Error()) } else { j, jerr := json.MarshalIndent(v,""," ") if jerr != nil { fmt.Println("jerr:",jerr.Error()) } else { fmt.Println(string(j)) } } fmt.Println("\nDocValue(): Looking for empty nil") v,verr = DocValue(doc,"") if verr != nil { fmt.Println("verr:",verr.Error()) } else { j, jerr := json.MarshalIndent(v,""," ") if jerr != nil { fmt.Println("jerr:",jerr.Error()) } else { fmt.Println(string(j)) } } // test 'recast' switch fmt.Println("\ntesting recast switch...") mm,mmerr = DocToMap(doc,true) if mmerr != nil { fmt.Println("merr:",mmerr.Error()) } fmt.Println("MapValue(): Looking for value: entry.vars.foo item=2") a,aerr = NewAttributeMap("item:2") if aerr != nil { fmt.Println("aerr:",aerr.Error()) } v,verr = MapValue(mm,"entry.vars.foo",a,true) if verr != nil { fmt.Println("verr:",verr.Error()) } else { j, jerr := json.MarshalIndent(v,""," ") if jerr != nil { fmt.Println("jerr:",jerr.Error()) } else { fmt.Println(string(j)) } } } func TestStuff_1(t *testing.T) { fmt.Println("\n=================== TestStuff_1 ...") doc := ` val2 val2 val3 ` fmt.Println(doc) m,merr := DocToMap(doc) if merr != nil { fmt.Println("merr:",merr.Error()) } else { fmt.Println(WriteMap(m)) } fmt.Println("\nDocValue(): tag") v,verr := DocValue(doc,"doc.tag") if verr != nil { fmt.Println("verr:",verr.Error()) } else { j, jerr := json.MarshalIndent(v,""," ") if jerr != nil { fmt.Println("jerr:",jerr.Error()) } else { fmt.Println(string(j)) } } fmt.Println("\nDocValue(): item:2 instance:2") v,verr = DocValue(doc,"doc.tag","item:2","instance:2") if verr != nil { fmt.Println("verr:",verr.Error()) } else { j, jerr := json.MarshalIndent(v,""," ") if jerr != nil { fmt.Println("jerr:",jerr.Error()) } else { fmt.Println(string(j)) } } } func TestStuff_2(t *testing.T) { fmt.Println("\n=================== TestStuff_2 ...") doc := ` val2 val2 val3` fmt.Println(doc) m,merr := DocToMap(doc) if merr != nil { fmt.Println("merr:",merr.Error()) } else { fmt.Println(WriteMap(m)) } fmt.Println("\nDocValue(): tag") v,verr := DocValue(doc,"tag") if verr != nil { fmt.Println("verr:",verr.Error()) } else { j, jerr := json.MarshalIndent(v,""," ") if jerr != nil { fmt.Println("jerr:",jerr.Error()) } else { fmt.Println(string(j)) } } fmt.Println("\nDocValue(): item:2 instance:2") v,verr = DocValue(doc,"tag","item:2","instance:2") if verr != nil { fmt.Println("verr:",verr.Error()) } else { j, jerr := json.MarshalIndent(v,""," ") if jerr != nil { fmt.Println("jerr:",jerr.Error()) } else { fmt.Println(string(j)) } } } func procMap(m map[string]interface{}) bool { fmt.Println("procMap:",WriteMap(m)) return true } func procMapToJson(m map[string]interface{}) bool { b,_ := json.MarshalIndent(m,""," ") fmt.Println("procMap:",string(b)) return true } func procErr(err error) bool { fmt.Println("procError err:",err.Error()) return true } func TestBulk(t *testing.T) { fmt.Println("\n=================== TestBulkBuffer ...") fmt.Println("\nBulk Message Processing Tests") // if err := XmlMsgsFromFile("x2m_bulk.xml",procMap,procErr); err != nil { if err := XmlMsgsFromFile("x2m_bulk.xml",procMapToJson,procErr); err != nil { fmt.Println("XmlMsgsFromFile err:",err.Error()) } } func TestTagAndKey(t *testing.T) { fmt.Println("\n=================== TestTagAndKey ...") var doc string doc = `
one
two.one two.two
one
two
` fmt.Println("\nTestTagAndKey()\n",doc) v,verr := ValuesForTag(doc,"parts") if verr != nil { fmt.Println("verr:",verr.Error()) } fmt.Println("tag: parts :: len:",len(v),"v:",v) v, _ = ValuesForTag(doc,"not_a_tag") if v == nil { fmt.Println("no 'not_a_tag' tag") } else { fmt.Println("key: not_a_tag :: len:",len(v),"v:",v) } m,merr := DocToMap(doc) if merr != nil { fmt.Println("merr:",merr.Error()) } v = ValuesForKey(m,"section") fmt.Println("key: section :: len:",len(v),"v:",v) v = ValuesForKey(m,"not_a_key") if v == nil { fmt.Println("no 'not_a_key' key") } else { fmt.Println("key: not_a-key :: len:",len(v),"v:",v) } } // ---------------- x2j_fast.go ---------------- /* func Test_F_DocToMap(t *testing.T) { var doc string = `
one
two.one two.two
one
two
` fmt.Println("\nF_DocToMap()") fmt.Println(doc) m,err := F_DocToMap(doc) if err != nil { fmt.Println("err:",err.Error()) } fmt.Println(WriteMap(m),"\n") } */ mxj-2.5.5/x2j-wrapper/x2j_test.xml000077500000000000000000000021731402172443100167720ustar00rootroot00000000000000 help me! Henry was a renegade Didn't like to play it safe One component at a time There's got to be a better way Oh, people came from miles around Searching for a steady job Welcome to the Motor Town Booming like an atom bomb Oh, Henry was the end of the story Then everything went wrong And we'll return it to its former glory But it just takes so long It's going to take a long time It's going to take it, but we'll make it one day It's going to take a long time It's going to take it, but we'll make it one day mxj-2.5.5/x2j-wrapper/x2j_valuesAt.go000077500000000000000000000057101402172443100174040ustar00rootroot00000000000000// Copyright 2012-2018 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // x2j_valuesAt.go: Extract values from an arbitrary XML doc that are at same level as "key". // Tag path can include wildcard characters. package x2j import ( "strings" "github.com/clbanning/mxj" ) // ------------------- sweep up everything for some point in the node tree --------------------- // ValuesAtTagPath - deliver all values at the same level of the document as the specified key. // See ValuesAtKeyPath(). // If there are no values for the path 'nil' is returned. // A return value of (nil, nil) means that there were no values and no errors parsing the doc. // 'doc' is the XML document // 'path' is a dot-separated path of tag nodes // 'getAttrs' can be set 'true' to return attribute values for "*"-terminated path // If a node is '*', then everything beyond is scanned for values. // E.g., "doc.books' might return a single value 'book' of type []interface{}, but // "doc.books.*" could return all the 'book' entries as []map[string]interface{}. // "doc.books.*.author" might return all the 'author' tag values as []string - or // "doc.books.*.author.lastname" might be required, depending on he schema. func ValuesAtTagPath(doc, path string, getAttrs ...bool) ([]interface{}, error) { var a bool if len(getAttrs) == 1 { a = getAttrs[0] } m, err := mxj.NewMapXml([]byte(doc)) if err != nil { return nil, err } v := ValuesAtKeyPath(m, path, a) return v, nil } // ValuesAtKeyPath - deliver all values at the same depth in a map[string]interface{} value // If v := ValuesAtKeyPath(m,"x.y.z") // then there exists a _,vv := range v // such that v.(map[string]interface{})[z] == ValuesFromKeyPath(m,"x.y.z") // If there are no values for the path 'nil' is returned. // 'm' is the map to be walked // 'path' is a dot-separated path of key values // 'getAttrs' can be set 'true' to return attribute values for "*"-terminated path // If a node is '*', then everything beyond is walked. // E.g., see ValuesFromTagPath documentation. func ValuesAtKeyPath(m map[string]interface{}, path string, getAttrs ...bool) []interface{} { var a bool if len(getAttrs) == 1 { a = getAttrs[0] } keys := strings.Split(path, ".") lenKeys := len(keys) ret := make([]interface{}, 0) if lenKeys > 1 { // use function in x2j_valuesFrom.go valuesFromKeyPath(&ret, m, keys[:lenKeys-1], a) if len(ret) == 0 { return nil } } else { ret = append(ret,interface{}(m)) } // scan the value set and see if key occurs key := keys[lenKeys-1] // wildcard is special if key == "*" { return ret } for _, v := range ret { switch v.(type) { case map[string]interface{}: if _, ok := v.(map[string]interface{})[key]; ok { return ret } } } // no instance of key in penultimate value set return nil } mxj-2.5.5/x2j-wrapper/x2j_valuesFrom.go000077500000000000000000000076061402172443100177510ustar00rootroot00000000000000// Copyright 2012-2018 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // x2j_valuesFrom.go: Extract values from an arbitrary XML doc. Tag path can include wildcard characters. package x2j import ( "strings" "github.com/clbanning/mxj" ) // ------------------- sweep up everything for some point in the node tree --------------------- // ValuesFromTagPath - deliver all values for a path node from a XML doc // If there are no values for the path 'nil' is returned. // A return value of (nil, nil) means that there were no values and no errors parsing the doc. // 'doc' is the XML document // 'path' is a dot-separated path of tag nodes // 'getAttrs' can be set 'true' to return attribute values for "*"-terminated path // If a node is '*', then everything beyond is scanned for values. // E.g., "doc.books' might return a single value 'book' of type []interface{}, but // "doc.books.*" could return all the 'book' entries as []map[string]interface{}. // "doc.books.*.author" might return all the 'author' tag values as []string - or // "doc.books.*.author.lastname" might be required, depending on he schema. func ValuesFromTagPath(doc, path string, getAttrs ...bool) ([]interface{}, error) { var a bool if len(getAttrs) == 1 { a = getAttrs[0] } m, err := mxj.NewMapXml([]byte(doc)) if err != nil { return nil, err } v := ValuesFromKeyPath(m, path, a) return v, nil } // ValuesFromKeyPath - deliver all values for a path node from a map[string]interface{} // If there are no values for the path 'nil' is returned. // 'm' is the map to be walked // 'path' is a dot-separated path of key values // 'getAttrs' can be set 'true' to return attribute values for "*"-terminated path // If a node is '*', then everything beyond is walked. // E.g., see ValuesFromTagPath documentation. func ValuesFromKeyPath(m map[string]interface{}, path string, getAttrs ...bool) []interface{} { var a bool if len(getAttrs) == 1 { a = getAttrs[0] } keys := strings.Split(path, ".") ret := make([]interface{}, 0) valuesFromKeyPath(&ret, m, keys, a) if len(ret) == 0 { return nil } return ret } func valuesFromKeyPath(ret *[]interface{}, m interface{}, keys []string, getAttrs bool) { lenKeys := len(keys) // load 'm' values into 'ret' // expand any lists if lenKeys == 0 { switch m.(type) { case map[string]interface{}: *ret = append(*ret, m) case []interface{}: for _, v := range m.([]interface{}) { *ret = append(*ret, v) } default: *ret = append(*ret, m) } return } // key of interest key := keys[0] switch key { case "*": // wildcard - scan all values switch m.(type) { case map[string]interface{}: for k, v := range m.(map[string]interface{}) { if string(k[:1]) == "-" && !getAttrs { // skip attributes? continue } valuesFromKeyPath(ret, v, keys[1:], getAttrs) } case []interface{}: for _, v := range m.([]interface{}) { switch v.(type) { // flatten out a list of maps - keys are processed case map[string]interface{}: for kk, vv := range v.(map[string]interface{}) { if string(kk[:1]) == "-" && !getAttrs { // skip attributes? continue } valuesFromKeyPath(ret, vv, keys[1:], getAttrs) } default: valuesFromKeyPath(ret, v, keys[1:], getAttrs) } } } default: // key - must be map[string]interface{} switch m.(type) { case map[string]interface{}: if v, ok := m.(map[string]interface{})[key]; ok { valuesFromKeyPath(ret, v, keys[1:], getAttrs) } case []interface{}: // may be buried in list for _, v := range m.([]interface{}) { switch v.(type) { case map[string]interface{}: if vv, ok := v.(map[string]interface{})[key]; ok { valuesFromKeyPath(ret, vv, keys[1:], getAttrs) } } } } } } mxj-2.5.5/x2j-wrapper/x2jat_test.go000077500000000000000000000073501402172443100171260ustar00rootroot00000000000000package x2j import ( "fmt" "testing" ) var doc1 = ` William H. Gaddis The Recognitions One of the great seminal American novels of the 20th century. Austin Tappan Wright Islandia An example of earlier 20th century American utopian fiction. John Hawkes The Beetle Leg A lyrical novel about the construction of Ft. Peck Dam in Montana. T.E. Porter King's Day A magical novella. ` var doc2 = ` William H. Gaddis The Recognitions One of the great seminal American novels of the 20th century. JR Won the National Book Award John Hawkes The Beetle Leg The Blood Oranges ` var msg1 = ` test This is a long cold winter ` var msg2 = ` test This is a long cold winter test2 I hope we have a cool summer, though ` func TestValuesAtKeyPath(t *testing.T) { fmt.Println("\n============================ x2jat_test.go") fmt.Println("\n=============== TestValuesAtKeyPath ...") fmt.Println("\nValuesAtKeyPath ... doc1#author") m, _ := DocToMap(doc1) ss := PathsForKey(m,"author") fmt.Println("ss:", ss) for _,v := range ss { vv := ValuesAtKeyPath(m,v,true) fmt.Println("vv:", vv) } fmt.Println("\nValuesAtKeyPath ... doc1#first_name") // m, _ := DocToMap(doc1) ss = PathsForKey(m,"first_name") fmt.Println("ss:", ss) for _,v := range ss { vv := ValuesAtKeyPath(m,v,true) fmt.Println("vv:", vv) } fmt.Println("\nGetKeyPaths...doc2#book") m, _ = DocToMap(doc2) ss = PathsForKey(m,"book") fmt.Println("ss:", ss) for _,v := range ss { vv := ValuesAtKeyPath(m,v,true) fmt.Println("vv:", vv) } s := PathForKeyShortest(m,"book") vv := ValuesAtKeyPath(m,s) fmt.Println("vv,shortest_path:",vv) fmt.Println("\nValuesAtKeyPath ... msg1#pub") m, _ = DocToMap(msg1) ss = PathsForKey(m,"pub") fmt.Println("ss:", ss) for _,v := range ss { vv := ValuesAtKeyPath(m,v,true) fmt.Println("vv:", vv) } fmt.Println("\nValuesAtKeyPath ... msg2#pub") m, _ = DocToMap(msg2) ss = PathsForKey(m,"pub") fmt.Println("ss:", ss) for _,v := range ss { vv := ValuesAtKeyPath(m,v,true) fmt.Println("vv:", vv) } } func TestValuesAtTagPath(t *testing.T) { fmt.Println("\n=============== TestValuesAtTagPath ...") fmt.Println("\nValuesAtTagPath ... doc1#author") m, _ := DocToMap(doc1) ss := PathsForKey(m,"author") fmt.Println("ss:", ss) for _,v := range ss { vv,_ := ValuesAtTagPath(doc1,v,true) fmt.Println("vv:", vv) } fmt.Println("\nValuesAtTagPath ... doc1#first_name") // m, _ := DocToMap(doc1) ss = PathsForKey(m,"first_name") fmt.Println("ss:", ss) for _,v := range ss { vv,_ := ValuesAtTagPath(doc1,v,true) fmt.Println("vv:", vv) } fmt.Println("\nValuesAtTagPath...doc2#book") m, _ = DocToMap(doc2) ss = PathsForKey(m,"book") fmt.Println("ss:", ss) for _,v := range ss { vv,_ := ValuesAtTagPath(doc2,v,true) fmt.Println("vv:", vv) } s := PathForKeyShortest(m,"book") vv,_ := ValuesAtTagPath(doc2,s) fmt.Println("vv,shortest_path:",vv) } mxj-2.5.5/x2j-wrapper/x2jfindPath_test.go000077500000000000000000000052261402172443100202570ustar00rootroot00000000000000package x2j import ( "fmt" "testing" ) var doc01 = ` William H. Gaddis The Recognitions One of the great seminal American novels of the 20th century. Austin Tappan Wright Islandia An example of earlier 20th century American utopian fiction. John Hawkes The Beetle Leg A lyrical novel about the construction of Ft. Peck Dam in Montana. T.E. Porter King's Day A magical novella. ` var doc02 = ` William H. Gaddis The Recognitions One of the great seminal American novels of the 20th century. JR Won the National Book Award John Hawkes The Beetle Leg The Blood Oranges ` // the basic demo/test case - a small bibliography with mixed element types func TestPathsForKey(t *testing.T) { fmt.Println("\n================================ x2jfindPath_test.go") fmt.Println("\n=============== TestPathsForKey ...") fmt.Println("\nPathsForKey... doc01#author") m, _ := DocToMap(doc01) ss := PathsForKey(m, "author") fmt.Println("ss:", ss) fmt.Println("\nPathsForKey... doc01#books") // m, _ := DocToMap(doc01) ss = PathsForKey(m, "books") fmt.Println("ss:", ss) fmt.Println("\nPathsForKey...doc02#book") m, _ = DocToMap(doc02) ss = PathsForKey(m, "book") fmt.Println("ss:", ss) fmt.Println("\nPathForKeyShortest...doc02#book") m, _ = DocToMap(doc02) s := PathForKeyShortest(m, "book") fmt.Println("s:", s) } // the basic demo/test case - a small bibliography with mixed element types func TestPathsForTag(t *testing.T) { fmt.Println("\n=============== TestPathsForTag ...") fmt.Println("\nPathsForTag... doc01#author") ss, _ := PathsForTag(doc01, "author") fmt.Println("ss:", ss) fmt.Println("\nPathsForTag... doc01#books") ss, _ = PathsForTag(doc01, "books") fmt.Println("ss:", ss) fmt.Println("\nPathsForTag...doc02#book") ss, _ = PathsForTag(doc02, "book") fmt.Println("ss:", ss) fmt.Println("\nPathForTagShortest...doc02#book") s, _ := PathForTagShortest(doc02, "book") fmt.Println("s:", s) } mxj-2.5.5/x2j-wrapper/x2jpath_test.go000077500000000000000000000100521402172443100174470ustar00rootroot00000000000000package x2j import ( "fmt" "testing" ) // the basic demo/test case - a small bibliography with mixed element types func TestValuesFromTagPath(t *testing.T) { var doc = ` William H. Gaddis The Recognitions One of the great seminal American novels of the 20th century. Austin Tappan Wright Islandia An example of earlier 20th century American utopian fiction. John Hawkes The Beetle Leg A lyrical novel about the construction of Ft. Peck Dam in Montana. T.E. Porter King's Day A magical novella. ` var doc2 = ` William H. Gaddis The Recognitions One of the great seminal American novels of the 20th century. ` fmt.Println("\nTestValuesFromTagPath()\n",doc) m,_ := DocToMap(doc) fmt.Println("map:",WriteMap(m)) v,_ := ValuesFromTagPath(doc,"doc.books") fmt.Println("path == doc.books: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } v,_ = ValuesFromTagPath(doc,"doc.books.*") fmt.Println("path == doc.books.*: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } v,_ = ValuesFromTagPath(doc,"doc.books.book") fmt.Println("path == doc.books.book: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } v,_ = ValuesFromTagPath(doc2,"doc.books.book") fmt.Println("doc == doc2 / path == doc.books.book: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } v,_ = ValuesFromTagPath(doc,"doc.books.book.*") fmt.Println("path == doc.books.book.*: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } v,_ = ValuesFromTagPath(doc2,"doc.books.book.*") fmt.Println("doc == doc2 / path == doc.books.book.*: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } v,_ = ValuesFromTagPath(doc,"doc.books.*.author") fmt.Println("path == doc.books.*.author: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } v,_ = ValuesFromTagPath(doc,"doc.*.*.author") fmt.Println("path == doc.*.*.author: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } v,_ = ValuesFromTagPath(doc,"doc.*.*.title") fmt.Println("path == doc.*.*.title: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } v,_ = ValuesFromTagPath(doc,"doc.*.*.*") fmt.Println("path == doc.*.*.*: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } v,_ = ValuesFromTagPath(doc,"doc.*.*.*.*") fmt.Println("path == doc.*.*.*.*: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } } // demo how to compensate for irregular tag labels in data // "netid" vs. "idnet" func TestValuesFromTagPath2(t *testing.T) { var doc1 = ` no default:text default:word ` var doc2 = ` yes default:text default:word ` var docs = []string{doc1,doc2} for n,doc := range docs { fmt.Println("\nTestValuesFromTagPath2(), iteration:",n,"\n",doc) m,_ := DocToMap(doc) fmt.Println("map:",WriteMap(m)) v,_ := ValuesFromTagPath(doc,"data.*") fmt.Println("\npath == data.*: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } for key,val := range v[0].(map[string]interface{}) { fmt.Println("\t",key,":",val) } v,_ = ValuesFromTagPath(doc,"data.*.*") fmt.Println("\npath == data.*.*: len(v):",len(v)) for key,val := range v { fmt.Println(key,":",val) } } } mxj-2.5.5/x2j-wrapper/x2junmarshal_test.go000077500000000000000000000030221402172443100205040ustar00rootroot00000000000000package x2j import ( "fmt" "testing" "encoding/xml" ) func TestUnmarshal(t *testing.T) { var doc = []byte(` Mayer Hawthorne A Long Time Henry was a renegade Didn't like to play it safe `) fmt.Println("\nUnmarshal test ... *map[string]interface{}, *string") m := make(map[string]interface{},0) err := Unmarshal(doc,&m) if err != nil { fmt.Println("err:",err.Error()) } fmt.Println("m:",m) var s string err = Unmarshal(doc,&s) if err != nil { fmt.Println("err:",err.Error()) } fmt.Println("s:",s) } func TestStructValue(t *testing.T) { var doc = []byte(`clbanning
unknown
`) type Info struct { XMLName xml.Name `xml:"info"` Name string `xml:"name"` Address string `xml:"address"` } var myInfo Info fmt.Println("\nUnmarshal test ... struct:",string(doc)) err := Unmarshal(doc,&myInfo) if err != nil { fmt.Println("err:",err.Error()) } else { fmt.Printf("myInfo: %+v\n",myInfo) } } func TestMapValue(t *testing.T) { var doc = ` Mayer Hawthorne A Long Time Henry was a renegade Didn't like to play it safe ` fmt.Println("\nTestMapValue of doc.song.verse w/ len(attrs) == 0.") fmt.Println("doc:",doc) v,err := DocValue(doc,"doc.song.verse") if err != nil { fmt.Println("err:",err.Error()) } fmt.Println("result:",v) } mxj-2.5.5/x2j-wrapper/x2m_bulk.go000077500000000000000000000065011402172443100165570ustar00rootroot00000000000000// Copyright 2012-2018 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // x2m_bulk.go: Process files with multiple XML messages. package x2j import ( "bytes" "io" "os" "regexp" "github.com/clbanning/mxj" ) // XmlMsgsFromFile() // 'fname' is name of file // 'phandler' is the map processing handler. Return of 'false' stops further processing. // 'ehandler' is the parsing error handler. Return of 'false' stops further processing and returns error. // Note: phandler() and ehandler() calls are blocking, so reading and processing of messages is serialized. // This means that you can stop reading the file on error or after processing a particular message. // To have reading and handling run concurrently, pass arguments to a go routine in handler and return true. func XmlMsgsFromFile(fname string, phandler func(map[string]interface{})(bool), ehandler func(error)(bool), recast ...bool) error { var r bool if len(recast) == 1 { r = recast[0] } fi, fierr := os.Stat(fname) if fierr != nil { return fierr } fh, fherr := os.Open(fname) if fherr != nil { return fherr } defer fh.Close() buf := make([]byte,fi.Size()) _, rerr := fh.Read(buf) if rerr != nil { return rerr } doc := string(buf) // xml.Decoder doesn't properly handle whitespace in some doc // see songTextString.xml test case ... reg,_ := regexp.Compile("[ \t\n\r]*<") doc = reg.ReplaceAllString(doc,"<") b := bytes.NewBufferString(doc) for { m, merr := mxj.NewMapXmlReader(b,r) if merr != nil && merr != io.EOF { if ok := ehandler(merr); !ok { // caused reader termination return merr } } if m != nil { if ok := phandler(m); !ok { break } } if merr == io.EOF { break } } return nil } // XmlBufferToMap - process XML message from a bytes.Buffer // 'b' is the buffer // Optional argument 'recast' coerces map values to float64 or bool where possible. func XmlBufferToMap(b *bytes.Buffer,recast ...bool) (map[string]interface{},error) { var r bool if len(recast) == 1 { r = recast[0] } return mxj.NewMapXmlReader(b, r) } // ============================= io.Reader version for stream processing ====================== // XmlMsgsFromReader() - io.Reader version of XmlMsgsFromFile // 'rdr' is an io.Reader for an XML message (stream) // 'phandler' is the map processing handler. Return of 'false' stops further processing. // 'ehandler' is the parsing error handler. Return of 'false' stops further processing and returns error. // Note: phandler() and ehandler() calls are blocking, so reading and processing of messages is serialized. // This means that you can stop reading the file on error or after processing a particular message. // To have reading and handling run concurrently, pass arguments to a go routine in handler and return true. func XmlMsgsFromReader(rdr io.Reader, phandler func(map[string]interface{})(bool), ehandler func(error)(bool), recast ...bool) error { var r bool if len(recast) == 1 { r = recast[0] } for { m, merr := ToMap(rdr,r) if merr != nil && merr != io.EOF { if ok := ehandler(merr); !ok { // caused reader termination return merr } } if m != nil { if ok := phandler(m); !ok { break } } if merr == io.EOF { break } } return nil } mxj-2.5.5/x2j-wrapper/x2m_bulk.xml000077500000000000000000000047541402172443100167620ustar00rootroot00000000000000 help me! Henry was a renegade Didn't like to play it safe One component at a time There's got to be a better way Oh, people came from miles around Searching for a steady job Welcome to the Motor Town Booming like an atom bomb Oh, Henry was the end of the story Then everything went wrong And we'll return it to its former glory But it just takes so long It's going to take a long time It's going to take it, but we'll make it one day It's going to take a long time It's going to take it, but we'll make it one day help me! Henry was a renegade Didn't like to play it safe One component at a time There's got to be a better way Oh, people came from miles around Searching for a steady job Welcome to the Motor Town Booming like an atom bomb help me! It's going to take a long time It's going to take it, but we'll make it one day It's going to take a long time It's going to take it, but we'll make it one day help me! It's going to take a long time It's going to take it, but we'll make it one day It's going to take a long time It's going to take it, but we'll make it one day mxj-2.5.5/x2j-wrapper/xml.go000066400000000000000000000005421402172443100156300ustar00rootroot00000000000000// Copyright 2012-2018 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file package x2j var castNanInf bool // Cast "Nan", "Inf", "-Inf" XML values to 'float64'. // By default, these values will be decoded as 'string'. func CastNanInf(b bool) { castNanInf = b } mxj-2.5.5/x2j/000077500000000000000000000000001402172443100130225ustar00rootroot00000000000000mxj-2.5.5/x2j/x2j.go000066400000000000000000000116721402172443100140630ustar00rootroot00000000000000// Copyright 2012-2014 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // x2j - For (mostly) backwards compatibility with legacy x2j package. // Wrappers for end-to-end XML to JSON transformation and value manipulation. package x2j import ( . "github.com/clbanning/mxj" "io" ) // FromXml() --> map[string]interface{} func XmlToMap(xmlVal []byte) (map[string]interface{}, error) { m, err := NewMapXml(xmlVal) if err != nil { return nil, err } return map[string]interface{}(m), nil } // map[string]interface{} --> ToXml() func MapToXml(m map[string]interface{}) ([]byte, error) { return Map(m).Xml() } // FromXml() --> ToJson(). func XmlToJson(xmlVal []byte, safeEncoding ...bool) ([]byte, error) { m, err := NewMapXml(xmlVal) if err != nil { return nil, err } return m.Json(safeEncoding...) } // FromXml() --> ToJsonWriterRaw(). func XmlToJsonWriter(xmlVal []byte, jsonWriter io.Writer, safeEncoding ...bool) ([]byte, error) { m, err := NewMapXml(xmlVal) if err != nil { return nil, err } return m.JsonWriterRaw(jsonWriter, safeEncoding...) } // FromXmlReaderRaw() --> ToJson(). func XmlReaderToJson(xmlReader io.Reader, safeEncoding ...bool) ([]byte, []byte, error) { m, xraw, err := NewMapXmlReaderRaw(xmlReader) if err != nil { return xraw, nil, err } j, jerr := m.Json(safeEncoding...) return xraw, j, jerr } // FromXmlReader() --> ToJsonWriter(). Handy for bulk transformation of documents. func XmlReaderToJsonWriter(xmlReader io.Reader, jsonWriter io.Writer, safeEncoding ...bool) ([]byte, []byte, error) { m, xraw, err := NewMapXmlReaderRaw(xmlReader) if err != nil { return xraw, nil, err } jraw, jerr := m.JsonWriterRaw(jsonWriter, safeEncoding...) return xraw, jraw, jerr } // XML wrappers for Map methods implementing tag path and value functions. // Wrap PathsForKey for XML. func XmlPathsForTag(xmlVal []byte, tag string) ([]string, error) { m, err := NewMapXml(xmlVal) if err != nil { return nil, err } paths := m.PathsForKey(tag) return paths, nil } // Wrap PathForKeyShortest for XML. func XmlPathForTagShortest(xmlVal []byte, tag string) (string, error) { m, err := NewMapXml(xmlVal) if err != nil { return "", err } path := m.PathForKeyShortest(tag) return path, nil } // Wrap ValuesForKey for XML. // 'attrs' are key:value pairs for attributes, where key is attribute label prepended with a hypen, '-'. func XmlValuesForTag(xmlVal []byte, tag string, attrs ...string) ([]interface{}, error) { m, err := NewMapXml(xmlVal) if err != nil { return nil, err } return m.ValuesForKey(tag, attrs...) } // Wrap ValuesForPath for XML. // 'attrs' are key:value pairs for attributes, where key is attribute label prepended with a hypen, '-'. func XmlValuesForPath(xmlVal []byte, path string, attrs ...string) ([]interface{}, error) { m, err := NewMapXml(xmlVal) if err != nil { return nil, err } return m.ValuesForPath(path, attrs...) } // Wrap UpdateValuesForPath for XML // 'xmlVal' is XML value // 'newTagValue' is the value to replace an existing value at the end of 'path' // 'path' is the dot-notation path with the tag whose value is to be replaced at the end // (can include wildcard character, '*') // 'subkeys' are key:value pairs of tag:values that must match for the tag func XmlUpdateValsForPath(xmlVal []byte, newTagValue interface{}, path string, subkeys ...string) ([]byte, error) { m, err := NewMapXml(xmlVal) if err != nil { return nil, err } _, err = m.UpdateValuesForPath(newTagValue, path, subkeys...) if err != nil { return nil, err } return m.Xml() } // Wrap NewMap for XML and return as XML // 'xmlVal' is an XML value // 'tagpairs' are "oldTag:newTag" values that conform to 'keypairs' in (Map)NewMap. func XmlNewXml(xmlVal []byte, tagpairs ...string) ([]byte, error) { m, err := NewMapXml(xmlVal) if err != nil { return nil, err } n, err := m.NewMap(tagpairs...) if err != nil { return nil, err } return n.Xml() } // Wrap NewMap for XML and return as JSON // 'xmlVal' is an XML value // 'tagpairs' are "oldTag:newTag" values that conform to 'keypairs' in (Map)NewMap. func XmlNewJson(xmlVal []byte, tagpairs ...string) ([]byte, error) { m, err := NewMapXml(xmlVal) if err != nil { return nil, err } n, err := m.NewMap(tagpairs...) if err != nil { return nil, err } return n.Json() } // Wrap LeafNodes for XML. // 'xmlVal' is an XML value func XmlLeafNodes(xmlVal []byte) ([]LeafNode, error) { m, err := NewMapXml(xmlVal) if err != nil { return nil, err } return m.LeafNodes(), nil } // Wrap LeafValues for XML. // 'xmlVal' is an XML value func XmlLeafValues(xmlVal []byte) ([]interface{}, error) { m, err := NewMapXml(xmlVal) if err != nil { return nil, err } return m.LeafValues(), nil } // Wrap LeafPath for XML. // 'xmlVal' is an XML value func XmlLeafPath(xmlVal []byte) ([]string, error) { m, err := NewMapXml(xmlVal) if err != nil { return nil, err } return m.LeafPaths(), nil } mxj-2.5.5/xml.go000066400000000000000000001207761402172443100134630ustar00rootroot00000000000000// Copyright 2012-2016, 2018-2019 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // xml.go - basically the core of X2j for map[string]interface{} values. // NewMapXml, NewMapXmlReader, mv.Xml, mv.XmlWriter // see x2j and j2x for wrappers to provide end-to-end transformation of XML and JSON messages. package mxj import ( "bytes" "encoding/json" "encoding/xml" "errors" "fmt" "io" "reflect" "sort" "strconv" "strings" "time" ) // ------------------- NewMapXml & NewMapXmlReader ... ------------------------- // If XmlCharsetReader != nil, it will be used to decode the XML, if required. // Note: if CustomDecoder != nil, then XmlCharsetReader is ignored; // set the CustomDecoder attribute instead. // import ( // charset "code.google.com/p/go-charset/charset" // github.com/clbanning/mxj // ) // ... // mxj.XmlCharsetReader = charset.NewReader // m, merr := mxj.NewMapXml(xmlValue) var XmlCharsetReader func(charset string, input io.Reader) (io.Reader, error) // NewMapXml - convert a XML doc into a Map // (This is analogous to unmarshalling a JSON string to map[string]interface{} using json.Unmarshal().) // If the optional argument 'cast' is 'true', then values will be converted to boolean or float64 if possible. // // Converting XML to JSON is a simple as: // ... // mapVal, merr := mxj.NewMapXml(xmlVal) // if merr != nil { // // handle error // } // jsonVal, jerr := mapVal.Json() // if jerr != nil { // // handle error // } // // NOTES: // 1. Declarations, directives, process instructions and comments are NOT parsed. // 2. The 'xmlVal' will be parsed looking for an xml.StartElement, so BOM and other // extraneous xml.CharData will be ignored unless io.EOF is reached first. // 3. If CoerceKeysToLower() has been called, then all key values will be lower case. // 4. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. // 5. If DisableTrimWhiteSpace(b bool) has been called, then all values will be trimmed or not. 'true' by default. func NewMapXml(xmlVal []byte, cast ...bool) (Map, error) { var r bool if len(cast) == 1 { r = cast[0] } return xmlToMap(xmlVal, r) } // Get next XML doc from an io.Reader as a Map value. Returns Map value. // NOTES: // 1. Declarations, directives, process instructions and comments are NOT parsed. // 2. The 'xmlReader' will be parsed looking for an xml.StartElement, so BOM and other // extraneous xml.CharData will be ignored unless io.EOF is reached first. // 3. If CoerceKeysToLower() has been called, then all key values will be lower case. // 4. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. func NewMapXmlReader(xmlReader io.Reader, cast ...bool) (Map, error) { var r bool if len(cast) == 1 { r = cast[0] } // We need to put an *os.File reader in a ByteReader or the xml.NewDecoder // will wrap it in a bufio.Reader and seek on the file beyond where the // xml.Decoder parses! if _, ok := xmlReader.(io.ByteReader); !ok { xmlReader = myByteReader(xmlReader) // see code at EOF } // build the map return xmlReaderToMap(xmlReader, r) } // Get next XML doc from an io.Reader as a Map value. Returns Map value and slice with the raw XML. // NOTES: // 1. Declarations, directives, process instructions and comments are NOT parsed. // 2. Due to the implementation of xml.Decoder, the raw XML off the reader is buffered to []byte // using a ByteReader. If the io.Reader is an os.File, there may be significant performance impact. // See the examples - getmetrics1.go through getmetrics4.go - for comparative use cases on a large // data set. If the io.Reader is wrapping a []byte value in-memory, however, such as http.Request.Body // you CAN use it to efficiently unmarshal a XML doc and retrieve the raw XML in a single call. // 3. The 'raw' return value may be larger than the XML text value. // 4. The 'xmlReader' will be parsed looking for an xml.StartElement, so BOM and other // extraneous xml.CharData will be ignored unless io.EOF is reached first. // 5. If CoerceKeysToLower() has been called, then all key values will be lower case. // 6. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. func NewMapXmlReaderRaw(xmlReader io.Reader, cast ...bool) (Map, []byte, error) { var r bool if len(cast) == 1 { r = cast[0] } // create TeeReader so we can retrieve raw XML buf := make([]byte, 0) wb := bytes.NewBuffer(buf) trdr := myTeeReader(xmlReader, wb) // see code at EOF m, err := xmlReaderToMap(trdr, r) // retrieve the raw XML that was decoded b := wb.Bytes() if err != nil { return nil, b, err } return m, b, nil } // xmlReaderToMap() - parse a XML io.Reader to a map[string]interface{} value func xmlReaderToMap(rdr io.Reader, r bool) (map[string]interface{}, error) { // parse the Reader p := xml.NewDecoder(rdr) if CustomDecoder != nil { useCustomDecoder(p) } else { p.CharsetReader = XmlCharsetReader } return xmlToMapParser("", nil, p, r) } // xmlToMap - convert a XML doc into map[string]interface{} value func xmlToMap(doc []byte, r bool) (map[string]interface{}, error) { b := bytes.NewReader(doc) p := xml.NewDecoder(b) if CustomDecoder != nil { useCustomDecoder(p) } else { p.CharsetReader = XmlCharsetReader } return xmlToMapParser("", nil, p, r) } // ===================================== where the work happens ============================= // PrependAttrWithHyphen. Prepend attribute tags with a hyphen. // Default is 'true'. (Not applicable to NewMapXmlSeq(), mv.XmlSeq(), etc.) // Note: // If 'false', unmarshaling and marshaling is not symmetric. Attributes will be // marshal'd as attr and may be part of a list. func PrependAttrWithHyphen(v bool) { if v { attrPrefix = "-" lenAttrPrefix = len(attrPrefix) return } attrPrefix = "" lenAttrPrefix = len(attrPrefix) } // Include sequence id with inner tags. - per Sean Murphy, murphysean84@gmail.com. var includeTagSeqNum bool // IncludeTagSeqNum - include a "_seq":N key:value pair with each inner tag, denoting // its position when parsed. This is of limited usefulness, since list values cannot // be tagged with "_seq" without changing their depth in the Map. // So THIS SHOULD BE USED WITH CAUTION - see the test cases. Here's a sample of what // you get. /* hello parses as: { Obj:{ "-c":"la", "-h":"da", "-x":"dee", "intObj":[ { "-id"="3", "_seq":"0" // if mxj.Cast is passed, then: "_seq":0 }, { "-id"="2", "_seq":"2" }], "intObj1":{ "-id":"1", "_seq":"1" }, "StrObj":{ "#text":"hello", // simple element value gets "#text" tag "_seq":"3" } } } */ func IncludeTagSeqNum(b ...bool) { if len(b) == 0 { includeTagSeqNum = !includeTagSeqNum } else if len(b) == 1 { includeTagSeqNum = b[0] } } // all keys will be "lower case" var lowerCase bool // Coerce all tag values to keys in lower case. This is useful if you've got sources with variable // tag capitalization, and you want to use m.ValuesForKeys(), etc., with the key or path spec // in lower case. // CoerceKeysToLower() will toggle the coercion flag true|false - on|off // CoerceKeysToLower(true|false) will set the coercion flag on|off // // NOTE: only recognized by NewMapXml, NewMapXmlReader, and NewMapXmlReaderRaw functions as well as // the associated HandleXmlReader and HandleXmlReaderRaw. func CoerceKeysToLower(b ...bool) { if len(b) == 0 { lowerCase = !lowerCase } else if len(b) == 1 { lowerCase = b[0] } } // disableTrimWhiteSpace sets if the white space should be removed or not var disableTrimWhiteSpace bool var trimRunes = "\t\r\b\n " // DisableTrimWhiteSpace set if the white space should be trimmed or not. By default white space is always trimmed. If // no argument is provided, trim white space will be disabled. func DisableTrimWhiteSpace(b ...bool) { if len(b) == 0 { disableTrimWhiteSpace = true } else { disableTrimWhiteSpace = b[0] } if disableTrimWhiteSpace { trimRunes = "\t\r\b\n" } else { trimRunes = "\t\r\b\n " } } // 25jun16: Allow user to specify the "prefix" character for XML attribute key labels. // We do this by replacing '`' constant with attrPrefix var, replacing useHyphen with attrPrefix = "", // and adding a SetAttrPrefix(s string) function. var attrPrefix string = `-` // the default var lenAttrPrefix int = 1 // the default // SetAttrPrefix changes the default, "-", to the specified value, s. // SetAttrPrefix("") is the same as PrependAttrWithHyphen(false). // (Not applicable for NewMapXmlSeq(), mv.XmlSeq(), etc.) func SetAttrPrefix(s string) { attrPrefix = s lenAttrPrefix = len(attrPrefix) } // 18jan17: Allows user to specify if the map keys should be in snake case instead // of the default hyphenated notation. var snakeCaseKeys bool // CoerceKeysToSnakeCase changes the default, false, to the specified value, b. // Note: the attribute prefix will be a hyphen, '-', or what ever string value has // been specified using SetAttrPrefix. func CoerceKeysToSnakeCase(b ...bool) { if len(b) == 0 { snakeCaseKeys = !snakeCaseKeys } else if len(b) == 1 { snakeCaseKeys = b[0] } } // 10jan19: use of pull request #57 should be conditional - legacy code assumes // numeric values are float64. var castToInt bool // CastValuesToInt tries to coerce numeric valus to int64 or uint64 instead of the // default float64. Repeated calls with no argument will toggle this on/off, or this // handling will be set with the value of 'b'. func CastValuesToInt(b ...bool) { if len(b) == 0 { castToInt = !castToInt } else if len(b) == 1 { castToInt = b[0] } } // 05feb17: support processing XMPP streams (issue #36) var handleXMPPStreamTag bool // HandleXMPPStreamTag causes decoder to parse XMPP elements. // If called with no argument, XMPP stream element handling is toggled on/off. // (See xmppStream_test.go for example.) // If called with NewMapXml, NewMapXmlReader, New MapXmlReaderRaw the "stream" // element will be returned as: // map["stream"]interface{}{map[-]interface{}}. // If called with NewMapSeq, NewMapSeqReader, NewMapSeqReaderRaw the "stream" // element will be returned as: // map["stream:stream"]interface{}{map["#attr"]interface{}{map[string]interface{}}} // where the "#attr" values have "#text" and "#seq" keys. (See NewMapXmlSeq.) func HandleXMPPStreamTag(b ...bool) { if len(b) == 0 { handleXMPPStreamTag = !handleXMPPStreamTag } else if len(b) == 1 { handleXMPPStreamTag = b[0] } } // 21jan18 - decode all values as map["#text":value] (issue #56) var decodeSimpleValuesAsMap bool // DecodeSimpleValuesAsMap forces all values to be decoded as map["#text":]. // If called with no argument, the decoding is toggled on/off. // // By default the NewMapXml functions decode simple values without attributes as // map[:]. This function causes simple values without attributes to be // decoded the same as simple values with attributes - map[:map["#text":]]. func DecodeSimpleValuesAsMap(b ...bool) { if len(b) == 0 { decodeSimpleValuesAsMap = !decodeSimpleValuesAsMap } else if len(b) == 1 { decodeSimpleValuesAsMap = b[0] } } // xmlToMapParser (2015.11.12) - load a 'clean' XML doc into a map[string]interface{} directly. // A refactoring of xmlToTreeParser(), markDuplicate() and treeToMap() - here, all-in-one. // We've removed the intermediate *node tree with the allocation and subsequent rescanning. func xmlToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[string]interface{}, error) { if lowerCase { skey = strings.ToLower(skey) } if snakeCaseKeys { skey = strings.Replace(skey, "-", "_", -1) } // NOTE: all attributes and sub-elements parsed into 'na', 'na' is returned as value for 'skey' in 'n'. // Unless 'skey' is a simple element w/o attributes, in which case the xml.CharData value is the value. var n, na map[string]interface{} var seq int // for includeTagSeqNum // Allocate maps and load attributes, if any. // NOTE: on entry from NewMapXml(), etc., skey=="", and we fall through // to get StartElement then recurse with skey==xml.StartElement.Name.Local // where we begin allocating map[string]interface{} values 'n' and 'na'. if skey != "" { n = make(map[string]interface{}) // old n na = make(map[string]interface{}) // old n.nodes if len(a) > 0 { for _, v := range a { if snakeCaseKeys { v.Name.Local = strings.Replace(v.Name.Local, "-", "_", -1) } var key string key = attrPrefix + v.Name.Local if lowerCase { key = strings.ToLower(key) } if xmlEscapeCharsDecoder { // per issue#84 v.Value = escapeChars(v.Value) } na[key] = cast(v.Value, r, key) } } } // Return XMPP message. if handleXMPPStreamTag && skey == "stream" { n[skey] = na return n, nil } for { t, err := p.Token() if err != nil { if err != io.EOF { return nil, errors.New("xml.Decoder.Token() - " + err.Error()) } return nil, err } switch t.(type) { case xml.StartElement: tt := t.(xml.StartElement) // First call to xmlToMapParser() doesn't pass xml.StartElement - the map key. // So when the loop is first entered, the first token is the root tag along // with any attributes, which we process here. // // Subsequent calls to xmlToMapParser() will pass in tag+attributes for // processing before getting the next token which is the element value, // which is done above. if skey == "" { return xmlToMapParser(tt.Name.Local, tt.Attr, p, r) } // If not initializing the map, parse the element. // len(nn) == 1, necessarily - it is just an 'n'. nn, err := xmlToMapParser(tt.Name.Local, tt.Attr, p, r) if err != nil { return nil, err } // The nn map[string]interface{} value is a na[nn_key] value. // We need to see if nn_key already exists - means we're parsing a list. // This may require converting na[nn_key] value into []interface{} type. // First, extract the key:val for the map - it's a singleton. // Note: // * if CoerceKeysToLower() called, then key will be lower case. // * if CoerceKeysToSnakeCase() called, then key will be converted to snake case. var key string var val interface{} for key, val = range nn { break } // IncludeTagSeqNum requests that the element be augmented with a "_seq" sub-element. // In theory, we don't need this if len(na) == 1. But, we don't know what might // come next - we're only parsing forward. So if you ask for 'includeTagSeqNum' you // get it on every element. (Personally, I never liked this, but I added it on request // and did get a $50 Amazon gift card in return - now we support it for backwards compatibility!) if includeTagSeqNum { switch val.(type) { case []interface{}: // noop - There's no clean way to handle this w/o changing message structure. case map[string]interface{}: val.(map[string]interface{})["_seq"] = seq // will overwrite an "_seq" XML tag seq++ case interface{}: // a non-nil simple element: string, float64, bool v := map[string]interface{}{"#text": val} v["_seq"] = seq seq++ val = v } } // 'na' holding sub-elements of n. // See if 'key' already exists. // If 'key' exists, then this is a list, if not just add key:val to na. if v, ok := na[key]; ok { var a []interface{} switch v.(type) { case []interface{}: a = v.([]interface{}) default: // anything else - note: v.(type) != nil a = []interface{}{v} } a = append(a, val) na[key] = a } else { na[key] = val // save it as a singleton } case xml.EndElement: // len(n) > 0 if this is a simple element w/o xml.Attrs - see xml.CharData case. if len(n) == 0 { // If len(na)==0 we have an empty element == ""; // it has no xml.Attr nor xml.CharData. // Note: in original node-tree parser, val defaulted to ""; // so we always had the default if len(node.nodes) == 0. if len(na) > 0 { n[skey] = na } else { n[skey] = "" // empty element } } else if len(n) == 1 && len(na) > 0 { // it's a simple element w/ no attributes w/ subelements for _, v := range n { na["#text"] = v } n[skey] = na } return n, nil case xml.CharData: // clean up possible noise tt := strings.Trim(string(t.(xml.CharData)), trimRunes) if xmlEscapeCharsDecoder { // issue#84 tt = escapeChars(tt) } if len(tt) > 0 { if len(na) > 0 || decodeSimpleValuesAsMap { na["#text"] = cast(tt, r, "#text") } else if skey != "" { n[skey] = cast(tt, r, skey) } else { // per Adrian (http://www.adrianlungu.com/) catch stray text // in decoder stream - // https://github.com/clbanning/mxj/pull/14#issuecomment-182816374 // NOTE: CharSetReader must be set to non-UTF-8 CharSet or you'll get // a p.Token() decoding error when the BOM is UTF-16 or UTF-32. continue } } default: // noop } } } var castNanInf bool // Cast "Nan", "Inf", "-Inf" XML values to 'float64'. // By default, these values will be decoded as 'string'. func CastNanInf(b ...bool) { if len(b) == 0 { castNanInf = !castNanInf } else if len(b) == 1 { castNanInf = b[0] } } // cast - try to cast string values to bool or float64 // 't' is the tag key that can be checked for 'not-casting' func cast(s string, r bool, t string) interface{} { if checkTagToSkip != nil && t != "" && checkTagToSkip(t) { // call the check-function here with 't[0]' // if 'true' return s return s } if r { // handle nan and inf if !castNanInf { switch strings.ToLower(s) { case "nan", "inf", "-inf": return s } } // handle numeric strings ahead of boolean if castToInt { if f, err := strconv.ParseInt(s, 10, 64); err == nil { return f } if f, err := strconv.ParseUint(s, 10, 64); err == nil { return f } } if castToFloat { if f, err := strconv.ParseFloat(s, 64); err == nil { return f } } // ParseBool treats "1"==true & "0"==false, we've already scanned those // values as float64. See if value has 't' or 'f' as initial screen to // minimize calls to ParseBool; also, see if len(s) < 6. if castToBool { if len(s) > 0 && len(s) < 6 { switch s[:1] { case "t", "T", "f", "F": if b, err := strconv.ParseBool(s); err == nil { return b } } } } } return s } // pull request, #59 var castToFloat = true // CastValuesToFloat can be used to skip casting to float64 when // "cast" argument is 'true' in NewMapXml, etc. // Default is true. func CastValuesToFloat(b ...bool) { if len(b) == 0 { castToFloat = !castToFloat } else if len(b) == 1 { castToFloat = b[0] } } var castToBool = true // CastValuesToBool can be used to skip casting to bool when // "cast" argument is 'true' in NewMapXml, etc. // Default is true. func CastValuesToBool(b ...bool) { if len(b) == 0 { castToBool = !castToBool } else if len(b) == 1 { castToBool = b[0] } } // checkTagToSkip - switch to address Issue #58 var checkTagToSkip func(string) bool // SetCheckTagToSkipFunc registers function to test whether the value // for a tag should be cast to bool or float64 when "cast" argument is 'true'. // (Dot tag path notation is not supported.) // NOTE: key may be "#text" if it's a simple element with attributes // or "decodeSimpleValuesAsMap == true". // NOTE: does not apply to NewMapXmlSeq... functions. func SetCheckTagToSkipFunc(fn func(string) bool) { checkTagToSkip = fn } // ------------------ END: NewMapXml & NewMapXmlReader ------------------------- // ------------------ mv.Xml & mv.XmlWriter - from j2x ------------------------ const ( DefaultRootTag = "doc" ) var useGoXmlEmptyElemSyntax bool // XmlGoEmptyElemSyntax() - rather than . // Go's encoding/xml package marshals empty XML elements as . By default this package // encodes empty elements as . If you're marshaling Map values that include structures // (which are passed to xml.Marshal for encoding), this will let you conform to the standard package. func XmlGoEmptyElemSyntax() { useGoXmlEmptyElemSyntax = true } // XmlDefaultEmptyElemSyntax() - rather than . // Return XML encoding for empty elements to the default package setting. // Reverses effect of XmlGoEmptyElemSyntax(). func XmlDefaultEmptyElemSyntax() { useGoXmlEmptyElemSyntax = false } // ------- issue #88 ---------- // xmlCheckIsValid set switch to force decoding the encoded XML to // see if it is valid XML. var xmlCheckIsValid bool // XmlCheckIsValid forces the encoded XML to be checked for validity. func XmlCheckIsValid(b ...bool) { if len(b) == 1 { xmlCheckIsValid = b[0] return } xmlCheckIsValid = !xmlCheckIsValid } // Encode a Map as XML. The companion of NewMapXml(). // The following rules apply. // - The key label "#text" is treated as the value for a simple element with attributes. // - Map keys that begin with a hyphen, '-', are interpreted as attributes. // It is an error if the attribute doesn't have a []byte, string, number, or boolean value. // - Map value type encoding: // > string, bool, float64, int, int32, int64, float32: per "%v" formating // > []bool, []uint8: by casting to string // > structures, etc.: handed to xml.Marshal() - if there is an error, the element // value is "UNKNOWN" // - Elements with only attribute values or are null are terminated using "/>". // - If len(mv) == 1 and no rootTag is provided, then the map key is used as the root tag, possible. // Thus, `{ "key":"value" }` encodes as "value". // - To encode empty elements in a syntax consistent with encoding/xml call UseGoXmlEmptyElementSyntax(). // The attributes tag=value pairs are alphabetized by "tag". Also, when encoding map[string]interface{} values - // complex elements, etc. - the key:value pairs are alphabetized by key so the resulting tags will appear sorted. func (mv Map) Xml(rootTag ...string) ([]byte, error) { m := map[string]interface{}(mv) var err error b := new(bytes.Buffer) p := new(pretty) // just a stub if len(m) == 1 && len(rootTag) == 0 { for key, value := range m { // if it an array, see if all values are map[string]interface{} // we force a new root tag if we'll end up with no key:value in the list // so: key:[string_val, bool:true] --> string_valtrue switch value.(type) { case []interface{}: for _, v := range value.([]interface{}) { switch v.(type) { case map[string]interface{}: // noop default: // anything else err = marshalMapToXmlIndent(false, b, DefaultRootTag, m, p) goto done } } } err = marshalMapToXmlIndent(false, b, key, value, p) } } else if len(rootTag) == 1 { err = marshalMapToXmlIndent(false, b, rootTag[0], m, p) } else { err = marshalMapToXmlIndent(false, b, DefaultRootTag, m, p) } done: if xmlCheckIsValid { d := xml.NewDecoder(bytes.NewReader(b.Bytes())) for { _, err = d.Token() if err == io.EOF { err = nil break } else if err != nil { return nil, err } } } return b.Bytes(), err } // The following implementation is provided only for symmetry with NewMapXmlReader[Raw] // The names will also provide a key for the number of return arguments. // Writes the Map as XML on the Writer. // See Xml() for encoding rules. func (mv Map) XmlWriter(xmlWriter io.Writer, rootTag ...string) error { x, err := mv.Xml(rootTag...) if err != nil { return err } _, err = xmlWriter.Write(x) return err } // Writes the Map as XML on the Writer. []byte is the raw XML that was written. // See Xml() for encoding rules. /* func (mv Map) XmlWriterRaw(xmlWriter io.Writer, rootTag ...string) ([]byte, error) { x, err := mv.Xml(rootTag...) if err != nil { return x, err } _, err = xmlWriter.Write(x) return x, err } */ // Writes the Map as pretty XML on the Writer. // See Xml() for encoding rules. func (mv Map) XmlIndentWriter(xmlWriter io.Writer, prefix, indent string, rootTag ...string) error { x, err := mv.XmlIndent(prefix, indent, rootTag...) if err != nil { return err } _, err = xmlWriter.Write(x) return err } // Writes the Map as pretty XML on the Writer. []byte is the raw XML that was written. // See Xml() for encoding rules. /* func (mv Map) XmlIndentWriterRaw(xmlWriter io.Writer, prefix, indent string, rootTag ...string) ([]byte, error) { x, err := mv.XmlIndent(prefix, indent, rootTag...) if err != nil { return x, err } _, err = xmlWriter.Write(x) return x, err } */ // -------------------- END: mv.Xml & mv.XmlWriter ------------------------------- // -------------- Handle XML stream by processing Map value -------------------- // Default poll delay to keep Handler from spinning on an open stream // like sitting on os.Stdin waiting for imput. var xhandlerPollInterval = time.Millisecond // Bulk process XML using handlers that process a Map value. // 'rdr' is an io.Reader for XML (stream) // 'mapHandler' is the Map processor. Return of 'false' stops io.Reader processing. // 'errHandler' is the error processor. Return of 'false' stops io.Reader processing and returns the error. // Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized. // This means that you can stop reading the file on error or after processing a particular message. // To have reading and handling run concurrently, pass argument to a go routine in handler and return 'true'. func HandleXmlReader(xmlReader io.Reader, mapHandler func(Map) bool, errHandler func(error) bool) error { var n int for { m, merr := NewMapXmlReader(xmlReader) n++ // handle error condition with errhandler if merr != nil && merr != io.EOF { merr = fmt.Errorf("[xmlReader: %d] %s", n, merr.Error()) if ok := errHandler(merr); !ok { // caused reader termination return merr } continue } // pass to maphandler if len(m) != 0 { if ok := mapHandler(m); !ok { break } } else if merr != io.EOF { time.Sleep(xhandlerPollInterval) } if merr == io.EOF { break } } return nil } // Bulk process XML using handlers that process a Map value and the raw XML. // 'rdr' is an io.Reader for XML (stream) // 'mapHandler' is the Map and raw XML - []byte - processor. Return of 'false' stops io.Reader processing. // 'errHandler' is the error and raw XML processor. Return of 'false' stops io.Reader processing and returns the error. // Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized. // This means that you can stop reading the file on error or after processing a particular message. // To have reading and handling run concurrently, pass argument(s) to a go routine in handler and return 'true'. // See NewMapXmlReaderRaw for comment on performance associated with retrieving raw XML from a Reader. func HandleXmlReaderRaw(xmlReader io.Reader, mapHandler func(Map, []byte) bool, errHandler func(error, []byte) bool) error { var n int for { m, raw, merr := NewMapXmlReaderRaw(xmlReader) n++ // handle error condition with errhandler if merr != nil && merr != io.EOF { merr = fmt.Errorf("[xmlReader: %d] %s", n, merr.Error()) if ok := errHandler(merr, raw); !ok { // caused reader termination return merr } continue } // pass to maphandler if len(m) != 0 { if ok := mapHandler(m, raw); !ok { break } } else if merr != io.EOF { time.Sleep(xhandlerPollInterval) } if merr == io.EOF { break } } return nil } // ----------------- END: Handle XML stream by processing Map value -------------- // -------- a hack of io.TeeReader ... need one that's an io.ByteReader for xml.NewDecoder() ---------- // This is a clone of io.TeeReader with the additional method t.ReadByte(). // Thus, this TeeReader is also an io.ByteReader. // This is necessary because xml.NewDecoder uses a ByteReader not a Reader. It appears to have been written // with bufio.Reader or bytes.Reader in mind ... not a generic io.Reader, which doesn't have to have ReadByte().. // If NewDecoder is passed a Reader that does not satisfy ByteReader() it wraps the Reader with // bufio.NewReader and uses ReadByte rather than Read that runs the TeeReader pipe logic. type teeReader struct { r io.Reader w io.Writer b []byte } func myTeeReader(r io.Reader, w io.Writer) io.Reader { b := make([]byte, 1) return &teeReader{r, w, b} } // need for io.Reader - but we don't use it ... func (t *teeReader) Read(p []byte) (int, error) { return 0, nil } func (t *teeReader) ReadByte() (byte, error) { n, err := t.r.Read(t.b) if n > 0 { if _, err := t.w.Write(t.b[:1]); err != nil { return t.b[0], err } } return t.b[0], err } // For use with NewMapXmlReader & NewMapXmlSeqReader. type byteReader struct { r io.Reader b []byte } func myByteReader(r io.Reader) io.Reader { b := make([]byte, 1) return &byteReader{r, b} } // Need for io.Reader interface ... // Needed if reading a malformed http.Request.Body - issue #38. func (b *byteReader) Read(p []byte) (int, error) { return b.r.Read(p) } func (b *byteReader) ReadByte() (byte, error) { _, err := b.r.Read(b.b) if len(b.b) > 0 { return b.b[0], nil } var c byte return c, err } // ----------------------- END: io.TeeReader hack ----------------------------------- // ---------------------- XmlIndent - from j2x package ---------------------------- // Encode a map[string]interface{} as a pretty XML string. // See Xml for encoding rules. func (mv Map) XmlIndent(prefix, indent string, rootTag ...string) ([]byte, error) { m := map[string]interface{}(mv) var err error b := new(bytes.Buffer) p := new(pretty) p.indent = indent p.padding = prefix if len(m) == 1 && len(rootTag) == 0 { // this can extract the key for the single map element // use it if it isn't a key for a list for key, value := range m { if _, ok := value.([]interface{}); ok { err = marshalMapToXmlIndent(true, b, DefaultRootTag, m, p) } else { err = marshalMapToXmlIndent(true, b, key, value, p) } } } else if len(rootTag) == 1 { err = marshalMapToXmlIndent(true, b, rootTag[0], m, p) } else { err = marshalMapToXmlIndent(true, b, DefaultRootTag, m, p) } if xmlCheckIsValid { d := xml.NewDecoder(bytes.NewReader(b.Bytes())) for { _, err = d.Token() if err == io.EOF { err = nil break } else if err != nil { return nil, err } } } return b.Bytes(), err } type pretty struct { indent string cnt int padding string mapDepth int start int } func (p *pretty) Indent() { p.padding += p.indent p.cnt++ } func (p *pretty) Outdent() { if p.cnt > 0 { p.padding = p.padding[:len(p.padding)-len(p.indent)] p.cnt-- } } // where the work actually happens // returns an error if an attribute is not atomic // NOTE: 01may20 - replaces mapToXmlIndent(); uses bytes.Buffer instead for string appends. func marshalMapToXmlIndent(doIndent bool, b *bytes.Buffer, key string, value interface{}, pp *pretty) error { var err error var endTag bool var isSimple bool var elen int p := &pretty{pp.indent, pp.cnt, pp.padding, pp.mapDepth, pp.start} // per issue #48, 18apr18 - try and coerce maps to map[string]interface{} // Don't need for mapToXmlSeqIndent, since maps there are decoded by NewMapXmlSeq(). if reflect.ValueOf(value).Kind() == reflect.Map { switch value.(type) { case map[string]interface{}: default: val := make(map[string]interface{}) vv := reflect.ValueOf(value) keys := vv.MapKeys() for _, k := range keys { val[fmt.Sprint(k)] = vv.MapIndex(k).Interface() } value = val } } // 14jul20. The following block of code has become something of a catch all for odd stuff // that might be passed in as a result of casting an arbitrary map[] to an mxj.Map // value and then call m.Xml or m.XmlIndent. See issue #71 (and #73) for such edge cases. switch value.(type) { // these types are handled during encoding case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32, json.Number: case []map[string]interface{}, []string, []float64, []bool, []int, []int32, []int64, []float32, []json.Number: case []interface{}: case nil: value = "" default: // see if value is a struct, if so marshal using encoding/xml package if reflect.ValueOf(value).Kind() == reflect.Struct { if v, err := xml.Marshal(value); err != nil { return err } else { value = string(v) } } else { // coerce eveything else into a string value value = fmt.Sprint(value) } } // start the XML tag with required indentaton and padding if doIndent { if _, err = b.WriteString(p.padding); err != nil { return err } } switch value.(type) { case []interface{}: default: if _, err = b.WriteString(`<` + key); err != nil { return err } } switch value.(type) { case map[string]interface{}: vv := value.(map[string]interface{}) lenvv := len(vv) // scan out attributes - attribute keys have prepended attrPrefix attrlist := make([][2]string, len(vv)) var n int var ss string for k, v := range vv { if lenAttrPrefix > 0 && lenAttrPrefix < len(k) && k[:lenAttrPrefix] == attrPrefix { switch v.(type) { case string: if xmlEscapeChars { ss = escapeChars(v.(string)) } else { ss = v.(string) } attrlist[n][0] = k[lenAttrPrefix:] attrlist[n][1] = ss case float64, bool, int, int32, int64, float32, json.Number: attrlist[n][0] = k[lenAttrPrefix:] attrlist[n][1] = fmt.Sprintf("%v", v) case []byte: if xmlEscapeChars { ss = escapeChars(string(v.([]byte))) } else { ss = string(v.([]byte)) } attrlist[n][0] = k[lenAttrPrefix:] attrlist[n][1] = ss default: return fmt.Errorf("invalid attribute value for: %s:<%T>", k, v) } n++ } } if n > 0 { attrlist = attrlist[:n] sort.Sort(attrList(attrlist)) for _, v := range attrlist { if _, err = b.WriteString(` ` + v[0] + `="` + v[1] + `"`); err != nil { return err } } } // only attributes? if n == lenvv { if useGoXmlEmptyElemSyntax { if _, err = b.WriteString(`"); err != nil { return err } } else { if _, err = b.WriteString(`/>`); err != nil { return err } } break } // simple element? Note: '#text" is an invalid XML tag. isComplex := false if v, ok := vv["#text"]; ok && n+1 == lenvv { // just the value and attributes switch v.(type) { case string: if xmlEscapeChars { v = escapeChars(v.(string)) } else { v = v.(string) } case []byte: if xmlEscapeChars { v = escapeChars(string(v.([]byte))) } else { v = string(v.([]byte)) } } if _, err = b.WriteString(">" + fmt.Sprintf("%v", v)); err != nil { return err } endTag = true elen = 1 isSimple = true break } else if ok { // need to handle when there are subelements in addition to the simple element value // issue #90 switch v.(type) { case string: if xmlEscapeChars { v = escapeChars(v.(string)) } else { v = v.(string) } case []byte: if xmlEscapeChars { v = escapeChars(string(v.([]byte))) } else { v = string(v.([]byte)) } } if _, err = b.WriteString(">" + fmt.Sprintf("%v", v)); err != nil { return err } isComplex = true } // close tag with possible attributes if !isComplex { if _, err = b.WriteString(">"); err != nil { return err } } if doIndent { // *s += "\n" if _, err = b.WriteString("\n"); err != nil { return err } } // something more complex p.mapDepth++ // extract the map k:v pairs and sort on key elemlist := make([][2]interface{}, len(vv)) n = 0 for k, v := range vv { if k == "#text" { // simple element handled above continue } if lenAttrPrefix > 0 && lenAttrPrefix < len(k) && k[:lenAttrPrefix] == attrPrefix { continue } elemlist[n][0] = k elemlist[n][1] = v n++ } elemlist = elemlist[:n] sort.Sort(elemList(elemlist)) var i int for _, v := range elemlist { switch v[1].(type) { case []interface{}: default: if i == 0 && doIndent { p.Indent() } } i++ if err := marshalMapToXmlIndent(doIndent, b, v[0].(string), v[1], p); err != nil { return err } switch v[1].(type) { case []interface{}: // handled in []interface{} case default: if doIndent { p.Outdent() } } i-- } p.mapDepth-- endTag = true elen = 1 // we do have some content ... case []interface{}: // special case - found during implementing Issue #23 if len(value.([]interface{})) == 0 { if doIndent { if _, err = b.WriteString(p.padding + p.indent); err != nil { return err } } if _, err = b.WriteString("<" + key); err != nil { return err } elen = 0 endTag = true break } for _, v := range value.([]interface{}) { if doIndent { p.Indent() } if err := marshalMapToXmlIndent(doIndent, b, key, v, p); err != nil { return err } if doIndent { p.Outdent() } } return nil case []string: // This was added by https://github.com/slotix ... not a type that // would be encountered if mv generated from NewMapXml, NewMapJson. // Could be encountered in AnyXml(), so we'll let it stay, though // it should be merged with case []interface{}, above. //quick fix for []string type //[]string should be treated exaclty as []interface{} if len(value.([]string)) == 0 { if doIndent { if _, err = b.WriteString(p.padding + p.indent); err != nil { return err } } if _, err = b.WriteString("<" + key); err != nil { return err } elen = 0 endTag = true break } for _, v := range value.([]string) { if doIndent { p.Indent() } if err := marshalMapToXmlIndent(doIndent, b, key, v, p); err != nil { return err } if doIndent { p.Outdent() } } return nil case nil: // terminate the tag if doIndent { // *s += p.padding if _, err = b.WriteString(p.padding); err != nil { return err } } if _, err = b.WriteString("<" + key); err != nil { return err } endTag, isSimple = true, true break default: // handle anything - even goofy stuff elen = 0 switch value.(type) { case string: v := value.(string) if xmlEscapeChars { v = escapeChars(v) } elen = len(v) if elen > 0 { // *s += ">" + v if _, err = b.WriteString(">" + v); err != nil { return err } } case float64, bool, int, int32, int64, float32, json.Number: v := fmt.Sprintf("%v", value) elen = len(v) // always > 0 if _, err = b.WriteString(">" + v); err != nil { return err } case []byte: // NOTE: byte is just an alias for uint8 // similar to how xml.Marshal handles []byte structure members v := string(value.([]byte)) if xmlEscapeChars { v = escapeChars(v) } elen = len(v) if elen > 0 { // *s += ">" + v if _, err = b.WriteString(">" + v); err != nil { return err } } default: if _, err = b.WriteString(">"); err != nil { return err } var v []byte var err error if doIndent { v, err = xml.MarshalIndent(value, p.padding, p.indent) } else { v, err = xml.Marshal(value) } if err != nil { if _, err = b.WriteString(">UNKNOWN"); err != nil { return err } } else { elen = len(v) if elen > 0 { if _, err = b.Write(v); err != nil { return err } } } } isSimple = true endTag = true } if endTag { if doIndent { if !isSimple { if _, err = b.WriteString(p.padding); err != nil { return err } } } if elen > 0 || useGoXmlEmptyElemSyntax { if elen == 0 { if _, err = b.WriteString(">"); err != nil { return err } } if _, err = b.WriteString(`"); err != nil { return err } } else { if _, err = b.WriteString(`/>`); err != nil { return err } } } if doIndent { if p.cnt > p.start { if _, err = b.WriteString("\n"); err != nil { return err } } p.Outdent() } return nil } // ============================ sort interface implementation ================= type attrList [][2]string func (a attrList) Len() int { return len(a) } func (a attrList) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a attrList) Less(i, j int) bool { return a[i][0] <= a[j][0] } type elemList [][2]interface{} func (e elemList) Len() int { return len(e) } func (e elemList) Swap(i, j int) { e[i], e[j] = e[j], e[i] } func (e elemList) Less(i, j int) bool { return e[i][0].(string) <= e[j][0].(string) } mxj-2.5.5/xml2_test.go000066400000000000000000000161201402172443100145670ustar00rootroot00000000000000package mxj import ( "encoding/json" "encoding/xml" "fmt" "io" "os" "testing" ) func TestXml2Header(t *testing.T) { fmt.Println("\n---------------- xml2_test.go ...") } func TestNewMapXml4(t *testing.T) { x := []byte(` William T. Gaddis The Recognitions One of the great seminal American novels of the 20th century. Austin Tappan Wright Islandia An example of earlier 20th century American utopian fiction. John Hawkes The Beetle Leg A lyrical novel about the construction of Ft. Peck Dam in Montana. T.E. Porter King's Day A magical novella. `) m, err := NewMapXml(x) if err != nil && err != io.EOF { t.Fatal("err:", err.Error()) } fmt.Println("NewMapXml4, x:\n", string(x)) fmt.Println("NewMapXml4, m:\n", m) fmt.Println("NewMapXml4, s:\n", m.StringIndent()) b, err := m.XmlIndent("", " ") if err != nil { t.Fatal("err:", err) } fmt.Println("NewMapXml4, b:\n", string(b)) } func TestNewMapXml5(t *testing.T) { fh, err := os.Open("songtext.xml") if err != nil { t.Fatal("err:", err.Error()) } defer fh.Close() m, raw, err := NewMapXmlReaderRaw(fh) if err != nil && err != io.EOF { t.Fatal("err:", err.Error()) } fmt.Println("NewMapXml5, raw:\n", string(raw)) fmt.Println("NewMapXml5, m:\n", m) fmt.Println("NewMapXml5, s:\n", m.StringIndent()) b, err := m.Xml() if err != nil { t.Fatal("err:", err) } fmt.Println("NewMapXml5, b:\n", string(b)) b, err = m.XmlIndent("", " ") if err != nil { t.Fatal("err:", err) } fmt.Println("NewMapXml5, b:\n", string(b)) } func TestNewMapXml6(t *testing.T) { fh, err := os.Open("atomFeedString.xml") if err != nil { t.Fatal("err:", err.Error()) } defer fh.Close() m, raw, err := NewMapXmlReaderRaw(fh) if err != nil && err != io.EOF { t.Fatal("err:", err.Error()) } fmt.Println("NewMapXml6, raw:\n", string(raw)) fmt.Println("NewMapXml6, m:\n", m) fmt.Println("NewMapXml6, s:\n", m.StringIndent()) b, err := m.Xml() if err != nil { t.Fatal("err:", err) } fmt.Println("NewMapXml6, b:\n", string(b)) b, err = m.XmlIndent("", " ") if err != nil { t.Fatal("err:", err) } fmt.Println("NewMapXml6, b:\n", string(b)) } // ===================================== benchmarks ============================ var smallxml = []byte(` this is the end `) var smalljson = []byte(`{"doc":{"words":{"word1":"this","word2":"is","word3":"the","word4":"end"}}}`) type words struct { Word1 string `xml:"word1"` Word2 string `xml:"word2"` Word3 string `xml:"word3"` Word4 string `xml:"word4"` } type xmldoc struct { Words words `xml:"words"` } type jsondoc struct { Doc xmldoc } func BenchmarkNewMapXml(b *testing.B) { // var m Map var err error for i := 0; i < b.N; i++ { if _, err = NewMapXml(smallxml); err != nil { b.Fatal("err:", err) } } // fmt.Println("m Map:", m) } func BenchmarkNewStructXml(b *testing.B) { var s *xmldoc var err error for i := 0; i < b.N; i++ { s = new(xmldoc) if err = xml.Unmarshal(smallxml, s); err != nil { b.Fatal("err:", err) } } // fmt.Println("s xmldoc:", *s) } func BenchmarkNewMapJson(b *testing.B) { var m map[string]interface{} var err error for i := 0; i < b.N; i++ { m = make(map[string]interface{}) if err = json.Unmarshal(smalljson, &m); err != nil { b.Fatal("err:", err) } } // fmt.Println("m map:", m) } func BenchmarkNewStructJson(b *testing.B) { var s *jsondoc var err error for i := 0; i < b.N; i++ { s = new(jsondoc) if err = json.Unmarshal(smalljson, s); err != nil { b.Fatal("err:", err) } } // fmt.Println("s jsondoc:", *s) } // ================== something with a little more content ... =================== var xmlbooks = []byte(` William T. Gaddis The Recognitions One of the great seminal American novels of the 20th century. Austin Tappan Wright Islandia An example of earlier 20th century American utopian fiction. John Hawkes The Beetle Leg A lyrical novel set during the construction of Ft. Peck Dam in Montana. T.E. Porter King's Day A magical novella. `) var jsonbooks = []byte(` {"doc": {"books": {"book":[ { "author":"William T. Gaddis", "title":"The Recognitions", "review":"One of the great seminal American novels of the 20th century." }, { "author":"Austin Tappan Wright", "title":"Islandia", "review":"An example of earlier 20th century American utopian fiction." }, { "author":"John Hawkes", "title":"The Beetle Leg", "review":"A lyrical novel set during the construction of Ft. Peck Dam in Montana." }, { "author":{"first_name":"T.E.", "last_name":"Porter"}, "title":"King's Day", "review":"A magical novella." }] } } } `) type book struct { Author string `xml:"author"` Title string `xml:"title"` Review string `xml:"review"` } type books struct { Book []book `xml:"book"` } type doc struct { Books books `xml:"books"` } type jsonbook struct { Author json.RawMessage Title string Review string } type jsonbooks2 struct { Book []jsonbook } type jsondoc1 struct { Books jsonbooks2 } type jsondoc2 struct { Doc jsondoc1 } func BenchmarkNewMapXmlBooks(b *testing.B) { // var m Map var err error for i := 0; i < b.N; i++ { if _, err = NewMapXml(xmlbooks); err != nil { b.Fatal("err:", err) } } // fmt.Println("m Map:", m) } func BenchmarkNewStructXmlBooks(b *testing.B) { var s *doc var err error for i := 0; i < b.N; i++ { s = new(doc) if err = xml.Unmarshal(xmlbooks, s); err != nil { b.Fatal("err:", err) } } // fmt.Println("s doc:", *s) } func BenchmarkNewMapJsonBooks(b *testing.B) { var m map[string]interface{} var err error for i := 0; i < b.N; i++ { m = make(map[string]interface{}) if err = json.Unmarshal(jsonbooks, &m); err != nil { b.Fatal("err:", err) } } // fmt.Println("m map:", m) } func BenchmarkNewStructJsonBooks(b *testing.B) { var s *jsondoc2 var err error for i := 0; i < b.N; i++ { s = new(jsondoc2) if err = json.Unmarshal(jsonbooks, s); err != nil { b.Fatal("err:", err) } } // fmt.Println("s jsondoc2:", *s) } mxj-2.5.5/xml3_test.go000066400000000000000000000030141402172443100145660ustar00rootroot00000000000000// xml3_test.go - patch tests package mxj import ( "fmt" "testing" ) func TestXml3(t *testing.T) { fmt.Println("\n------------ xml3_test.go") } // for: https://github.com/clbanning/mxj/pull/26 func TestOnlyAttributes(t *testing.T) { fmt.Println("========== TestOnlyAttributes") dom, err := NewMapXml([]byte(`
)`)) if err != nil { t.Fatal(err) } xml, err := dom.XmlIndent("", " ") if err != nil { t.Fatal(err) } fmt.Println(string(xml)) } func TestOnlyAttributesSeq(t *testing.T) { fmt.Println("========== TestOnlyAttributesSeq") dom, err := NewMapXmlSeq([]byte(`
)`)) if err != nil { t.Fatal(err) } xml, err := dom.XmlIndent("", " ") if err != nil { t.Fatal(err) } fmt.Println(string(xml)) } func TestDecodeSimpleValuesAsMap(t *testing.T) { fmt.Println("========== TestDecodeSimpleValuesAsMap") DecodeSimpleValuesAsMap() xml := ` 30102 Mini Drone Inteligente - Branco 149.90 ` m, err := NewMapXml([]byte(xml)) if err != nil { t.Fatal(err) } fmt.Println("xml:", string(xml)) fmt.Printf("m : %v\n", m) fmt.Println("========== (default)") DecodeSimpleValuesAsMap() m, err = NewMapXml([]byte(xml)) if err != nil { t.Fatal(err) } fmt.Printf("m : %v\n", m) } mxj-2.5.5/xml_test.go000066400000000000000000000134441402172443100145130ustar00rootroot00000000000000package mxj import ( "bytes" "fmt" "io" "reflect" "testing" ) func TestXmlHeader(t *testing.T) { fmt.Println("\n---------------- xml_test.go ...") } func TestNewMapXml(t *testing.T) { x := []byte(`something more12`) mv, merr := NewMapXml(x) if merr != nil { t.Fatal("merr:", merr.Error()) } want := Map{"root2": map[string]interface{}{ "newtag": map[string]interface{}{"-newattr": "some_attr_value", "#text":"something more"}, "list": map[string]interface{}{"-listattr":"val", "item":[]interface{}{"1", "2"}}, }} if !reflect.DeepEqual(mv, want) { fmt.Println("NewMapXml, x :", string(x)) fmt.Printf("NewMapXml, mv : %#v\n", mv) fmt.Printf("NewMapXml, want: %#v\n", want) t.Fatal("not DeepEqual") } } func TestAttrHyphenFalse(t *testing.T) { PrependAttrWithHyphen(false) defer PrependAttrWithHyphen(true) x := []byte(`something more12`) mv, merr := NewMapXml(x) if merr != nil { t.Fatal("merr:", merr.Error()) } want := Map{"root2": map[string]interface{}{ "newtag": map[string]interface{}{"newattr": "some_attr_value", "#text":"something more"}, "list": map[string]interface{}{"listattr":"val", "item":[]interface{}{"1", "2"}}, }} if !reflect.DeepEqual(mv, want) { fmt.Println("AttrHyphenFalse, x :", string(x)) fmt.Printf("AttrHyphenFalse, mv : %#v\n", mv) fmt.Printf("AttrHyphenFalse, want: %#v\n", want) t.Fatal("not DeepEqual") } } func TestNewMapXmlError(t *testing.T) { x := []byte(`something more12`) m, merr := NewMapJson(x) if merr == nil { t.Fatal("NewMapXmlError, m:", m) } want := `invalid character '<' looking for beginning of value` if merr != nil && merr.Error() != want { fmt.Println("NewMapXmlError, x :", string(x)) fmt.Println("NewMapXmlError, merr:", merr.Error()) fmt.Println("NewMapXmlError, want:", want) } } func TestNewMapXmlReader(t *testing.T) { fmt.Println("\n==================== TestNewMapXmlReader ...") x := []byte(`is a testsomething more12`) r := bytes.NewReader(x) for { m, raw, err := NewMapXmlReaderRaw(r) if err != nil && err != io.EOF { t.Fatal("err:", err.Error()) } if err == io.EOF && len(m) == 0 { break } fmt.Println("NewMapXmlReader, raw:", string(raw)) fmt.Println("NewMapXmlReader, m :", m) } } // --------------------- Xml() and XmlWriter() test cases ------------------- func TestXml_1(t *testing.T) { mv := Map{"tag1": "some data", "tag2": "more data", "boolean": true, "float": 3.14159625, "null": nil} x, err := mv.Xml() if err != nil { t.Fatal("err:", err.Error()) } fmt.Println("Xml_1, mv:", mv) fmt.Println("Xml_1, x :", string(x)) } func TestXml_2(t *testing.T) { a := []interface{}{"string", true, 36.4} mv := Map{"array": a} x, err := mv.Xml() if err != nil { t.Fatal("err:", err.Error()) } fmt.Println("Xml_2, mv:", mv) fmt.Println("Xml_2, x :", string(x)) } func TestXml_3(t *testing.T) { a := []interface{}{"string", true, 36.4} mv := Map{"array": []interface{}{a, "string2"}} x, err := mv.Xml() if err != nil { t.Fatal("err:", err.Error()) } fmt.Println("Xml_3, mv:", mv) fmt.Println("Xml_3, x :", string(x)) } func TestXml_4(t *testing.T) { a := []interface{}{"string", true, 36.4} mv := Map{"array": map[string]interface{}{"innerkey": []interface{}{a, "string2"}}} x, err := mv.Xml() if err != nil { t.Fatal("err:", err.Error()) } fmt.Println("Xml_4, mv:", mv) fmt.Println("Xml_4, x :", string(x)) } func TestXml_5(t *testing.T) { a := []interface{}{"string", true, 36.4} mv := Map{"array": []interface{}{map[string]interface{}{"innerkey": []interface{}{a, "string2"}}, map[string]interface{}{"some": "more"}}} x, err := mv.Xml() if err != nil { t.Fatal("err:", err.Error()) } fmt.Println("Xml_5, mv:", mv) fmt.Println("Xml_5, x :", string(x)) } func TestXml_Strings(t *testing.T) { mv := Map{"sometag": "some data", "strings": []string{"string1", "string2"}} x, err := mv.Xml() if err != nil { t.Fatal("err:", err.Error()) } fmt.Println("Xml_strings, mv:", mv) fmt.Println("Xml_strings, x :", string(x)) } func TestXmlWriter(t *testing.T) { mv := Map{"tag1": "some data", "tag2": "more data", "boolean": true, "float": 3.14159625} w := new(bytes.Buffer) err := mv.XmlWriter(w, "myRootTag") if err != nil { t.Fatal("err:", err.Error()) } b := make([]byte, w.Len()) _, err = w.Read(b) if err != nil { t.Fatal("err:", err.Error()) } fmt.Println("XmlWriter, b :", string(b)) } // -------------------------- XML Handler test cases ------------------------- /* tested in bulk_test.go ... var xhdata = []byte(`is a testsomething more12`) func TestHandleXmlReader(t *testing.T) { fmt.Println("HandleXmlReader:", string(xhdata)) rdr := bytes.NewReader(xhdata) err := HandleXmlReader(rdr, xmhandler, xehandler) if err != nil { t.Fatal("err:", err.Error()) } } var xt *testing.T func xmhandler(m Map, raw []byte) bool { x, xerr := m.Xml() if xerr != nil { xt.Fatal("... xmhandler:", xerr.Error()) return false } fmt.Println("... xmhandler, raw:", string(raw)) fmt.Println("... xmhandler, x :", string(x)) return true } func xehandler(err error, raw []byte) bool { if err == nil { // shouldn't be here xt.Fatal("... xehandler: ") return false } if err == io.EOF { return true } fmt.Println("... xehandler raw:", string(raw)) fmt.Println("... xehandler err:", err.Error()) return true } */ mxj-2.5.5/xmlseq.go000066400000000000000000000662041402172443100141670ustar00rootroot00000000000000// Copyright 2012-2016, 2019 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // xmlseq.go - version of xml.go with sequence # injection on Decoding and sorting on Encoding. // Also, handles comments, directives and process instructions. package mxj import ( "bytes" "encoding/xml" "errors" "fmt" "io" "sort" "strings" ) // MapSeq is like Map but contains seqencing indices to allow recovering the original order of // the XML elements when the map[string]interface{} is marshaled. Element attributes are // stored as a map["#attr"]map[]map[string]interface{}{"#text":"", "#seq":} // value instead of denoting the keys with a prefix character. Also, comments, directives and // process instructions are preserved. type MapSeq map[string]interface{} // NoRoot is returned by NewXmlSeq, etc., when a comment, directive or procinstr element is parsed // in the XML data stream and the element is not contained in an XML object with a root element. var NoRoot = errors.New("no root key") var NO_ROOT = NoRoot // maintain backwards compatibility // ------------------- NewMapXmlSeq & NewMapXmlSeqReader ... ------------------------- // NewMapXmlSeq converts a XML doc into a MapSeq value with elements id'd with decoding sequence key represented // as map["#seq"]. // If the optional argument 'cast' is 'true', then values will be converted to boolean or float64 if possible. // NOTE: "#seq" key/value pairs are removed on encoding with msv.Xml() / msv.XmlIndent(). // • attributes are a map - map["#attr"]map["attr_key"]map[string]interface{}{"#text":, "#seq":} // • all simple elements are decoded as map["#text"]interface{} with a "#seq" k:v pair, as well. // • lists always decode as map["list_tag"][]map[string]interface{} where the array elements are maps that // include a "#seq" k:v pair based on sequence they are decoded. Thus, XML like: // // value 1 // value 2 // value 3 // // is decoded as: // doc : // ltag :[[]interface{}] // [item: 0] // #seq :[int] 0 // #text :[string] value 1 // [item: 1] // #seq :[int] 2 // #text :[string] value 3 // newtag : // #seq :[int] 1 // #text :[string] value 2 // It will encode in proper sequence even though the MapSeq representation merges all "ltag" elements in an array. // • comments - "" - are decoded as map["#comment"]map["#text"]"cmnt_text" with a "#seq" k:v pair. // • directives - "" - are decoded as map["#directive"]map[#text"]"directive_text" with a "#seq" k:v pair. // • process instructions - "" - are decoded as map["#procinst"]interface{} where the #procinst value // is of map[string]interface{} type with the following keys: #target, #inst, and #seq. // • comments, directives, and procinsts that are NOT part of a document with a root key will be returned as // map[string]interface{} and the error value 'NoRoot'. // • note: ": tag preserve the // ":" notation rather than stripping it as with NewMapXml(). // 2. Attribute keys for name space prefix declarations preserve "xmlns:" notation. // // ERRORS: // 1. If a NoRoot error, "no root key," is returned, check the initial map key for a "#comment", // "#directive" or #procinst" key. func NewMapXmlSeq(xmlVal []byte, cast ...bool) (MapSeq, error) { var r bool if len(cast) == 1 { r = cast[0] } return xmlSeqToMap(xmlVal, r) } // NewMpaXmlSeqReader returns next XML doc from an io.Reader as a MapSeq value. // NOTES: // 1. The 'xmlReader' will be parsed looking for an xml.StartElement, xml.Comment, etc., so BOM and other // extraneous xml.CharData will be ignored unless io.EOF is reached first. // 2. CoerceKeysToLower() is NOT recognized, since the intent here is to eventually call m.XmlSeq() to // re-encode the message in its original structure. // 3. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. // // ERRORS: // 1. If a NoRoot error, "no root key," is returned, check the initial map key for a "#comment", // "#directive" or #procinst" key. func NewMapXmlSeqReader(xmlReader io.Reader, cast ...bool) (MapSeq, error) { var r bool if len(cast) == 1 { r = cast[0] } // We need to put an *os.File reader in a ByteReader or the xml.NewDecoder // will wrap it in a bufio.Reader and seek on the file beyond where the // xml.Decoder parses! if _, ok := xmlReader.(io.ByteReader); !ok { xmlReader = myByteReader(xmlReader) // see code at EOF } // build the map return xmlSeqReaderToMap(xmlReader, r) } // NewMapXmlSeqReaderRaw returns the next XML doc from an io.Reader as a MapSeq value. // Returns MapSeq value, slice with the raw XML, and any error. // NOTES: // 1. Due to the implementation of xml.Decoder, the raw XML off the reader is buffered to []byte // using a ByteReader. If the io.Reader is an os.File, there may be significant performance impact. // See the examples - getmetrics1.go through getmetrics4.go - for comparative use cases on a large // data set. If the io.Reader is wrapping a []byte value in-memory, however, such as http.Request.Body // you CAN use it to efficiently unmarshal a XML doc and retrieve the raw XML in a single call. // 2. The 'raw' return value may be larger than the XML text value. // 3. The 'xmlReader' will be parsed looking for an xml.StartElement, xml.Comment, etc., so BOM and other // extraneous xml.CharData will be ignored unless io.EOF is reached first. // 4. CoerceKeysToLower() is NOT recognized, since the intent here is to eventually call m.XmlSeq() to // re-encode the message in its original structure. // 5. If CoerceKeysToSnakeCase() has been called, then all key values will be converted to snake case. // // ERRORS: // 1. If a NoRoot error, "no root key," is returned, check if the initial map key is "#comment", // "#directive" or #procinst" key. func NewMapXmlSeqReaderRaw(xmlReader io.Reader, cast ...bool) (MapSeq, []byte, error) { var r bool if len(cast) == 1 { r = cast[0] } // create TeeReader so we can retrieve raw XML buf := make([]byte, 0) wb := bytes.NewBuffer(buf) trdr := myTeeReader(xmlReader, wb) m, err := xmlSeqReaderToMap(trdr, r) // retrieve the raw XML that was decoded b := wb.Bytes() // err may be NoRoot return m, b, err } // xmlSeqReaderToMap() - parse a XML io.Reader to a map[string]interface{} value func xmlSeqReaderToMap(rdr io.Reader, r bool) (map[string]interface{}, error) { // parse the Reader p := xml.NewDecoder(rdr) if CustomDecoder != nil { useCustomDecoder(p) } else { p.CharsetReader = XmlCharsetReader } return xmlSeqToMapParser("", nil, p, r) } // xmlSeqToMap - convert a XML doc into map[string]interface{} value func xmlSeqToMap(doc []byte, r bool) (map[string]interface{}, error) { b := bytes.NewReader(doc) p := xml.NewDecoder(b) if CustomDecoder != nil { useCustomDecoder(p) } else { p.CharsetReader = XmlCharsetReader } return xmlSeqToMapParser("", nil, p, r) } // ===================================== where the work happens ============================= // xmlSeqToMapParser - load a 'clean' XML doc into a map[string]interface{} directly. // Add #seq tag value for each element decoded - to be used for Encoding later. func xmlSeqToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[string]interface{}, error) { if snakeCaseKeys { skey = strings.Replace(skey, "-", "_", -1) } // NOTE: all attributes and sub-elements parsed into 'na', 'na' is returned as value for 'skey' in 'n'. var n, na map[string]interface{} var seq int // for including seq num when decoding // Allocate maps and load attributes, if any. // NOTE: on entry from NewMapXml(), etc., skey=="", and we fall through // to get StartElement then recurse with skey==xml.StartElement.Name.Local // where we begin allocating map[string]interface{} values 'n' and 'na'. if skey != "" { // 'n' only needs one slot - save call to runtime•hashGrow() // 'na' we don't know n = make(map[string]interface{}, 1) na = make(map[string]interface{}) if len(a) > 0 { // xml.Attr is decoded into: map["#attr"]map[]interface{} // where interface{} is map[string]interface{}{"#text":, "#seq":} aa := make(map[string]interface{}, len(a)) for i, v := range a { if snakeCaseKeys { v.Name.Local = strings.Replace(v.Name.Local, "-", "_", -1) } if xmlEscapeCharsDecoder { // per issue#84 v.Value = escapeChars(v.Value) } if len(v.Name.Space) > 0 { aa[v.Name.Space+`:`+v.Name.Local] = map[string]interface{}{"#text": cast(v.Value, r, ""), "#seq": i} } else { aa[v.Name.Local] = map[string]interface{}{"#text": cast(v.Value, r, ""), "#seq": i} } } na["#attr"] = aa } } // Return XMPP message. if handleXMPPStreamTag && skey == "stream:stream" { n[skey] = na return n, nil } for { t, err := p.RawToken() if err != nil { if err != io.EOF { return nil, errors.New("xml.Decoder.Token() - " + err.Error()) } return nil, err } switch t.(type) { case xml.StartElement: tt := t.(xml.StartElement) // First call to xmlSeqToMapParser() doesn't pass xml.StartElement - the map key. // So when the loop is first entered, the first token is the root tag along // with any attributes, which we process here. // // Subsequent calls to xmlSeqToMapParser() will pass in tag+attributes for // processing before getting the next token which is the element value, // which is done above. if skey == "" { if len(tt.Name.Space) > 0 { return xmlSeqToMapParser(tt.Name.Space+`:`+tt.Name.Local, tt.Attr, p, r) } else { return xmlSeqToMapParser(tt.Name.Local, tt.Attr, p, r) } } // If not initializing the map, parse the element. // len(nn) == 1, necessarily - it is just an 'n'. var nn map[string]interface{} if len(tt.Name.Space) > 0 { nn, err = xmlSeqToMapParser(tt.Name.Space+`:`+tt.Name.Local, tt.Attr, p, r) } else { nn, err = xmlSeqToMapParser(tt.Name.Local, tt.Attr, p, r) } if err != nil { return nil, err } // The nn map[string]interface{} value is a na[nn_key] value. // We need to see if nn_key already exists - means we're parsing a list. // This may require converting na[nn_key] value into []interface{} type. // First, extract the key:val for the map - it's a singleton. var key string var val interface{} for key, val = range nn { break } // add "#seq" k:v pair - // Sequence number included even in list elements - this should allow us // to properly resequence even something goofy like: // item 1 // item 2 // item 3 // where all the "list" subelements are decoded into an array. switch val.(type) { case map[string]interface{}: val.(map[string]interface{})["#seq"] = seq seq++ case interface{}: // a non-nil simple element: string, float64, bool v := map[string]interface{}{"#text": val, "#seq": seq} seq++ val = v } // 'na' holding sub-elements of n. // See if 'key' already exists. // If 'key' exists, then this is a list, if not just add key:val to na. if v, ok := na[key]; ok { var a []interface{} switch v.(type) { case []interface{}: a = v.([]interface{}) default: // anything else - note: v.(type) != nil a = []interface{}{v} } a = append(a, val) na[key] = a } else { na[key] = val // save it as a singleton } case xml.EndElement: if skey != "" { tt := t.(xml.EndElement) if snakeCaseKeys { tt.Name.Local = strings.Replace(tt.Name.Local, "-", "_", -1) } var name string if len(tt.Name.Space) > 0 { name = tt.Name.Space + `:` + tt.Name.Local } else { name = tt.Name.Local } if skey != name { return nil, fmt.Errorf("element %s not properly terminated, got %s at #%d", skey, name, p.InputOffset()) } } // len(n) > 0 if this is a simple element w/o xml.Attrs - see xml.CharData case. if len(n) == 0 { // If len(na)==0 we have an empty element == ""; // it has no xml.Attr nor xml.CharData. // Empty element content will be map["etag"]map["#text"]"" // after #seq injection - map["etag"]map["#seq"]seq - after return. if len(na) > 0 { n[skey] = na } else { n[skey] = "" // empty element } } return n, nil case xml.CharData: // clean up possible noise tt := strings.Trim(string(t.(xml.CharData)), trimRunes) if xmlEscapeCharsDecoder { // issue#84 tt = escapeChars(tt) } if skey == "" { // per Adrian (http://www.adrianlungu.com/) catch stray text // in decoder stream - // https://github.com/clbanning/mxj/pull/14#issuecomment-182816374 // NOTE: CharSetReader must be set to non-UTF-8 CharSet or you'll get // a p.Token() decoding error when the BOM is UTF-16 or UTF-32. continue } if len(tt) > 0 { // every simple element is a #text and has #seq associated with it na["#text"] = cast(tt, r, "") na["#seq"] = seq seq++ } case xml.Comment: if n == nil { // no root 'key' n = map[string]interface{}{"#comment": string(t.(xml.Comment))} return n, NoRoot } cm := make(map[string]interface{}, 2) cm["#text"] = string(t.(xml.Comment)) cm["#seq"] = seq seq++ na["#comment"] = cm case xml.Directive: if n == nil { // no root 'key' n = map[string]interface{}{"#directive": string(t.(xml.Directive))} return n, NoRoot } dm := make(map[string]interface{}, 2) dm["#text"] = string(t.(xml.Directive)) dm["#seq"] = seq seq++ na["#directive"] = dm case xml.ProcInst: if n == nil { na = map[string]interface{}{"#target": t.(xml.ProcInst).Target, "#inst": string(t.(xml.ProcInst).Inst)} n = map[string]interface{}{"#procinst": na} return n, NoRoot } pm := make(map[string]interface{}, 3) pm["#target"] = t.(xml.ProcInst).Target pm["#inst"] = string(t.(xml.ProcInst).Inst) pm["#seq"] = seq seq++ na["#procinst"] = pm default: // noop - shouldn't ever get here, now, since we handle all token types } } } // ------------------ END: NewMapXml & NewMapXmlReader ------------------------- // --------------------- mv.XmlSeq & mv.XmlSeqWriter ------------------------- // Xml encodes a MapSeq as XML with elements sorted on #seq. The companion of NewMapXmlSeq(). // The following rules apply. // - The "#seq" key value is used to seqence the subelements or attributes only. // - The "#attr" map key identifies the map of attribute map[string]interface{} values with "#text" key. // - The "#comment" map key identifies a comment in the value "#text" map entry - . // - The "#directive" map key identifies a directive in the value "#text" map entry - . // - The "#procinst" map key identifies a process instruction in the value "#target" and "#inst" // map entries - . // - Value type encoding: // > string, bool, float64, int, int32, int64, float32: per "%v" formating // > []bool, []uint8: by casting to string // > structures, etc.: handed to xml.Marshal() - if there is an error, the element // value is "UNKNOWN" // - Elements with only attribute values or are null are terminated using "/>" unless XmlGoEmptyElemSystax() called. // - If len(mv) == 1 and no rootTag is provided, then the map key is used as the root tag, possible. // Thus, `{ "key":"value" }` encodes as "value". func (mv MapSeq) Xml(rootTag ...string) ([]byte, error) { m := map[string]interface{}(mv) var err error s := new(string) p := new(pretty) // just a stub if len(m) == 1 && len(rootTag) == 0 { for key, value := range m { // if it's an array, see if all values are map[string]interface{} // we force a new root tag if we'll end up with no key:value in the list // so: key:[string_val, bool:true] --> string_valtrue switch value.(type) { case []interface{}: for _, v := range value.([]interface{}) { switch v.(type) { case map[string]interface{}: // noop default: // anything else err = mapToXmlSeqIndent(false, s, DefaultRootTag, m, p) goto done } } } err = mapToXmlSeqIndent(false, s, key, value, p) } } else if len(rootTag) == 1 { err = mapToXmlSeqIndent(false, s, rootTag[0], m, p) } else { err = mapToXmlSeqIndent(false, s, DefaultRootTag, m, p) } done: if xmlCheckIsValid { d := xml.NewDecoder(bytes.NewReader([]byte(*s))) for { _, err = d.Token() if err == io.EOF { err = nil break } else if err != nil { return nil, err } } } return []byte(*s), err } // The following implementation is provided only for symmetry with NewMapXmlReader[Raw] // The names will also provide a key for the number of return arguments. // XmlWriter Writes the MapSeq value as XML on the Writer. // See MapSeq.Xml() for encoding rules. func (mv MapSeq) XmlWriter(xmlWriter io.Writer, rootTag ...string) error { x, err := mv.Xml(rootTag...) if err != nil { return err } _, err = xmlWriter.Write(x) return err } // XmlWriteRaw writes the MapSeq value as XML on the Writer. []byte is the raw XML that was written. // See Map.XmlSeq() for encoding rules. /* func (mv MapSeq) XmlWriterRaw(xmlWriter io.Writer, rootTag ...string) ([]byte, error) { x, err := mv.Xml(rootTag...) if err != nil { return x, err } _, err = xmlWriter.Write(x) return x, err } */ // XmlIndentWriter writes the MapSeq value as pretty XML on the Writer. // See MapSeq.Xml() for encoding rules. func (mv MapSeq) XmlIndentWriter(xmlWriter io.Writer, prefix, indent string, rootTag ...string) error { x, err := mv.XmlIndent(prefix, indent, rootTag...) if err != nil { return err } _, err = xmlWriter.Write(x) return err } // XmlIndentWriterRaw writes the Map as pretty XML on the Writer. []byte is the raw XML that was written. // See Map.XmlSeq() for encoding rules. /* func (mv MapSeq) XmlIndentWriterRaw(xmlWriter io.Writer, prefix, indent string, rootTag ...string) ([]byte, error) { x, err := mv.XmlSeqIndent(prefix, indent, rootTag...) if err != nil { return x, err } _, err = xmlWriter.Write(x) return x, err } */ // -------------------- END: mv.Xml & mv.XmlWriter ------------------------------- // ---------------------- XmlSeqIndent ---------------------------- // XmlIndent encodes a map[string]interface{} as a pretty XML string. // See MapSeq.XmlSeq() for encoding rules. func (mv MapSeq) XmlIndent(prefix, indent string, rootTag ...string) ([]byte, error) { m := map[string]interface{}(mv) var err error s := new(string) p := new(pretty) p.indent = indent p.padding = prefix if len(m) == 1 && len(rootTag) == 0 { // this can extract the key for the single map element // use it if it isn't a key for a list for key, value := range m { if _, ok := value.([]interface{}); ok { err = mapToXmlSeqIndent(true, s, DefaultRootTag, m, p) } else { err = mapToXmlSeqIndent(true, s, key, value, p) } } } else if len(rootTag) == 1 { err = mapToXmlSeqIndent(true, s, rootTag[0], m, p) } else { err = mapToXmlSeqIndent(true, s, DefaultRootTag, m, p) } if xmlCheckIsValid { if _, err = NewMapXml([]byte(*s)); err != nil { return nil, err } d := xml.NewDecoder(bytes.NewReader([]byte(*s))) for { _, err = d.Token() if err == io.EOF { err = nil break } else if err != nil { return nil, err } } } return []byte(*s), err } // where the work actually happens // returns an error if an attribute is not atomic func mapToXmlSeqIndent(doIndent bool, s *string, key string, value interface{}, pp *pretty) error { var endTag bool var isSimple bool var noEndTag bool var elen int var ss string p := &pretty{pp.indent, pp.cnt, pp.padding, pp.mapDepth, pp.start} switch value.(type) { case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32: if doIndent { *s += p.padding } if key != "#comment" && key != "#directive" && key != "#procinst" { *s += `<` + key } } switch value.(type) { case map[string]interface{}: val := value.(map[string]interface{}) if key == "#comment" { *s += `` noEndTag = true break } if key == "#directive" { *s += `` noEndTag = true break } if key == "#procinst" { *s += `` noEndTag = true break } haveAttrs := false // process attributes first if v, ok := val["#attr"].(map[string]interface{}); ok { // First, unroll the map[string]interface{} into a []keyval array. // Then sequence it. kv := make([]keyval, len(v)) n := 0 for ak, av := range v { kv[n] = keyval{ak, av} n++ } sort.Sort(elemListSeq(kv)) // Now encode the attributes in original decoding sequence, using keyval array. for _, a := range kv { vv := a.v.(map[string]interface{}) switch vv["#text"].(type) { case string: if xmlEscapeChars { ss = escapeChars(vv["#text"].(string)) } else { ss = vv["#text"].(string) } *s += ` ` + a.k + `="` + ss + `"` case float64, bool, int, int32, int64, float32: *s += ` ` + a.k + `="` + fmt.Sprintf("%v", vv["#text"]) + `"` case []byte: if xmlEscapeChars { ss = escapeChars(string(vv["#text"].([]byte))) } else { ss = string(vv["#text"].([]byte)) } *s += ` ` + a.k + `="` + ss + `"` default: return fmt.Errorf("invalid attribute value for: %s", a.k) } } haveAttrs = true } // simple element? // every map value has, at least, "#seq" and, perhaps, "#text" and/or "#attr" _, seqOK := val["#seq"] // have key if v, ok := val["#text"]; ok && ((len(val) == 3 && haveAttrs) || (len(val) == 2 && !haveAttrs)) && seqOK { if stmp, ok := v.(string); ok && stmp != "" { if xmlEscapeChars { stmp = escapeChars(stmp) } *s += ">" + stmp endTag = true elen = 1 } isSimple = true break } else if !ok && ((len(val) == 2 && haveAttrs) || (len(val) == 1 && !haveAttrs)) && seqOK { // here no #text but have #seq or #seq+#attr endTag = false break } // we now need to sequence everything except attributes // 'kv' will hold everything that needs to be written kv := make([]keyval, 0) for k, v := range val { if k == "#attr" { // already processed continue } if k == "#seq" { // ignore - just for sorting continue } switch v.(type) { case []interface{}: // unwind the array as separate entries for _, vv := range v.([]interface{}) { kv = append(kv, keyval{k, vv}) } default: kv = append(kv, keyval{k, v}) } } // close tag with possible attributes *s += ">" if doIndent { *s += "\n" } // something more complex p.mapDepth++ sort.Sort(elemListSeq(kv)) i := 0 for _, v := range kv { switch v.v.(type) { case []interface{}: default: if i == 0 && doIndent { p.Indent() } } i++ if err := mapToXmlSeqIndent(doIndent, s, v.k, v.v, p); err != nil { return err } switch v.v.(type) { case []interface{}: // handled in []interface{} case default: if doIndent { p.Outdent() } } i-- } p.mapDepth-- endTag = true elen = 1 // we do have some content other than attrs case []interface{}: for _, v := range value.([]interface{}) { if doIndent { p.Indent() } if err := mapToXmlSeqIndent(doIndent, s, key, v, p); err != nil { return err } if doIndent { p.Outdent() } } return nil case nil: // terminate the tag if doIndent { *s += p.padding } *s += "<" + key endTag, isSimple = true, true break default: // handle anything - even goofy stuff elen = 0 switch value.(type) { case string: if xmlEscapeChars { ss = escapeChars(value.(string)) } else { ss = value.(string) } elen = len(ss) if elen > 0 { *s += ">" + ss } case float64, bool, int, int32, int64, float32: v := fmt.Sprintf("%v", value) elen = len(v) if elen > 0 { *s += ">" + v } case []byte: // NOTE: byte is just an alias for uint8 // similar to how xml.Marshal handles []byte structure members if xmlEscapeChars { ss = escapeChars(string(value.([]byte))) } else { ss = string(value.([]byte)) } elen = len(ss) if elen > 0 { *s += ">" + ss } default: var v []byte var err error if doIndent { v, err = xml.MarshalIndent(value, p.padding, p.indent) } else { v, err = xml.Marshal(value) } if err != nil { *s += ">UNKNOWN" } else { elen = len(v) if elen > 0 { *s += string(v) } } } isSimple = true endTag = true } if endTag && !noEndTag { if doIndent { if !isSimple { *s += p.padding } } switch value.(type) { case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32: if elen > 0 || useGoXmlEmptyElemSyntax { if elen == 0 { *s += ">" } *s += `" } else { *s += `/>` } } } else if !noEndTag { if useGoXmlEmptyElemSyntax { *s += `" // *s += ">" } else { *s += "/>" } } if doIndent { if p.cnt > p.start { *s += "\n" } p.Outdent() } return nil } // the element sort implementation type keyval struct { k string v interface{} } type elemListSeq []keyval func (e elemListSeq) Len() int { return len(e) } func (e elemListSeq) Swap(i, j int) { e[i], e[j] = e[j], e[i] } func (e elemListSeq) Less(i, j int) bool { var iseq, jseq int var fiseq, fjseq float64 var ok bool if iseq, ok = e[i].v.(map[string]interface{})["#seq"].(int); !ok { if fiseq, ok = e[i].v.(map[string]interface{})["#seq"].(float64); ok { iseq = int(fiseq) } else { iseq = 9999999 } } if jseq, ok = e[j].v.(map[string]interface{})["#seq"].(int); !ok { if fjseq, ok = e[j].v.(map[string]interface{})["#seq"].(float64); ok { jseq = int(fjseq) } else { jseq = 9999999 } } return iseq <= jseq } // =============== https://groups.google.com/forum/#!topic/golang-nuts/lHPOHD-8qio // BeautifyXml (re)formats an XML doc similar to Map.XmlIndent(). // It preserves comments, directives and process instructions, func BeautifyXml(b []byte, prefix, indent string) ([]byte, error) { x, err := NewMapXmlSeq(b) if err != nil { return nil, err } return x.XmlIndent(prefix, indent) } mxj-2.5.5/xmlseq2.go000066400000000000000000000011761402172443100142460ustar00rootroot00000000000000// Copyright 2012-2016, 2019 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file package mxj // ---------------- expose Map methods to MapSeq type --------------------------- // Pretty print a Map. func (msv MapSeq) StringIndent(offset ...int) string { return writeMap(map[string]interface{}(msv), true, true, offset...) } // Pretty print a Map without the value type information - just key:value entries. func (msv MapSeq) StringIndentNoTypeInfo(offset ...int) string { return writeMap(map[string]interface{}(msv), false, true, offset...) } mxj-2.5.5/xmlseq_test.go000066400000000000000000000045651402172443100152300ustar00rootroot00000000000000package mxj import ( "fmt" "io" "testing" ) func TestXmlSeqHeader(t *testing.T) { fmt.Println("\n---------------- xmlseq_test.go ...") } func TestNewMapXmlSeq(t *testing.T) { x := []byte(` William T. Gaddis Gaddis is one of the most influential but little know authors in America. The Recognitions One of the great seminal American novels of the 20th century. Without it Thomas Pynchon probably wouldn't have written Gravity's Rainbow. Austin Tappan Wright Islandia An example of earlier 20th century American utopian fiction. John Hawkes The Beetle Leg A lyrical novel about the construction of Ft. Peck Dam in Montana. T.E. Porter King's Day A magical novella. `) msv, err := NewMapXmlSeq(x) if err != nil && err != io.EOF { t.Fatal("err:", err.Error()) } fmt.Println("NewMapXmlSeq, x:\n", string(x)) fmt.Println("NewMapXmlSeq, s:\n", msv.StringIndent()) b, err := msv.XmlIndent("", " ") if err != nil { t.Fatal("err:", err) } fmt.Println("NewMapXmlSeq, msv.XmlIndent():\n", string(b)) } func TestXmlSeqDecodeError(t *testing.T) { fmt.Println("------------ TestXmlSeqDecodeError ...") x := []byte(` William T. Gaddis Gaddis is one of the most influential but little know authors in America. The Recognitions One of the great seminal American novels of the 20th century. Without it Thomas Pynchon probably wouldn't have written Gravity's Rainbow. `) _, err := NewMapXmlSeq(x) if err == nil { t.Fatal("didn't catch EndElement error") } fmt.Println("err ok:", err) } mxj-2.5.5/xmppStream_test.go000066400000000000000000000025021402172443100160440ustar00rootroot00000000000000package mxj import ( "bytes" "fmt" "io" "testing" ) func TestXMPPStreamTag(t *testing.T) { fmt.Println("----------- TestXMPPStreamTag ...") var data = ` ` HandleXMPPStreamTag() defer HandleXMPPStreamTag() buf := bytes.NewBufferString(data) for { m, raw, err := NewMapXmlReaderRaw(buf) if err == io.EOF { break } if err != nil { t.Fatal("err:", err) } fmt.Println(string(raw)) fmt.Println(m) } } func TestXMPPStreamTagSeq(t *testing.T) { fmt.Println("----------- TestXMPPStreamTagSeq ...") var data = ` ` HandleXMPPStreamTag() defer HandleXMPPStreamTag() buf := bytes.NewBufferString(data) for { m, raw, err := NewMapXmlSeqReaderRaw(buf) if err == io.EOF { break } if err != nil { t.Fatal("err:", err) } fmt.Println(string(raw)) fmt.Println(m) } }

K^|.Lj{@xkԖD4.W/rjmbF*`|] ;QfHU@ܯg}JtP{(]xNEVҫ/r9X&?yLmgF1cn6DNG80=4oǤ0rݻ+.,@W'W 3`b h]!e>ܧ[9(CʫdSu` ^@\nuP)TnD\녺2yIwz $V׹p92WM<.0cYX16k'_7`G6>o}⺗VטFJ:Qr8c&ohZM$zW ПX#M:8^Ӭ2 ,*UTG6L⾰I7d ~ål}"Cś"_o<[ F dxFKt@.%ܖ"^D t"މ2̘bT=.Q5,1T~i~y=}׺^ C9Y2-y^Ljd_ϫ_\.@Sy]շ+՟o_UQovJX }ޙ,`}$G@uUb= iyv!l*ǩܙ8ZvLn柳7OW_IC`<&ɀ(F9:MkeϣN j.J/]gC;۩h7\} nB4XC(쀩%" ׯTFqB@D l135{ NzoADR [p2nC8 ;te= zPG ~\!DӮE]2Զ\đk++Y?>d|ý-Z|y~8]R7#Bð] à>&9X|9 &2}'DQsJeе!$ϽhՔr,Γ5@_㔤EǬe5_㦣Fa ՍAVbtc 61@o`A7fd|GʃqG-֏J'@7=>%Ÿ6IaEݦ4%}zic|WoVI4b!D,Tq-aAh3UpHp_xGZ[X&G/EcgrbC8`ҟ#}f, ('듧 E6zJ;gcƬP Vz\$ݿHBɩ|x.r`&4 'i麩ʨlQzx[wD,oMybBZIG+&p9v,lbOhCex.v奲Pd~2߿MJBtF17rx$ezn\wEZޟ w!ޡ0Ʈ:a7סz]Ze&7h|U0d8`::OWƲQA˕rJEÍ {u[}"x!J+^dՇ+1LV9/ݾMD_{182en^LH̠̘nisk ¸Ս-FLi8<R1uh٫}ƻH!z Tdʝ6[~|T?B}:>Lt436$oל-L rx8]֯.Ʈ,B7uƵ3n)B@ EERմ=R2{#4U__U#"N;JKTHߝ8ΐ9>vPwݛfM*R&z2YZ#z+ v?$ⓙ"|xh|91WıMwEO?d~VF۪G55o߯"ďqE#qBިɨ`rwY"|# F!8-&>-zBq\EEr1ů/kBd[bt!D%0bdPhh1d32o{~:|@W,׎.٠cC ۯ֣C?K)ݲv$0=eYh0-9"N0 '@A0DVzǂcՐы2cEo.C7H^zl_^ @(jˑ5pjl5}}$5DcBTNV JEbE/)ENDp錱̩5TY \1Ŋ!A6qb'"3]gL㎭?ղa{kP">xcǁbERK·Q>(xW,@W/첊͇&|Nn-km4E9(qV:Cwv!_K 充&[:.[jx2!,_O"Vr^Q,ʈl ܴ l4I a͐s5 wkCWAry޽륞fDk_hV.o\C̀ZmSc ej"1L#[7mQދ0j&7ñOp-b [Ck&{Zk~w(v6?@/'>oE{DO_ώg">9qU5#ozO5펕X ݾu6`d~"\+ĩP{ dD-m8u5lۀ+dc6 Ð8'>FOWu@ ,ʈШ@^x ?a&Pm4L@<et6n?ݗU&UF~Fu.r|1h_&a+S|pX:d\i ۨD7 Ul~<0Oڊ%e[!Ymr\vuVa xQMQ,g VfRig:[%&|.oUCAK$s1D.8CpZp)32]f%RbY{a %Aňmces9܊X#ī8͗ݐ$Ίt:L q9>R6vj#OzA6 ZzSpb)|0t[h)Gv-,d. -yf)`'[I2m-1lK^5j)@$T^ g4 ߀bz"*Yjپ_u%nM`~@rthFiYmjan̓ b /Y(?/[s[",SG+'pio8SɌ֪ ''^6y!FU0">dwقS4B d<*6. +|+v8~ yx$`'oF56SS]8?#H8W8Mx<ְ*te-6q0[|cł3lr*9ȨoDaV 8pf#yԈZʏL0nBgI9W`(&Hi EurObٕZ0tcyl9GAh08B9ix-e%,ߞ&ҊooFdW۸]BLh)AͱO|-[,`p Crc"#NEV`!ǷJVv bAPiǃA79?NukQ6^픦/')0F"a@W)ڑE2`*%ҁ㇁kaQc>b*p$\@,:0/ z@"-띂uIcLd80A1]ap"; ʾEZnפ U8oH+oњ2е }Ig(|f0cxn(h Q6S\%_ye[`!: ?>ο;dl?|Or[ݑ6$7&QsL8buNGe5s}{eJb9" >@,a :JHwNN$ mcA,p!eefX U",1%H9xN򧟳%ׅs.@@?(àuso˱_C8I>l u'¬y.#4,ia>Bb; Vh+َYZ;8;" c# :TdGWa1nwmY-[֐4;{Lok̗МVY|Z`2s*Dud>y۲ovbN]KK 8MvīuIy~eی &bƩoҥ?͑ajžζθ\OLovo hkz~zdb`H"l9x'S|ˉ  ^l@QՂ'X\P|=6[1` I;<95w^252yc0b@ `H(2Ϭ訓7z0X: fUAdPU4C6H).n} Pjw G½"*eSJMbNT#+${#G7f|[o^S͟!{K ~dVI .WsX4? ;ϳE*{DDϷzT=Rw"%Pͱa~|ͻOٛɛʈ/;l:]T'l֟a`穴ɶ ^/|r|O77w~k֪o{l{]KtBkWOϖq&ݖ]4p"RmՋv``9`HQ{h|KKɎ$ߣ7C!+9ԦjroF)kt7Mq$)Hfc@E\}?/|z5^F!e{v?wՇه7CHbẘTdZN̮o>Sږz)LѨfH4 jdi,zy *nXhsS$*h {^,׮2BGaxY3yPߊo:X%YL$5PryrPzˊ(.n(cښ-ƢL>bGw,&UU (#cjhi|  73$Ry2sv`E$/fG7<q CsqK=Q0?$`-GCi4UT%!~ҡg1/˖} v.ZДLGkK;*\ ;Kl21լYNg2/ -3^Gvg V'v>90JC4,'|{@dL 0Ơ!ē0׻ll%7ip|VM{=J\^kTɰ9(_/=UoTiZ*dЉxheMOZxH_jAqs^É5hLqp"`gz)B;`|AF0΄}I' ߘ,oT]aWNrϘB"Zi,薅I~4YK]6GQ@cn>_K9 ؆frri:t||Y:+#oݞ8D7'hO=]PKOi /O~Ub(57Pv~[̦7YƠ1$c*]܋j=#_OD=Glhh!r zI!RB0( Cc2pi-PyHkirxaB@ j擟$e8Si%A̐xh&~BsÀ s B3˟^l%3@}oK_KdI:`Z\ۇa#4BzD=,M%T  q[$}z?WhX-֒D!tL%+oq׵{ynqkos˗qYLeibD]YL\o2Ǐs, \z>INЧS BY-IC$3NöþY"3mK?L+O8ӫ34I'zҍ ^t=UIn$7䑂V7@|_xA*3 gV#aǾ7,oAl5@E6R<]%`G6`/@G9,V9!`]t!#vo"+ l}t_movlObT)Q#1F+sg<2oT}̹yp.j~?=CF$6u8.CW8y{ՎXP!\rKNh,]S4.. YY=-V\PM| _ <_<1ğSz5cOcv-M]aBXSsG&p}(OtDo{i@F?U%Ʌ>X%L>!-х"QbYe\I? F}Q䐻G; 1ܚ M`4=!YK#922;:āgᨎJCTث"'%uG7:@*+fz Ci=^.YFdh=+0~SCsM,#>[c11&0&G@tߤ( gfS?&v@eu"Yd5Յl;WLeb.} Ԃ.Hڐ3@@coGE8V%QeSs`ͳ'99Kr n-I,ɀ2<-u?P:.hs5D>z3:eW%q6H;[*^:CLD3rȾN= kMn&P"E;ГK害:(FxUA:@Qvl8A'9KWI 8HMyt3Xޝd2R˱ˉ /|_G8+rБ7.LWlw (W;.㔣P !*Sq7"vsesi I=.ձ5`.3rhT \{pƵj'U.9mY--q>"}! Ͼ#77pky<5&D=Ʀm0mmru">1ʋ5Z*GP3^tbwdǾ\+S6Ƕ!8N&;ȷW}{ߗ@ܪ [sMٝ%=-tD$]deUӠ(~r$]aFy{mR-JÅ3< ۹u;% a2F~_eE4GWv{XN2UPhR @B4H!s 08,["!7_W3+sdNL tu@ڲѲ{3ǚ)K9|0oy"CҀ;4].݂+?gF<s1Õ 6+_W:yzX?_փ= mM?^gr)[eWq[)zM q7^.ޚoѶoi>y"9L_ K/pFOnb/av=qjmq8^jFeJ!NKWtyaz@}hJC㭋5:],ep<$Dxv`ߩZ/f Q]o7%syPkiUcoȢcP=섵K8}N TWXe`{Kcwd(GLW+39>::_@ƗMau4DM/z{|ws8DZ.y`E ȁ&2wѹv+64G ←t`[`*shD!ڀO8wg3vZ]c[n4DZLbpCfn/Z7E!qAxoKcNm" `GCi<29%y݉M+}iw6bd<0 CfcXU>Y>&E>ʭOXR 0^- {Di} (|y-'0ڷ|u8ǹ3CˠsUJt5 С4#Kk>҄d"tO)ɒc軘"iG♦cYD L}8q-z|\٤[Z+oqtT ҭY™C\yArf^Id_>mJ҅2CB@G!?N MJk<&Y u!e6tM}S::IQf!68|yw& Q}K̤ k>h+o~}d|C0}N9;E0~ g"|@?6yq9̿ns.v Ms ^W~{SRf .d0(4xQOW zM՚M4i@KH2^!IC8vd} xѥ=;}T}ۼ η^?vmUWu7pxm;|]I}|x)\2yH̊kŗ1Sna6Sj]_YpS[&oPW;4M5*EFDaϖj.&s0ʰ);$Bu~q~RgqƧe.qʟ+5٨|)_F0sesԤ&V:bhQ 8v)ȹb˥{hzSXz'AŕL8N(vexTt;VBu=$ˆC:{gY=f:*VŇ1(MӡpY uKkq VC`&徠^-O7N_nɦIC.ɻ7m=` <gkSFJ֜Bc;UppMz)VLMjȊƘ2 wij{e5_V uy٪\ !R1FA(]`~To#_pIi{٢:Ew]ϠG@ *da/9 ^2i:2Hk?5>]Y[kޯwPKi_c"Ub2Tb(ֽ}v.r3aK΀/)4 /62X>s@GbOzQdWF]Z[M\Je+^"ʟAp~[&F @yƆ4 \{O:eeǐȻY݁|"BXm2ǁzke;*1c7@xIqrI[Rd~;:yi L4n/)SF1<ƚ ^Hj 9`8J|:-{tz(/z[ Ԑ %iI]/\=:MER&L\hIM31kM}.ƚ2]X^{œ~)sqΥIVŲ†~ >=zp0g>ܨusXXDv]2.+_m\[jzc@=UL3;O+Ox .ίa>:Esi+˿X΋isR[ú8 QUH"/zK,w1֭׵ʦ}/ BEs¦ZY 8J3ncaL6+0C*q朳GӐl' vK;;OM oyvkl"-5oékm@mڊ°"f0W-K@ge}]1ٷR?zTkJ3
H#;_l/NF:Cvˮsl8zfNCۤDQ껴.N˱z8{\fO(VBvM5d{oQ'1wzq yt؇99hz;)9dtY鲵.I't9|a#?7l׃eZ &Q `4sdfE(KT3tE<(#e,1]H;]iz$^I d;IFC*A3PlGǿ:[;<&';^bS5{{SmLPEa&znz2yU[p~ s1T!T74fFEMSa}($}mR!vSƞ3 mnply.l7FÅ /%ۅ1-ᲠL]^]29H'yh1m܇"i 8WCFrY@xރ6uR?$iR]mD$2Q&J"Ͳrv}Yժ0kc#.2zKKf!~ ȉx*}|| EȚt콺kNqM !3#G@ hCzq3n3 R&& `ЄkV3 z򺔹.on=҆hrQNh[g5z{sϺ<\;py%!Ĝ)_$oqFEW2J%x,t]ז "AT3=0*}ZϿd5(4Sؐ\7%Uq2_CA}zpH.qQsVGF΍f6GhI9 IaM{PZoJzѹSw|)8WOITv" 8`CUS2 Lsjۊ%u@aC10u 5ӛ BuYCdkN:UYE`E"+fpWOpAEVw^w<ҬJbkj9@ZX#d9`?!^ևc,5 #uѲ  x-T X?cb _"j7wFض6QzHTL|BaeP=G;,-ǿmHS c\(w L.AIs8u4l;]miGFx6Պ*6h~dٽT]X0lgz ^g]_Wn]~tq3B>ؒtN}8iRND]A&"un[RlY%X64%!ld& .؃=TwEw6I!Rʌo=NKqC& a]/]Zw^l dPHQh4o,Mh8?a)qYLWpBs Ѝ!+\^ {w=:Fv-/dP!+nwm G:1$z׺X WAH7}E" kݛ(x|Ф,<]+oY6QD*V)-ɤa j㚍sF^UR YNg`:*LV.nI&d,`g64"g^),-"9|7H;oq)&[:F4xpFq q2)B,8^SbGAhG7!#Z޾y *L)XdVX۰&, ) dfFeN bh}0EGvy;0\%Ϋ^rk訯\/@?K+VVRT+ ,3QY_3) ^t,' 'Sao97g,A o!+w[BXEN@Bw^`@vΙY2Ρp.. )\i6>C6!aBF $\$epUrg[hİiiX$m!ґNnSuNt躨a0"$̊~ /.rEɶZk,]+tJZC;!ѷGyˤ)?+/S,v)!BO*,3DLZ*:20uh@r+RXQT/ 2EX&tjkHX[ @D tqѴ8=>ycŞԫ{a!L7gZ>¬8xT8"qly8G<.^Wq.ι/>qD(SUnvˏ!NY,ϋl WT L-@I/h=F%SG.,Pˈg%Z\,O斸4BSTaSRLENёlȩ|xمM3OlM? ypY–DVM<-`K!+/lbs尝'M^ daNϦ7bj1X,ήY[>֏*Qf8^՚2l:C:8BC;/J4*A6ƢvC; +ڒc&s edsy;MP5ɣetC 9C^0 /?Lr>EҰ F񼀴r&y.Duqlh~6`5S }Hx<& yu["jRtK4gHLeCu`%y$7&'Egl{XQ0#Sd@hbD8*:+ҒT17NV#ek"nSbo𞅯sYe Kyb֌|$yrabyЁJOlX,91 b@Q<}9X"1_>υ=to[C&ҙ0߁bU vM*DN Ϛ6R*,܈NueTMtNtPN4m̓jՅ"wݑ?VR-Q%ʼ_AFbɸ` qXyת| ׆5^poCx@TX x 2xk$%!ww`ZϬiGd|?KGyA vD`%Fe1<-O$Fn\Cni_`ucjRUg~۹v>o_l`@x!J [ߵ?Ʊ@oxP6ܘV0;]lh-$qXS2\yưcA nXvRu0}K jKk߿h ,F9EIf0)j[w;gJ\ :lVwK>.s;e2X=AJR JRfwY ް%F cJ/N0NN_ o #gCG9e OeTA@8a0:g:0 [mH;SP~\]ˁychRޒH&8RZe8-4zMK>-ƹ8 H< 1\Mshg/A)GOA eP i5sZ Ttu|ŪIEa@`dC jqijCr*%" ؔ@ e ZP/wle* AqLUBj&!^؀jKנѤQ=E1]۰$3 ;3f--L[2[uM [7w Ae28,ZNJ>RƋD-v T.\d,jgl`\ĔɈ Ö^bf -3a̳*jHV2l 6zf[f$(q'`"(˛?̱ZlU^BxesA ;/Ö06v4NM@,uow|L Uh6gbfviY[vt;@L& zoRO(vX]Rn'` u֟a`?AnH}`&ׄ]Z(m1 #\\@=܊~dC~mR&z2[Ei.SzPƫRYe^|H^a5wy*Zd_CQ3PG٤ (0E_{l58vX㹺'>ՃF;b=fqx"ؾ7fFs}cK!A(_mڵ:t(iG7%#nϯc"gzyzgOG ܉O 8H`9wn+SI󏺭3X)]bo\tµ, ~ggZHdoH|odc.UO2\<EZ21HL9lJT$IՑ#I'Ibf0xA8ܞ Mr z|_7As5$bEaZ1 X#cBI%CAFENL2͟F%9ɟ,cX3[Kڋ6 K/,E 5aaw ܳ&~=4I(6>t@8p Jip߹w (qNVP.NDuOq>dP!z+[E_=uT"O,nHݠZM}TrAD}hU^!!I6'BZ^o}E˒dhg2co};gV^+La  Ni%M0]Րxo=2'[VjC-W:J~``KHi^t ,4|,aEӃ`˦ +]:=fX0ӃP F-eDn-ł O+_K 0sÿt[D}]Z|-YvJG`\pG3xaGbn6Tx :A_ OEϑ>˲o"/q ɐ['W['ˍ; 6A"tA"DiV#UZ.e]gkfkIFd0a` ^pf}jYquK!kRG$G@~'$GF9οL}%WzS%;!,&9ʬk*ƙ-җ.DBb31o_2oNj+%iiA_\{X#3TsǷrvz7fWT|wk3}gnՁx4suXpd*2pc1{hmPE܏"yD$0T$don$\1˂Ϊ>KZWx'!ozat9Q/D,*XK'wDF* I @ZbrcM$>_ )W{ĉs!V@;ze]?_֯HLq@qNZZD%H-E$;VȆB}EJW9 BF$Loh0 bV@iN|b kR t>9kH˛J1a/`Q|bO4Y* d& 5A[S%(5z%߂PQFʓ٧i?+XbCo݀O:|NdR JG;{}%hƋԿR" FDJ8xާ!MrTψ|-!RZZcϳuņeVIse3mv4)HnJSԼXu6%xR"GCzIKO*Z6\}15<%~2V$\-g"-!qV7Oiet( m躯YLT,L‹h؇̀UEd<1b물OFXUk<<_##ZFX>R@tuoQ}zO&Lw6KߴjZ w6p qAEjIpq|%<(> 4#A<3fbBߦkqI E>,. $JӊiEh("rHjBT'Ҕ }MMQ=@9ZId$ϔɃ$epʈ K{R:m"&J6J C0dGQ8T=--x6cnC XX%U߈55d@r# MƬ 4MJht=C]GC5aBеjhnfn>Ԏ kDq L WNd%cޞD/LߟϤS40Kעf[ϩ2eQl(*ߦ$y4-*U>DAHEU%ELf.DA{3ViqU]4^ )lCt('S5%RQ4#G¹&9:·< 3u8 ]g̎gU0TU+Vm>u;~X|^-E.a8~t}Ou*L+?UXؕDv˭pB:bْ;.Y̲fVo6A~xb mYnj-967\&uAydWI'" `Ҵ6A>4|oOT#W>l ]gD?Ӌa3]J2g )dԜtiF$ta9W=iv1>¥E_7{,fwt=z67`M dD^Xz7} @U˘)LE<Hb,2-YDLX@yLYfj~nNe#:/ǎ+vVM %^SȞ>4''yy.7=\>t~Uyi.&?iò4=OYo12GBK.cmKNEOzUCrvR'1%VH4FH$e_F\ r P(١;N=`FwoC!DlR93&jyYkG4(Cvdjgb)l~GBmp#OJq@.10O6 [rEq @=.kEzzgm1oTbOw8ˏ.OJ܀!fFE^.!cfT)5#I$Y>&E<󵴩*^:e6Ϯg*վAy >e zz&<!N\0cdąBc2B*cVƦgQe9]jURf5W H]^l`mO~Ʌ Β -x7RI'M ?%m!miS"-]Y[X1UwfpC&  b0F ɈCGDWw#, ސ"H87'y6DBiL8ڋb" A܃(QI_3N_@z!q j#<fA~=74,S,CdԑR|8qSRf:35RH~*fWS [[-xJW 0X5df;83 ~}Ċ~Mh -< {pZFl0㧫wfc!"UpHM&akWʍOBst0LFI p,Po =iG:2W¨*48B+RBrISk;'<ͷelѵ$|a!HrkbX6%*\St$Cײ0,c 9UcCcDzl&ߗ^{Q~:L_cB _Š<]C㩡jt C \БpionsZ<*Ӱ8ѺФAL@MdV DЕ=pr/ޛ "}`]Kt5 3 ԭzճF Gd8 ueJ>;?a?|{nv"D]LE@Rn;t1O+x~ 彆|ŀ/SyBxN\$ݮUZ|}?l~}?ˉe]}{Ru_f QʈuEd?^]M} 첒_״Kl_RYj'_$bHrCc$?>VڜI>r§|ubq^/{+3Ѷ'0%ۉJ;UXpgiڮ 67?U,"ٙa3wG#$6b/|עI BQMx<9XKt1-- j1@Rpx-ޤOfgPXΊG.ƹfgpt#t_n-iP7t*n7OTV6#y'D"I~=m;M ;8Zj  UZPҀ$7 4@dv3@j:nvJa~R#UZ~nk"#!q$%ŠBgڱpo<$DqM602!ʏ|+cc?63`$DQCktv&9D|}FzV2cRi2#Vإ&ez:"pהA} -mL=ٯS%!KxAЖ8R~KM+wđR"zM0H`nڦVi e/n\6& uG.okwAb=sK_oeN9[ :?YBd uvV}X]SjW;cPgWb^0ڬ6IG#mf[ɫ 4 {L6(Q5]؉  2?߮>-#i8<]4@So^-_\W?H돷RWՏ`y]Y~AbZ$3Թ8b%?5\K$#o c T~}i fbe?J *:7i.˶-uYК8@$y 6V=y$3U W3D qG.hu ok'E <9>r 'ߙ:HR5FGy o&9c2]aKEA#fw0}^1q 3Q? CX&`n=-"Iǡ|E|k^Yna) /b[(ݡ+/r(BsINLr䶴@R14]8ɟZ dWz?h-'VHۧa֓ Qif)H?BMZK%lW{t@]m<. ^9`Fٻ I%fԢL؋sY.bQb{eZ. , miR'gSI<&"j/ WQ{5hy_~ h.k 7;@5*)Sx$nì4w=fTO6!v؝9 2@;lLkmn2R7 z [1zBvYۥlu*Pu8@>K|%ϊaw8P5t/|#ׯ(BH,j{AS2yöⳀk1MB#}KҦc\x,_'I#4@PCK> U@ v՘:O+2cX[ik\w_54X,qndy;53#jUC%0Ge}YOe )~%ګ=bl0kt[h)Gv-7d.8EyՑB #rVLj֢lЃoKu]~DAh}̿lmJGzmoER/r3jF:9-5 9]oP..'*ж-J晣o[[f2c MC85OIoYZ(60:m SPquA$tyԧ!\8U y-/'?kl m&Ed.7&k{Jٓfƅ)=.|_.YllZRqyV~,Avp"e;:ʚ.Xptglr]@ĉf fƅ6M@( &퓲 I<8V4{% `O*BQ>O6{I(a8&^~ iP7|I/$;2E;!܁bf8`%}۠Kmu` H<bE]dF:lgdi):`-*仪ae˭f D0$]4C7&9e$I0[=k0@P=IimLF8Y 7\;혴I`' ZYV'۲*}lKk-#w#߈j+f .n|cB[񢃰Y8v},+c]@n'Oy rF8[S֛""a~kߛsAZC?W;u ţݘ 7 5Ռ0Ju)wޛTXZ9=à&=\2iм0KrP )7Hzd}~8lyq@N TH]pM08Caje_"qszMos3Vsg.pm>O(,]+uZ  lE)3ƞcA ;>.*T*V#Cxݑf@G,zmўJebvA:&2&5mi0X=a x"Ri1]^lv;؜.yݦ+6.id_t>b? gh pעajM2fCE{Wˍ:q2)hci;o>uJڡ= atDU;rSuk!qy0@=Xَ1xq' kz:QuH@d"MT6n?PHQ|cԕXlM3kѰ| d(iGp?-.4wAYԯ++)q |[H"yLa;hfțhqfѼg[#tv°30톈ёFf6w@9L2w@k҉Q껣+mvưWЎ̃vj6Y,R-kH| =hKhlz>^Y? jmr yZ &ݸߖ=u}X|@Xqh;.&^WC g]`rIl.fZ/Ƀv0|@K0p-^d؂:x)p!@>)]$6Wlw=RP$ђAwUZXdOI27"$i54bhXm-}x>^ot`Ohw0|}5L9|g[DOg\o?|G 7|w5}S]=?O2:TٷY㏞/6@GR!#\7 r#tx jdR%`ĀLTǠjW= `P]uS>ͪ2.^D 4|LP](w@&6>$8{E6N3lHu%=`o'F ߗoo7?|Sz# Bb?aWBk\.Ja]4? ;ϳE*vs{DDϷzT;Rw"toKcͧwfW777_-J3۾MoWu|O'ǧ:?4sz3z^ӷ]nk}ߣ=RNI⥐LCu2!z٤KOztH;JV/ځ!=l|XF G]>|8:w57X1L+_ͧz'Eu%*qտ~T?1\>b)Zͅleȵ*dE|TD>t9,أQ1^ ۧX9dk5C*\98h4" O|cqu[&E[% hC'M֙0c!lW8^2G&MJ=4`ӝOfw ݁ϡiepC,|󙊾Io<丯yJ&{p`~ ~-1X>@xiP,ccwd(BQΤ3(&3;ǂ,bOF[l?40)9\nڎ JFY1լYBC֘$Xʼ:~ӣ:"DN<}/>sMwNm|ͺ^Eunvݜ`OEn{^/hk /O~UJJN*MD6+פM" Ce9ciȓC*}--@n. Uv4phL[ {VR_bI}v =IlqV{耘!o*Ϊ{݀-: .~..&)tSoiqQJڶi67ʄpTҧw9ȓ̋d"/ʆsr;ޜd쟸ƴ՚H}L%I0,m^xbۛqYLF|'3?wf 0_a} NyBv;^@v=?zR'Pa)Đi+$p4a kQGQ mW$ۤ]jC)Q+_"H[/B5e!:^ ʂqFž^]捄0` gEӵR۴EH&W+ʅEe2MYmwœF[q2qjsq=lGIF]h'_F& 2/)¬V_4-VHi%lyX9&i$H)[O]{I%`7UcdžoV+~XڗtM.;#$Q _$O }y&rABSikxNt]Z^ONBs:x9_a529*+)=hVA(q3 &ϭ-^ nvVo,ã,HH1@ON ?8w6M~=Ư)#`v|M9ԥ -$ݘ:k# Ņ!*)%1`WogY](ɶ\'U^Mװ=X^݌yOHRuIє[d0XU * 3^%ӴUaڠZZIfbl}O-b2.dؽ6s6kVڌxꝜ$.Pe};OʭА~>&E,ǁ6tr|u\0`08oxXlT22>OtgdMFjH'y]'pRmٝ9OU+jp(?ID*glnh+ @djiwb2 ~( xlv)Zvz,LH<艅[;DVϗyCՋm> a֭T%"U'Q~f&sc_38?M7.[3 k|>}]7L%A񪁹_0=Cu,ji3tfថ c 㴌O\<yN{9y((ȯ[pvĥRؼ\`bQ=g%8bg`zNn))IA'9&>~t,Mc{ lL՗YL/_8TLo}ZLjv+/8_'yWGDs\jeU-*!hdәgxI,؆ m;˷,drrᖶNqb\N2[m7R9e.,- Wl!Sc8L_"60½w]< d\CCI5@8¿6?ϫg^GT2!TdNdZ吭ͱmoru੝?lr͚LUXdވ6aP{vJPd׍UgQ-(ss.ɭ&~+ ǎKs܇ڕk:Tk爈:RG|$dx&iZnW| پX{4NyIʨ4P=_+\u`2K\PqJө#4&uslB:kj? nP w$G}ûx>]lH\,9~^-u鲬PO*$oy\7q ' \]3B_<{n= "uHPIY" i[{VIk6'PN9"Ln$;ދ;T&NSsQ90α\[%k+4v7o|繩CF@:Wro7`sC I}a_FKoMpg3rTo=KP*s/GX rsuAZKcֵf5 tx5ņ}%g6^WxYnڅuJ%rO\t 08 ȳs(LBUDsFS-ƣ#SYS."Qez#R/2kץܨq R7ߊ"P͞NZf 1Qʔ@ SpV⑕P@ݐ1d~יyf{C:}̤Y]2TP+z@E1Gr ]v&.W=hd %.uxJ](FDߩ? a^Ӱ4I#{2\ncCZNq6Oj|cc^ms~ia=%@٠c&A,o^Hp\q{ODjZmEh°↙0\V є`[Ǒ(G:?s\ ƀkkBՆB_ c@GXLIc2^90GKa:|2<-*^-noJ \5'svK8GQc'E-&E-nsZ<*}qoq#a4EuN{i hH$4&Iu)4^;<]%8n8ӳ?G>y]'Ğ~ Dx-OQoZUW}(s9FN# c[ 1eIyqYX0diR|N+"$GC:Q "H={?[ p3/j.# qy DckTC"~L.ͧ8!w8"y(rH@x4pO<@Id+BT%dhZYլ3ZnIX|K*iOzl<(9P)Ք><5`m&7>:6tųA7dDwF9ᑖo_] UAaஷ!d8jH+ѐiؔ!Dḝ6]9ԝ7L Be=e+\2P؆smRm'$]S2=7;jkг &@ ڃfP|"6_+sgso +^& K$D'iRYCt8 *1C2q`SecrH/Lýu>b@ r r?=CKC<| jhq ܱ@ pFH]By(҉厫ʈv K>Ƞ!do %r}<:jSx# ca_XB|J?"y^lPEפ380ߵlwD&9H|P˚0 '|5j܃ F4Bv/3 ߮Dp%*4{⽻43.dȢ@s`,cq% J±#n-SS8CEbL#Ek/\iqb9#b,mih,0tˑy19EKċFz /=$]YD'a tŦz0xQD CAP?A,/2mJjLH&Ǎ**!Mi^yGPՇ^2#&%KC J©yْ?Ůӥ5|] Zo\^c ԃE͋{#EPܾ:ծ9;Â;_wՑ, 8.[G)]A\ђC^lO Q_?0R~S> 1voo!Tf0߶;zX 6Qt"BzА0n4zw&4_}][i8j=򚻳\|BGK&;2vt =(ܑW2XHɁҜ8x(p Ljg p-,F)v[NOC 5H3#> h2.ϸ z/UF/ 'g"svQĺ1"/u0׻cDw~]] *ph pGoUb|׊(luwkJf >a6J1.R2CxӤg_`3zQgjzl̾f⇂f=كo}Fh<@E-- ;/%4aQԈ0 PC HQ#j1)~N[eS`8U:C"N!Ł$Uhɪ Э!:}ZZD=9V)  etKZSb#MXק4sdSP@y*&\"ɑ,mGzMWqXo刋mF0 ݊9!'bqîe IEF|/E4wd(]NCBck8d4M<-Z*.\bl6D$TP^mv7Oa$0i+Wd01hl:'Yѝ/4)SH#Mr7rnvk8@MrlJ%3?ItAfE^zV@d?(yvL?`J(Gde8RuRW4$F-T0^t, |hsR<Ł>PIє8=JR3#XktE < =G2shP&=Lwp{s ][@٭C l!@,0CFus1f+~S:Uҁy( ț$'4_fwϟO1 Ju"M0J A#'!t gkax?c?MGr^ʓAZ(>z@Ӈ.s ߄hM'^ c ErAM׉7G:ʅ@ru)]HL.R$"!2E5$(_5h0āoR:%G /ZFx 6 ~m% 0jß;kއa `l_F^j-/eהx4{bUP_xi^\^q8]fZ՝kLz(嗑uE#:|UN9Mr7iZTYi_q ɤĹLXċDA̽EM<" d%ק;t(¤S G 0-56ʇ9a]Sh$tEƕF)y8o3dX>4%tQyC]?:XϒUu ʠVZp>{Y.2Iһl3 b@8P:o#;`<ױvJl]+?,)k D[T s 6ISpE ?J 4{X) ɺ"d$a\I >ߒ̻4^I.0ej t-/e"K֟ 8d@YK+$ \bWIh.!~þy,?">M6<2p?' ȷ2"#c؞3#"ͶʪgzblXS%nn\oZG|;Ukt61āK̷<*9چBnXj#?5mkQ>HKX~o?S%G瞴cuIg9_ŦcKUaٵ̀RiI{# []3_ƣ L2p2rIUs*S!TJ(ӂjXJ6v"/_lR_ێL2%7K3=m8lv9U .0iᡨ4*,^Jw{ Of#}#渥QCyVR&V.824/fE{gdH F2RۀcQ5t[OɪhsX<0 ݹ?uE։.Il%ˏ n{h +.Hok.]/B"ՙ(h9d4Z#ڳ27{[ lvClU5̥ri $G@ `srU;_蚽I?&ʮ_nK?6N`!` Ȥ&-Xt\?H*D, L<[C3"℀ \E;jpnC$..Ƥ!Q~dyzWȸGfAKRR a-ez&0aC)5%DePh%2m  W;[̝_}lBIYPܐ4z[=:\`Iĉs{;Z(ZPGY YqqƖg^!7c \ ) GH8 tCe!syE`s}Fr qfȋ&Git1P$mggVw[Uˢ4N+O^KGxhҩ`3u `KC/ 5iH4e? eؑVaV̺#B;A+?+e?}P]GM+VYNH^:f!?$m`ɝ>]$S FHV._&ˠBɩ|x<$1+ q^SXtiyfN<fjk|q.MwlHx=b_չ 7דʺ5' ݀@F0y/I8M%H,WG qB!=M}.t\"-B!FG W1Lx U ۮfuV!Œ4OQ!!luԅePfz`C5! ~⢲Zjfk$>R}xU%gAhU}*:10 AXwE׽&<5-\2☤Lq>1~Kj6]fOuɁ5ٳBЋ41D]ORzFz/;%(! ɧ3h6,h Lxa.*jixZDs%l8om)}Q5Ļ,-\t%C雦ePъT0⃳w~er6 s+,YQće%bC.dwviR8)R:2qp+bW$4iVQWgM9JOm~Ky]L4nIˣ J #ڡ */ *qAU_O":Qˉ9!Yv^J[8'wV:pff,X}T?^&"SY42!}RSe>`Ϝ?=&ej,awˌџU%\ ,#?|-Oԥm(\<ȩ?_үmBjc:0脧ӲR8cfƂm &bAe.Bf:[es6T{C{@ qP.]X32)32:[b` gMdA0+JxEP/ύ, i#[H 1 ¢zMg(@T:=5`T'R + ^vD3vu^,=0zǑNfʝrR|>b+0n2ΆD\?9WDF|!OI80"Αa3lהKSn.ļRb ̤Sٌ륺Y hHDMɖ W&pG\Qo4aB`YA? TgIhjXw?DUGGC8PQ!oWTv1۳-8hìWԿoYu-ɂ-ź՚udYݪeqPw9+a.5ĝ!+ rLY* L-vKڈ@8l|>=Xz+.E,d&#R$v[h 'Ck}d ٨x>Q+(i=^.kMy zRVsyu)Kvc.AvDx2]OiphR=c=Y{ p7!6uUX$\8P9 Ny30-#H|rBf" Ҳk(02HuH] @GyUMuAN~ cu} Lx)mbrES;Je/R=Za2aF|9k*T2VS#z-b~'6pNSpzdX Zn Q\fM Tӌ81`>l3ގc0aZŇ10iP(Sb`!n*?kl Pi@.x@cO$w נ|xv\_dH ^|*@b4~Pieo[ N8]t,o[Mk vg?O#s:lCz?M0QҰA;Ұ_#Jwstmp*3E:A;٨h:ސ.Z4.ñ \$w3OjaZx\Z2/!$Ƞ$l#$v`ɠvl~L6 NIDę@]u:z1 -HU|Յ9Rm?؍U^y5{@D}C!(.IߐZv}vuz MGO 7;~ل &zVkCE#Gv!Vi_3Az߯ 1?*>=ޜ޳"$k*7 UfbwRNM^j" [M*9LkS3zFyCwiv ƖU/]N^Acefr+f [9|ߐR# 2d08~_ꅲi/҈X['BflCK/\PQ e}U:)n8mo U{G"gbȌ͵XNLM#8;f %6Y/dcxQa*_' 8qAsiqD߱I"<61*ZD҂yvH ".o#H[e Um`LfdnApKOC۝XV4MRT&/ bflWRb7 !nQݴ0W-d9BZn /ނC>]gme/2Ϳ"3Qs_ Aokp, 6Q*|ɠ C+OaT"HB%<3KcfEv638cŷX+"{Lo߱0s,p gZ r/߬&⍅P؀c5,cC'=P'k0OFiW2 o,'adjRi'q{}hunLTJЌT8A(gM skrs6дLsf,y./Ptuٞ5)ԆUor?;`y]^u+A0BVg8c&YF 5E=7t$Xk/EZۜϻ*Gd}Y-9#X(*#;'̑s\QjdIS o+HD…b/N&1w-fЉ)1 - 5ƎS#εKhKB0FNgqdojUbk^>Br$j\4&نSE1ݵdĒG'.֒=$' H1 6I<ŴpwpWpXj;+&SB"yUҥLi>a*}Sl6+.݄Cmj^/WJ[)`\[qw7խe:*-2Swߦ(!B ڐBNtװ 9`.PGZ` fDkGlIKɒ"Yrq$<#VRkyѧw,[;Cv7weP%%T}/" msAcLrִn0y^l¹ZA=!v) ZD%)أeoEF}AsGdD7sp= BLrV~ʫttHs>Vq`f EkK<^RΏ+^V޷%T ' jOLn"kl%\R7TT8@HWC)dG9Xb6ڌ9K~sKC+I qk$ !̓%I/ H R2d'LuڬG#_- Q8D%JK)HiMtKbIX~QrFS=^,f"iPhGnMM^8Ά:^<02[bXB:QAKn-T9g{Ga:Ne7I|~iDM,6]TB-h {o*MCSOzs{S*afFDH2>PKP4<)#5|gPN5&iK+t"%k+M+B $/҆BvLhь0ThxښLģ(ĝԋGazl(vy;#<( Qx1$1G˝GwϐJKāi! =KP.2!(FWLGGbUcєҦ楢2nMq0hgC9CjyJ{݃yI(@?v&彬(M:b9uty*yoGKݸN#uw 7P=~sW/%!P6:*#\M\dv9cBfH4QA_pcªhuq5% f F~4߽"鄱R=\;#үvɯ{wOpw~|f>RfˤLB ']ĉ 'Q;dˍ+~.@x1!-{eJ_ @ȈߔZd{t6|5#]oG6 Xe=KDJnLx[V}e:b`QF@ZY }bC&ypȩ&V3߮>-Lpy* cvku}ƻH둷z TӪJ([ӿ~|Լ?*B}6t;& %ٝLT՜Or D N _E/R,ǐ5`!H|Я3וȑXq]=68Gʞe lGQl{d=8Q?aNOӤ0hH4BXJjG s4B R)73 V+<\-U|5CFx䱢X1 B$h8g,4n`@$+jG?5影lML 07[ @l `M12C4w@hoL; Kb'yQ܌`$t}ȷ JL= 2 Oo(-A٘# @LӤO5uT({WqU+)"i勎,m:^t>Yr^$a5qHmЩji<|w0bXvb X |S|EheD/N4R}/3Ix WWٺ d@z{f.o=.pQ9W7 "zWZF()&'f7&&B<^Tx8oMpQ ɉH˛J%58(ӷwoDi.ń$4)Dȗٿqa]gU.һlc㼵f3.aov.仐Pu6Q||4 + ҠV~nn^@ Xy쨣r{$;}^1%Me3(Z6lO- Jjvqu9Alų]L+:r;4[=Ubz'og<8}Y%As/|oA%)pcZ$ږOe{& _]7پ P}?VK8Fͮd7%Wf# fAU#xlW9ZHk9t*-iI@b胙T(93@aAsS.͢3a'7!r\#|lˊi<w&Fɼ,_ggs&|.R  J*ѻnv.`0c`fjD]/O兂]KqO/⧘ 57<: m e6Z6;Q!I_;j%e ]X~lP~/A7q5 DKeFUΎis6LVNc+˶eZTʡEg_ן--.5ѩ:"Vbe17Z>ݭZW^/lPXe-]-NW7Ap5HtTha' &=\Rb(y74= K{۬"^ uZűC.,\:ꨜ}a48KWH$136tXe &,!qHD("xRjbV9V28;JB,h.ENs%xgt/-)7!Aوjt8Z@Fr.Pn,@vӧplZZNg_տDұ, , |/Czĉ>!#R;͗dxsh@ʐ9@Ԃ(;j89[snItqKֆ=C"N١ݼÊis\;OEn+eiU,l;ى"/ܢBN< ' ;pY#H 7 z B ð̙V%ʩˆmceR,'ܘ9EZ,y u$P$M$ m,/o1RgcoaSH+HeYvO_QY9jGKU0J2ǩХSaUzOcIk(YMV|#‰^-eh!t B2Oim+"ƞ0?ޒ*RFbϾȍ}v 1Ub Mf*D7 0`A *!#-az-CP- c4 Eq", ; $ɢjU(•.E" lX]43JЎh(xIM=ek.*[ԂcAIXʟiq}Gz>֚]>U.Ƅ)H[%յ{F}*KUÏ vtx\ݦh$( Qs`Z_i☱0ÿ μpW|62hј/m-d_w+[-mw1^86Γe׳~s$'Vnu۔S-D\IԪof}Ͽ` O^KqG B2+{uSph:4ċE2AV DCY, :Jvy>V# ,)IЭ&NʽWk됓,˶?L?=!~~"WA1[zdmӹzzfkzt~/i,ӧtQtLp/9XK?.zh) 8V*-,=a/j܃ZФE\pdP}@hx s 3Xsp0\!oI9RKX}}x_eBGS7QÒհ}m ='oo7WhOo'ˆ >,W;=$6^uZ|trf9"JNl'yowO.XlC&CMPnj=02/ ÓS}=Q#_&#(( IXdĀ>ދQ?#]u$[}0jW}0x9}kXu%o\U[UY  Q&LK88*C4a: ߫=(dn9qk?>m^dU%J>)?86t9 3D:d"wY)Y=ҋ]É- ^bMu>hNqfYeS% =R烕P {#7f|[o^S͟?!ׄ*$)Sqy%[%ٛO'4g\FATG#}-Rqb21C/ r'DuHYZ.lW>̏/|:yiv}5{s}3y37a>|8:G!:>wS'Eu ~_ߋ~Tf?YډVKSV6E׻|"%?^ G~A&9,أj. 1+2ܤAfǏ lRsRN\9^nÍzr9=Vtr%ǰ9Xߋ?kS*a1Qd7DxQPt7IJmdy/fϹv׮wռF#°e0.I ">6c5-\*JQ$9'`H-l1eY~sXI䎅լʪ}eS7'%y?4[ A,_m~\nlW9W^3 FȢIy `FG)"9ȹ4Y>0r9}O_0aD`=EL+n`jS< As|K=Q0?`aEaU9: 57m!A0^"%>ԛ IgP|['b, wgݻ@!#L<#}scp 4Ѯ0huT /u6q2yL5(MKҵ!#g>$LVjveR%JMx/i"):ş1OD>Y-kqh&. MAqOQAkcm-DCxt39mC04~c٧?g-Vf]keD"W A{sݜeX[-$c֜5fp|Ifmҙg"IJ@u3?/[ _#o- J/<s2=-o!ܠ>{uw-R0CT=x CK{Q-#:gkrt[xGuKϪoOiajC [oJwL4)DjS+8`i4ߡŐ{tso{--@4 s.QCfڿ#HoIRf 1#  GeYوPdw԰BFCz&#6 d`fR9\&N/!ҁKh{hu&Qf57XC2MRT&.R { v$ +6}8~lPq쨐MÂF'2dOG$x;] a4,{4YܗL-KU>y;KrUܸs]'H' ^336/ ؛~,E!MhbO\yPd8~D|8ԃF; ǰAK$0bЕZici˭8}Π~b[)% %q:ǖǃECFptlq}ܤy{hI ya+:6=Lʆ~qʕ0 4=hL- }d pUwzuyr7D~21x»B&}z&ܐG  C`zXAyĂqF‘B HhH'_$w5@ՌD6R<]+Aǭ#"}hC-}Um|R G8j0o9UfGL`^8qr7Q%:=>};yA"88v[K(\#x1E=16_SՔ+HwT֋Sw4V\D͓ALΞO5rL? YEpq> 1!:{:/2\!ሂv]A9:$j0PkAv\$wG"կy܋Ԗe}fg"8C̶*˴ߣ * !ݖ, "&U(1%VY!e>6Xw˵:VlOrhXV0PJ1dk|I+Q]ԿJ&U]X/O4̿0Z d/d{S"jy#T5R6 痢*=s5ɢRn2;O{lǖo<4!@_h*jvJOJW_]}_&jL%/Ge<lD<ݎ.`nU={.ikAS,vúS~"Pnl~YJh=2yα2Y%s-&_z86:{4[_Ttr|xCcDvzZw)+!5'Hx{sޏ{'5۾KpLIoQݰi ^cYM\t+VaB2` c17X&eF챋d8KɓmY{2{<ƹZ zuKl=ӭ4o%YvM Xm qN|e8,f ΏvxCcj1Dm"8>1!/(!ԱOD <=5 sR$B$sKdck aj]OaM{taK-cVB_V n K+fF9B`FAIRGMhGffmv.bQS _VcP[%Y/cT .y:? Fm6˦N5=Ls>97R'au2ы*B.ނָ7gkGvӓ=$#'ڳdDԑgK3x;ECɁ<U 5#{+J.ڍIZOC #G@G;SA?;Pˀ;XSpld, w( υ}7(T` +%B(]pN Ðl(ӽ;K=É2.6=}͟#G{lk-3$-hl.,m^HkfR[bdQ>.˩s2mߎ\0Mb 3傌Hw2rۭSn.C=]R#cZT]iO96+4}'ESO7ɑ]g;GrٍGpfWW2f2 OU|?![{V}vDokTAu#ڕ?]})jo2\S.qt~[psuIuX lG(t^\/ЅQ\2'YZ"at? s~[(cI:{1Z(_Q{ Ru Q&{09L0ǷCbA=T~ mFEگ?0 &kmC[~c :"p9X\ro 3kF}{PL-]WdgE;X%]Erv=f.bR-{,r-asTwHV{Ց#0ͅB4 Ӊ VcrnH&m ݲ\z!Ї,a:.e[}h8~NfOKwǬmJ7 u$pY Lnev l7ΪYL"U{k%&~˦ o[4aD; Ěm꬙88QF, i%*=iO4$N6\z?vpIɪ e6jSsͼIke˅y$ }%V۟rX]ҕm̻B{AB ]ӟ%v;=dYm嶬VK?;(z'ԕs&$COˮqk<_o䫼QDȎJ$KW芣s"|vi }i@Kݘ]yvNMJaAUQA묬_ϒۏ>/.<`P~lmi&*R:_IɄ>ԇp{jc|wLul3 w'U;8, w%W4FWcVYWkϱMcwQ)6k.F613&sXzj6\=nrf4GlXdv@;%+I蕋{ lZTgtru2i;EY3jq&n3/ނdMp 坱r} vynP~IYU4.{Ot[`MUn,?ï{FGDGΔk:\8Z~]-Q55a .~]e~-1p5xjO7=]'Vmu2FYu3*w[s5k/ի9o4Ǹ}TC+u8' ;qx,]g\n06k49?M3`VwSB)69o9m4eV"u2Z\K^@(O~st#[2igϙ fO  5A3so0mNDqw`} Qt "s\RUK|dW3 xqh BʯL/ .#鋋#PAqvB8%+GCr.OX%e]*_-"v,=&F6[z=:] u7C.Idj ] p{,w2hGB0*h8=. OyCd1֋cE_޽i\\{u` mhrx/CċGBM0p b q/5d܄nL.^ߠ$~{Es'B<]׃2/a;- .xiA8۽&m a-rsR%,ez;4\xOx.gE8l ].Nd Ї``> %UxW3DވGx=MrD)pʬ 7ӖpNgAg k92!“o- [i6B(}ꨗ]ODnHE|_|<Tݚڣ#6IMiuw^$[hK KzHPg]t[nup4TƑ idss>4<<\=lQFym4=;r- [Wú*>Z:Hcudԇ%5,ɦ(#JeJA+⊕A.zPhy5Rfcz[L29dORc;H:U )ɬ"+?!)4RabLGC.\\$KqYe*|uuk8fGuv 772̀qkD٪ [ n_s 4NF4džarYq81M2][rǶC.4³ߢ!k0CK&)tmiqQf7h$t D/Н +akOba @ =(6K~rҺEu &EBkiR`\U]#)ޭ9n*{"De2%WʒUL:*qUDdią$2A"){fڕ / $#N쏞T ͞&] !ホ?@v%CKELUJm思U]ҭi^bO4c]QY\ˋ>./ؖ3)HFaƇraD͂ WҠGE3x- ^wؕMAHQJŇM( ja'{Wn+F#daczC9<$°OHbQ ˽\+ʆ6N8IT {w߃ UIiԐ|~*^e֓.JoZkSv+=WG? Imu]qZ5}BfN B% ENj(.<{k |Bk>?B. +dgAaK M,3˽q gݶȴU'_ҧ|+BJ66B-e}*I3H4Y" m:VAF!Ç{C[mDOfʵV? IIgFcb :])$,}(ωrOOx8tlrZg-Le{yh^ؒC.7l(Hi!dAE".jAazh?g Cخm[mdxY*!Cg_A3*Q,d[;X'Xnd{.{d/w.5m1?Jz BD}eCG9,{ngi+iHR'.'vҔuӵ'-pyz6@ ~w@ޏtYxz0;mvu/4WG$vfhi#eXv{qZ Dї4Fn堤 'U)W*ډXCkHuN.vV黎'm"Ц F"Ó bD97`**@v| 5?|?ԙ/zWhI-Z%5JFcG}8Kxd.`$zOۤJO\a76ϲmS ͝eG%\u@iؑCFB_FY;gQCpHTFӠT#6:-ծ<B!F o_54l oQʰ*khh蝊^]"GM LO[#;0u YyW*z"9HSz,W)#h[Y>^jSAU\ʈ8N3EplZSeM"o[}BEjjiߠH>u^ Բ({ \Lz9|Ѹne"@k6ZjWk /-Ҽ`3=&r2U]tFEdAأi{x'(v σ}ƀ|v#P(a&囙Fʷxc19ʶ|5d=#X! _SνqGr8l/uCal@e!%2Nb(ϡ$hqlwo[&cd͉ p=s>8}w 4e# QpM wKuΖXewDʧo!7臘rX`IϚtt1@fPl>P>H5g"wzǒxHm/Dݐ\nᮬԡ N+y~sUY1#`2Y!CSl6 { L2&eiT7nZUUڋ$F%*W C$'F@SfsU1mR>`R F q'+O|z}Yp$;98uGm2Ƌ$ācncQwG[#8DMi0xM8Nґ)"gI1 ؄` _ytaR6ҮDT1uA{DF0X7Jd oc`4kɀ`]:Y>3=-I+8;ңOgY!K &9̲kcP{cO s,B7Q[46Dրv`gf%!68΂`Lr݄o qxJJ{F$Pln 2b :fWѺ趟u==5 xs)˾N. 2Xpu/Z8w]?Y΂Yzez~er$&tՔ!'wQm_ܐyD_&wYEp}|rYzBM b2SdθrU%VS|#O!ͤ] ?$dk>m>CIYhUz !c!IeҽboW " QKŞ7yzŊEn?&5ǫI0o(`pBegY$ J}Uy`> muA T-_.zePGʝw>߫y{a> ~Pwz[m-< 0\GgS`ZaVJh \l**]%έLy0} Y}E;NlAٌQ-rdRAsmt[vn6V*̤^5C8 `PHESH;s6 T"P2mt(͌| k4FT1 t_'XtRwin`sf@J=f+ZSكR݄Y.aǥ4 ГS7 D.l5N¶|M ݎ`Y$͢EdV,\ӜrC٦OmLbĞ\Qq'gb3HB&¡6$֩pSIӷL(mGaBg!`Cd"z);o hFD((xDy#0#{D$e yqa gƄֱLGdȞ?J[lA_:w81x4)odRMB]8/l5|魬eEjKcg4W%̓Hj8x˱NٲB)>AY#}+0f pML=m8nl}̗u ōE~'~߰ڶNVba u3힆 QQZBF~04$$CD)Zva}oU! ..e6[rK+{? E$ʈ5kb-F6$va2E_ LN,kvජIJ9KHNJ}Q6{;m"M6bw#2ˑ.-A̟m_48]SU:]JGJ XnXٖ1RQW8 +xG!hwaF4ﴭYnI{5n1Ѽ-9?͇mI1}I2uY -"|f^ZVM~Yw܄Iێ AbE̖o5ECozwםo[u 25 XXҪFp5WvG)!GI>d.tZyw:$3! &Û YS6B:8=+W>Ph eH!̍Fԡhv\hb|HU{W' \+#[A+ⱁz nw2R)WO`W.eZqaTMJhBfN#jJufH2F+D1xvjH[s&-2aϠ$>Tz~ϖGY 1GZÉyS\=g/8c0ʲ͌66%tˉ(7caTQd }<@t`;tKT!*>yg&nW?V\.#Rs:݄hK N76mjK\qr V+&׻GE +nĕ3ϫmdp1nIne6Og󧮡o{p74ŜwosԻ,qRD:裋7xPC+i[ɘ}MƉ?/ϻ&cpcA[T'⍄@q ,wʷm0}8C''~· ˍqNqCwzހ|;R~ mFh<>z[[Z.ۭOT/p@Y }ncE [:PIg}io "Yuo'L>E"ؑK "m:]%>4nwtzUlPhZFEKDKzz"[:ZeRVUrXNԈ3x'N=6i=Q{;xt\wɎ}uΕx4VWI2;qŋN=F8kՅ11* 숾%B19?T^J#{ X5- _=mY? ։zo{2 b_b.%%*'#d݌TC ^([!fTl jH-Ҋ̷`3} yU _ ^mzS]VTڰea5|Og_8}$0ܾg>f=cщ0 g>?Wrsb@y6/i֗n@!"},K6>p gc*}o1ݥphC/,z&0\"N)KUaZH_BIۚcq,(dvMEwk@J|Ä7)UXzklCw)Ǎ)GqA-D24H[0Nj⍃~ª*o7RӇtY&͝WGE7z1lߏI;)Yl%߼6_߫԰VkR~ׇ2ŵDCw]"aw!Oᚯ\±pG#\.&ѧM %(h@FCp[;+iN/TvߖCv-? @[**=fX?5< oI2C]2= %gn]):renhh.yL2Ɋ,n 2 r\++tCfPޕqWa++Sd@,_Y+Jߛn )J麂&$,,-=E6=t(I@+Iiwo2 N4fP8BN-fxC4#79V`As_ imkGx\NdH֔nuD^>$OpN ?I8)29Іe;ANAAQ]勳Nl_9pd2Dd=W^;!wA\>tq-d #a:U; !KzE1`w*bb<+ĈJpCux/ fvމ;XL]ɾ^ongr$j/-/ăӜN .c^O p! ~} d0}sOO\dTlYnfN i='Djؠ T xLDUa Qp|[e~5Eg2+_< c(*á( tHIEf-]HuIs"#sJG!fIO<_e/3x,.} ]÷4U~V{KCek6)8lHX#)$)JPl0OY4QD! [ԯseNB֧$"5Fum])k 6N#Wܣd0a34.m1imL iJLfgQ]w IߊCoFp̂]8|ߧyHᬁ|76|0p suq{V 7E?ۯvh]Ӑe&^\+4|zk3܉ {L+b[GGe7u`La>5T P%gl_P/ k95Udsru."LeEytX #8WH-pM`o˚?ze7+j𐛗ngRXL ˕wo<ASVu?Mha2>gϟ,#p^؟t'{ @eCY;lQHBܕ$?)`lu _ߕ8(@Q.;&qD{b :F[2zF{"8їn}p 8C=|v^kOHoҕIGV$Ɋ,\ȘɊܤ] ts0y} LK*`-wV󋥄@ F 6 ^s2eg2x܀?`3 Fxf+8J 9D5m]r6e>I#I$Ad;u.<0ѨtkYh_z| y& X.hT:ڕZNݛpݹOAGB=Ƌ$fOvcWSu˙+[R2HA7"q-A<1L(xK.̍!s]y-?'bԓXK!U[{\ Z0iX "TI -/>o/:#î?i~+2+W ȗ"pK3sG}wr`>]22|/J^+th;A31ɽ_AK]4lJp0Sㆪ:2hv!܁wGBZL 8le#, AP8s+k8:}o.3 ̮#:`^8,L@E"`=BPoA}hGIp̓X6`¯L|R` '-C1n}0 F]9LܤuK-jIa9t7cMsAF@O(AJ;s\bh 7`%:E.^RB8Tg+zۂTMߒ"MȂSY7 3Afp }X0a s3Lp$}h-xٍhyZS\ϡ# 8 u|P]" bcI=hק'aywx8@SŊP$te ;`6B#^Paf0Xbrz"8]`Gir.w&}EcbxO".s62B#w%*`(!P2BF,#q箔ѹvkK Pn٢oPLP?LhMCnUUCn;E4G o"ndl Zctt*Hu3` _(leRTiu k947xߎ6!;uGѐAɸd ٙ*ĝ ؕcj3mtCoy3?*0*2׻4ϧ~*m5:o[-ox停-Y^ rxan^kB@maa>,Y[wV݃yt?N}2w#~dzxK g.ڟvp ߤ/ t.d8\P}Npp*ۉqو@t,:Z-B<'I,IzhۻW Ik~S zĉ>:7h1eR qYNf O4fp ji<8H\3(bP`9sazWT0A偑 Y|'P !~#:"=o2 *EVylS;*UԽ*v Lڄ ޜ-?HxEZ$VنG<}]=/' =Amݻ'4*,wQ{kb3'/Ᵽgl{np! PSyq `{ᾝGR|N+KIfC6r`'kpaia'| H|kӐL#Jv;._vKGsojxͭ$섈Od2QAYM@V'3q[ (i3 4\c*L.6iy#+T܄tXRyc]mEAH ÌX t bӟIO e3@**h{C5Bwq"J'A;6u[) %|tq6)SpM s[h ֤z CcCh[= ?zyB:v/WA Fm**dlIz)8 <[eq=O@(t5QdWsbӭ୸&>/,ib0-]UM cV%a̓ :H7`rd!]73 ) "JDEq=DQeJSB~eX~2m+;/wJ2Z;ېJueRzBrv8b᠓32 }} l+6ciɮ&=z3 ,>yxNa甭m[4fqG:&~˶m J]t4̆,G#g Tm UO[܀V03Nt8ȏ">oM~l貱 ,4N QWFj]k;n!x2a[ D˄R>61# * ._$%HC.'ZF,M@dom.cdZ-5F.wl'iұs05vEb[m&jW;ɟOH0ɉFR5ؒ:uofCcowmōŵxnZFYƈ7E>h9{x2k8KȐ̶-ssHD-sf^,m5*YX:KT [>؋De7=H'v@Q)|-AzD|Ibtn(zM9}o[^BYb,dcA c&7bo"HWڠ6]l7R5~! b8N E@P) ɒKM Q.ۭddه:ߔ\.Ta]`%10)3v?lD_doL.mJݷD Jx[s*!-̐;^m߅L_B$8]IE U.;^/H9K7麞sa+V0R>KQbԢE=e϶|Q{?UnVEjWF >_)PWrJxoO&K`bdž S"z[HDyhP;[e7Mj_uҫyNj`kR6L:\nef7/sڍHtr:yh\Tsi*%f@?^&eUHV9ө:/\69 =UK/Zñ$-]Hznvl7FăXǾDTOwrq{,؄( vIA# Z߆A }MO i d#m| tZ(AB."0..&O3,'шTAp(<_:lDvntN G7p@xVY E3R]Oўיo7 ̆f`  nnAlhAtF{z/{ԇt݈Mvt a܎6: |.#TO(͒q]|W*M;G!kB3SU6 (Fl Ev^opL-a~Ā+2he?OFl4Vť\kg1ӎ "N"1(c0#apJ"NX(3Kхߐx~E@F[((VEK? /DXR6j_XUp[ |߇-=W/(]!6c4J/2^=? ;n nO;.<_)U?tɩu##}4{-FXki["UVO}V`ODAk4ǧ]wihk(D; ۩Dl`mƲQ+z4rqr ~]vL@G>HM5QV;/o&ƎɈۅS[>@FqȾRRtf3xh6?][{YmS+/~EUd/ GE&,BpR1wZw]XY)Z;rR5MFB;eF=B-jجcPxA|3LnٵTG2_fhjA5p+΂mi>FtfYJC>7JyR^vK:ۆy-7̢=b_7.7#'؄'t44$2zPm7˰z?͛ ,#WZIo"*#:<۠Z}X_XwhY O<>T,-aO )ujq۹QD=7?y[@R&Z~NUGQv!qkdAF6Olf4l\Yp/qvqxkQСX>wxE~Z$ic2?Hn:ZN&ycx/ uV"E*M{k}dmR>TsM+0.$:]ȥT\.\$c&ǵ۷!i9fi\;ȷb3Gy64eu`QN1B$%xAxȋ or͆ʃ2?>};{f&!ǃx?AX{hi`QfE*=so7&+kOh1<ħE`4`+%eċ()]UBc@raAT0MB5 nd7I?Nj8pi6`!eccYD%Rl.zײߤ6r{pztRγ>,6mdLl3?Zj u(%dʴC,n#Ü|_C[8<"h詮uD{R@޶:_kNJ<씭 E|63ʦ]FLmldXe-K6޺t U 5딐f订i5dWF->2Œ·70 JG2QC/a"ًv(TΚD0/#^ rt o(0xcATܘp,ō(זn#EQ/l d(8bsBK'jdf&7qVB)0b,3:#jbDU?>QmUS*#\=d; MB0UTzjH%ҁil^cX;mXQUxqucrP`llK?Ĭs@F/ z=06s*<>BSM6) {Պ@`<2Q$f s?!4 +- (cimsm+~ EDwi\b';@bYLRӭGvuGQۣ^ji@Bi풿9d|Ʋ{gG Zq$*In.!,'3uАosi R6p^gXh.z E*$#XA[K? GTƸuϯW_VPGp)SavlfdA:k'noILe !?%\ap]Wlk0pTJxƗe(y^uZIPuA(پbni9z/=6omLwl66#+يqJ_U`dc UEd[|dfI~QVb$̉B ^ B.mREcY9Xa[o8wM h MuhMaʄ-`l+Tg@e8][H> \rZ=k+v`V(tM1I?._v˯~}/徃!t=QE=Ͻ"ʗq}{moÄgU{[D%!!$~ OR'˄ NҪ_@py` oFS Q/h*QF?4: O~y d=I@ ;6tv}y6b 8`'[ׇMV>H׮hbe3X"xm ]ozT>B~leJ5̽If)\rDne]5@%oZSxmOWYBzo!r0Yk+Nf1! ̎dvY@aq6R{5%b-a]!Ҵb w&ëĻB6-&,bmq9ҡ|,~zz;L'I%iX"ג\1]|ZPlV|\Ov8 ܍&ЈL:]<-C^T !jUf~D?J;8ΙaZ񎓝rH{'1Rl+dlɼ^$2^CZ-k]KР[%ģ+SO~v'pn10 tR / [Zpiޘ]|IÚHv,$e-T㘜zQ8Xq54!VݙjБ3H֐m\Ι/K2 fEA|OEͦġbZ \V,5O!$ ( '[ɛ6U-at`3b &揺tnDbNhT,V[@xNӡ\JwR(So1 &W{UTIn RQߡ[rױ^ǿ{R*}Pm ?~e-lZe*{R/ߝOwqumjh|6+UuiQi{GiT!/u;Ǎܫ|X:iA%KP-ю!ԋxn9ςx͟~u]L}dCjz\Sh0GY>\ÉأEȝ?^}&mJ.BVJH(˪1KX2`B^t[qu,J hpW|>=,=$4&mt~40©_gWP\);_e̒ʑ`jVe{I[p{ SuhNaAԓl-IZ2S.7{ZpfK(s2d rKX$bOs*cⓩ~ffTR6B֚0fZK r<ӳa 7djt ddu 1cx|Mv+}X<.$AgY&-0FW'GdU1PU;Q56k;\> ĞͲhDa#$gF $\I!ƊdW,@nR*9 wo /'|!*K@' #pwca^BI8ddfaTH﹥;.e34$(Te՟`]z}"( gIL M*f7>l{$eP5Mٟт3y`%#҈{v?75L}p>dA%2ӫKw~iͼs% &QBX}sZkqSP|R.yD@~ܾt}suv8[jj5rfru_go>-ޜή2T5O]-o:~~1#qQ`Weȋ{Y5~=27T!?W+_ö6ӐO揆׋H$M!HMVM ԟ_z T}m5YR{\4Hҽpz5_ޖ!uz;{ss|so͔p{)ןNn\_~g^dD(Ȑ51̩TWM"o/: ;vL4h\`'ϫiO2 a?^⏞Y3ɏ (>moiy)@J;+xX;hJ7'Ggh[t1d{m eM8S$'~۶͓:gPcM!tX7=zz@'fLlQ}| 8qͤSˎӿLQ#EgaYxb= Fh%p9^Ey`J,t'w983w?+y{/q x52I_Ň_=}l(~:n<FA#;6ߟ=-UZYUQby}Znbȶi ANBlj% ^oGKA"ĺ~xbRtrwTa5ٹsM ' Ӥ`ᏴLyr<@:%0p22kBXzL'P NSѐ+~MY |orOQK3j'\tYpſNss!׃×x"'l5FpBm;-:H9vK@BgA^Y@ ;xpWևC5 FY ÄSW" '>%LĞ&;0ܹS$ ´=DjP>#!taq *5o@x0&z_59p C):#]bJET]P,Mp]V;\ {:ġBWlZ EаJv3NuY0@O!Lb$UD tSܠ{E#r?tzhV'gԑ ;<$[0wgSĿKP>L =N)m͕^hd wc5ƸTX&1r) }M83kWgZP*l&-үE(WSu c/9'ֿ8T|! 2Xne68D9Rn"}I$}0t̗HwKT ArܗCNu QJV4C^;}Џdx2zH __uzsVF =W#t/ovx4jCTI\b)6 8ODzov< ],-]^T/`Z(jA Rî>3mvrv|eshR߳=(4&Ǟ2r#~l-,_0SC Ew!'~YY˒D.w!6gK+dPwkGߖA7u*kȈ¸.- 7O` 7QRDv9BLF#Uiӓ:]B0+ G%p{e#,tn<9$G=Ä[uhuaҡ΁iKoN4/`eV!na#FUDd9Uy Rpt~}l=)PnBn܄ m1f1.QӤ<]nF١$@0~!߭je%t=\^)-NXzp˰mXP͓JlC&+gnO%D*U+k]5CNF8S! ^ rȴgJ KA iSWAN>teSg3}{zx\I?}}iYVEx_H?!p.A` G*fS\ bsY#h8 XUwh٨$Ks7T[z&Nr!3jC.9- ǨjrPXV-LJeE,^$3Eaο4܉@N /I%}3B"Xw2Z#K fP=ds=Jx@E^wP(V(8fEAqXßL'4;tƯ7 ySK3n04۶|Lj;El>' Ffب`0"co]igQ#qns굇϶p?bhr#SS̊sV #`ӈfA4BIM;"ګ *ԮlsR%AZ7h1:Dx7Ş^d>`O?鑆 HOv+="')F%e*bkY+zѥs 8<`OQhr'Tg 0Š$~CT Vť`O5Al瀖aZx2/!ț ЇWRG+`0GUa7R&6M"FuDG|àBVVynVb\gWZP*v^ 35e*j]4-t y&y0 b3AHĉj<-17&IMO!+/nؕ+i1^"܆!;$7o_m5>Kæ[B>F T^`f}ޅ}Mf0 7>@ke%} t9,V,?¬h,z'ޱ'Wё1F\YP!Ҭbyܠw5;oB0HوO2w%٠75k&z}*gT Ky۴v'Y$(b#ȃ;DFC/l9F g)Ԏ2KzW6K&vjoIڟ?CnPom $W(,3|~o#:83;8GJAIU#0 m&4P{'f/ !6uAṈhod"ÅJQ; 9Q؊Т%|Ja*enI_)td-A0 ː3`&I mPh 0$:Ǭ/T1Бp*-Cу2@n˾QTNAHf(.%1ܐb+&.ldl1rEJ/!#G٥W.;PB~yѓ vC"key%//-9'*N`(׮מ#p揎ǁhmVDIaGQ+{ݵ#2!fMb=[1`0NkŀҌx!37k=>&D%JJ/DVzfSݔ*ܤa# u}Հ/s^A´IU?3%#*9bVi*j%^e^]|R|zelߋf[}>\_M2;^ *u~jAE*-'ѥWn yC;Z&"^M@̛JzBpI׮aZY=04Me2&1 `h2`v%C%X![GŧӫaJn9NTrh%րM2e7Т$nQg*9.FH~0U: 2|A/7U{MÈ2Vn/RTؗUUKmiQJ1[T*aӠ[kdӒ,1egii,KJrG.ʄ;bh0$e'kҤiö9aGu"v+jOX_XwhY O>e=ܤ t(*6LJ*u+2wrahh0k/lPSj?}XF$bz桲%]}  -j$c]xՑyDdeUfEE`tA N1m-[[Jog+֋iil_mH<Dm:X"-)߲d UМB49p\;,uQe Ƌ2 U1B| L2#QpmA3M'\! ?#ZO5o.FTy_y,Tbz͋mRT76A3AsAei+N$XL˹9s " -H@\G2U~ovk@3@Q߮(!@Rn$M@2MyeAe;DQ@Iu(tFQ@nEI4t>CJ(2ojG 6C| nF-EwYoiXJ  FލHvۼJ6oCXY]g8*/H/P*ϔ1Ǝ>j# SǨ3POpˆ)$?B&BGd0rE_dj-'ENrl|pT4 8bDPi/6%Nl1RL,"s942酥(qnR%,&r0խwгNRFH~t52P72/V!FH&:kIJ9Bnow+(s4 i ­-5Z3%7k:' nEl<^ 4W˧Cu(uES4k#bBp0kVhQb\+`Й ^Q~BEhKjG+MQhjC$/۰p_ =tA#Ȉt)= Ae+w"ƙesIjf#?E Eɞ-0̊ƺނ1ןg'lhw~I4-8vS $""&˙K#2eeg McRq55MQL"3q  s `3]7yQHy7(3'pcsD2{TL>zbGpUPaV%VRtˈ-mЙzlic q;(z<&}hBj@5eE*EЎ>^v"F C7/{E'nhkHFN 2l"XPp hb AG}+dD b1H1rn-^4 -?F.x(bH;P 42'ffj _64 ̊eԤJQ CPa_ l;"+vH.{u>: '.Q ҕ^:2 >ǪcêyD9e!(Cax.Ze28x6)*'FoW|a;/INMz_Cw4>RCݧ[NjWwп *-Im0–E (Mtb w : HSy`ֲ5.,'#U5,8Ej2r̩@ŲL.8Q9uh\Qj(a9TY^v z+3?4:(kgZسLJ$q r`gX<f|_{ ?o sy+vșLT\gOG!.I= >:+4,rw, toŗ[$6;ZBbZKH&7\N]^5n{abչ m/f3̊iH<^,k%捇Q_[_6Y64 "EI0 Mw_5PMa'7خm_+}/`J#6ITixV<^x3&xVa[M%ѹ-Rr"^#2ѠƈW+@uzc3Bh @3OhD@"a 4'q3V. xmIiׁ8V,MM{M~g(X<UQHͱ\8=ʷ@f\jq퐵L^t|s+ZL ៏B2: AvOf ?=v–/^iv$>4s@P(VK\ Fx@I (0F<c+'C~L4BMcM?AQ#r`[ ,ViX8d3kH^$UҔ"gK@"nx+wi35y1o53?RXK/(jiyX` 1Zhd(|ӖQ%(5 їk/$A ~&%t(}o44J;* K>͇fM- !f<^xVYrޟ$a5qHkL(Xsw0{4(д(䬄8NJ=Ia┌S9ZL4vB)ERFJD|?HIRkx{)Jf6Vf-6&J _br[tuS90*ňzR,!D&yYΓ=ˋS`dFمMgdeS^T}vRD$. th \?"Z4 2Ʉܐvdw5gL:/tAe~|n!c4/lWJ28kP'5Lt;[ȹL㛏o~N20wd.% RV%-i,kJ#f^S\#`7Ke%#!}}hyq>M*R0N2&*`};{f&': ^!1=@Q$ұ!G޽IfDΜ"_~!t|9!7ɈIiRӐxVϙ;$~ɽ̶YK/BIAG7"u:"8窋Ӈ$KpJ̄sg  Fr|X8H% ĴS1d{&q逸r4 J c$|ÏGSvDk\IQ:,| bh1Xw\9J0ꨣR`&9JoC)z i(4nHW + 3^5SL)r5[FGXs788bNGYM]rF 3(n[L-VGǪR9m/[w} mZSgG}F<ۯvI.ZBUkfY3p2 zXv-)]Y$[W;݉0rAP# 4\}mTP%0mqP;r[V͔+{5tD7Blu pAbbKWGdj^&+` 9 ̚CYn`7dFj\cބTYFU2YsB= ;ŁGAep*vv[\வVt׆Yf"G/AZQ/SRSmPk0iwt4`a+* >!B'.[ \3\(7q{Pm&tyJU^O$hq&OݯŞ'[j1UՄUՑ p6k 0]n1k7^@ '$)S>6GѰG'lJRV]4=7(([)Uw7x?fJYkڷ.))\;1m W,JYh+6Y5 MmWv'7i$Tii O;8ig x[+ 94taZ{v+n}5h*IX㿎9i9=U1Oӎ>=Jc!lxܿ#pcOBe=^Fc;@}=:pXF|EBB2!AT }EY7Vrq@+`IZQVۖ!5(ahhVT,kry+JXȝ cdbKT.٠{C|qs4dHnT'tN:;{]uWE4)-tk@'ߊLpGd7v%"5P^6/d:D&َn0V3aB1WiLnj-˷AC]"՟S6f#QAl6CʿusQ r7wYV @oOpkG7>>Tjߊ A  Nɘ-0!tqUC,x9/i8'@4 η%I>J(_WF´׿8zG42_&303߼'I<" X<߲"^Oc@] (D8 JMd6Ƶ46"a˭e]Ot Sa qqg`olY3fd=yi9PLYA>9OꭖCKfxPT>dCw82j0+,eVtVx֠yhrE"CN4lIV|==6i?s%FbF@o jT(j8,@Mీj, Þz91fW5,ssإ\+1)mWݢ)lM7БLe6ԿӃ23YnmĆO& DٳQ u#NY%[o=%ϒLePr5Ƭ QqKˈ=Sl',7doF\!Jo2XC&I0`LN JloVusSDVqX(;G`@қl!l{ƂA&6kl (D& '3Gz4]˳$Se웢֢=558)lROjY;\H & !`x0{i} GL>*f nMŗˣ[ׄ.l*{ާ7q՘Kgg}fض dؐ ^Æ\dQPrftg;st(0r`60L<$<#CnyU?֣ZƁwPdyݦy7Dv}+]01kKJSO!E:vq#/2M.BgP+aLɮʪ,.hz{Rqr6 h4"wPH(qYŃP7B7s|V0GQh})]eje]w G<00䃡;534i<܂ ZYlv,n kӏ#,u"$b+Ҵh\S/]ڝᄒ'a &OVf.U_ɓdjBS78$stz‘H0ϖk?e{AFx5dqA87LSleOzvO*ҫ`Ȓ`q @*ݮД"K)'e P 3ߤ+!/6yfԅ"b<\T{rrF,77RM2#6X˚kN[ 5¥+gN u$]lWp 4D#d0C 92y5[dC P4vTBKL&E/tZ:^^Gp*/m.~{E^W@߽(mwispM$~^WyϰˌL"2@}r~dMػ;O;-8^4J^; 6۹$ez5\` j:fk-a'{3zGkbVxvj.:*3.w`28vw28揮B dܤxiQelܓG#*ltȦW  qx<-`7"bEۭy>ȪH|,兕` 2XfLj`d# !ϖ8;nDϻz~[_ LEH,-E^o>ܾt}suvfj?TBfNjwU8ufneur6+PpmJliA\L=h| 'ǧ:?xsz;z>M]jt("LtC﯌Eoɐݩjߕ\vMZ6 7٤G`sljY|G9 }rT93+!|~ƿVogonoN3}3>^pz )e$/ s4-E*6I͛뫛O 7Z_~}/Louo_Dv:}(WY&:OTʿ"3 >H$[۫fq5 ~(=dk0(}%>|I5 &;0ΐh Tf(Yp<}3Q)K'.r~\O띚0-?;MeYzQJ:6E M2lN, J[Z6)֩끢 h, k<\=@4W{(bmh\!e]E+f8V"DRim!%5RSL2{JZyre!Դx( *J?AlOc#"8Ɏ=Yn׽cґYdINPJ; X)t@I}i \СrhPkfxxh4[$Y ģT3fhQc$I~3 B6݃C}wf8 l<aO+ih2)viǞ)n0{P-&5 cmyf^G~\̏O 45رz@'tukއ< *]jŮ5}D֕8[r2*5h%ɼt&֍NG_TG˜I'Pm#`.m 8(HM82I+^[ ˶@2Ɗ?wZ\gX_*D0lhE/SQEZ6ԕep9g^VejVݨ4]0SyWioW^XL(N–߲x@RxKY| Ơ0z ~]vكC:^kL2pwsNdO?^ y/+~v&6]Q*4lT)-Z+*-9Ovktӓ :%PdP4z_b2.!չizWd[5J l%;&H|e$&as\vd-|d} 'l Pp]a?:0|V%~xRffdhXg9)$@/N58 j-X*f =ɼ޼=ȩfrC? n]_ C٧߮ak.ۭv&)Ky^f[=M 32XIWWA"[59B8m|e5/+!J(&9B2|bֻ #u[_#"fّuB!=2 d jJLAXa?/#]}ev @G|h'I- d@:ϋ-! D44b>V}$&" H+L!3IPBxJ<6y03 i=|XU8W _I!P+;QWWi(7ìŔCGm('-3 mCRTA"Q0iHRug'0 KO HңMۤnm[Elf6 EfLvn _o3ǂ{Q`M2˟VIwG_ v{#Dt>MW8.Τ!鿱1' v_TȞһZҧCu(1kFWICͳz*؜]$jL¿գOSc֧yRLUЮ8j]MUIJe2pB>j«v ЧeZ{~em^A r7S^rS,eZT7TSA`TfA01c/˧I&a݇o3'EFgğ?(@7`x*1B~m3஥ŋ?{0 (Ғ̠sC3d7$>%!A܆bV*bHvۼJ6ou$RfWgԇ /{[}x&L Nŋ,Z]pGx!{U=c" BQKJ>iqv\f7_,"RB/^g9/ZoK7T|Z%٦$0 v< w!oB$_@&0ss;xg M&caZ<t'|i0<3:)|nC Wg@F JLO ܃H+N۠ZĶΦԖ+rƉvH&+ ѝ8Nv:Nlf$Muq>ݛ)ݜ&=N.lt.;&+oě]U/D.1 jcZomHɵ/.\݄g:g'vptFΰGE[s23\K4#wB&}z$HrC)N(I9⍄JxQTAAt(cV#aGo$iϴ"k$F4mEQ~mc'wx:_u`mcjЁ?j G857b}`Xx+ ȯǴ(8Nݛ`/⏃j?u;dD q'BǍ3` X% 2 QlXfrP>I$y6s,{aB8VAGނџs`Bm4.̫&=Nw8atEK>:7m`˴yذX#Ǿ1J !]~VM;LGbdFe&U#B{?JP|IgEA |DIa*8,X9H%A1E` \lOwj@ 87"Jʀ :z΀ G{Wh1Hacu|9_vxZYCP0hLoW\Z 3ķTB}H-[@4by qH3# ,!*UX.y F)yp%bn٣$!^eK %ǹf#,%X&+6ԱRVicM+qd6ԱRe];,TGRʲ (b~#ItI-ER^ǸֻU;-5Rڬ-K fȷJ-5F*]b,IK)n@^{$edOJi-M/QX$)' PRbf`8G˵XK)*jP#Z6@g y*YȀ:h2_ {66L7iZT}wz݊G8Jг?y˲`)%{Kぐl3(V PTFy#`fcjPPPC:$"3v$T`+1H$fLXy恲%@9u Ǜ$)'(羴f +B/E`Fяg$< ZZL,(AѻnH#%~M)x[?("RPS]߿iHz-f}4)Vr?By%mZ?ָZ'E_Mů- iiyzt2c{w~/d$$$,ds5ەUqU-ڠCƨUw/h hBC^k:bF*˸2-3oñšYﮞ_}'Si;=[^O߭BSi5DQfP m{E w"߬)VQP~wx*oPJIt t1*ȱHM5\W87}ufNy-)}!L 0P6>-uz_~wͿOC-xÝsxK7 aC) bw2B.pN]:P|^ą864t.%YcmĊ@aʅ{FW}H`y^ t=Euq|έ6yjw㛷 RIS֟L^p< GHKo!#Οt:WJ8IA07K~FĹG_QW*uc?&ň` 1N|MyJ?\g:['2I_dqnӛT/Y»-|:z#`"8ZjMj..]Vkl V:=xMRa1xO~>[?*du^[1C$eQC9Cjh"|c;13PȇQ :D嗯w*#(׆8=6U[L.&V ۤ<V򚎊%#TЉk4Bg *{jRl.qT*`:WTd|͒Ą(MS5+c $2(HYӱhW}I]>MzREًb&]ggR2iuj3UH]'W-c$vxJ[fӠ7wG`cI7Q#Kꮖq>%?PW|g}1&޿&U"7 )RM^x[*tO6ߒPcE6c@ыBʏ,iWC+]V ߅[e^l0{lժhkjGK= /W դqMmk1̮w=[$>2:Z={x(Ѝ - 3I;7O=T{F##G&}y|o=#2=vYQVea[6Q o+WMby]8Mj -s7=U8We݋va>v~ɋu Ƚ;9HWQLFTY='/k/ֻYG?& BƠeR&)[9asn=uک؞O T ](=>nͮ yBBXmAf&wj`QGAC k|5 9^O[2'Y6 +{g{|0T; ծwU{ 5p𝙐t^EVmdq*5ܑc~:ۼPC%wTg2s܉&(ܝth nҕ𯖇Yxj.2or b֧ꧣ&fֆX||wdOVU(%+qB+-)fƁ5{sq}(Ma } )?÷e|Uo:P&I@u=˫ӣۇUsX"FjfiF)P_I i8$l=fľG;OK? _͹Kq-+Ye=/d ۅ őD0$Ww2}3e`;"$G zM:P`?лal˖8EIA˶N[t zܵ@w}N>UvPIg!x\6[:W:#omOlP Ն|:fZxzaK;pB'J&^ ]Kuu?oCi8jF~3p=awj'IF}:KA&I3j J)9^I5`nl78s鈾i>dbY=I>I!#d^>uac&+ 2"4ۅr @ w(󒪢dyWKf#]>CWyA[1YI2t~?! \Eo0,|D=AgY+|(m JQGC' X2H @Mw~!6 V5yu"paﰮ_uuJ5qׇ-`dtJ6R.KYI>zXd4 '`oqH\*cH{^!]6}8Wˬ4OuZ/ KG|%ēq7䷠~[\VXp몔\D_Uƪ"&`7籢=a,7hWNFz#ݦ9/mV9Э}`fL[  um3}hBkǁKt\b ^\*l~ n[0R AŸZNjR, JeG#7 n310E1UY728&_4&*{3,fE_ >ϵ+ eH~ك*;^MrkAț_(!/Rvl!h6IBM)bɝC^G|/@;1TO*Y0ꌆ}s叞UNlbjO#^jk#=ܷ Okxz4‘.#$QW(''Vwd⬲m) ݀*!KǛ|6b2Ba[oY{kzvONM#ۣL4_grDXt_<}xuzWYu~^ԼhP^)ǹ:"ZO8| d9_`'"Z}[tC/ZbY2l4^$@  VWA|euŤSdvqVz"AQtzЀ'zl5ٛCzH2d֐,duԔ/GUC~wLsj{Ýn*|8 ]z^|WmSIٷLrϾ.B׿6~[>.H*2>썜`;gH³PzCݭdj4?F7- ']ڧP.SqFA~C] ߇i7IQ[LP(=3-BQ/ί~CmuMаiMr\Ώz'jha <݂q]Ѫ('V5OD1لܪ3я.d 6^gzY-;{G-]$ςe{ma^@헎6Oض2LDm-'rgҕiV@BCAW3=zGJ_~nu{~>Ar*8D A.,6.WOnc.݀܄$F@yRI&ff ?w~&o%b Y;r+/foHOѨxO1*DmA B6@PVe'A:T-tNV{%N\Yp<V=MG}6DQׄ APcvk! 9v}{!ܒRC>RB{U&r%_vkQ*MI{obCMmS7ӻԫ>FZ9q ~ǏM|/5<Д-2Q|! L r[pڔF8;yErzj5ĵ|6{:໛_q[pzvLϯ?u<w;ۏ7eI0yaO/^hß}n]!ic[ ϳzZ- 'ϛOd*~?"9TMR[N>>a 83-)uF0 dN̊2dDŽ&̊:VQ,/.4;4DȹҨ׵7yfl u\nXom3Y2ƯBӣϮjjECX#vG/֩8f0!FUWkiq?=!#~{Z4y54JntzooN.L]Vr!5S>-e;sywe]LHt"sŷ0%2 _?+Vu(&7qO0z$&%9)VSKhsu9Q KD01[3C qb@ĠNI8 Ā\< a 11o]^T/`ɷx1@1+JImH1bgZ5looQO*FjLmRiZ`3KfGZ*'!RutH^%ȺOt#^q5F81 tx&Ibю^SbHN#І fbz=?y> Ma/>Djq}W^**%@e*04.]b}/xl܌.؝%i0 NbZC(~/(!qUP4VB`颰_A(6͛P-='ىyq!~s N#tD&@Bh"7~ yg;|ug9`r̶"~a{g9lB 6P>8䑒alpmj2FJTT1?Ն6R 2=e|}&%%NLGJHx-t;-ɬLa0P$$QPaU~72/V.Ŏ@5pf!}Ha@˦YH; }GBLqj:^HO6K(酆$UM܂U2EA XS 悖8VLUV3zPQNJ}S*dg& WE uN7@F,mϖm= AR2b~6jIc1}t.w-MK8:nd?z)'BLF#>-*otW_؋z[QCqF#tp4 s `3@,΄pL^1!YϘ#œ={C;onaln5v{!}>Ŏ ޫ&¬:*-1J1VLi"5m#!#aܤMHkL߾75qt`y EeƼHZ~PtX Rz[yBˏfWe .~`Pl>L<943 9q0G'fEv2\#HRV!(U%En,0U'A΂ytF$?T Gk$pdpsyjA_ha»I|83 M.h0j#6חY C:lpu,<^,‹捇Qn}}d0fLN ]$"Dcq0ۛ"El֪F֑cwn35 IBd-5|c2݀,ۦ;' *E5ϲ vsjyg< O^Vw HB.Lcv/7!@n*<>S(5LadEcߩ4aa#ƣ)M"=ʷ2?첊:mH1V(/ۆ^T;O$Kɿ>CBDaF S)ecn1G\_HAdW Ĭ(M~g9u N4JaB(NLh !B|gVi9l-H,!cxkSۯdxcʲvg)1XŋqM{,wxcģrv%B{rV 7DŽYN@Ԑ z $;0AHn0mtܒ JۉY xI͋淖6^ER_@ M/r&V(v@A/ǩN:(y"FskF|U! $ ;LKD0C>Z5d_]e dIBk֋SB窥ѵ(aj>OGL&WEBSMVsC")ohL2zqn~ʍaA|Xp#4NzaʍR0L+IhYg$|OSS8D${{Hvte?UciPIƘ׸vKuX$Xżaт4[#sEGtCU6[IpN&@>&5v;P ~G On8)q G~aRr0`O N Yu{bO-X?jª }Kq0JxNFgtҟaj}MiȢ=xO,܍^U#4M1P1 4 fIG[O=m($1.vj;4Ҧ,PߨS% g],ޱCYO+6=5f MmWv'7iTQTi ꖼ~Y4yytl܅M jJyA6x-^lpGmcau-gZ6dPVVGSOXf4{8'[=+ n4"{5B4`sM謹'w=aOЍg30٭-/j\q G=ˣcB/QZn[z\"4|I6:?k$Jmű[J8Zu kƩ.n?6n16fmgeڵPf^8] EhDym9yJ cIݚ6\X)\H+T&+>!{q7&~F3Q@vThY\CVJ9&v86lJt/OPk8 |mY\m0d|\얗yJ|-_UZ-fQ  l!@V؆mnʦCFb-1)f'`2 g[nFwP|@JZcşzKI`V,TcT)mly` ^(Ų}(dup.+bW2WLC=q<겤O ;\G{nTleJ\V@J?0 zB+GEtG(-\RNĊƑKW!n!# C,B8u)!wYB'+X%Lj"dϛ}m(Df+{6LIyEd.۹ՠs*Ƴ$6N;TLjQY/䖷邨$ɋGc<`_!΅2ISJ,A҉2:"p<f% ? =` @G@8sa}&XG<.l8GrM2!_ WæB/ȿ؋lqo] 0b]G\FLhp1 ܄"*,1 JY=?Qπ{?{^*嘍t{p"v qXaKv"UK3L_1(3%r B 'wֈ7n9X<jC|dB*D9 }EY7V"^i >0 $l)mGFN )J[21B*~]HiR|1B=Lz9Wfct!@y Һwb4H"ݻI);3=^WUR~-t@'jGpG;7Ô 2ѓLnk(0d@{ǮNd;Jd{GY_3x.2g\}8"P.d89D(Yy?`!Kvb AɀX8az[+ 拉EII15)J4>}I2ϖl@a.A0%۴ZP-1݂ L( UT5\ S:꿂8&K_@z>Ў8=GBiBw)rkP##fhë](?U$iL,g6ݕh @Qy ;N,ъ8ͳg7^͜ݵS ī@C}`ϪCf^hI}̜V.\8,'b8&C+PAX }RZ:v[&p:W tΙF""Mz_ƻH3G"_vk (lP $66 'HgquV[ Cu(}n.gf]ض L h шQ0kBT2bɻ/ B ?TwaC,eN*anm-5鈬0` :qÀ5힨7dfa;&[N7?),IF?/Eg  9 -TstD.ᮔK10*Aox93kᘜLKUnCA M rH?4bh9T#TlriAߙ3n*kِƊ p+hW{uנ d^zWْ7 rh=)-3F{vHv:;ǁ5D8(Cahz;bŁ4qmn$q}FBA~82x< l'7|pM8ٮ ;=1q ;ۤG rBXZ_aCv&g #/0; zT7Xd5XV:zio*׳xl t. 9{gV5seˏ! hBI[FxsA(hE} QdfraN`F @WYEY<6G n{QП w\%Lň>N>tL>su-X`)&?T5!z6\XC $_݊ XElx(+etM+bCyvɘF^.{*C325>/}}Dty(nSU\MvMZSLҢ]7D|QU](\MƠ2Vgqe8M5(8oGmydWeUB v4==):}xn(v$u/)5r "᜷s$Q{7}}_JϾ?  ͌mf$)fB9ô1'ЎiU"!]T&2ۥ{rM~%@~\|ndi6?l_}IOY5eDF[dGH@=2ɏ,\k} 2\tU ʿ&R 厸3s!ry[x<vtċ]g"fQ00))-UeNlDk ׷gwM!7m=(1Ԯkx Ř))ozlf$R2\&zp=#~'AP'z%|=.:bB QbU` *=vuЄ=pXqfay&-ī*A;I[*엄Y+ G:dMQ˚^ bzu䝋[=",Ş^imtH~EϣJ`zeɫ c ؓ*B; igфYxCTnv9@,-kBxLF'|G͌r!0?jl(HMU)@rYd*/.8xݧ뛫777?&VKg6:9dttYvFjHnv[$R}Z~3iW7oNogWԥMo܏e Ra*#qST]= Ay>m$MxѝA-UC;j1LM6DQr -ȘT91 yuh3H)}:#k;T}m5JY{~IXb9ObK䀐3r5漐2g7^Woiv<7S@9kbjQNյխ(]e7<@}8ys}us` z}]k{6mS ۺN_Jecƕ&啞HT8hA?\'YgEfXwC=&{'fq $ M 'Fb(I"7+T< fŜlWbE˥ɤMI|{InBMB`35 cn A̼&=,job|#24~F-z@'tukއ< *]Nj-̮5}D֕8[r2*5hrV ~ᶤpCHÄb}!#N|jLD 'Aw4УcBX>[Sݸ-DPG/z՚-ҺK]#˫_DZLRj>#f*FM .CC5; bIV[*oY| Ơ0z #ޗ$bv=ۭcyv'}Zj{m >ۭhtEMej~i٨=JSֶV./Tj(*w6Ev=i <-Q[EV-E*& wz4)ęc孃L6\\C(JzG._='~2J>^|0H"2K_*h.E, v %QE`osՏ3Kn8 X3fOdYk,,ݬDN`:^4(/+4#e,GCgb'izmo\| |%>|N%~xZ,+.v4,m sxHAwl'уs^u.,xEwI>;frC͵ 0s]ān!?؆|qo0k.ۭv&)Ky^[s=L J3ϲT䁩WA"{,|b,|l]Y&uC3ob+Qh΃*hAüPɒݐ"M@geJ/n$ۊpdh$wvu K#_W %$GHݜ[Ȇ#38okRԅn}z|lp΃#!o(2l|b{v͋9IlIܦ!&y^l AfӸk|(2W5( ?N}$&%'qCnJVE >#߲AZQʯп^M,aCG('--3qP6)t[Y"l6#tXPFYA/@܁׋XPeZ$Ch|w/a6{ZIgX$* !rU/03. ~,v=w$ZSU>Fy#DAZLF<8Zdx:zPËt}y/.0dƳ;3h*֝W_WD3(os3j|[]$*W^EF>=-PSmO6n)SS,eT7TS;AVgodA01c˧I&QZSٌQ7l胧Vt7FP/mVxa$E\Zt&6X%!Aܝb*bHvۼJ6oC .doQeoU F KxVE[sϸK5dx~RxT#2J|I?_l_ b)[G_ڪhuZz' )Y:tCŧUmJC1؀l[ dp vx"F: 887׹sg?{7e֔^e{A^4&O-ܛ|yTӶ,WgD⽣\y9[ɌSR ՍP7|_}+S>SL?xy\H ne*/IԾ/y{4/@ 4*B̦֜3xlfo{7ڑs- w˹q&0%ؗEJp (dG]JhkDyyV puvd<3Z3@3>oCe+׆b 2pϸ9l%!I{ RM;O[7q$zXk 'u{Js+b/_*F& .#X8}{"X}.kR}ɱZf}W_p-Sof }õLU{d*/9f$Uoڶi߉Q[i(%1:&V~>XdJ(Bʇly躲A;q[~X~Pr5W?W1jU>ɻ_?l?ص.# YI 1'⋠^rrDa_YҌ}GWAorD1fܔ U/q˺K/ܱ:_9%,sW_B hg. O|Ui0QO`χy_QFL]<7譖 r0%-?88Kqk_-\Ul}AM̕B7YY]^MGn2IO[Gor=rV鳺w< “c;w#EM?H&V;uneu{t}˃ڐs!792Ջ}lGpľzo=?3rԿ9^uT媳$G<;/}vW(Wz_}o}Rg)no!~O97YN5ۮ6[ySVrIk5c }xzl%,Y&6ʣ M[*Vo{^x8 =x2f"gϙ Bb ZgQզ@ua[BO?\pd?Կ9SuNG*G|;?roOQ14o0Ri"3{@uE਋5$,"'ĮrcOJDŽ˧ %1 u ڊS]+WiCo>)G)͛ jPv=Ӿ;0{" Jo4YVզܺ[93 X8!Sٿjoa uue[Nuk!?9f9KCQ|-f+?3ہO6uJT7FU=eɡo²O} SY.0ߨ}OV5n2\cW~X1o&0 w_6goKP"OtgQ~Ws&=AeswQn2b [CU+tw8L;$nɑ3]"QayuuXJSo)%,=u#F{WYϲr\OrSUR6ҹІn^6wBX V.kz?1^~Dֹ@+pZVA"a2 6<#a˭8eF~|_^[L#~=LXr6b.1 0`~z@s,OU'Pnv39X¼#/剎rΦOYLWSRvW(9V*GJKHN!7- d䴳#+,&4!_'gj(_E.OB =Ü^i93TRZ ϩ?IM%0矐T]đ68pĥdP8v FC8\K jGq*bBX901!zLL&q %CT.!O@U9J(PㄲOuOP90zPO#&Z?dWJy3>YOԚLWce2A%Iɡ `N+afL-af!alR fj!bB1ɤ1⤘ &?EL b|U8UylEr Br "5`QA 1QԔ| lIuhw@q$SД"xL5H+.]4VF|v6t7` ?p6G`iXD(qUQ~yg1 O^&IB~p:suYcˊadED$lƄs6Hn)'pKbfƄeyDfV|̹1sBH adOsXBsQ 6 Q7H3#%MaԜİ PjI)ZRZdZRj4XǑ 0 ɉ%>?!E$9+v9gaKcDRd$P j6< ^pSI]w2pLU1QYRKiޣ0*rr^oif+h̅1A4fCY4~&Y03tZ3lnx#T:vjN]3u4nvӒ`@Mf@M@5KfC"5nȜxYsB @0bQ|tڨؔvas0a1\qqNʤsL&Dkh&SDՎ!vs8>MuOy(-؜D )|!8>_M/XL! CdB3W$y/kgDC/?c A?xlV$y5Ni`;W'_^e;y럂'i7':GknWfꏠsv#o epk] ɾtK%Y->eT^n}{ iWuU\G~x97s?~|M^i[O_3 / ;4'?[K_^/{J-g:/T7i1͐Wd}_~ŬG_>[|ΝG&؞b*&-e[԰&5\HC|hX /ty܀VΜE:j2Xˏ/]<2T-پ?Ga{+|-E-z3/Ą b_gj}7ۧZ|:S?Gdf3^ܜ\r @`~`9Tŝbv]ptM{e%֋*Và]sJlXDOAk;8_J: ߕ/@_xWtT2cDuoT^[AB|=_ed̉;?_s?>kȼ3i*Lx>?TAE AG$yA4ęI!LLP_l;Pe`y e&]wZt}1Ԟ^S"5N>ទ+!o"?-bY_i|Ɵ]+'u}[~= ]=fEk]N"S_vM)A ̱qOߕ*{?Sھřh?ra72PuwͅXYnה^&ϷM]^lmK\MPm'y4Fm^xHq۾ԇ"Bq6?S!eA?sL], w6d~3PhXmo;K4m^P%_rZt?3 b嫽aP/A8 ތx:mSqZ}c8 -Jlv>3\6/ݪeIyXA -@ƔGNc0՜5w!IBGWF<H4L  HAfP򶑿246 e#苘JQa ozr"d* !~Yܵ d r8Կn$M[9w#Ky?)HJ^ Z%L[_%oH$|Ț#wI"7GЂ7.Nr .xa 3 z^nmH}|y1P Br}^.@gpD4C hx Fnd!k09y+eQ-Pg: ]nW?%Z20+İ_ba!f'! ~ES|?9XΚ5 s gJнӐzCW8W73&obޖ:1돔ݬ&с =21*XɊtɛ&o0D_$mgt$G{LzI\h?9*y]R4?4ESlem/gd؅|zլ\׳z X+X(#p"SO~1z{ Jo6z%qFH \p[;y[ {K DmB<:\-dD^zL[S:Y^)zs:UІ ɱVjvޫF:bS7KLJ83 Ggb7rsITNUOT(n= ޲Xas?g>SN&VP7O"̺MyMah> 7:f-w 4؀&]3?-:#TB$?2[Cɱ>y $r)wxvKr<")Rr+^A%,뼢~ߨSkoYŭ?~Kh(!C};}$hUtsg7Ī6BS?w֟eSKY̙ <]RuTe4tXID7~`[bj hnj㻲B?ׯz+o[V6VƫڶSI8NrCK &-bEx]'B}\>/rRLQH֮o͈J|stc &s5T{R_fPjH,/ FJrdz!R‡BV O ۓ_7qx4f3g'Nu e]L^ !/lGNH )PL,Eb A(D|r]C)P3dᮽI7ŧYZ쳒Uq 4#  &ዹ(=f$W z 4we{w?S:"$U!FAIWL#4~r? bCx ?L4āB\6oèeaoWInL:jO@?t]A 8bJwo/PsWJ-͓"8vO!{לmagM,ML-a-tsPYE'5#},u$bS1Bh_1|< NyB\?p2(tNlF>eX߉D_)$;9- :nrbXP52L(}- j1Q/xL$$Р$KW)')rZ*EP05NNQfq^3‹AFujR o(3.4)I2R;UPP@naK~!u߅Q8WҾ=$?v˂ʦܛ'lٌWy;RHt_I 3s@+ꐽٝ%h#Q ͐0ӋPLnjsp?:Y\$8&1a׈!(L8 x?R-IP3_>euuN =-# @Mey)>xv^+:1V֎))HIAW Ta(k߈1͈EȆi8}䩯}Y.gb0}uNj*G(ЍQq@3Ud0!(3d"+:1ݝjЂ3.;FB8X8QA?Ҹ)ubP<сJ8QoFV#;*כ.TV$3I.wV̦sw<5LAu0\d9 *x 'er_q脹m\5GN.2eBg+8%NimJ|C!XL5{l1eA l_t T*Zuo@K}8 viMAsoJdD)>-y!?2>Ad1M0~BfY6DžZ6}~)rZ꟨J 4=t z׮IOH-+Ӝ8~5m\1ol@.@uAǒYpD9%ϟ_V3ۥtacy|P&bI zS(%$sP@>~>Rvwpc'kB,č5#^GLR7>)nSb;9ҁ~ gӒ8v)l)ړMs&?KSM``DM)X!0S,Gؒ2ޟ@m#¶?`v>BT|ٷIha1A|,a@>l9#t;o'h\%fc(U_ HU$x=ơipRVO3UAɓ7f}B*Q_ٝT7oPJ.ArK(qװ~&|5*QN16RF?py3%M$7CG<k@ȵ`NOy9fg|#8W'7L5Ht1/9qbEJH#hʤvlCb 4Gw@%G'{{'t83l3ۺÐ*$8pGIaqlaU6fV-Sǫ7S~uZ/]Y;, S$!(JI ˭%Xv$' >LACjW܄yS'+0)39@ø6 !̦.8}uePr-?/AB\Dv*̓.Ga*ew|nB=sCq ۛ}qZBeү񎢞c@ֈwՠd[_R }!Cv@tɴ?A.픪GusOӉ`&.XL d(,I:u7f0$'yʩ+XڃFO„#%tEVn ׶awGGE(] lT*Qe IxiҞCn0YlU@hLj\EMLsϨ\O}GLzO ^l+ ۴q ("Snޯ廙ClySqh X#xUsGJy׳y9H@5 Loh^}ꝥOn"Q8IוgӡVKȫ2~N.J+Ah7>={ ~&/3R/uڿ[͉gh$v<@Q-[ZZ͐wdD(zʈ"ѠsB+Ymj[BCg݇FfoR}٬|S(Rc!}`|TPgOpDo$q=gb-2sRQw6{k4;J`ȔKs*k+u#0>ϙSK'0d=Zq18^JGQ` 1z$ eW囀 :E ;@yC ]59]v7s)j%A~oA:Qi:kn/R)Yi]8C>xmޚ#b &\DrF])ne|$W"?C'—1C]H:ðu!pi c0.ʺ\KMۗ!iɜhҳ@ Zn){RmAogHi<@rQ@&UC NɓuJ덅1;R&gҜ@O?3q.g@Դ@_Ol КHq;6 WY%­rX 5uQlr$qmoMn)EA]Ӡ=Nί` =z!8Or ԇ3C5{kR.^?  4ahc<V,(MT탚aX&XJ5k<>ZB9r38doh )bqZ dYm SBv8AA%oC8(l g!l 4kB % cxMꯇjgd\]-)Ic 냩VWAel}soc?f 4q}{4b'ՅGTv}$=(xP'h2H <煫Fq|KC$I9߁'w4ʧ6PdžV.ϋcET# j/s Hڐ*'#wVWګiYi9Y2ǁb!Jכfi菱4Jݱ LlnyZI! j߲Mne' feRhR@gLϥEY#9X: 7EG@(hU|ar|DU&p KN=B ^'Ki\e$w(Wsh_P .<>pkhΗUOHmVrsJ RT_]G4iE{e9IuI ٌ4s"]^mH;'C !y໲C~2BQj {=Mt;#}َsaD)Ktqd!dޮNN[4vv6iʝ׵I۞_+b=DRF$ϰ ^}lh{JTryx+NZM~^o>.}C ~'zw &%}9ǁhMIQ?['a8qYiFw|' 0Їr9XL˭0­| }^Nn@a< \wW飕Q[ޫd%F(GU ㄫ)ebY:4$*=qQFnͩo䄠UlVթE wRCߍ3'ֲ؞WWCr0>X+YC 񙨎0mp )R{{Y!.xC9N%˃isOȅZ*N#Da j{;)$&9mtI YQ {HKɨyb{Z1S`p;k=1j=15'8g~\FS١!v_IYolT9\4EXګHRe7(7ۀ<2rp[KW ɱbhi *l1χ`TcN΃+>c7GRܔ rld[7VM.{?@_'sq>g3UM乽>vwf8)'#]p= Ef5hU}[2脗Vyd\`\ ŏ6 Ei'n EbߗD$P 2:\S0H'q-'[TЀ\jU$[mV=dW/AX"qS*/_DTcv!ԄSjg ؇BPΧ9"ygNl51c[ g7ٚxnW FØwjʄPa͠%P]iko WD]Nb_OzNӏmI3KgI=bn)?4<XG@f?3aحc=F%۴yd<J@0WJL{*e$g9 WyU[usP  9s Nz?%{ďgG- /pCŌt=gD蹷w9]:?:^])Z9V4ek{< 7wj#U18oS<p1)W{L0F(հ R~ >%fopŧv6V8Njoˑ;A9'!ތ(y*I!eܒR{>,\5@5׭ݜJ۴k`efYRVi.ZW}wss^&~/N@` !4j^.gg 鍀(#5J&{hdHA˓U~<exѼ$"N@~R8oĤ1hdtNtSf\6$Mzҋ}s;˹E=)2.uW#L 𫏳d}"qԆ3@'${QŜg)jY'g.?l>}gd)^j\Q۞xg8b3BgCT7WÒs ĝ"(xRtJMP:mt9lq7 |`#&32T% 987@هXǒ)@`t@[,͇ 5[:9o0lʜFv'msUtFi۪](?,(h$// *9xmhcՁD,?oTE ]C-9jy<i7):Ef:aC4g\nNKe׋#Br i%\^"WF.4L-"ca M7Rհ؜Y kX>jT!0)f]Jj}SsrQVi%=xC(nV=ļ WV#'Iufo[Ϟ_TblKj5ӚBR{1|M{jeo+ .PjYy4SOuo6'[*F:<Dz۪$n5sd% Z0q\eݘê? }edt$u) ~wJ @' W TaN.fX'p-8j%@nJaZT`"E mAX,7)pD'rGhфqҫ^!D{kQ.A&Q얠#/&p-]]ޟ˳Gh~ <I@P H@}cU'6F'Ed*:m (b+z2 mn얁i]āf{bʘw"J6]~8A8uN9L7@M@(wvlhٸ83Ct*7dSٶC˱d0:7GօJ (GQ& ݤ~KgHJZ,[y/U=OF>A7I+ Tq #vM:0Nyeqw?)~d6J 87lAr7Ȇ핲f 8;#A?1 TzNyFks~W2hO$=֜GPK j!`ao0^wkN φ,;/ BOjS8C//r-y`ڍ *GЅo?BYv6Z=_пRPf]Ȭ\/Gjϟͦ%u5{"eG?L&we}ĻY8mbY(ٞ ,+F~լ*֮,#5q(c&nX^y5)lghLgĎ=q9u ~i#yz֬&fOWiyy5헋QQ*ݤŰB~O~.5߿0H'ʍS=P}^|wcR?Ip Ƭj 5dz9Ck39ņppB_D=:.vӪ6ɑ !jUfP]LMa2@ie1yzzA7\:eLj8Ș( IOӟcv?uꦼJPLpYǬnf>7c\`.؜I9_jؖAkqi'fAMn OMo/zEN v9#hM?2%YUVC(IcM!=ǖ_66QLs$DvDam&f!iejg֌qlJzj^^fiͿ>B]e~󿝾ݮO0.%o$ar}ь)JA9>3-/4?u ,sti=)XMaM@Q"}0WBMšZS HN>JL;>߅m>尋w۱ަi(Ҟ47Cal992ZX2JIv>GM~[B`Uiq䭙Nۋ;#m|8ڦF X융+u. 's "v[~@?$v+G{D"6a~o9l#^qR{ο0yVc:XJVpwxI'sƺ#EXV׾1hh+e)d|WW5\$]2^R9C9dBl& v}UԧZtT+h Neщq8-ۉTfwKJ|Zf'#1C`!b#\S; w޴voQz\X2ܖ>EksYNnNurgL9~rWUxG85 EmHZ{ J=*w<(TǓ{;(yɖrGnSܜڔ Wqii߸O{)^gӢ+ᾥl5?ul%UϧU9.=Ye\OWT8~ .&bZ>yػ%3㜎.3,?Em:NAK+3lzr[uux1Lou sLLrW7ϣ7ǵDC|Uֈ)$l%ÕLxF4 I)(Gr),LJ#| ^ WgWvn r8-PL3,C7č$! ;vH4t b`~hhީ5iy4`;_eFs+g5Nn]*SRrę:q{7^?H`C(vu`d|aw+ĶM bmHÝ9͹!{ʂf49"Τx[tJC ;>H8AoD稬O]}*,y%w^n靌q*/N} :.厅|h3(ww >3HECD6{3{Ipo,`rBUQrXTt#QGg,ш,Ehij}8+ִ+>jc` kKH7/0CPQ4wvT2!hFhoq،I|%盃<ސ@&ƌHiDu8r y#(zP8ŠC׏َ O0Fr#o>3V'^= @ggV_iCXY8N%~Kʀtr8i39Y~w|1 .SSv7擞zCXډb2j!! =Ud5,uBB8+^BAruNasQ8_Od?D(Ⱦ ؁'r8[;ƄIInND^f y2J0 /V!J!=*M1tET1 $gʼS5TO# J0}Cb\)y??td\u1-3;[Q!Nk96כ DRs;:5gn"Z>:ȑgޖe ,Z ᠪ;QoڝaCIkrq^~KIZL/jRM@Cdcvܛ١;-6My(n2e۞K2<3!g'bo,Oiko]әa \rɈۉeܟ5u]"g1acmMwyhN|8lYu_t^Veܲ% G ( bNp(ob( T=+r1j}eCĬʾee>\0NMf ,g 7.!3͌؀)eCn/RmԞV(^\HH\f],%Ueiѽc"YSy^#y~g h,?msf[nI4S7r#(ɩEgȆTƓjmZFbs7@=) 9}>JQ󃉙b|aQN@9On_gcN?q9u!hebk^7K (.qGt3.U'ℐnbZ`W֓K<÷UCnzht">]j/va\ӫ7 jk̵RJX. i]#El`kP"N/'Y<"ŭ%v6MAFY  30'`6"i\7""7nWW{4]IWkEԃf}P/9I E+W27sKa2?cjDIXyfa:ljp6ÝzfaRd*99ʼQ5C:'_RX jL`LUЀp? լpl}ɝ; ,6@VLAժG)5WsZ/Y>/:`h9c_Zۧ[ou6|^&i$ .un7 pg`z0fjYYctvA<; y#C xRGIj}ʗRE%H 0P8U q^ w'0ÄG )xJo[Ou}SخyrpүQE]<5ӫK}o?S[d7;]Tg_%>׵~'K)L@uV Ȱ{$ RCAUoKIW| l+@ٖO|L|4$}I(h] *) a2 4,٪Ʋ(PP>jz<\X5E7.%Řv:I/sDm=SBQ+җDWT+<.Vo)j]|^{W?U}FMb E5Tڑ qvNbUf)IWuD4r$Ocߪx}b,#P˫a-^7YGڮm$?ڦ:o6;+wE3/P\*4ÑGk T1 46K>7pN90w%'s3~ .&  `FB= p˶)yߘ] ęzh %գusy;N/m:+Pڲ#+&˜L97S+ͦ&ިo+YTAm5I9à (6w7qŕ4'u}]nCa?OxuaT4+O7N?![-%N23U ʃLxPtm72nU->!0Dwx6B9`RsnpIFgsQ} c kqZ+JH7 C6%/})w#}QuĻX J=JH>TSRݖbV0 ]˧bwW+4S``n D; g8 ?~hN5&fxVϰֿKQf+^v.ϗJo@E)FJiWǖD:OhEC&?cI>wzB8SA_ J eQ*VȾogdc3AD!OWksh5F -^mvyơԩ3''`TM|WXvx/'Lc3B0{z砽-%_r@l iY'Um{c}ظW!8%!ihPHuzXJN8 Rnxx5NE?IL/44w ج~W qP=vCQ.|JjySNo\.*=癝j4oƾȏ3u1s9Rf$ynפ5KKe9܄}4k.mg-P(pL]e*7Mp(GM'%8Ϛ^Xc;3Iڡ((p1^ A(10j$w;QM<1GR5󌏂qHb䝜1c=Yi㱻zk#f!/ qԹ~&_-~zmwͮZՕe(]t<R~8xsějrV_NᨔVS\w p6Ms~Z7moCo͉-xJB2s}H4H2eu:\L ;XѾf͐]XHF|ŖΠŧpKcr$->Dӛ f?H\)c] ȥYNdm@[qh 광`8N9}AI'yL<}Hr`=eF3 /L줌pǗ7ޡv~9 N5Ŏ|;4H@:YRPx o ҬP0ܑWus(Cߧr2&^x~FD5Xm{+X[14PH_kw'm[xiFb{Z]I4A>mI-Q4n;2F :O ٝ4Hk6?8'bZb+t 56)A Ue0Uf,EJX)95_S<R5rӶ,D_ǣi'F߱&$BŐ~QkL3 HuToIVŭMKxMmgdf2 ܰtCaeUxHؼn}F`H2eڊe]ޒqLNa)98 M|&08>c qNGί8|qC;mϐuyTo0fWve&yxNH4ֺ@%;SOvl$pV#xjS0 K$Ø<o!:>${O&}!'Q#?[lR{;=qњc ckٮy$I79K6y}&6;OR".K7#ptVۨI6!R^t_W ~ZWk.ͧ[+Ws߼]8vݠg!T !W uxwT^)HgT-EN`QTꛁ$սsIW2X(btKuYyO<YbZ5TڮY1 /e JXظcN "&! $$23Y)KO 83*mvn7غS3Z1 \ 3frr'ZJ "5ČY).c^s]ء@vSH3uY3$'a/YO Kvp^դ, @F[pۊNOd#cOmɀJ̼*/jVHb&)"R;j zh#KC2?m3uq8r{6?`϶Kd$P`֯.|ְQ@{ 92rjNa,qǍm Ck>qVKan!—b&ckٖdyoIsnz/Qfǵ^o G:/ CM.T0os-x2F11dn5r[20a*EYLL/yJ_ *"I`zV;7;uRU巊 D/āRpĘؐble%z(`b#c24S5rruZ^*!lV®p~@*dh}*v|DS'S˱'3Yalr/ܻTyUIڛ;/?Hݚ<_c@`DXo:NhQ}{Oj QiDp0*s&WDqY!(gE%<ț)@/rݮWZ"gP.Inr+xJ2X+q0vԩ@̒˲&_'WK@uG3ߖ+XЮ'J~ua.& /8x£!D_tDUm٘}2$N~)LFFe]&HujExB8tPjTr`^{(VfPF5@o@ݲ9XhS[M/6Ā3GM;lḡ?" |R*עڟvvGVRҊA pk~=ϿƜhfP^>.jbpFO#T_E`W7RP>$M) @l!jR(=w^n 8yn\xC)r{^ }:]v5)OkV ;;rMh_ޑGH!Gȧ?}Dbq(n|Ѓ-$o)bP.8KaӁki$S?mk5r5-\,ZgV}ɪ<¾bDBr1T .O\= U;q*CzVU. *2yJ^ByMY-y0$=h+(.AtP`1n, |烂h y Ŀri9_ dB,6Jk;>N2ݦU访9zNmx誊hQv%beGr>l0-7\0Zޮ$DewB9!Hy|b\{$pcIf957YN%* ˨we ~xӼQR!H`1|Q]N"2fWsfgvM9@C;@Ou|nE  P35fme5;lZwfRykd1*oi-;3Rrnbi!,ա.WQߌr%1(@?5'' Z{g#HW:=ʤQYHMDwe{!#:v:;끒-WmJ='} YҾeb\Ĝ9asGI>z[{qg<_Xj7qk^i퍅Fy~# ia-C~ Av4FT$C9zB>Ή$)psPw&Ni.k rٷ#4{/n->‹kժԱ_ڗ,<-jp@2BBC|n,6E PXo[MBb9/R&[ 1ge>`9u&ӯ`ژ=9{wWgeخ}Q6N Qd3Yrr0XNt(VK^o"ގq*wçr*ǃβ _mnrRl~ԮL?لrQ7Q\N1!(>/kEpd"W}+o@sjm)t ҟ:32t1rs tN*2>~{-^2jK55'8/P?bÑ z,:?=7 I{1dn3(F_=!wkVқ3\Qۋ9'3Aٴf{b+%ҝo|BP`1z"ə7^Hujɠ;={MqCTׅ(LMtS8,8=7F=Cbe,\ֽ=x{GxҶ20`fbr)m&KՠgZ+*e%3,Q4-\֢z+W?cZX27b+ 9oOeE: j9:қLګjslcKQ&a*gÂW=_oMnz_YKɻd/zoW'%] }c뾁x֤tܶ% +)nOSVfUޖJz.Osr)h=& )C*)m9/RA92SHp8%ҿ,Et[34765 yh/05m䔐=EK\7WY(PyV}ѹWW8dBn~^1nW "O+Gn- xw{i")>u3`ϯ)֠ lWNaV֞C;LZɒyEY.nΙ|jP˕$>?SPnMUB.RJK|U NA ^|hB{: clI] [LDxHOtһ Lǔmzr~YMFoVUy-mL͉ SbѦfV` j2s@J&\^*K~p~oTVݾgyR+0r DܧyB V:\`N1"'~A]3ݑr=6R]s4ž&q ɢD]^IP>gXf .͟MJ,"ݕu< :$w7pq듥W FDQ/кX=VBQzuM`?^yo/]I ?d4Ԩ(kv|ZbrX[a9T%o#H,\6eNz]Fճ`Wk L}"-fQŷ.. rd+Dx(~\5nvr7 @,42oH(g f]'}P27)>O&Āb[X͏02 ɩ*Lg$ Jr#ΙꠂWJ܁ -#x ̓}&ŵI`'^ul4̘5 d\_m ): f:xU  NDչ8 b^`-/|/@B3E 2͋F往m>;>EĩOb˃3,| ~pұ;Ry@.$VGY<}^Sn !^g1pj:RT(4p"D8N:;x6ܘ3EJg":TޜW_o*>mu/M=Mek!0NۋQt\էj{~y"FNNVw7:e$l*-\Pɟ~8rj}} ˁ "Q@dns`%XlMa{΂Ahԋ7; 뱾QWQ-! /D[3SSuv}jUJAN=`P}A~x/8{7ؤQOC <{6d>49xN_Ŭ9E53 Ko+us_ _ VF@O63P{q xtC6s0ˇP!dm:~Sz?.$7GϊpTQ뵈 MCZ1>{8,8I+HTy=[*VbinL֛~ﱉ]wiZǭBs6 } +/;e-bС^P.Jqo;2?/,z=ht]TQ1 > ݮ4[v߸˸?Ml1ͤR0&t65irA YyAKO'܉ cNSv9aȳ9aiLyޘ6)3LiˈhP͔~ba6FFy2A@q*xTm!ɻZ s=/h!*ʓo{/F!>m!^P~9?_C{ߥ×`^}!p:*WU!Ӧ&.eJR`*SC`ߣR'P:{IXD%UWޞt$?2*Z嫿8y3$NlD+ov0P̗vSeXSyv(?h'##E4jM9bu*RWx֙6Pow da@bn2wf+tDYxoh+ ƄOM4/:CkGvBS11C},2ڮ'3:TS8)oruQUcƜzVwm g+&ŷp8_w; )I,"X]fdJUՙ0κyh# 8yQV&/Xe2|[ImwdY1++sa\d"Cr[Dǁa&hϢxd3 [ $"JZ+p>!a֌ ?:Zʗs8}&>)<.b޷E&&\ayeV*~C'9pK;M2g(a|X)a=uSp,a:cRM}&܄ƤmdDfItA82$ 5Nj.z5|"VچtXQgWO;q~ܷeMQ P^#>TK4:갉ᦍR_S,WbLeB ם_۳sj5h||2 tdiv>S^!MߎrMlqJ"GojOSnZ.edo[ZivV+.h.W:Ȋ ~~4 g(܋\L *dȨ+ 3Dy9vP*eKy,Q/UF5%ћu8[Lj_H{0Bf$P/qIl?keil/r{`] Kx1G3q=;;SGb CH.i1˃z yg}Yy FCM!i_3O68-N;"&D13P-CdRUq%;kG?Ђ+Zo'WԮC~QlNJ[Z8a<’z*T"2`<>: ȩpSi-ݥپ(0ݕIm}Y .9LaH),Je KjVr怈-Nx7"\+b1 t<}ds9U^wٮEON$CqxeOiV<}v+{AZ:Qr;ΨpDs*L6ơ73wR_ţ^ mɼk7 IP1d'$T8fe'D]uNyeOaͽ>M=}UHu3Ez<+Bh.H0>_jx+2C@6/WE ։e52`%88a'JjUy)R}(e?l%r |hqJîA1):Te*ۅN|SĀOlLE2Mox_Vvb넊Cr6gm*٦0~0mYlOth-6%EW@2pco|Wt x}4(Wǘ*1N{ohIziB-VNRadqqGvp~9> Uzwyvr r${tO񆇂f(жڛO^xfԊGQ`c!h@?ɘ^M鑅Xd@ft `]aFP8b֊H EGMjU-Z/v׸uD3JIVJWdssĒqma>6]<H-bY'Y9`Z)'WJnId}N7 E)@ {{W1o3u̐8c5(Nbd'a>vcpb/;|,_C= }d3q_ٮ`>glX?+S+S^ GoO"`n%kv߯?TQ'9Ǒ^;S\bHץ ԢW=)򓖨YrLw^ ql:B`~W c]XaD(; [kJ (gK Hzf]4Tr" #N& H/_/o<>8/A!ro3Y~.QQtJ>y|;wTLWcH3O?bkcao}+" mآϼvDh > \ZjtCRs0@Nҩn|-h'v>4xhIԋUsbۻPյőt@`'2McAj$j̲d.<\*^a?G;6D` 6Έ%#]n䭜pE(q"PoboC/(u˭WRnk~EJG 0jn*B>T Qu  k*Na_S =ЮѠGwpv£$tաv[ 屛P*>!NIHɑD˪f'2FQ~IP lM)&.Knv髬!XfysβRDN7_֣>$zsk%$u- |E<<)u t5&gćKgvLbHBϳ6QxG'ŤYJU?qrE$H?`oLmh :8YM&-dNO~hHB]S}Bck cSgb7XLTd}`(_*L|PJ|'~)x3&#$'g"#O^Fd}'-UNWm:iiOf'-3W8αJ̐duN Y|~?zZY@Hdg Wς5}:%na^9:ϙ1?un>駤z򳢆[J a+y3a;Xvn2c]ij cC;9eZTH*>.5d\}udYZaʸkKyFn T[sͺz?O~ѡvn8`7qˑˣ-vH?pZ~6luhDO&և[Ndtx<&9\BYקqNF rLYLw9|=KHm>CF?:(g 5iad\ {j_nQbᖶFxtV^:%u*=n՗>!}Jyܴxa/J-z!ݼ766kE"Q>Kgphv7w IV;lO.m]p׶z> NΥɔ˻'V5njv}t ?NjߗsH>S@juz s)'^<~fXo# L$}ʬi$Ssgi1l[l[~*K{9UE'SFXG9`̶dsR,N?MCbZ~I"8 ĔٺxBDuOA7Obe,v}\H18!<ܐfJ;c<@^WŃ5y3YL%DKlvϷZ \Ŝp0<vX:!+ųRdC\d.D ۡ۠Jb}lpmfi!~>jq[.2DCܑLq'be~04SDABz.%k(欄2iø{]IS}Ul9t?KSV}<lWGooJhT7Ħ(:WPK gof*R0:6F^gAt%tk⫒rCwY zPUƠHubtɕbn6*xYO"VBrnrlyͬOzR_áH[*߿Xx(J@kQ7bڮg QĆ6P$j_7g榀Жݻ9tU"T[khP/xNϗNib!姴BfmHwO}1PGh`Џ-axʺ#MÔHsʔrjU1!LI]TǗe#5}f7\x'& CAYE Lp\od(W@ k맲 r`t2IS\d qN~X;/~ ˥s.NdW1&Fj @  R/A޶U#]$וJ$%Y]ʼ>c|&A 9^=ZM밼= xugpP7er  "@v#ijt!Tčlmg;L}#z%lJZ Jlrs_?!E&ϋ9,HKK %[FI*[㢏f Ft12NUq80gE^>jl Ir 3]Yʝs~OcvWX:KfGz vcjLYt,3p|?*nK*]3Vjy)_ M%h^'W7kqPw[~SljC%gus=Ρ&iN":%CEhu|vvgRtsSAt;IGdx{Y{fL\E3 jPmHL6aQmaUlEj3~`VJOwܴp*~|<;R~gv =QayHyu4Li4 .s!ԕP{! KfRYu aM'eQ?Ȁs)VYRPڠ%u/ۜE &D/Hz.o~ WE:= 4q 9)kZD&eSިѫǼ;Y0h ֫{Xqugw|*̪Q%7aN =Mbʣ%T d1P%~8\}'L -Vn2 Iaru~f.w:y&#xtU8W0H5醙_US6SqnVfHLJ'ۆWx(Ta$!uִwXytj! A\N[V.lZҶgNw'AYq_MC555JWf}ʧBfz^(k vR}~- "HN?8*'a Lξ*!'(aBYB'%o&oSyݖxoL?~Wtf °øj}6?#!)M}ݤɜ)~R[nyG(P]ZJJg<f8>©Ə8Gs3DiU:ܔ62D\[Behc>-:hjlyF&EN GgH@4l)6ԙ6Fen,[(KRgoMk'1;Gffm2SߤY&_L:Ϫ!6Vi}':ҳ.Ŕfmiώ+2%!1w rɤ" ك:̰{ YK~9f7dϒSs|87t.lr:a/vᦄD$N^33Vc*Rjc%J^;as$MI|pE5N:JO5TC9B*VVҊ33d)*zxR"!\B]kXl1x%%1 FE첬#ȗ2o쮞L֘؛jгB({x>}- G{41 C`þ9YoŒc$P}DʛpZ  Wvdn0"$M^J~(t{/G>& [* &ʨoRv-c!X?Wk (|CfV [0r `x:sp}2k~4;AJHy=9C@d<^hf*J&2 CV(X7rX/ţWE!ڠ mx\" #e-;%˗ҹ2 OCj-Np\ oUОXtvQ}6‰?=Dű/)秩]5s (xd=3;4)7,}xXkݧaGW8Cs V+J3/ Q)N$dL*y|PB镙|XwƷSeobco/VP{WICGH lpL} u>cZdg9PȨ-jx~: )]\_ xD7 ~rxƄf'G ~nRI1I=zZ+ɩE p~ܬp:nTɉMҐA=qitPNltN^~qzcrJ3]cl.:+qSIV[3dSoAv>6&~~۽6lӺmc+?4}G5s|$|?a*]͔\nFNm ~@/9L\WЎ} zVEUzGysʳ}jyXUFy <ޗ;4k=<bYΓ ^vu^_J]no{ԕJ@x Y9 It|DpߢҳhΜ>I1>-wJrJ #lJ %Z҅Qi͒fI-by㖭Ig[[&L@rKIM5XYOEwiteN%\T6Y6i>Cls9ԉSة\юlGC>3rDµ!I@;B? ; @%aXmٮCm\U9eGN8{ӶM,N$d}kV6zSJ,A+IZԱ?[c3_'a]:bSLeVN$@z+E*5d<@K>{g7z". 9X gf3e<.X F`NOa$z2o|v"(N=7DVwHbyF%GNˡeE#텗=4\%*S@'ich^F2E˄LјQ3TV3&NaIM=Y/qTB\VE3ɲ#eyIfHJͤ'<2:ԲIQ0PZMdlfo;E!@ m~Yb_pA!6y\lv$};k1$]n }pF[7/Qzcb{R2(_;EӺ|?s MNt z K4'o<)SLduvȃӬ^!KgS]E~<ۈԵO_CaRVjuݮ焬?yz^=A/zi1ׅPȮ@")PNH@dO"4f9kjOiZ6P6N+&K5Mm%Xt٦\T^D 8OfEn*!2+.HeNnYɸSRt1K]BALlS'}]ەd "B ?D=r?$!'-`9v1a޹vߢ*9Q>yPuy|8hvZݖE xrɵV0q:eV;'iUFq y=}U sm@]1}ANcbqU"}1Q9lՌ-f>eO5KjWN5'u|Cs2V( \24IPVu n"2$ZS[I?߄@]mJ)IWo:Qݲ*j+ˑ jG(ITބh dԑ],A"&u )ն}_/"L`KUt>U*azn:Eƃ~%|, #:^YFu5+ zwngH\}CM<\nQv˵3S :_Ev<r6Wodq O@e2Iz4H`77/Uw]3]9=Ib!#f(āKHiN\mzVa|%JB8Yb>GQ+֛*7"FYђh/9CUёi]JA#vN}Q;OVFt3tEB Re '9L,K9֜SVݾ}V ~q'[< 3=X"t:#y[\}L̬pHvR=9>N^$WpU@}fEgkvW+{:{Va7xBz٢җ8R:_{0-~R}Ͻ=y{dOvVu?+Xn2yLA =˂!{j,^)u-6`}c﮿_s$tUsYn QuB㜒?SQjcfs!OO- iP£ N@mZ??hupN7>n_Є<,Cd}ܲMhwn^b}ˇj᧣]?>'5ޅ/t6 ƒ9\O2}0ORV>&D8[yNҡl7Qִ?hٹ#wqY?>3/П> 9QK^o4YN@E6<B,~&U@#6V퓠udL0bu>Z@8t? 4(ŒtF-=zB>Q{H+)^h^. nFI4T5(X]MՏ=[XpQ: dġM`7N:nk[ebcXr$ ὜7yrFL59sLdR ^(?u?TNf,R ֢SERFCߛOn.YtϼCؠYL^3ݢBie0RF>Ip"eHRrFS>9$jD{WB㣛)SYl#Ivx7.Iyaڪ^jĝ)a岬v^kh!iSKJ݅-N/DU W G)v8VlA^jAIU}=J;{=vh,cfݱ >banpϵ'"v@ExϚ D K)écr@!# or*iX~9+@!D_W٨%gTZjugtVUߺQrYT;OU֢H+'.',gґд2iu}:a,$>6-,iy?\վHQc4a5it[XY-qb.](fLHkV#ԣ7/g8Z(9-7Q׺ͿeVj;ܐI ^M%}eVfkju`lhDVǝa;:1Vr. <# teY4V vZ]nwl$P92NsBgjJʞwm]kI>0*)1h'*2 \☒uQ;`8~هaDO0 ĚLfuZW!By_)DQ#މ]y-~^d5t/&X)V Wyݪ6EUx3p8QL)Kd 3+:S'=HC&wΚeC :1yu ŠHO$LZvJ;xL> ݎ<އh6::L,R1!I*Ww,U@Rs3~ )M8#egM츭Aco/1n"̬91j)8\$2Uo$1nX֛a2ݨ[P^jiEvɩXgd(TُܻFь; }9 巾n I2⪐'C5J{ ;~'"yk/=1ג.^(~5jVrB \~9}%˭FFٱClǢ݊!tHiØ^/C>whn^&"I : GJ>Zf[V%ÀjUvQ[a+:ҡc2ߔ;t (2B@HNӆL!7@(ZkxKhTSNj dߘuFĿ$->,VC}Jqj ~qX:Ux5iVM4vO(Prf zƖ*}i錵'€\[DO;*hFC{;,mގ DRI/C;2PTy0T t9)f{gUόxCu6QUxSuXM(ꉂ9]cTVK6$R>ȴJA{w)NyIF0O;^ZaϠrygh1-:R2Mv:{!]I8.R_sِq WڈZƊ<.җm)d<+ʸͪ3⸨'0*..uz'$躡ceXg2ٛoON:N)g^s($7PY.ܩ0>%Zu( UUW7 i6Ů> X:X>2+\)K>ܭ%We,Ma&]ǑS쎈(SN!BW}<۬^ʌ#"2i^ǢrsL;AB-J,X;y-i! /ذ-6h NjFTZpt2Ziѽ-\'v( #oz@,/ ]9gLYK 11k}|EPy$Y:4|7IR1y[JsῙOObc'$3 [q45d+A8M̮-D'(?տfBV P B82aa6@Hfo? ޖikwjɎql5۳ A梍vXi"Qj> PyQT5UimRdВǣl]ya6 I+X;:kGSf#(OL *5sirٴ ML};U 3}qp~jmE?2{)STpLrLޝt8v4iz'pS,ʮ*f\JjV'4~g̓Y) 6\0,Ajf]kO+nqsb.%k Ruc9ˇB_^3/L@`=κ"UdgDzy(${,(y13YG53SxJ>${ɯ1Hv廵FQ*]d5G:y]{+uTշ 3+Of Bή[|B7zD 1l-`.O!ڣWlNUIʠh_4{PPZ0 JM {y?J #R8mnD ɤ%J r_mW{c@[(()[ӮX4?Bѝ. F0:3HR n8m#,Y:JRJi( $Gr(oJ*m<( "eޙ,u8^'++~[zxS#<6:MssZwOe3X5: qpW =ɒqҞxP YFrkz}P+g@lң3uԴ} Zr!pܛ+G:4vy}fQ3.X|<6Ax\Br[>׳` K#y4js@,BA6|~uLCbnvǂ+J^Ff7&[ =[`?0.e*a Uറto^H%s֍& Na!ƒjK,l6AC éZz!bgJgH3"rlsQA]fM'Kg(&/Ui*okjGCpsQQmhōNܸ߇jHHhpZ>yctPz¤\reΘ_2J1e2 cE1xR1qս>^r{_90Bx60|Y?:EUG8D{JqhM"pxIXD)$,R &RNDhPP}+ _EU=ZQ]Py4H۞ATֲX[6}Xt'g |880o#qzQ70Q܅Ɓ3p\ON]v}P H4ńo tny5E4a?/k~}Şk Y%pt& _fQX0<?6V~0ˀB:譇Bc>rµ;+G,vLī [5䞺aĔ7ƶ#fƕ|,A*o;27a;%+) o8BueәtJ-Za˪xNoXb \OrT3 xXSV VuL`6Jm |7h!`rK(o`zzTݮǠZIA%F쀢Ge?;MB)0X>˟xh'!Y\8*f<0!ᒸprtaLQpc^l/|A_izZ7}PJ' 'k-W`Bv[ $nOVfV**:ۡS{|'P'}U^ Q&Kx eѸi[$aM#3 A".c;<\*pw_n=G\1XԽ=ܚ IGpY0 ACl+wG8z_qUrBCf%= m&oZbאr2L70Vk'Х !:7D=9C{#">8mVSp\Ƀk P_u v {))!t:?[&}H9> d!O%ۣ݁lvGB8+,f2'&a&f"Aa`@Y#ZFCک_ /l1<7FD#Ppk'++^+tjN,nti,:~k[2 ;Gb/[`Tgڮ_2Z1+Zϵul,l&+]-D:q!9q>5VT6_[yi0pAup b&`(@~zC*V#W$xIz C &ɥcr'}҆qz9S1 xY@vBHczW@Eu0k$ |(rTH]l2V#{j*WgsBV } ROs.ղi:"(dU٘gM]c,aR. Mo|0A*+πG: , 8_Om]k>(bP\ꞀL~/DMC.F gba\B(%yug[kTͳ"/708'S?>}.AD%0;RLW<"ZpdKiE S5-߲Π3np#%Q8]!+2OcI!7e[5+gY\}v|.wؔZ꽼Γ'ө6G٢KQ15KBe <EOu4/FoSP*=3:ayu_hޒCmJ-ۻ}=~`r \]տǿNT*F:%P俱m!][c_.\^(khP*AbӶmlꓧ?؊ǜPLAiV!@X2ԝ=V2rjY8(3:"?xf o"I󉮛*RdlZu]!,Zǔ}sV.Q1 Z @hV.!ScXApJfA[%Mw@.a Y޵ͺ說Lߧ]=Cze}^S)z&n6WY.#qEcdJAp0HWҢ¸3,ƨEn 6gpPbK[4yHRey-C)~@S@RثD+9} ldw±w ti;?8K)@ 28#TebSCUۙг"1bDJ"ە~-ooֈS76InodrE2; =5NK9_AspEcV߻~z؞CxCmYjr~"Ҹ_1QGg *iyb򳎏CΞLsߴmӺyCq)sXBhEѶ6{aR2Pp/ 򡧎4~rxm nTq!*32R\>bp%EUf%]nqt?˯ϦpKr^O?@[|Sm!&@ulv֑AD+ .L_8 8U "IB'%Ţ !nt"*ʂ2l,˕꜌\ޠ!z$%H-0sD*qb?^Iae's%ԑL$ :/=״.M꒕̗{۫\ qB-ZtwMq*T6nӢ!b_t=sc?J˃vUa/J`lZ9Ow'KX=2| 9ߜ2ڝ^# H62Q&[D` IG}ؼV6JY~uL6qur  iewEdz5|*`8؀>7a3DZ'ٷ_a2MY O|{'#L!<1x 롴yď_,"v?x ?QdwLMٮu3(q{ mS3E.Nޛ?ޖ{::k2yQ'LOu?ѩ ZV 0>RMfŦڊm:i]sWd:$|x8 C fFA/͂A2SFz*$?10yJB<\~Q7KY~)mke]ud <3OYVɏ>UacpBJW124 z*\?<4kCuԫք%0vU9OuFYF#Cǚ6{:ђnX0>zt63]GNk( =({$xQ`0zBouA_=  QCU#O|Ih5ATz_lIo//f=°l_#8ʜk'&Z4^()i蜪g40$(-7EZcD8<6Ԏ JE~0]&)i; Sgι/x):e'UEQyF4.N*tb{Iƶ DnX_ρU{uv̑,e]$IQ%v-tg407ӜAObߖJäNa,țbgO 6ք1s prtdcS4 )l U RE|ir>8qTqdVNy=C9ĿpGZӮSefܧ'[Ҫ;ռ=(/cp;ozXH> ʔC "Yd&,0\!nCGitgcFrNj_xdjJ I_ p(šەbXC'!ppkuh[rˤ>\JX:=lCIl!–4-f~V25 !kZ& %vȳSP%w{11Zʀ+ /uϓ+#-I'2[y- M}(]nKB9{QcFrUxyOR<23lʁKWs]Jk7tHp^x䓡{ {l8b3hlb61zt⶝Qw n&6ʯBwpOϓz&! ># z.O%'k3ŋj׈pWª<}ִ-X.7= e/M@9ц=UBh^%h>ߩmPa#iUdMbS6o 4y;ð4G3t,@PjuӹJܿo`a+)!K:_+MekC39$ R,d+Bhsu:R3gdtab{JE-*gREE\H1`[?nGJ Orn1GtҦ{S$;Pɡ>3`!֫fAX XG@CT}B𒎂R6MLʱֻ"qB0+TʿɢW6HӔy X }(1jq9L`آB.<ݨ$,_Xb>Qzn ~:y`t45>`n:yE]/{{4!pr="B]N- 3QjXT{͛72h>0(t<Ť=lٴ+td.'"xr7u"a[$INKICXDj 5z}Jw$Nx'b6E#8˃za u.5s)iaP<7UۖER?D1 (+vjo]SSDki+GtU M,B1o{b|?,IlqDE $wrBvǔ]/~^W(RgovI>Lʱ[B00\ EJ;pWCf+@yVn\-ݿV@B>Qn ^ܜ5R z 8)zi &ʬ. `f, AX[Sx'qKL g]\IsfXuyy!ʺ!nbVZ|r(!z4e`}_|REr3C ?V>G$>0frawQwqLLd:Mp9Ṣ싅%!&!%4~pY\}.4a*ˤPԗ_BSQ˜I@R"6mdz)4i$MA⡷@z0ܹdDq7|g{_MdËִ_bq&~r1v-495V4tLNr2ۧY8-vLȳ^F *GA<`]xK!%/W. /TU (H`>gkO Pa+Uc3ڙ 8~gyuQ{EI)1#k UJu9 ly cSeL;75J9R+ռ1} oa5{, ۏO%{) ٴɉWR<0Ҽk/wDE{Vn}q|#.x H>hGB`ق O[kTIs,JPMfq& E`qEhڱ]V;{v):E[~JEQkä=)wS^`7hLOΟ?%'ghOڙY41,8]q "NGz NL|q)|sw.C RfJa3Ά0j#jcx:G =ɤ_~@<ț=ANkj'SZ xN.ɟ:;#!Y}U _ LilG2-%SrU6v&_ћj|9~L3Jz%Į=`=0KƓ-,i< /.Nݔ6-^i!s?@tűafĒ╙\#eKAS d1KVtI}ehe6_wP,*ZhB!A-' r(H&5p?a4t%c^N d~Q tds:7eܞ Qڪ>c6TwA5NMĝh5#d=L/WCkD ]Vx V?l̺BĨ!A - 32>m5NTfuq <[a,}idCevĀ͡OgoJSZO}ضCUeYJzRGwE+ur #)ojl˶V3Cq -r VShֿ>曵$tڙ(=o5f]3DCe׭=5-SkrS9l8=?ã{ ᜾Ul<IKD@7D*9+ĆT99B:oKao{(xKRR2C[lX|a=ksF+tz->Q)&r5\5O)t'Oˠ+pE-"N>iͣ5jjeչ.uJ"\jh䂛1p"e4Go>NV8P7ZqUܡ;s^[osM8#DѕҺ}TtB7?GxvPd@:U廝!jK|~K~9ɺӲ FWIKqkHw[ȍGG4Qc/gx=lG*}P<gѷ }~E!N -ԢX(,V( iCd탙PRߦ7ɲUQwL|%.h#^U2V y58ߴ\c!Hx>h5(<^cQ*rCW/6A7)|`kMi"`EpSJ]g l\1OUp/$QUf<!r.T#^ nɟחdrNL*5ju5 ]n EQ/O M$~W 28LȻ|+1mȤh^ji]AXHxfۛj=:n=NYqIUfe ^kn*Oz--ҡi& sd"p\hZbohyx(%cj19:l@h\ileQXar7Zs,/{ZeQ|3a? zZY u Z^:0$IF{PNx!KqQRW}'q&ls$|z73ކq8M~@90kDa cHhD!Iᾧ]G  %Qyޕk]-=9dB)$lSCU!pMuXt < I,sQ~hFsD%.Ym: ?[ b|(@{rŮ(ǂ襢G\j|FDg !D(3$}d[v~;|!z%iCVr#؞\~0߉Ko$204۲{;M^uI]7Jg&I!P&=EK boR$p6# 5G& |R!Md*mbͲ4*ְ$K_E¶ivj^Nc>Po^9>P[lWw;#^Z N<馩IG@9_bJKqDc\]0/~+3bAc(<&\zs4u'UfPCĻI[BVU];u@,6M|4W?b$UDZdcEˠ2r1ۗH f#T((ZxngTil)f lh;!@5PZSSꀠ/U7'O+)^Nl}i5 0K,BwR $2z7k?cQqEceK9~!-qYQ1p1Eݖ7$ɣaBIh=A\f>\}=̊αþqפd| <;mA9YטdI!2ONmCy`H:Ɛt;0}Y&Mc1%?,Ky!걽x- ;̸7gstmָ2Зee݇@/TӢ+O<<~M+Piϐ%hr>ÑWjM 4C3:{/Z5[$E&dܖlO~/D>Oƹd +o_Ty6!Hwg᝟+GnUߛ'o?10d)p/NG$p04$:;f soI>hvl7 JIW*ͭa V`.q3 uS0&Ɇė?Cz$%:>W} ruhKwQQ)Kův+qQ6^C:@72ЬIx&C+&qҼ,adWt&@*SL֯9⥀SOqED7%sG>ɽ#6l{-R_5Lb0 eN};T+Pj`QK,72=A.$ջlJAXrމ^v|svhGMS]X?͵¬O155Å6X|]콴nqw*-4V:/#Pw`uQ'/d+M]UnGF/䚬əvD?ATu9\5DѝIILG)rYT:@j[vpuAFse22w~iI-\F`[j)JDv`iͺ`vhx`JÂ,Sx̍Dd kU12{\z+{.걩D,N'[wOV¶w "Ct`0(e D!Zq&L ͊&x;ciĵ3o ZV` ^^o.pr}'Y^Фg{{R*]^e 8Il=YyC 3hMa"0>:,+ H@lK@/gfwʽ%@\C!uͷB2Q&C8MJGm9ΨHMydKOYa#%(Bnʜ@ #s&2>3H$Ị7E]<Ɍ J8TpfTG+sY>,Ab٠obFDABP` 5R%([4hpH w[BS5ղ$iؒ3Gr:RwGM6D#dX:F-&dK~g2w%)e(ʝ5d^2Z-e{D7 "A5nOA)gr#KB_$<=_qz߈HeN*aSi`NҔg =Q `/ <%f_b ~y8ćm?C~O}L)zy([D?}`}p $rǃBE*<~:mh<[4uO+; @Š=^1{/MJA=hdW.tx ±?DE;&yA!3rQ~Z|ǂ lߪ8u%|v;2}N ؓ72У;ًyx`ljQlN?D(u:ec%ބrXIoy&]imGB$!GD }:ā _oho:0Q-l7=IfY|CⱬWSM.T$n{77{8_Lf۹e3c- $"0B*9h@~nu[G'pHi$jFr/:uwf)V Ǜ^M6zul5[}4߽^3Ahyk*%d1奁KSafACOf| 8~W*dyp8>-o7\*~8g?u(}ifI0Lr|BDqcʿ\r14Eam$r LQvsuE=_"6 V/|Rq|G+6+pPAX5oCt\ZNȗxGef Dp;?s52-Zڃ$a}Ӷt/e&- .$W%y.jGW`5|fRo]Z7ddwW$GB_e:fe| f`BG^w/-Wu؜A)$[74k]e 84"7_qL#@ZAlaj#inhKߗg:\h?}n[MͬԶsoLH1ưSZzW}.gw}DWҠQHYŮyn$[>.%=Q:#5dll\~;uxG~MV.j|š u8Z\R:3qNPPqO^mp7Cߑ1X!}ސMon*V/8{&! [ ̥|('kXU D<ܟ~[p I?]o܎`dK.TtGv}?x}ZHԩc}YZ,¶\qNGNn4Hb_Eqe&4MN O-!ଵdfouRP|-Bok? bƘр#ҬB`{}?IMkΔrɓ t,^߄B!ǡiD]֛[ټ3F*]xh'l t8te$#בwԣ!  ml R=`j\Јkw˥l3W61wq<&JoI82"1&y^y6*n>dϟr!P(ke=VJ=?籓 2,V CǩƎy4Dq2,%ϕ@ 9/K(SN&c 7/M9]ibTJ:A>4:jR?[Ua_p';=do1oh$;?n=STTr]ǰ.O~oNVfr:]t h!7a4\W# L&֑iI:h`# >KdbGM׼pb-;?XRުDct} ]_Nq^w {NxW nn+5~1|J2hP7pGI)t鸔7b,2xjJKjBGVuV$pθ#%w(IP&흙8Uli"pc(YbEYps0EQSp/8 I5Bca m`#ˠ ԺZT˅qCqU:VB A2 5=ѿ^c{x(tqLaSE9?9(Yѧ.ut/_"n$<2;Q}kuJ/AaOD>LsK7G>EU'ȩ x=VWXB?+a\*6.TfO6&E4,4e0AjV9}ꆐڞ'6 [OP2zE5,,_LVt-x=B0: } r"KS@/v"~MxJVdBNbHGXl$Oe5@)By2{o3tYttk.e_7:ĎąK~!9=l?R0\;zb\ʨY> fxpkdl 6UnS\ /jy($+'s7a(1ЈV7y`p5UM8,4: F.7WɊyT. }VI ]Y҈Ƥ;հKjU`,OI;f*{B0-J?KQ>sK@A@zE4M̵nÃŁ#RZ򽉏{Q5ېLJq d4\5) Isu|ml~ y5NQ{edGmmhL]VDv:CbƨYf2]hd8Ó"hUx oMh-ϴuC?g7 e4S)a<3 zyhpjD<+0`ɈJ^D[qV 5{MLp?%0k rnJ `{ 4M*oeKT-u'[jsE1Jw .IF+ IM♉lG8t\΋\ Omjj#m(S5! CϊSZ0:cb?4gd5 KNd,ՙ5Xo'c 1eRTZD7RE8H_@\߆is0;=ubz2ޖvb]$Nݘ}|{ݟta'hH翚Zv֝[QdoGB6&*d-]Aڂh_PR)xvHCV Q+ݰ[BFkD$mUM#3h;~ aإ Ѭ_;f)XG(pyL]d넍[36oLU J6 mygZP*RJCJ|Ǔ my3x3Q%ulTzJ0/.M"ƧFMfTd^ 䪺۵N(eX.?6T HRblA|iM:,wgƭ$Uf}v<眈)x>=r҅ V.V@?^PMw|Sx=5ab'KVw$Ң <"li:wx?a4pVIx&᫖ΣB@_D?<5 4X2,d.g:e4@>ڞ|dţ`mSţFun;x ^%d,hw@.^ˍ?W;q9B*|z;-y?:]C[fcޖ[;NH2@+2p7<6/d2o%b/,淐FK l~If :+nŀu-=E_v7o+();{>@TSZz֚U:d"kRfJZRy>dY3U"HA+B;'T/6<Љ'pSM˝4xbJ"%쀶t_Ya8Ҭ,im}toIWMMd㶜'9 Nx0*$ ݁[{7FaW6֍BiU&)XHjlx>yɔn?|3PmڶﴞTiͰF ǎDt \A#a6+q$!6.KΟb|*&:Q7MmT[ /(:%vsC -Bf#DKÅ.Zڜ2pEHh.>mFFXhօ&P `(li\I9Sɦ}\!!~HQ !L711ۏ.Isp+䋸[IGX{q)P#"?ÅbE7EQ_J>TD&ǔ3CM*D-ťݦQt ȔoM4luz`* m~tvpKU*W%jԦ 'ί>F/0>%$39SR#S|F]JZ9OGS&HYXx תg qJsY~8 ,2ɖ+!p}& 3ǁ'6I9GYbS˙s&6#8KtnQx0pp.XFݗhW{5%fة@L]$MSٲA!<)`KRMt9(Q,FtL@04("-l2_dX~kʀ̓]}Wl~A4E@yn!kvUلm^bo!rt<{]J!Qңw˞eUu(됩Y+'5u^1UQ茅*7m֚o !5U{SN'eλFG74zM]%-^\l>rb9/LEiڍ7Bq)WiH$G]$G!KoZ9e#Qn<$ǎ[Mw>o3 .w:w-Ŝvb<)>/ٚO]ݼT E*[/VOY\c'as#ogg2kua j.8挡(`2ƅ'X"cdO4"rN?E}HNqDf[1>gEG弡_{1TL1zzbBwIw<,I gHU%P$6Xl/5a25/}OC@Nlm9"E-!9W[˰v%gJSq3ͪ$/9T!`#PUk֜A]Aet@)f1q6#'mD}UM ' b1dOQsnĴ4Qh U5O _ZaP>qN.:@~gISG=Py;N}NFS}hylG:ZƫQ4z3YE;£}j]v߳eV.= חsdvm]orڇS,Zmv痞t9blr!/2! "wyg%<OX¢Aa̒4xrg8lG/[,\"NOAƠpkGKuMK213$?-$y$oO m`l5ĵv<ײKY12CK|&)-K<ܳY7m9$|Gg DX@(%!aO!'K=9ʝPŻFhѨ&O'wl1R- Ơ]?7i|e{~cc _$uR39ϓ$?űXIwhKc |3EoORx 4f r&.ؼs1$(;HlζGQl y6L'nK|AK(BtL_O<+|6] mRTӾC` .6nc*aJҒp|/"#>%j0aR.L~D1yS4RqSĢ'v(0~bӳרGM4k|#k!F1XC{y4yB誗8ttRhsp$0[L:g[CtӝBv̵^G%iX'v #u! }hWnNAթaa^ &AlOV|&prjvIHa1Y 2 O;(hi@Qlk+TM>)bFyRn[c46s-GFT7)KFNa%;-5;#Ƣ0NA%Qv^ۇH$|3N̍2\i(°zf@DAٶQ8DI XF}eNJ"Sڝ|Pqfr] .f <>yNR2\}m[wr\^? |"Rɏ-冭DsE14h |O_&uuۦqb'h C' cʨ*I^= Uv.UDVP޷EVV֚N#roYLHDl=aO&.,%l#KOWBk!mf6rsכ{ph?yCW-huU7ERh ˨ŝh<+S=&K%7Xityٻq=ni5\2^r Y1fu~P Ք նP 8D5 d}UJWb֭aRn߄pPvD?S"{i;J/dхj58ǁ``c];|;).h.L "%6A+f葏-XB =_6s#IR@_U JmLZ-eS ܰnؠ-)tNΔŇ4eڝGm@R R <|wp8 csaP)Yflg||kگ;+WJÄ"XW5J15X(Cv/yU|/g TB.M7NY<^i3}0k=Uʤ~dP-NhJ78dV7F>[=<w.qeG-np%R)*"g3M10ӘLrv zA#sHǥs &82Rx;,â?t Jk386٨ZRVH.]?jmh"\{/6N?'/FP&ZRuz귡^S |%.]fțmˊߘRfzu&pw9yBf'\LJJ+^vCet{)w#G1\LHwT}K4gUΣql"'Sx4-PQf#>U"=VUIFϟ}S ύ_+6|sS`3/ϱ+ʡqx,(0𳬜B8Q ^,/}pe]r=ِXڜA2Cd!x/F#poO]>K`up䍣./ 0m~ۧE@z}S$S7}Qtdwoi $BWTnF[!*; =!8?yS.߬z]of7`^1 mhk=jH4( s̱s]I9F>xU$V$sAU"W7(,-ܴu:lH԰OIGL7r]gM :u`v1Ԥ\|6ΛzߴcG^s&E !BԹN[ .Ѓ:uEUqygk6+IuAPﱰh꿶`o`@DHuV)n$Q4]ĐEgzppqLRE  X*'\ n1 mDolY=L X}M"+f}HbiY:{,3OWS!lE޸/h jC,m{^H 5>* IMs`Eչ"LMz䤅6 kN(H5T\%@xE #!92JZx:aĆSHC>aMܴ/^3/EO1>}mh:Dw_ʿ ʓAC:{wDB<\}Ǎ2s3ٙ0ZJr?mɹSCCDb930j|"PDfqʲ>Vӿ`TM;;oʗivoIqf1 p!:# uap# )6ӧKi n/{r9˨DCaX &>6LǘcSIgL ?m\~" ul|7ٗ`R]jf*krטvltVy.A ޟ̚}8=j3! zAKr`b lcrL 2gA/'#hq܏f[`?x~#T%"c ǖ<"K(c$CB)r. e<&yДSϫr׌2W]tIg|2.̳a 1Dl,lv~Ljdڰql<Ԧ 2@(Gm"$CD2Ե˔Q/ H W6m7*+7@> xjE`$)`tUKZuv`쏜 -^ߵ4] dNLztIAQ=1 Z6FWJ j: l\'b)&iD0 oʶMxƹMA9jt|:B̰mucXHKPZY^5iD'ddi~Q‚brDouN`aOkzyG -삗 O<^[C%pa5߰ޒޤo:5\Bn^q+&'>o^٠}HFȴ1x>Ĥ.c+ ) \P Wݏ݇7<,5WwIl_BJgD2ftl<3Ni{Q9\o\nܧcs/}(uosVE&Mv!#Ud=@4}_QChck&c"ҫ_BC+E鑸zH-Y|SƁVw9`A3/*aiޅ 1yݦ?} Q '*I g. 6[, 9 ZVx[ŮK|$TI,ϐ13@Vl<םSa)?fcy3'3=rp-uAٛ8hя{:Ǻ-BHlb1E#@ I% ۞!(u{ 8nMzIcqd(0&h0Y WkZ9UPBRK6 > 'oi`\ejb18H`>Jfl"9UA A'RP+il‚Bh05͎ V8h;jI=Դ$)ˏO@v^ȳ)IV-P"0&,H҂&Od}ɫa%8ܛrr^J[DNv<ɲ4y*;>dv#@P]EJe5.K+=E]_Ne‚ َnRچclN|l1"_-nLV.ƃfWvn~DUau/퍮YeyR]]Qyr$0΅j_jZfNB6Y.6?+)i 9غ ϚAf 5?̍ } ?B33sEQ8x~x.GY~^rN|oPN WOi-_WzU&^Ӟ;j!NimUɈ YX}y^\E6gz[fmhr0~U~[&LT; E5g_)&b;[{ | 2R 2 DSB&OꆉLv,diKn4oC8/i nj8z`qs"m Mܱic2`ݝt\X( Xu԰;^hEӉc|.e|O l-=v=XT?{ ~\wlv$c`#5km9~Uk'(me<0j+枭B2]PSry7l;Vȶ{V`a)N`a(7w NIq1o0}V,#!+!C"X90F7p!#Jf$mG/ܑ``;V2FA\|'Y{%M{Wm xKDdo~' J$mKg̀*]/sz )B!A?~w'1wĮH_w'S9idvˤoEo7+ڗ;/z>jj:gi |0>mHG+|)5pVrW[08r d=EU-lC]UOA=lrpfۢת qJճiKrp/:F./0|_CXX=e'#¸sLh5 X 5 {Mj? qM% ʰypEHڨ,,A_=,;IJ0|AH׃ Z<+hqnWVRmO4]O&vy)i?@4weN /E^g u\/6ls? ~+"+<#E/O⨀/T"h[٘Xgw\j>}/4Vg >dWr9h]kcE+Ųoom`e,">G~8PDՉYk.w3x~Y>AܥtbcVsnU=b8室7Y:Kum&6w]ZB-e/bFŊڝ82)D4 Ί~K׽snbA_K)ꚃAjNL{&o<DŽd*59>XI?\v)6>oZP4l֕8 xNC0 Ibz6Zd > sz_SEboiggM9eX3%x10DpYf3+ ֈJsx̚}fY^>&dJ4?aa-\y{}E{8)cR˒P0a#W2 = {+Vr4fF .Y!ťSg񒆛C![i4`_yu|Ȫz2<|Qp?~|&Uv Q`!^=mił6wZ/ٗk[{?yN< ~$NERL9]g %{ Ud"_%7`hԶJynXg|S4m 9ifͷ8}s 54oUE,t4t˷Uo0w'%MRIjEO`$@ǑYU0&SHwo|zTGyeK.*!&%U $mŎz!P7%:; 9u/TT,?KҊ%K{N"pWjfwߥRx!xIɎ :8pndLJhF2A9bL(un0%>~u!IumJz*xWYfUFi-pHfxlFk,X1rl:n4Les ¶C0.szU Y㛀R˓})e ||^fӐUeuc"*#UQ[>_Kf/le^a!WɧDb$p=K2qnz+nEt:O7l?V q v;oc(#~@0닠0tadld}YE}f!Z֜'N˔2o4]dN ֈ}ln`RHUb33 O9z U4$͟9e; ˆ\`BQiEGTMT?`:lŮRw>kՇHᚦ5|^JGáff=B w0n_5A<dzMܣ0}؄8 ukY^оI_-ۄ2VAU7kinpEt"GGXQk;.rPѬH1q$k6>#}D旼}bTUa lU^u [xU8/l #Ys}J'ٯرPY~Ĺ~ 0z+_$}]fOK@& 4kuqZU`{Ok\ g-t44ZVo}!*NrO>x$JqtI";~nʨO@4N I*뀥9!W61Lf]v;SbgM+^f ѹ;ƈSSS L*C8AZ{,l==~^ߞ{[4 ;Fʹ!ЭYBnF % _eJL̄GnNAz;XfPZO_R` Xˉ|*ksw:TK .EـĹodQy&kv0 ^ ,">0=…=ߵ2 [T ʄnT6j ^/3ج0E!k!Ҧgd ٳw&'iz,~5*Ça'.)ǯ4θ G2Sz?摝Nk­e<˽a.{Չk0oR!',W 1z{ ă/y nfq 2 [̲Naid pc t3 *< &ְ"r1zȍ&xOSFabV`]4F¸xl+2DyI~Hylx-xy53PyẅcH+x\/|Wro̟I~5*kAiAB0 B{@hxiIg YlT#H^!u`E>6b3L z >65?za`:W Nf4C"?]5ۯ̙`ϟ)"L_deS3\'v)Q@fX46iuMg)a? 8Ip -6\HۄNgeU}E,oZ\yϪCf]SId\q)m9X_N ![Mֿdnf*)(ͮ[HHtC!9aӀU!A7qRO 1n/edN9O@C>mw"(W `^Yor _/5fƧSa`QCwrNYdg2@Z^lP{@g; nH|Z#44i@Ӆ/OWkaN`vZ<w-}m1恺%@ý ~ġdcbEޤP7@DMELOIM"_bpv7%8Qd4&+-5@!c F1hhPE턘>6vcEOy2o "+." 4ݺDzRYtBLF:0<,Gά-I]f{&JJ$q&&HkžAд q*3+{govߝ ]1id |Hzm}R7 yt40t9]!x{k4ޚ4%ArlʰbOqb+! "T1U'uX/%΄# (}sl1T}ߤ[Uв[2;*v*l؋e;C /͂dhٍRԲ r&hdYӿۿyĐp(}Uc=r68mQuFΟJ4`tH4@YsYƶaLf=hD1mj4 mRqɄV|M:{W "<cC Y؎k`8#9m֥'骏d-|Z ؟AiKPNUQarwاha:̗7듴jI40o‡Ǭp6 !5+w|y%P+twgt\b~9|)b_1Wע` D%?|X٦rh5t0Y6$%7@oC3HaI*⻘I?XK^($\^I۹7PD#MAՔnyb=sB&ksV/fv"V!"Q3k]֭SߠEOݎ#nt{Q؇n˫f{ɪ~|-Ts֖*M;~26{>͸T|f%:dN8<$2҄QaT"tJA_)וIH"ڡ50,ަ`KMA%@'v4T@*Nb.kĘ.SU ǘ|QͶj]%ۼx7Q$p f߶'Ԣ0ݚqWcwhK.hmBXCӅ?Mޜ1EBxIӔP@{P>|)K.Dn)m,. l(cض!Mv􁛢8Դd:=fZ@P36~NbS CVa:Cptv䪪::fAVa#CUF$`+Zm6yΎrjG%q yzќEٙ0Hb,-id^(:TUFYvSd kZWTIep;!lj.q5O+ ;ax Wz @ RH|Y\/ْ!9kAA٤vȶvEoOPVBt-;b*_ӣ3E'L[Ymۇ {d[ɸMjѓiV_ך;59ۿK0u@qɂ@?L, s0tWQq'3 ) oXc6G&7.1;L1(~qpSn4RpႦrݔ/ޒ g-;RUU1}A4rkB$F!VC]Oh3tyR01\!Y7H"~&&XT\ lt{{WyȁN[y ~1ryC%&ar_<̎Ss >KΙzݜbbfzS -2"&=m鰗p XGdFILG&2S:D)UgW]Tz} `Ih8 n:o$yˬ8UQۏB)Kߡ9*R5j ɨwpdk-N嵢3j񔷱vvn228Vbrr+`}~eI1wÖ ?]mW)(@iʇ~C;˶䞂pqA@>:Kr_h 6ttYjO>J)Jk+4iR91ÞA%Xe{kTI33_V5iPn+d9h ZUu$"T\]_UM,zm̪>ꢬϟAAYh*t͊T9VqAP\-mhB1m39:Zӏ;;gn9_+ g5VSv0CϪL^r :UE)){5]ȰBD!&k3S:Q̒-42_LOIؘ2ЎWy? o6'kW˚x{2_i.˖y65ClT=+ ۄK(zMnR0圑i`H?Ez/'ZGj Byb~gM*>"`zaqdv@odjZ[@Vsu:2^vPfd[' &Ӷ4y ě*`C7@ [gv^d1> 5w8)8 *e;d] ^wG_yp:RYXq蝇*!uV125}J!l2G0qluu<4aACiٺܳWPEiw="ݬ]aN k+reJ1T Ȕg{/ "Qq;v] nx|3%V\ۤPH5ir}w'Z< yB;DD59OȘ0d/U~B=5T韛l.@ e˜ a(ܴ *nl,(w0,y}$!56nC~EXG XKU*WBJz_k9Bf5덧\[g_(" u[m*KuD>I{$fL4z"{p)3Lahy6AAA'r+̦M2` hx,,h"߃,щG$Z_3WT' =p Z}^岅D\I1&vN䫪oSTwZ&if͍] <*:IZֳK5E|2Jmn[^xU!Ini)͗\nW_dEhȧhahxM6e!:UXhDصdIK!,(goMUnO֏jic? 1D$(:v $ѵ\@FƴF&੽Sp~r]fFWD!*el fib"PE$"MdU;xEm@ EC@~:¸%f\{zW|PaP!>8a?%eZXөO3aB@L *) lR6tB OG̨HQJ&fd|~Oڧ{/bT]-plYΓek$ySq)*~R0bRc\>~_˼U,"Ū .زx;4"¬-WZCYQT EX<DZMG X$E(Apq0k[\*%dv[L27tS'"_+蟳׿bDlVgiZy؅%c*\N2~O禄 t L1g}g56[<!~UxyYhEEU/4÷vV, 84HI7UX%}x UΒ")WLԈљ,iuzl2RkCÑt@y qn:LM&xm1sc@OIT{wͯUB>._7 +]-   ч`c ? يK`0p)qT9Q.r tQT7=x G}WMK|(XGj9 &Sdd~Ajbk>.#׹M cJ{ɘf Ax_,i@ݣˇٹWAB:فYkEžV < =O,f=?4>%7E7];U{Bɗ)u4oƒ= Y)a]n2I d49}8ϟ4JR'QEjqfɘU6쁏[ R7re ?3t<W8pvFTKPhW2y,lQmt&€xi/C}!h~ #G&תAYV PvR,+M+4 Q,n&8n z1STZ-Ѱ8 q}jYf]vQ g\Udԝ,`q u,D b5?>>S8|EkI70V*߷վn߹'_`}y"ʩ4٩S2!Ռ;{Q"@A:yRlyKJ= I=;{C("+3rOMe/pg2&qzuGs']Ns$AnbsϜg| U\HPdž IrnhB3?7M)^=V^ '9(sPqn0o0xJzxu}nIc lp 47eh%] G5cTwaIdÐeSV|]Wc!eIPY,"Śȶa!5GGաv/t,Ȋ%00:&;|ddg2pa {l5v6;(*.mw@?l`#y? 2}D] H |ֹ_Eצ?,|2̊}ċnM/.!R-Ogt,iU0ӂ7<V~k)ݷLL6[,h*FV 36eњ>bYRtb}zԝT26/I ,yL:QAN^\6 v^9뙁* ^-쌰 ίi-z BXǗ?`*;|߿~s3zH,t@@$ak\uNu|*g1K^@w";AZRK>"ςp=d"ɷeUnPCHрBhBnwDwq4OY.XE,2zPZ֪(| YvKCz =Bpݜ6$t.38P&A>LR_H$8ȩ0 E Og;@`46QD:QHbbڣs9ݸJzZH(wD]jzR#k#EIyzL~cg wT]CqE)&Ew@NJ{&@ga.΅(4n=Wj|u,nv+%cYi >EVAWfJOsv tkh! i'[џP}pϘ!rSLb)323f_g E/^bW+::sȍ6KqSaI8AQ·S̎]in9SR۱mOɎA 9mOhTGD] wq}d u׷ҟD!A#9rU9wfpr+4p=2Z|%$|`&;ZDycaq Jk`ALqvO'kb1C!&Ԫ -ь0Ur9?>lCj.{~HBd>Rxiwn5m.O]m,e( W%9V_uFlʓ>ڟb{NҷfH8ϛPN0z Ɨ)Kro]]yL>D)7&V5r]gi}f_&Kt-Յvӥff(5lJ5m;eQࡳ5@=e*$o)eE4LְEPS#$Xl058\nHNz^on>Tj x- zָqNE;^O/3ũJA18SW*#1E{aZ '"K6L6.fj\䫼5 y&9#.QJٲaO蓀q. /L)IӞ{q9۾A4K>]Lul;ZR|%E{YL[!I+t_iwqgjYqn\ ǒn"F|Y3:c31I|Cߦqg?bW\=P:̰'ڜi rȣ8dtdEthKsPPn-F= #m`b.BÀeh!uAF=.$z%t9ɯGg.У7)Wl-JH6_$`/F7E3U\^WIUFʮX},qO}qPݵ/V2v۽#$"ijtǩKϲ=$^oa@mҖ׹f)k8^KU7wq2r6#`_lTl&}  R5dS*^@:7*J7=a&*v(X9 QlwY=BŠr$=I'2VS-XO? \;@[]VI^OOv4کLַt:_(xvrk$1ԙM\\O>-WZVw) ܴI!AbQ$ Aix)l߶Gۃ9^ 罰ݬDsDI/P%w^r* GuGvl4v4ȶX:0>'cWьYM?)S@ r*(U/r3+oTk7H\ghfBI7<0=9S߳f*TF#)zOrkVDž)7jqg]Ud?@` "(~UAwݵ*jt0Ⱦ܆/$*RAS^ ONT(!3.>zt$0 />"_]u%% jeUNH'U{~! Y7AlC4OdJ 1S촄e,:MV+> ~/q0G7]oYޫ${TnQX_cB1։Gb=D)Ԧ3g^GcϏBMG΍к@c b[`+SZX;OY+gH.@(>$C+_֠v +7,)h#1SЭ@ OTd)znu}dU"2=7'$h*rJcld1bpwKGٶ W_7ȉ%&HbIbF`'Ta* ybM䦃sE+eKky%({!RXWZ(_=? V굄1%mMCGja<~]!:)D BA逸sOG 5 ( rlAkWt_˼[ϳ$-zJ'@ ~G(%AT}.Ѥz2C,ńާz4=cyUT5"ܽjIOCN?vjl'}(kbsv ɄnŪ&ICc(6PVSlnhpӐTuuu‡a*mI[h+l=pQIXMYld.-8liJ*Żao<nLP)i0rSn-P#} \>2 ; k9Qz|^aJe5NgbN"YdLLSg| SN\4KT'iP$M6RYi&aG=6=VQ2s<-tgԩ Y|d'(YDywod2v嫪߀\oagu$MGg//< =OU5 1AcL7Ysވh#`vJoLu޸bFB,T!iIm˜ėmE]mq&AGQE(Eٚa:>L\֢$\ AH ]xwglC'C4Kd!~:„ { MVj1!!ďVT2pDrUV},ЀoWD2Ƃ=m}4y8, 0sS$]lVIlCL,7MZ\j4B,7<#W. &UՉ.'ҎW˻"cL ݱ_$>>M rNiuxxb4tDÕ, \Ŝm)uk:K,(BBta v>d)Fc{hU8lР_J-E `-RM%\otW9Àt37Lĸ zmCqg$]Tk+cn?8{P>^?YLC7n9 YڻI2E;FÅ;P1HLzc$*u$w\1t2)#\Z !reBsa .m84hÀ€8ڄ;rM.Zq2=zD#tTtn _4_u '>ڸ J"HmL+,Ȟ̲h-"zl4 tBD!z&ˬOȮv~v%9|+ Ljr@ h&ڕwqx\d]>Vj>#'ܐեQܬ%*Pe'{YsXd yE!vJo{C@7T|)z㱅m.kЗ!(9#]opn/]wg7Rぎ>fTL;Fcv FwfM,ǡw*aεmRHS6ou\2= R[ϓiViK16ػW+ڀWqs FtٜC9 ѡ$(csOǎo c_Ŝ`tYۖc#9?&Ўaa@U5OHwU>6MԌ蓊@uB5oT2PcDqst#Y62^XNAd4ӪJ_j&U쉏H^h@LJ{[53=:2MjqsYAN9ƕs 0Pfd}m1Ժ ĭnGCҎ CB;vɰp\kW=Td檶$>~5iep}SFfFO2Dczo%ms`؏b׫Z0z-ϩ?t_>IS m8" @ȃJ oF/)WYv1Pr&NPhWNRpeVE:%Ο"Y,MCԂwNgs rʎ@s&d<**ɦOR3xuuESU!J~^5[>iN^N 4pD~LjL>+]#䊓y6֍S ij :~ UWFҬ2e? Q̅t*|7ۯRS3%]bqKU_V|5F JñMΖ/{GegPfN\}@[:wzQ@BԘg2\i'=OkH谰:02W\hW!пevq\&T2G=dd.bP2}EBj'(.) Ӗ_ LU.]=2TAٴ;qh;k>WYD'j_¿L5h3$0hɞ vnrO6ۮvA:p opO҅%Ģ;:wRB՚ZOggdcJ* 734xAQp?;0]* 5O ۖQYKw(y,S,6sܢSH3CHgv jrݢ-#qA;fFfG& [ViQ9\Ln+zMIvyjy2rp0nXכ uo9/6 h η>P} wF_ڭGɬބBxYrNjZ9uhutzT6k4;<)g|0M_!T//mDAtE'4պ-qC]atON60Prݬ^'Lّǖ6[!f2"N{xgCE]BӳNf;tqzLEo?̾50٠ۜEq%PȔI$8cz\r&"" OYH+'j4?zy[k@x }]zMw48>xy~bvy_UoO]zcGk.2Dm=BKB&g[kkePZv7dR|k Оo]nv3Uip/C2ְUy{ΊjI"ihT`$LRmO!G *'ձ>ƢvE4P yo>I$E4*W/ܺ* X!M?[RVf|q:! [a"]~lYzXtdi]cOuJ=,&doj%f/j }Ն|{zQ"1 '\UEU_̴=<ERxӐodVu#de)oM`({+n-xY[~x2?.窀PK!LjOF;"q8; ~K>[rfT1GL7d&Zw-e DߍhVGf3ЈJayaD\A:|>DDɘcc#:!)9"[B'Uʢа6R L戮B#\pR4luAM?PnmTG&1.bwS)Ĝ|ʻQt2_w +g-DS>S2F ;㋥6RHunDK5("\_G;T_|*h-n޽>^;k+oǧpx"uQڧL=r?OLm1,Pkj t6- ~E^-)[}GQ ?OFO#[Kd敏OBV.jb2C:3r^@Ut 캠}tf:^\lrZ@`][/8e;Ӫh^C+P$"C^K!7՗VS?8 R}|B>? p?JFB=c|tgfTi**tzhs \| |"2tij@2Q(l}>6yv_EDޔJ8Dڝe 4`h\ pnu3;]@XMDfS5!x)㶨M* zqSeؚGv\6/O#_T$v <]gExڷ_SU} .n);y[ RǎV7dIO*luިc|@!KȒ'vyN`2M%lHGn1ƘFmMi~Yd'EY3TW 2W)oM14&:h x\}?Z'27 0ڶ4OrӷbU:r [쓴M[QDS#i-%i UU]M(<'kgJ[k"aǾ(:Ed)|!{gR$֎`jC@$gҴGy,q!ISxYʐ َ>9rҬnՐX=(Y;{ˤ)LuwF1]X+qiT +\-2/]y"b zpv ?]"X<-۸LJΫmL>.8dr,S}\h?ly ||Ry̋T0?y N'_Qt Ng'U^w \+5&Z@;ENEem޾"$iރ1uDr٬'ǧׇ?pXGC Ee: Jݽ|at}Ŏ{`<I/yoLt‡&Es>n?P.{Uh<:Å=fAY RAV%v_Elc۔I47e aCxBrL; pr£Ie ^WJ[ǔuǫgdl;_|3&(H%<-:m c( 9DhĻ}{S "/\QæuOQa)\WZn<?\6r\[Q&U5g ~XoBE|.7!¹a:s476[/TB$Ӑlvwtߪbo&Tx'w᬴3k"5URޔ%QA8ScUqD!v-r`yЧ/ݡ<\l^ yI]?-ڴ֩M0@ SF&V3R5-])f% YKZm}gjp0IM <0>O3<)jh0'(qka`դ㎀|*g 57b⏵E[6m4L"0D Ѷ "r+o(T;a2쉓:a*Z{D=gE[ҏ̓b`ZttpYxn .^Eնb-ώEZ8Lk<>hȦ.%xmDvB$E 0>!7`JZHT ?X ͘ ၇Sթdcmm s<0A:SLǴUT9 Y 8~`R.%8AM [/l[+u([c'a0q fج/&;k6T4F#r`m|cp%Uj8nן _܈,yR2KNoCDW#!ߓ;%m٠ˢ(+oG Wȣ/<8N$}-a s@Ll]xj:wpfm϶{ "WwMd@-; 9gXω5W2ɮ,c-#Ԉ-Kmٯ2QgySKI)_`II6DjZ0 H7y.=ƭp@1N|+<Lʪ|Vf*++-0Izc/{vU 0* ٩+:! t˾kQ2]Sy^%eZ7g:o_l^K`$<>-WTeU}_FʙY%utP>+q%~2*1EcHkH\"+َ>L8yS}oxblP i#ʟ%+5s} ,} X$]c=4w:-!ITC:cuU<N&#iEAAϘҙwG0x3)lp_6Nл"[0(9B+R}3(gy]f5fS1ʼnĆ& 1'?-8jbc ώ+(p2M,$/=bf"i{/E9i 3I7mfW_( Fׅgk Wyb 테:,Mс )Gd)W|kxdn:ߍ@7 %1;et0 X5Czb:4U++SfxlȂRW6Þ褍6|=u'G).@Ӣr32B'ah-&Ӥ'2̣ɸ{o-Ҵ*Wi~UCܥm15Ej΋\au.yÔd(mEd'G~wmRsÝ+2LJz/['؝X&ΤS8јJ쪏rkr$KWA7?B%FULN.4gf݆bQ>dE%Mmlh.Yq \  ˛֙'/]%h6FevG+A-D %2$@nc3e@$dcBիQ=q ?дYjJ> 307L{72&HH1Kȥ/Ѩ@Jj+CnV>)fI@a{Sb= ?eME<L>4l>W0 5(a&k:uۖ*rYu-iB 'bR4d$_2r% C|!Bh]~@K^'u5O  ޡPa>ưlWUNm o[N{DzB' M)dؖ=EHec ;u#1#Z]֍KCp̰e PdSjH+Yy-ڒLG1Ďb oۊ^dux;֩bnwr[E+*6$S|0qHMe5ԝ"]ݞ}MrFN $6NgcRt̤U4܏D>]g@rЖz6| t >p޻$֥7lf{yVhNIA.PG60/vi v+lQ/D؛Y/|=hU3EV/g?`-8KP8]~%x* 735z_k*MvS# Vn ig8T6=O䥤9-hMnhaXv2+V[peM X=lm͡V}:4վUu.A+zWW4*,H~I۩y6[8Ջ]RO}!Q\Ue6f-Dَ ٭|:5ꭇTRԡ83>v]w\ !M_WqAѲY7[Pr,1ȪT,`45wLfu\DDAb/pL v-NR>Vҳ~xb_4 VR[>S}/&qt8] yVlq6KhB( Exhn?pAw>PҒ.T  4f.uCi~C-DjTdIDMgې;N#Hw$hM49导El,@Sh [TEmR\Rx|O#k\m| 3>̇Hv̋8)*o ҃dŁ7U[X.0>U?t/@ԭـſ6q3Tş DAʸ7j6!vZD+ .as3CD `KҤfxl~IR6&tMD/]2]fO+4`H" RtaGp(*y\Tui a>gov#E2fhWޥ+tzOJp:tSl0H6|J'D:S.6NJgYI DJ" Oo(k\U% ӭ֬z3ۢ`1hcia@?^XDB v5J_/zml2"7bݤws0OlO3L>*;!U{*L1a }",H76!=cuCsT]geV'b~ԯfK7õY|yO7/3b2|&힆cND:~xMѻd>}-̥Q͓E dGS<¿%6I&GeNv;-,`X0(NBσ4?o4>Lr+t0A燘$`9kJ;?c7 8`@0mg#t Rg 1z0ɑ%14}"Y{ٲSvvsF|,3dzd)6I,RXuBg\o=Y6>vvdNAǶIߴѴQhԠ4ysnY/3z:eY;i}tW4 bL WCk'$MI5Qf 3 k=!!4} H [hOHY6k)!5=Q0Aj0㘺x c$xBDxl*L ɛb?2*"A,cB$vGct/4dLn%9g`SIZKԕ@-De<8OeVhYP}R&`m19:O &1 \˜iHƜ' cmm~#j=O>?id7N-S~p* h!sgI_(NkWڿtYaM@_zB ύDWEn?zW=o^fmxךJhަir."kLy#,BRw/  2fSvTF,WLTډ_O!:Oܮy&uBXP/ؘu˷.\Z(t/zGPԢ;[qI gbXNa])k y %W@7OJb[48?ش^iX*{yLoOb ¤KBQ{sYdJ01  jiӏ;):3jљ"oߪb JJS"VtKE?gfsCjΆ͘ #[xJQ?VMx AZ}^vÅ)$h,+G +*)cUˁI,ɎT_{F>LlL o2t`SrXWy@;mM&+8Fqr`w@`h{:\PFb{@.ƕuazP4 X5w,.d&H6 m+Fĥ\k?D}S'uR[h $(Q涽<5T``wSZ~ߒJ8VWVXe*h+vvLs+}v@-1 ʜS}ۖyZa.AMUk\#P^n6l~b!q{g㓴}Z,@ f yY |_Ifu^`j$#c1w?ؼV!TӄhXaJK =ULj*V cӥϳ4ObCYUNh:lǜξ\t_t:*B}hxÅ2(x-]]) 3!)}[iا6Mvի$n?KpP9J*I!E7kÓ Ğ8#? Z'y;c= }@AǏ]Z^Փn(27Yˊ{(-e5VD_2v!%gKKly?4}ՂS ˊJ֔ ߺ/|q`xޒ1{w.0ؿ4|j)b&t^T߳_Qȹ]kboV>냼R6ى7=$>Kr+ 9ziKgj,Sr$$Vp8j%; -LRژH+[%Oֱ /hrղ,~._Nֲd75HM=t_d7ŋQaxYVkXl.bh؋ekq30sm8]zU>\Msz+i X|}5 h!\AJN1o8N-gOZV4>xbd^caaw4wRf sv{_rymd,F^]0,gTO`: gv dJfАd9"z!6X/׵lvv O;#:=/v&_>X1QR2lO$ۡTD/=êE%$AGYá?%YQP4ȁG%F%Jh*V3uJcp0]VN%Բʈ=Wnʂ,ݴID՟.٘{@J|x:{LIPɵ = EVL'r:"_wt7/lHZ0p7%TLw$ZP>gorxޝlRwW^)$A<|g#2(l,UQ,g2Q2юY0.5X#SStQI'Kisuϛ .ۭa,y#+ڙ#HNaH],o..aŊ,U1(U{ ΆY\,L#P\%ۼx&ԘDgMm;R3G X@]m"PiR^@2y9{UuuI࿖ !f[ӇIeMh &sf5dHP.H#߅l'D L?t%mCC1Ɏ^U67YQEX9m''?^R q6:yFnG6ih˪)l#ҡAge2/%uӂmQc n_olUi3{W)"6vTH n:N>>zUִ씾W<0~,ހH}#@<\fEJf=-je*XK:>mT_In" -_9&`v1#а}b\D'+XRDCai]I5S8(├oPJd)*fj'PzI*g ~5ys W^-_mlN%' :S [Ay៱v".¬j )NUYp>vlXe:c[EX7 YC Ӱ\oDSYDP3SkUD;=K_M Q7iLD2%:̻7:HBySn1iwElr2zN:}Jl>XkT&>' ] L[E"Nq;Ro~ ?~?x% hY҅!P>ةn/v|N~}uiޛқ58]WGrXQxڞm}ѽs{RNOlrj^dA'j~D+'5OXN@4rz@~zz ➵)_k5YEU_!3.O~LGak%$ElU $=7`]x}L_R#_pM  y AGdO^!E7N8 4*yR Vgl߶Ua7YԬZb7QNBR4t˾J=?Mm8W6t..^)ps걛l5;#ʋδrw-6][Rd[<Û#̓~T3ژ ࢫ Z{r%p\ZxO0?_E3_dZ:%던bLӾ⹎69S٦Ε[vl|ȶ9D鿮w)*n o݆wt!򳘴NxKVde t敆DžoVMbiDgʛнgwjwySʭe/pw1E72W](REq4$zۮ$9ҥ):/ +S׭7e ЖTg|. .C6ky b⎅I 4uEUUkynFйh`rJՈfkFOP{s2{IOXD ;q8'9`,sjuRZ}lolU2 N50h#__"RF^&#`[## ժg̉Y~_na9(rW=77v>d*T#,ly]f5|%M7>>v.\^2ΣZf[,1 _Mc;Ddd)C5r 20ٖIus1{bLc s}^r$[PjxG& z{^/ˋlQ1Ya|A)EsWUQك:J?I "Cw"WV}xv_4zlmԲFwib4H6)LxcW lRǿN꒓x(爪Х!? ( ͿyR2 Ru& L<6g/fUȗL,2]+ ۽ EsJ`!L #ۛ3-WTeU}_S(֐aM$WxáB٠X],:$8e| \V6ͫ{4l#G6>8XB*EJ;*8ZK9&L<&75$_'7mw{ƏFd`T=~ `J#٫@V(BètA$0=y`VhubOBGj da8^?cVW!"dgXF,"7Z43ã 1,ޗh){2 .nyUIt0$r6yñ:qb*2Iemϭ1^%#v&&?06<嫏R|0gcKfU0\i`ڿrl~{ 'QТw'aɘc g 9w@%$36k#u+d%ωbƟ̳\`*^8^Rk FAo$WI}vFڪ80 !m&tS=o8)ciGϷIl+R&X"^F1dE ,NɱrVzl)ĐJ"EQ:q,3oh"$o{)vF_z=(o;wͬY;/4|&"mJJX ȥ82Ihx`$Zfƒf5̮.n,vL-AQTC Y 5f h1F%d Ⱦg0ɌOx$=ʃ_I Ov[D%yXog*jg#1wwԤo-{;u͖VIO0* @AH#my@C1iݯӧ3l$播bL٘fmiId8*) l|{Ѥ+_ :/jt1@bP1B6թ}d+1(_:0 t)418 ; $_D.nKe}} z/2a]G"FLWM$<*~A 5xti@A$hЍG2td Cҡ >-g(N`6ek/CN,M WӛW4r(EP-J[7tmE-d$te|-ƯD%(EJT`L<㨠j:Hޫ}w2:d۱#ɈM-+zR'Qo؀2D Kٻn {gVꮠ\MF]]PJN]z3h|^޻ԐG [i'O')P[F?$R:\O6zu1#M>DJElšD%R읯~*)JqUkciԄn,F5#*$|M+ y'Q)БJ,2f'bȅo[`#^ *~`x,?*̱"`^͓⿶0zv& 8Bbϟ"D7Fgi,OYz>~^qP>t~l_âm \;YUS Mm @BN)|dL iֱVif" oҠF@GK|_)~y)h핞5V{//Z _Xſ Gzcrݶr'U>SKMƞ;659<0)N{1}QސE72 q׻O+!^*"yBZla35Fq0b%}:sE ~<4mRZr<5 D{De^Ud 8*e NB%+4<|!n /Bv м<  3.nNF_~  s4W6/mkߺR옑2o?Pi);!>S Ն53k~n6މi Éhlh1QӺ.µjxÖV#$hhf\I7Si FMoVu*m91p/2Cȷyz:[mjSM>2,C [?)@Uѥ]=x ~8p_o%>[ӊ Ž(@$GŔ6Sw{a:$49Aa%4Uw7In׳G7)YleF˔ƢWv@XƠEAzŮˁ)r!y"O"\1 ]$, I(]pA'e@x\r7KƏ=w|" sILa<4-o 9Ʈ)_O̶dS_<ryS6 s"y®`֒ЋF; X !yRfYg);l)m( ?($<=O-{‡,"1\M6i,lnjܼ۠KygA3KLͶc"|l| ny9 d:{I!ƝWznUѪ,t&Xddƛ7UK1ZN(ihg|!hvt"U[twN]GA$32@9~,7n`ײ5WEn=h~"&&fe>NYQT=0b[~(/ؓUaH޿*aGLjflLK!kT#ߓ?9RyƳsKkWy!T!j*#d'◼7eA4UFlfIecD/Bp}fWQ~ɂ9״ғL[ŮHawjhY~x(/ELOkg.E~ ?M:ªl{jZWx)ϦզTd[X@1|QQi-z)*0*i CƶƸSۍM] ; +Y"t;ؾ신*$jN#u,4_e&ZpkO )Zt=<ݨgp{mR3|} jt(u:PS)̪7{e> T0sDbi]nwEy61I}XRIIo2ӱ`cv岮k~B).DfdFG'(-ſXN2|_Z 0`:uy2{4*'#.Rٜ1(MTrYG*DE" ›:¡G1&=wq$)}[?_C~rd?6=Hv:T+ޏշrz X Rޏr/M6A*[C6kP@G.>(b0tҕ1nky$"&ATp@ϿԹ?a_ 匈WERn铥˩9Lg pƴbOe?ӱP %Rm1#ŤDbs5ĎoOBm3;B~5a.VRyԫ'rUcfW!O։Ix4ͅ@$DN썺/GmNJB0DE$QE"KfM %MDGu%m\>z_`?|jEe@l^gKHMXw]}CC!LhHuu(ι`?%i"к6/EknjOs=Rы $aA5 { Wr'YAoe&]Aaa߫s -ŝM :MDYA Y4dbMHqUu69wrւ$Hӣ 0RG6z~g.+u]'b])Fx()b"s_WҾ\1Ѥ-NlY)/;cLA=o^fm-# +[VE. V"vn%6s ߦ`)œ᭑mG_i![j|ڻl ^Nf(^ZP#_N_Vn2 50H0ia,Lxu/Dv.T`bt~,9fD0ϒՓ+e<O26Y4eX,3ynIzKGx.d8lfOeU'o ope\)KE~g&BFߖ`xﱲ_ްJY|:[3Ib4*.狼\iHfMK֥z 2>Rne있UdfFH @WT.{,Nu{yy/yRjkuNA3E]LтSFW9<ώ|(Nj{_kARM[fo`wr^SJٓ 9>C-x!+r|jrtWE V i$;p ۊCscbsRbwX̯ ܲ^O0w%^f{  )%|SJ0]wLF̷^cXH02EA gwH.gEU?廐/< ]Q%iZOGl? &>= =Ej<5u#zm  }›p9{]n0@%5(GuwB\e_[p̰Տ>+CP+SDh㪳._m}]ZtpjMݜD^f o u9,.{섊_p;~fCȞ3ZJp,,<2EBIi12᩹hq*H&i75,bCobt2"UI0Dn{8_Hھ&U6 ulUإ%=2AEb/b "2Bu&]~$ehRLtu:q\'/}{#3(W2Fmpc=BGMn=-ڇPK/0\aD(fC\W9G,>gBlI L {,l-d&)v"CS5G5O=9#~ˍ\3kwoGZD3=8x>W Mam#{+ (?js#AI$InNJ^YޜT[ŸvߴpʯBQxf?nWdǪ)PE!ٗn<‘)>%͓DC}5 GZ1+Q .eʱ΋r9Ǵa;˱ȧJuR/ 嫜JYDgEK)5~r2hC(|)P[?iO>&Z^m[ggpr[GbSWE޲b(7O0@Kw仗\ ٝpc/gvr#{T1N73:3><5p OZ }eR{ȣ6a un f|||W'g%z֤>"hs K4Ŀ,ɗM;>I-:0 ,ͮFJUTnj8@yJ3dcǢU`&颌=FR3{m-=4-%m|vE: )YЦwi6 5:|* rsNf sG“Plrd%=rl8f^’ta Gjs*< 04mf LOVZ/ھsTZWX>J tohhp 2iR'8"{ &lJ #R\m&ĎFIR|qYsG96(VLv>Q Y6b-S,b2fPۇΪL'ʮIw|v)[Cqlp`!tjB! + ~fPC]Ba bV'e*P=v2 tw>."]9q-! ~yzғqQܬ*/ۓq",Lq2ERdP=/cCL5A$:Zķ OSSSJy~&kU }[a0[5\gF7Ig ~f[c32ȏ{%G0z`&&K#\Ů)*Ž&P`:_iK3`ݟǛ-W]VD+}HR)fz=L2]^ʒH`O)56>Vc:G{Ț},<M}jV`ݷQVR.kٳA]Ըkr =ݚ2WgoN5l_<&E |E7 K8M.f46.a3||N 9cڢv~Nd1>khl+PB}^ՠ7~S1*@Ӻx瞚^RU-li<l5^p6[\J2isT-FP M"ys9.* ! G매L &5ȩ0T [G S r^H"`fP#MB+ʣGANjR7ٗ5a9;F:!DQcx74{4f !Nd:Ksބ}hPOr)H/3(>X N5:|\JOLGL\BANŽpمS#ʮ*Dw{aJnzSg8^@;ș}}uQUt4>KdP?v*MW;Licx!5? B՟GQKUL/8>)ZZDVFñ;9ƨiih&@!bU0TpQ^'[koPZšҴ"fŖJt;{g)b$MYBPG" :)0 Sh teL2{f-pՃGhww#N]*=ۀ%q)Etrԗ& Ɠo-D`?Xj?̠gb4æYs@\Sn2?}yAJ!;$|%[m葽B)zV& E݅5I7֯ZM%$:Ei ? LfI^0$0>-$zEsz'.gSiHZI~J̑g*+ xgEzJ&p1LpgQUufA ISc'8RTXHO@?V\= Ȇs JDfkv }qeBb/'0VX(@ .}t]+`rdK[ȨD'J(# *]kOVUSI\w2k"7g1kj=c"LPhꦁRt9VYTI0}`/˘jWÌ2?dDb(R 'ǿAä\Ycz}gx;uq\e{]|1\nlUK"hP_N#*34yퟍ%lyӦr,hһF,ӕ  e1,Ga¦lVdȽͦ(ej*W!mJRF.f$gJYHw1=&54Xg5]++hB,jjQGWW0x>s|hpӭ^{#3,I'$~~[{;cp4MiDŻ` ?psIWc<ѨO1hT|? Т( nġyCtPKxcy(a$"߁4Du~لa,FLG6"2"Ѯ`ɎuB kЌf0(BĹL+} gə il_UQuRK+--)UL(Bd7Ge?/l=:7İ~s8nr  l(qn},eV!5!@{ɐM>obyϛ}&|<'sߖb&p(<75 ȔVG͍H7a*ܼ̜swblvyƲՖ{vDT$,q"Le|%YJ3%#D"x!$*$*hv3+2y} NCUQ˲Ofdz6'$zUKeuP+T]=Mo>Hߜ5p0&dK ڥRBuwq Qyqz/>ct Fh]Z C]QbO./a-U=V8*PL.UCᡙߕ?T~uF[Y#2<~=1n7ʖ5"~_&-H˟]nZ?Meϟ&S??-:%,'zxg<oe{w=ڵW}f'_w<Ϳ)PT)zۇf,2-ZU8\$?`PڻKlqF O2)_2tRsI^ɨ0ɨ0ɨ0ɨ0ɨ0JJ x"_褩?/?A:Y/.< f( ]sT>swDܝLqJT$ή z1-=|ȉ9&4ut0 2k ~_v~Tj/{elV`~EMXdtzb/ tCGM6=&_Guosw@ `]:]JbN3$M.όa[,NjR=g{٤m̧~u+ฺlL_fb;\Z) zKَYoH{ւi%1U^3KB$xc:msSpTr7-"&(pF?N0eQ]$;ҼIUz!KҕK_,y{򲑴#|}l;*61=0Z3;FAwH̃,B"iHBHI o&W-P6|^BA ym˨tRaȝo.߫}a+|? Ȩ=P~IYt_(؂9 ?~~n/X/Xy7N%t=fv6VEjrUgezY՛{\M埓_s?_-d1WxG`}Ӣ ܆vNݯt!)lo}; pԬ,q7[g`_UR_pPH="&4֎#וE ??\+F{XZ<rnbCE:/_%󼩰2\ʎ[jG p7 Epğݭ|87])ܕTjo7@_gp9< VPB+( J`%w"2ˎs˿R"Kn:/xa[s]_1BF Kf_t6_8* ]#,ֵZBvmdSNwH4vB'uD2ձPXbhnHo~ \,TY0nA2Jv3xSwA$ I )B$7MˇAAB[;0LvU'._!F:v#b`^"]5r@LH4AMz.Y)ZV4jqG!Tf+4d\6%Ź3z辁kuq5aTej09lR#YD`35bS|ƅ7 Ra LU=n?D7\#!Ӌo0^1қ"0lC0t6V >m?>}B``0PۏA`жOxۏX1pg/sWT .UMs^&*?߂!ϭD-.HGA 8HGݮM<(vCYv.K`Po( 5 4u,˿wtG]Kpxnrk]AyRS{=o:Q|SL^e:ߍ/?`jb$H]{7_K&x mt}f%Cw @35 !xl!1kd,_Fo PNRxQ}y۫(쑐WMjm&0|X}Vv:li"9 r{DHakx-7u]r>2 BLL|VM8&jP ڄVm6AU`mGZuodb=Mn?A_!#ȾeQoK+%J^ioUU+\;4 ܾ͠O8Nx9.xu"A:1I7ՆmQ~'bC3Z.zPY fOw+ZPb'9!ٸ/bHaȴY3s27tb婗bn߲"YU3:/_إF'dإR_{0DX]7TAV/:?2a߈\}`͂Ajн##Lh(b P3Y$hCkWYb|[?:'𤚼,vN RZwG\4eԎEтS.R7lK-+Dr/:3m(Vх- տr59gM]iYRe5F7Gwhᵪjro3aΌ/1I]!4+2 N1*:Gtm"}&_LIbg_n.h,%呸Qr6%6%)qQ.WeE& LmW5=7XY8Nv'UgۂM2Wۗ?&}1FڦS'*`.*~XprH@nuo-Ԭt-lOaqbGϔ޺ rri$t$7["xkrwp٢Ҵ(jY%Ǜ eV{[nQvʺ*d+֟nr_Ogg8#6Czv8 hS kPM@z.iZFmV0nc%HHb#!I$8HH"#! $4HH#!$7HHb#!2)B~p(鵌ϨBgU0b )5ǻN"R@CJB\F%@2)1hH V{gnjLX%OpC3>c!3;V($_YӏT,:L đ̄MhN]=_De2mKU@ 4#$D-tƀ[51j7g! nD2|F":+D`/IV Piz O=2&z{v"~6ݱM2/ eHeߊI54Y襚 ;B GVNx[7WiPi:Je;{mnqRi2cNB؏rXnMQ]Pyfi$IeUkI([]#]ڲgIw.te nt%仮|׮F /H:Oo?OE)P#0겺IJ0Z.ya$TCR X$xC{DqI=$XCBqI=$tCBq =$Dܳ=v=T*wz*3 2?>R/c.Ut֯WbkPcj)Nr'w|{!V2$7 *<Ս&r,jCx# ?5˦Hܪ4I8Dpm&y{E4RjBY?α@{/mܩU٬ ;-f}1&C:% o7< 4Ѧɼ:ye;W{k'^@8d[\aGex!&&3 "2_n*KIH?eώԌJ*3篗/͘I6s3X1G|KKC CL_c Hnαtvgpg?aLáJkfş5y3tRzi\w2Ssz=)R#YւM_Wޅ"\l0 ҷ' 4$!ᓆLtҐICH8iH2ICB' I(iHICJiHؤ!ᓆM>iHICKHҐICKHҐ$SO|ҐIQ2D!$xҐICH8iH!$4$!ᓆ$4$x0P(}s>/{6 7 hS: S: ݟ8x>x3>z gm'e8Zx8Y$Մ"+7-WOg|#Su%A;/_0MTژJhU/TKl`eK6_K\֌4el .{Ͳ6{vʯRc]ƪ0qZMrYd[{&l&hNeYw,L)-G@=KꉮW3.$^mfzLferewa#~*+(\B qY9$;$Lg1$pD3R3A Lf$9$љ Ir&H3A Lg$<$ It&H3A Lf$3Ir&؃g$6/Hマ07JA Seb4AlTf4E㰉LSi6MMMp&&ii+8F7˳c\w5;'~VE/fnY|ϊi)Y֬p-N~Bb k3?-kpFh|p5k#u_~qLODکT?,b|}֯<a:Ŵ3n6 T/:mPmc#MIC{&52˯W~oxFö d K` mMSY P$FhZeFe,u1x ;e^Vs$`, {߮*Oټ\} ds}2 oEiHdj+X Z>|N ІIBCX! m3CI uܨ~M^og +TT88s&`U?{? pCr\zI>كΏ t6;RK*|EhOA mk~=G#@>,`gGz/vjj P Y~)At+7=չN8!N-@ʟ_c5vHIf|` Ff  ?mR *MPij1Lw|MhE$`bGEY{d=2%0]K>zl:K?̈E:15CGu!:V,3?ҹeWzY>kݵtк@C:퇫O>(;1#@e}ۯL8SV|/eG*MWgeyGGdYnJ:gܪxSL˟vwЌuC2/y[A-EY5y~_].W5iVߖ\<\&kjJ)y'º{[@N`4UhZ݌Ymtg;?V3dllllHp[$ [$--;SHI;ŏ4%U_M×rAe=e:9;&_Ks%R}HB}>Ra6qJP#1Y!ϡ s#E@ $$$Qwh,qgGgciګr-W1_o7pRncUvY=E*'])S|6у@e!pF"F@ #.0c6ZUS7_ve3fDk4e(>Ձ?me}dL|g"u>V|̣+7v o3?ZЄnY7!0M+b%luȺ dkHu]迎r%y o#D  E~;nх_|#,3zh"+vM._VeUO2D2d_VeVt5^f)h<dwzy7mjX;X|3}Y:nh(vj*˵{bumFsn<8NBy܈Gw&2# uEXL azehԝq^uj[i]e2*Wl_0-͜ Uw&wY3^AGF U5smc.3]uKa')+PPBRA გD%t@rQ%$LPbO|d@9=!XCbO<\ƺeqS@FmZM^0y9Clg&HE3J"8KҠvsA/JpǪȞz1t Hu Pr=L'!qe?؉2Bc*,[Hڻй?XF* xZe+%x1QD~`⑎QW:U$ Q]؜C}E<5]a$%+eIT2zVٽxUz>$A$:tPB1t.A޿}[GVx=I:Z~lAK|o9Ip!E.GK6-R *+dd']=Z>؃kL!0ƴ f2hpl0n_JY.:_݉́Go\Uԝva'j}儦H`\&>~۟xQNv@eծqV_e@zꋽ-_`nLm볖GWWb+U ~06~@JKbq.q]S5wLLD2 +$W,^!x j;:^+s֎T/jK Y^UY,ۓnϏ,9&Zdp= \ɂU4c~wxJm4X9 kZ7.p?*aA*>B [;5ТZ u">$?eE?916Iw%?C8;^+N4Om_6!CR{' -l|M(C&n 8P@Ԗ~oYՙʿn(\;kӝ$[0NЉ+0=qkh{~WtEۑEm.C2ߖ|Ig|(Q^$ BV(a$'YS@yu^IͶ)ܙָ VtU}޹GO&\zu$MI>J*{絺!AU Z;4嗶+ mҬ6޼̊ڃ] LG1 v'{۝yZu7xyCP+ʢ,w=CF 7" 6"4ѵ6D&we}wņoixyѼ ϺzR3s`mOGX?n&@@Яe&z5?p pL9/_֮ D!фdFM> FB&M=z4 o &`GM~w5z"3Kש$ )B ={7ߕD /$m]V'cBW/,†"3 g~AIʚ"} >[Wj\>?BYivh>%^Ay$^Ap3+ @@ŐŐD =#`1owWmΈ1шe 77z)}(rd&(.l &PfK^"+mPf2E]Pt)VNPADsA! "qe ;f7_g([ꂲ{іYԕJ/s!nzswpu"N;˽lOݝH+Iu=RбHq)U6TgucIj]Xމ F1$^NH )z!:S9X0d8 POt8\WHc}kh`4zR0̼Y%p7# pܡJ'` ldgr@rs6.2aG.Z/ N: =(#>A7A̠ @#S% ) HBcU I#zҺ~Ecۆ򢡺\v* 8[~ ?Ii%F+|$n#h>IUJA ~~@)nPᬁz}>M@#Lw#VcUáR0#MI'LwwY p>67.%gAJ;lёr |V. لŔl1G 8 Z `3Nꢆw9 h{"wԶ0ëoK{i[RzZf7>!uaEHIDaJ fu$:FqXSo}ThU5*4vF`…~OkԎM!` Gޤ۠A*wMfkE竉*tF͋] 顢Ʉ{h=t{d(>N7b7`X&~e[ׅxUL@% }U〯fNZ O!x SW-y^vݥG\r/ָNÏ0 ;%01mq@h{ =J@Պ Hl`3ݫ5ҫ0dw\HIcތGˇ/1:aH=\OA%>nK#*I 3Jd܁Sr-JU~cĬAnLQKď,3fPsA2HMIB%T~7.@((17*\ LP||c)>B p~*yDY?ÄҞ|{>A?'~(+N'V z}fF3!A!XxO8ʍ\˕ۚ?/ '=>V9SuSz5uOlpm(aO A-3x7\>kfͺliZfkdR]V8A0wc  2ٽn7VU ,"_``;WU/r{$/^i8f.=<4T{"5l1/Q{`;"; md svh}~JZguՃ$Us6g3չNkoY ʈ6Roo/SK0%L(* 74&p5E80&b-)o:20®{*,uYb̪ nbVD-LOd Q/Y" A-wdoH=,I0D`O/fkLrH&GKc؟r(p ?$8L{423Ӳ3.FNޜ !sV<QQDo e슸.\!lʔ2QML, #O@F23|u:{Ut2k.zP)F !j6|/xol`y{2#z1v4rJo̠3alkG'ik8Y:Bg1Z'Z 2С4h >So?%ۈ_x91 ߃6Rt3%BĬ{{|8̓(~SvhxfgVvhNcB66H(fPD#gEVg*ȲI'fV^BݼLryY%{*yd@6Ⱦ|zҮ"iR&J0 g<{yĶz^&D&\Sm5#ea|{'$z9\S6ᭈ˪*^!e#vʯ.Z~ n6e:_u̲xo,3D&{FFّpB7ϪT'; εq(90yN@I)A[(+(HʿNX. g NNqA zX+j*mJ__|NU֟W&Mݕ 1X*Y$~$UD ~6:|CZ'@^@4lvM k;‹3t lalA輄ML10҇cf*(|~+f5Mv&ɽ=VH0/Yܳ:dL6Gʍ9o76_3H"""BXU2V}Q,6bqmBe{H(9LEE,oclV_+f7tE+׊paiU"TW7Ϙp7F괮XJ81$LЕgB<~+$LR+τ^y&3<[90| %܅W@peZy-(?ȕGWH]ry[ye`WHg\y-"HجAK+;, Ʒ%Vw00JF<+o 7 xy_yaaW;  Vs\y~#<{89TX_y+ϻ(. ¯<ﰐ+;G`Cí<`+;s&r7t #XyI W0gYy&3AWrZW8qWI8RlhZ.ΡZ3QY DPTݣAjߔ(vUi XPa+CB!U AU U,Ҫ&YAú`{xFIu(Qc8|,_ *t+DZVe;)OfJ.KP\?tݪ ?tQs.GKcZ70c '3LLCBC2C2c$ٳ~4r:zv\֗ve!z*'¼"Gtxl$t%q9p6=hxtҶ|ۧ ERMhOr}|~:{f# fPnRcGL mݙxE Hx̃ש jxBC'?d!8Bv$I#$ G !(Drd:R8 V$U "{ s]ʅMQWDی89n2IT0uX`䪬JMkojKUݪb!`8+eȪɍ":x ElQ6d܆v x{v 9)tR$HI"'EN9)vRsw]qэv]U&ߗޓ+IMbISÉ[7#9Fu8^Z~(?+? *?*,ǂ(N 6|h{iJY'չ z|vr[P">VjBHdĊwY!v-oe`q WrSBu\ i0{u '~TD@Bwɀr D8 P.VHS*}vjP o KTS@V|as:Qy`3Ybe^з`ʾ #NO^Iޝ7cB c+%0nn>d\H퓀'''q.vnq}7uI;72rT:B'߽L&Çf0RW$߮a_BJYxX[6^ޤwshju%,G杚poQ)HUW[5}ѹ=/Yq_h1G)֋A1_ϖ RfwDW'^]\Ѫګvuʙﺒ2qv{FBd *ň_:Wwc(g~B[%E*jl°n>2rSV֍b.߆;ïIL]*,gWeY5V)47VY!w7u(S y3mQSR`XȦK upȘny92/D-F">5[zӺ_Fd,JYݾelεg#3U XrN,tBI/tB <yR8S-tzHhHv] $ ;L,tB .tB.tB.tBI-tBI,tB /tBWt~B ,tB-tBI-tB.tB-tBI-tB-t~$Hd+~$ER ]_".Z".X"B,tB ,tuݻjW@hVNՊ;6Ѐ?B'@ee(̉̐?BGh#>@>H-n"ۯC?[j"Dtݕ'1ǧ"M$ILJ76GgiǛa䬩eVOjժ Z(}4S4a _-jr_dԨWIjGWyj)XFRe\plJ^o0%   7 Yo6]e5:!mϟb'-͟Tn)X"Zlǩ֑8Ui:DFDD6P{kWmn-#jxpR(Wh}9DbmGRmGRmMbyW}xAZF׺fѝgr=Kժ.RW*?ge!;xv irp6]>ubvs'#a~@ x/$g)FgC-g:60aц~! G0~&Iw*Bݸmxf!hoNGxS=C3AOdT$` WF:_ya2vk%^)BN.@`8X4 c4&JTaYqׇ!Gғ5QÝ9 ys(E?1)`2S?K/%>WzOvO?;ܛtG޿R=id5਱zx&: @"N F x-vV@ut f{} ]ݼp\h h֓J43Vwx(StCY=c e>ndALf9r~ ^b AA$z]B.m7\QawI!gUv7 "\N_w;\o§WY Ko:mo%]~ԻϺ5Vr17D 䢩"n I(oȝ0=ؠbxQi>a&bS0cy豸]1Xhp R/caj=B*?&nN^tyr䡛,1@7K,zÅg\x% Bt@d8T@dyXt DKTBt@N=WzcIBۯҽe yU镪NieϗѴ{C*ECu\G۳?~´8}.J'h}iM*0v,|+ooόGx1,(p"/4 LX-n0$!y f[drif[ܟ8➩$#))vb5+c}{x9`69`p{Z}݃WgK6U`a@BX&#a$e'8HOOp'ۏm9& 0bEc*>Hҫ\ζh'6c#_] V|{S?>xXφ'Y("4&0IPL#砣I0F`MBz GArs|:c P tb^~1#7bdeyX)2JWS 4}şxB@ޕ@ ʾ*LVP% 6l qD( "0W89sA{oIpˀ&XA}N 6l؀{=-}{ >Q2} vĬ 0I+w=H c~(̚0fLkhېeOX&IY&-$-IbiHx|th*:jTFdw*ogB%N.efՌȂ(#7f}9!<8uO ?y)Qd`SU7(#*r 57LkQ^E{X}acrZ0JJ: ].фX" A2#eX ׹Ѐ%`'xv  X"%{A@: X,Kh#:3E8c|62ʦ6-DK9 ˄刷fVЅ0gZrj^{{aJtu}@m9^hh2/duttnܝ<4+̤?@L˫\eHٺϏˁ[rAR/Te**,1waM]\卨W"uA8 [dO _UjŻN@וօޥX\ŚA-H$eu.r?(10IH*&dk{I$'N]lKr Z %U]w7Cywfb#Kπ<'\6 Q! J$3 ag@΀>DQz 2 4ӄq">XUNB$BV8x{St4??%*4K҂HaՙaSdKf3XH.ƚX9[rE{Ůr0q2_;rog-KV/̟K(ugX/R4y8P5,('ڛ[mn |{F07^BWSMϚ4'{3|Y?+DqnrEp{+@:X/CQ]xaZf ~qVo8t *#H1c !@"9q C9˶Vg9 P=?EU6'||dZC 7{쯫tsX`U(P5TU}~O|/K ­?E#̔<X >!>!>Iˍw@vY{€p-b{VdQNf2;Ò&}L8/_z'Ypc`$. %nPCdѝHy+ˢ^ YoIa92wgB$c WMυqNP*b&!фuSuSuS F 7E(7yTj:U@~j>^tpܳ?uuvZE4+w17Dߊ*ɵM1[as :g,@7Db% {AXBcU(KzѻՉz]@}`x͌t$ V0V3A0 >3uYGQ윭P XvM4|% >z=\30d],/t.0)gR0_C8Vt N+ Y0pEÇcy2(!d0C2LEvx\G52CXDfP?bH,U\p2 .AR||+?V,{$Gܤun;ʘ'-o%|:X sMeeFNf-3<i+ ƒ&ɺTes;H70&\#! iw^J\0qpNLؓ(;Er(;Д"O,%;hϾ3 TDTF k -/^nm8n8A۬c.7"02">;g5ii4t*U_Szܞ_;7I(:W%떊Uď%x`ҤBo=0̩kh&`N$eN$hN᛿!PHβK^|o&9f6C&ȗ?L=J[L,Ɋ97(Lȁ)Ň̾ 0C6/ͮ-C} u[d)`dFHIyQ$EIċnb`U&1W_rAd\5jq$SZW*7XIY U/bo^ܹ[|i%¶[)"7|AuB5;0&{쀍E-a_b;@"!agk`+ JKJK`9*m~XUnO,h8:\t}}DcpmM&\[m>^h Zf޼) K~o/%1'=EfPaJm+w3Dcm.!lO=;Lf%~uNe*"q7&^3oA_q>źHVHPA8=] Wq^JDBndJ]mm{2v:myFTsŏٿ ĔP  ;l;37s sLj ufjT9 f')I;1 |؎XS)G>`09|N݃6ch{v$^q] 6ӈRW)mI wpQ% { jSAzP 7cۊ6t^LkU7>.k?#/fgC;g@$AS@tT._0V+*O Ќ5۝I*=:Vfrvׅ,=[-JVL? B0] 8nhUDTQ3x*ϗNkO +W;l.˜yYf;F Mw 22a_@?P!`#y;|w翕oW6#w2Lcn.6Lr7'+ :r#"weTHwֶd[1^bQr&{], &o!*[Ab"nLveB%x1UJqވLf|պ?|pIdn͡ ds7ro300vaoCp+nו #3V T[0#vGYvwUO[%AΊi?}3ee"vRi/*p3&gwI'gly)pc3O< ?$̓3O< =$'I<c;9$i!L ?&3zŭHDfI3H9 3a'$6%Ėd&$2 rdE NF`ՖQu]F^)Ѱ@aCGPG.6PqYaHIuᐧHLi EVUߵFáwvv2<,|`#(~ n2'LߐHPTKi/̗ GؤzIUdԨ$w!UInʠ}bշpV`ŲFW, yE#T y '}@mDp tE<O'PX k]FUqci8#6+-@$# A?J-kTM=蕮.UUċ4D4G4т=60#Ɏh$<܈F#=sw@#>izޙ^v/w5-3t#:VwDS lr$O`И AN|]".nt+'A+'1+'A+D0۬~7nkoDo5[uU~̴. =IT9 |ea2ǂg*kºwzKۜIVqV\dUFh1yzr&b% ۑ*G@! ٞ|%\烐&1wM555Iks$I]&1wM$ܵ=zv},$[n{@8{ qVxZ x6(DWYgG4 = s 69=, ,I,ج=lubdHơ6xX={Q.m aX PﳂnovV?D}?$ѫe&Vv.C_E#􏘁 V]w֗59҇`{?OEhG}scg^‘w=WB˗_>}&T۰O V򹪓G<}('%x#d܏.#]`+#9⁉9`>dfh&61@$8{`2Em#h1l3MƏ/⦀=+Ixց1u#ng%JBu?N` #W2"V|# |ȱ|U(z>7sb3B `e^B{KZNPeFHCu8T* s qou3'?~w#^B1pm7H$ pa܄~1#3!PMwcTe^|y .8qЮńn]f@VԳ8q:x݋‡V h"6y <*|&f/aBp;/(z9I.'" |lI.IrDk]l\$"$͡Kr/d \x2z]dkPF05x( I&ESP$s*E"/Va@Bt^y!rһGVzo?pᛔޛvg=pFBهIz7D`8#pv L g$5ɛͳ&/:_cxxZ_~!2\: v32xۦEwl3:sw+ehbTYğ/Aa#;mby擎~]#\s45y0 ^;6=qq>!xǼLrnD(z#f7_g_"޾Ekf`;VEK>T? u\ R='gg僬tH/Ճ}\9bR`2ʍxu@aL$ I+Ev/Ng*)OEyi+u߽۟mx .vV\:%PΉ(*7Pd^.@+;ÎZװK*&W/ǎ AH`!BB#H?g/5P8K"# $1B# OYO<@UV||pNZ`Ҫh8Yl#'+IMAu$vyBgiz^#_V-WÏ`yJ>saB $x`xn7U()?xwh2x'j#4t+  & G(o$b6o7a͛;ǟR'Gڨ<,|U,DNUjP7Ejo([R;zNhֻ҆?,Cu@)@O:жV`'ce`P, bHyuB.W`o~|l!rsgqAfy1ȼI}f{.t/ 6KK?? 6]$]Ѐ!+;;pf7_o(` 3_/a71H78|-ਿN>~`QE.:/dI<użIU 9?Bx(z@ٻcr,ve3ܲU9KO-\+mSy^%.ush} OOY-4Zfݮw]١r?QW2w@=0p"۬U Tp9+*rYNtHm\p,5kTU:VN*]Mٓ3LTxޞw]3PWX'>Ίl,G굷у2{:[F@8L36*_d CW s xs w| 3^)R 8禮Ճx+3A8ukR;M#W~*֤^郲%"Ke;,ِ&U,_!=.M=n6`oDx7EaMq}v\=kEin|λtT{lE &X"jXkf&*(B&u _"-G*nrM]0s 'MRF$Hx ĖGRKp$GbKp$GKp$GrKp_w#F` .X Z PA -\>2Kp$GKp$GbKpt%8X#%x%:3Eh Kp$X#ɭ "Wo[^e'RˣK1W߲_*uD!c ݡ .XHFK%R%,3V;s"*]WМG Y&Go5t@{V/rEI|i{]%V5;C #]ɱ)ɱc+I8$q1:`qƗ^$s;LD_t*$ {zeQ_,T/Ze9MnAq4rXAaÉL03jzY'NLqsnT|XXi-ߖ )$I!YA`LpLrdr4$H8d;=NCE8p줭E|G0 @ޛSfV3R_A9nKmFhc(g,H39]r <rlFh08y-b$"ZOBC" $2$tqrC" I #@dH$g‰$4$ĐHCb|BM@sF.D/giAXRe} *T"REO?9_rl#Rx]` Mz1M>{A_2php!y((aԍ˗$o({8//&WIU !zrZsNњBe|K3r>Z>A;1=Fv|'is'v:_k]p~?/\6T"ŏfȶ7-sIcA .a_s1&H%X#Ml@t1m/<|{ *pŽ^:aAK4%<p1pK<%2, (XuXi b ATʪ4鐫zGxwň:ߕղ/J#WaF$KmF gɊиTz9YZ4ʖ #K{I$oA] H`ɈWzrKD=/t_+2b`"J=܏39>FNl.Èp7 CM^eSV[겂ѩ#g$1=#ᧁĦg$9=#IMHjzF"ӳYNxzF3C$gE !<=# LH`zFپ59FzzFRS'gC+i\ ':ZcR9oLS]s csD{ ɥ[;>z(7 pD,e>x'9oK\O|# P.#K[?U|@,Gp!rȏ!&l$p.0L 0 3I $& m)&2L x@0aÄ˹I/QcǍx~|>~Gܭ~`j]$JA"=Z'ehf:f6]@Ps0N`r "tHZWClg'O6^"  /JVڌRY6ftZ[i9q@NhLGUCOGQL],<4;Ȭ,/IMJuz}Q.W0 ?&0̀U@BP8挄XmƁȴ 3OLä$5-%iS;)ho ;S6ZEc=WʿbtzcIBRugmQLjtg 3IQ W]Q(Fmؽz p-L2CHVw蛏~s[nU0og f`N"ͣ.HP)EUY&YLJW7W3)xefʯ2_W޹6HrZ_>IswtUJa\+Y>v( x,U3P t=^&ɽ:|};KʿH?m/?7SR!)f 흗,XLUɱEi|>xlpRevm4gޖbu(+j7&= 6f>Tw﶑ݪ\QI@[ Dfi~EμzE$HlKt QDJ :VSYUNޤ7M:MzN$&2I'Ko қt&"IM:]zNޤ7IQ$N̑l$#%H8gFB>[[vb"xV%6>vpq/`lݏ.Ѩl @8yz^аMd$[1Pv써FF QCl}"D?$`^I+L')|bxz }"IH$9h^+&]os_I{wPM`lʴ ջ ]`D./+$i6 m2tC.@䦐_ŠХ 1p3&H?/HxXl l@F==0vTCޤV^GI2PgeEQ?5dNHIXIJILpΣ74Y'ߺL=9Cy'%`"qFI%()\o`ouak6Š O6M):s˼Y@$겨W!C˼u%Rl=?pX1eQPC$QAr~ xj.JUmUż1 .q?̨,ݓ۽?wI2 * ĥȇel:OnZg;G8{W!f*:͖Y}[&X~r&ACܿ~-uk~rkuy쏥ޝ&fi} <ܯZ &9߶9}Oa*_ߴ=wΕM^]vS0vڰ=]~/\7뫰޻$LW!*q)mr Mv1Au}VD)_:j~hh h+T^yv+R;E_eJ[2˧B:/xp9'^A䮛`sb 7̇̇'Z ɘIɘ O | w W j;Z$Z6 HJnF#],˪+}J;ql Yތd`CjfD3)w| qhp/-HRx4^7S)+z:'/X~]3Pz!eY7`㹿 ɢ,d@eVx& &&1;ly9"o-m$_б *}pڢV2 N]|Ӊ[d`@IM5B,W/4?_tqLs ?2'9ErSx“$$7M{\)颬ܠ#8)b@ @mWeeMK`@!& )&d&&H8! XSdl=}/]{d WHnv p IhDD@&ڪ oZl*ձLKx*҅S ]`2e{ҙYؔH󷟧b&JbaIIbl[Vw9,H4{kyPnT^$yC&j` )NV@O3<˅ɑ{U0׶{&<L&aX~+$Y'7+0󓕷&LU.4;0$MBM9IYJėL0֢QcL"kaf4qA/Œוa"e0|KeSWjUs\nIe 篤ϛ']]s4 #x9I`ɗ#iʑDH$VDbH$_D(G#ʑHtr$+G"r$+G"r$.G"r$,G"r$)G"r$,G"r$,G"r$-G"r$:Y9I#P9 #d9#iʑDHtr$:A9ɗ#P9#x9#P9ɕ#X9ɕ#ɢ$+H+HNPߒÈW>ѩ+dO!a '|"ʧȡ PDV>`NQDbO$XDO$XDO$YD•O$[DO>R*HNQDO$^4lj@<Ɖ"F E܄ _Y/ѯu >:vyuuy1l=ϗWɍwI6;ܖʳ45M*7?eu.B$F $:` / f&2 9OA2<š#}]%]ݦ`"ξ_R&ƞVk#>ó%w yA+; `ȡq-m&mC #mIے Ǒ$miEW jeNgd(/+DU"9$A , QB*Hb*H*KbN$,̏`^#yHB1 ֍0&1B+IcfXגY &1ڋBo450ux(- ݎ rVJFKjw"1(Po# 4DjתH ERxO1f*sĐLq~N̒@Zu C3o`H2zdWpQ@ 58k0U O0$ oHhjBSYhjBSd8=$^=&$45! LM";0$ IMMHljB2Si&t f`H/35&Mշ|l|#lNܤ*>꡼w@6>u+dtRW*/{=.ӺRb %,E=?E7" [4X4Yci{mVuguH_UYC6-etvϷ>'?z3,񚻽nx|7:}n>5Vm06]g_܃=Egr.tT;UAجR=RW*LT#k{|2ßQBcϡ&#ه} P`{!{'>K7tclwyVzBNOgw8ޣ7@4]'z8' 98{^ օ\wHoG0&>iCe,yd_~-_Ǽ_v/;N5f#ȝާ26^A渌6!<4xVh\61daGHņW ղ٦V멓 r lڈEUEֹq $A&YTZPHHHH0' u1PYE֗BpHŠWv@J%?Kd*89&Bupx?BQmH+#{5%2 @} $|TEA&gݑ"D!nxΒ*[ҭx$hG]$N\G x&4Ӝgm&bc4M#z iO%4!! :,"ngDټxhbcW9;Zo R$@-%38nC$sgw8 m&^6Ek^\@Ƅ@`]L{Lo_Md;ϊ ʦs$- p,/dOcX 0H* $`PA2 0‰KB& |A# 0%6o䎖-9Bۍu- K%T}ky*W2ݐ½c Yw:Ur^X^RthNx""]֮fWVrT"i7tV2ݶI*+{=t]uyok٬9gVwwvrN%?af$BSAo>O mt{yj$b7BG~kd.Gk7u=p;k?g|)췲U.Z qCݻ_` pB]:!BN@xA?ۃ"}dy *UU$HWWE86":.: <.?m0>:^Bv .d+e4jW poVYPYloI|QإU0`2K]}gaen))Wβm"/e.D8߉>pq3sgWumwj(ZZZZZZZZZ{lpsuv9WwRn91l.ߖ*=W*U&B*(}ܻQ8Nl|9|Bta\\L{-LHnLjth"Bp7u7t7s7sus6*x<$X@# `fD0  aq%^)rNlA+` إ4=h\b}+'FXU߽I:||J)td%<Ձc1V@`+ `ѠLë|oF>|҃.Qj޽Gs`f<!Zz'< {YvC5HjϠC.D8F`p|(8^NJ*M j\a[x.$ 8`Np4_bYrop<7bMLU( BO%p@AO_}D!*ͷ( ZP۲K:4+›+W O-c"`ɪF~:\"-8NFƆ)mn]c7w֡Ev~ c1ӓN[zA8Zwl凷28{yuTq=ś=O$\Kbc'X6~)==x+Ї 8H*v 4OɃk"O+ee=ep\)-},uu_"=ꅝO<8N&_&s:eG tVN|I/Wx,_ɂ/:IEWdۍHԷ  CpĻ4%Τm*OJW:A)Nү5MpfxqkcV,! 2?a[ \ ,hb fu <5^ 46E99Y{02@F9 4:Ap&G $X~b %TD)٢ K@iD JU)1$#?@1?ZH`pu PdU(Mh@GXه2'hdZ6D3-h` `1D3U1G Y@▙Z5DD:IKL*0S=,LB[w$\9.`32*ѺN7:rxz"WD \SʩɆT/)Lt`(?ҹ6r9Uu=p\N+19< E T55DdNB!jI?u u u OY^4T7_$xqyF۳wo':Gu;iH-ܛ챉^NMMaI% A.Ue C!7ӳkA^4->|; ?^&+!vEhWL8WJϲIFXp.$@FH^uSVtW L}q8K0W꥽&G*}/Vv@Sn@!&p;Qp>ˀ9%:%;%;%B;%;%pJuJShx}^098|^> SOŏν?ͼ2r8!!! 5i֞ir^걓t^,T)7iOWo|BP^Z,aBl*>V~BJ0v/f&GE:6} _7Pcp8A*Me`H @H %(ۏ޹QVA?L{*߇Q_0KEg= #ywG)78F;HxpRlOMoxbx]Ue-N'}x*O N?TUd~>ç4"2O wI=7v{&I,dh~{zbu@n(Uʻn/g$lp+;Cv&D.{$r@,3:s!dە]p.zNNN"ȅ{$$ ,GNJewψHR}^5K]}|SDo\x?&]]̺@DM~y]/U/IgQkqlnC m"ak;2HHm6uo0"trC9SNe4-p>fUZ݌`qz:KAMbU[vH3JZe &,bbN8/FX/Fx/F8/FH/F8/FP/^dbbcJ롸` *:#E6W_A5FDq +g66k0@.|Yfѥ2MbDGq?FSh[pa_fr{vg{0_N3V8/P~op<-t"ybֳgE=@^(t UyEcTIuKVBOy&"^^4$m6w%7%@D'da0GH#Hvkv oH#1׽+g EN*cꟊK)}?u(=YU*Yd1ws+^HSa)LwR>]vFNzS.=޺8?x}y6"mosRjP<(Hק1[g8~&,U0~E0d"n @hѻ]E]N8B)F8-2sSvhL;0:1уRh\Q~CrLm\!%#fg0$ qR<8=x(q[5c [,*6_"^B7#. GPV2^^fXO# 7n RJ^8[#M7SwRZ~GQvY̌̎XFD{eWs{=f kڋfdɊxЉVUYpRd0[C7 `%"<1+ B?&A 0 t,@XbH& p,@XDb$ D,@Xcyb:MODZD| \SgFyn1UP$6F8 kՕ,1a-bMBDԞsowlAmOx+ɫ}| ^"*:djldfK6 BZ06<uLN{~+Iw4|`ha/1@5v6v5v6v5v6XZ]5uS`gM>pq-~L9h۲??%vѱ4OGzkLR]*.'[EܟD5ܙ; It%CGr\C|ȀI*`e02 &dgy^5ɴ:{)$- ̜*x,Ueb fq$QF11ӷ,P.t{@IX(MUë*.FScAY1ܹ#za3MͣKNY6[Uk{I<9a/e}k&blMAG ש5=蕙g8WwSx8;PSx^f\YMWe*wޕ8#< ;໐G".8ݥI?E(KE(/BE\(`DlR$E,R EQָYƃ[*$w- n$ْgK{- $ڒĜ9C InVjŌVfLjifUY?W5Bl' -v1nZ3NF[a/T\_2/SNWȰrhuuqc?l&j4yEl5{]_LW\ԻƔ3Ĭʂm w_/vŰJ?g rSܛX. ){A5a}.wc]/Jƚr+ok/f2֊o iTPYWr; t. nڄS5XrȞvIm̌ZUuzꩦ nP-~W˰9C` 7CpoV&@9+zR|:7^[\ֱ篶`VnhWB.:.R#t^)+gUfKpaR%m?\mwqQHx/e"^&Db{${Hh/`Q2^&DB{H|/ e"L$^ DB{%[Hx/e"ѽL$2^&DB{Hh/ e"LL8 v/e"L$2^&J2^&DL$ȣH`G*zPGU)zPG'zPqGU&z أH@D _E^E^&b = zQ-FHpπb )><sbA9k2^7 x/e"]F> Fe"^&DL$2i2^&:^&fDHd/e"L$d2 2^&DнLCw2lBLtL${Hl/!2N#o"^&ej7Jh[/i¶oceMŢ  w'.)ySY[֜}T&82?un$ Bf2_Dqx,gND܊Nu"zz9n,qpHAFH,N5i4:ɀFh$;F`@S h$?4va{C[+=<4s9d!{< )BM=Έ$sgl´NwbA{c6):NЩFv mϺ|zn H=Vd`f`Ghлy''8{ ;9C  "P{DgjK⁝eęVߟdWY%J\)GXNg! {/oGR~`+yG/{gޣq| 2^:°B H=ea'[ϓdo#=پ:$4%|43% '!PΛD]\w~5gˉ<eyfzF" 2;ܐ.~s$jyHgq|t-UNpWsL_ejvۍHy=w0k˶\l嬜Z4ɜHtu?$E -=`z*%}HPJeO-ɺm%mdIa˶'LDot/iEr^lAI(Ay"^}HA!F 5RPŒd#)(HAF 4RPȑ#=nlʖ  qT+{oޤ`-)*Nm; UJo_kgBx'y1-Ǜ?*j9n,&@꣍{FkyŁ1p1D5qb_dV]_pd\?Yc FGdexk|˜ro֘lطcp Y [8'׾9 V|7p VDIi]LC~ss͝K wyN1[٤չI,7Or:{&/7I zc _A O!wJ/(IA \Hjjmr0)~<#E/YYn + yEdFwe|%J,Q Fy?C*5J(`V/yaO}1Z"<'!zܐ? D!a)kpS  P١0 Pg8;١wv(C Pg8; C;;١ΎSXot1u)OBDUF0=0lD\Ju !4}eT^0",ii}XT7[K(Β2w X-̔]b&-K<4̯&Q74A;1qvp Ea\ P<塠.vy(C\ P0ǟF]BPnWecʗ.ǕEa틄feG(f;PcPZg8m{S12}UBs*x#2Ջ%̜)LB/PƼYEy@%fȸ/Ԫo9!MT2zKvne*H9r.޿f6GA{azI!Ԑ6\9d{7E תgqR7)Anyf\U_/Gi?Hj%rmyR.7߄HqY= +&XKu;ÓHE]6PEpzXbh%Q5eQ 2LYx_JBrt]eMIzP/$"c"'xjbu e p3E&ݼIK~/2Ѓ(Mv3l(mA/}y9m)4>($k6gmEҹ>d,,%HD-)_V~ߠPCWdkm(_rO_Rǽh#.L^"T_GTD27a`}Ŝ'", iXvd]^_K7:VTUE2dg盙 4fޮ\JN'(;HG@cŜ­|Ŝ+`Ŝ+^v&O5eɿW}Rfm 3*H=/ MGfvvj;- ΣX6"wx rXdo2zVW'7#))8ճlʠJDHc@**!**{!@xB$3)-r"NFqgъQۻ85Uz K_T4W# X-3jC$c֝LmI9p/o,#`r"~([FmoJM`D{,FqX1:WfJ[db ".ugU]^6Q{i:wkv þ=A=þĉ[쨂ѻO@]A6Q\ <8AHAXAHAHNy~VC2u!ȝh_9>dZS\N,S~dzdL7G]2fnjS;M=PC{+CQ}tN_ac Vlfzi#V}\_n U<*%>)5䔖fQm(Q%l^YA!^>ua ~Хd%r,uF9q@%$sn۬2PK.1>%^^o} 0[c&XlK?=@ؓt%P;wɟQ2@B a$$A!<u$NPH̑-SHH80ъ'Eb!h$<V}\GFb!\$p !t$Eb!|$K!\$FbYH !#1BEb<{(zғP\!uW}6?kbJͷ-=<ƀ#3j|n  2cm̔IBG_EP*7\k4XA1nX5ob2\AY' z#`r"Y@Rs79Ǖ?v2z45t433 CY8|0#`*@g<'s8q89C(E.(E./ ConȨ 灌Х_\7~0{tvu0S~A$vϩ4k{^ܪ3q%d#Xi3sBU=ba l}1=2X{8qol[a2)*z1:9AK A3/ƮWwN$g2eb`Bae /S oy<f$eoșO/ڥ%CNaeBCqC~yX˄ /_eiI完uڽ[6@V ,Aáwȹv~QggмVGV2zFQ˨2<ȅ'b2<ޅ0J3kn0:T́ ,s hGюTC}o4G;BvCLF]<^uhGγGyM|9&auqwݶ=jZdq(@9Qrnzݿl%}^ӳYL6L3z!S1ydPƪ_^::{x 9:`= = =ӄʛ$Y Y~y0愘<^+?q3}2P}f#c:խǧHJѻ]>BVQ*LPHp>u>1]8JR}g%`ɡY`>疱uIsX+2 c N~/Lg (3tهS 1w|  caX\_p#<2R 9#|ڎ|'SO` lŗW'i-[+&}"yI}2ڦѩ y9ϫ ,KB X!x̙63Os*͗uTFd[G5!>EۿW!k3ú)_pnjU!Q*r9jօ2X3Bu=Fˣ=BbpʆQJarRcŐeSʨmpLVm|'p'`'d'|}{9c>A[B-!58vEcn'O B&eF1&&R)~ĕe,>=l13jiohyE&  |a=kegj|8cy    =aAhW@ߪTa0I?85DR{h'k_?JZ F Zmmm!m!m!m!m!mm@P*pnְ" YގK(C7E\F (\нXnB TSsi:#+&]4؟x0ụq$rPr|tBt*JӃ |tHcX? 6vx%뷄?4'6Ǒ4E Zj V`CE_vHpeT|v(j6L #s 'N՛% POY8D1vRŹ( j( fӒ'Pfbg1s̝1>ɞ:~UA)8lRYq~sbdJQM#̨sFJ:1l2_Obaő>tA!Hhц6s- P&Hq ؀<EUr(s)=1ӼS"fgB 3kK?pt:r' GO8zIekX1/Ld \_k$CΝ̈́U>1࣊? @[GwzMɑ) QĴ)2)BrKr4_,xbv:(n7լGGx33R(Lˢ -˻[ײʾV:sdceE yE_FٔA?C.idȌeN2)'*TΉia|MMM潭/h.m"NVeY-EM&`i+ƨJj#ªE*ʲH@Eܰʨ\]3˪V|j34*ĨfWԱucZ_ƪDy.P={cy?+D]7Kgg/=;P`f3IF(֦fEӕ?8|IKtk>a@A7L$OGb)?m[gs7F7,V&jl #i^ߕ|;MM6s k& d& f& a& h&ǽIU<8rmySmXgQ.n؜lY}J0+0ŚB"NvQ'Y7|A~ݼA(ۊG|uy :F"3Ԍ:06+`4ϰ΢ oo l=W)p!~S(_ hՃ9 8H ]jb^g(v|zElXڕ˼pY[N|.Io *렴іubPmmj(/$+dX% Yl-3u,*wx3=j(rpoIhy+}4,Rwk GuX[ҧYhϲS˂#9~>^y6O(E, g'Y ~ѵPbP? $AY, gѧY*$.~~WJJc};ڗx+(.j3ߊEb,u 95سJR6 8.l⣦1al   `'k'I4NNP;[e%;ʿ: xlpŤLjҏFXgmʏg #HtaNw@ֻ뢶>nGr}~bԱ{BHQ/ӟ2ygP)M^J!:b<`sfq=ip u&u&u0֙BY灵8FyuX*cYgBZgZgBZgOFWVv"AGFaLm+3WI (vIv./%놬≠ߢ"m=sb(@spFW_fˋrG[ @ FW8Lֶ c{sGt mg0(D6H[) PO`@D$@F [y;CCF>o3wN 󅐬Ug̘]v\O||͙(W2= Ł=a F ^C4vPgc V6}9R6oe Wz#2%K*,IE2O3q B;ý"/|W@/P~;}(Kg >H<5bY|Q5wˈd 2N[vDtHdCҌk$m i! ;" Pks2MƗNqF7 3<~ԡ0o>PQ:fԡ0u(ĨCG{:n*;*by5fh p3*P|L@ MmB%ě k] ōrSSB2PBt|_w%LѼ+0h])B'oc ooya>npG"t m`ϰ65g7+|ϐ"vzg@@dxG3p/=w.'ȝ͈'K]kFN?`f͈f֌t=0 @X#Ɗ4t5Y1Rݫ7 ߙB -xp`%cǶq4F$V ^(6=[dv@Z"=R1Je͑@vCCE 6oY9nunHާ>y&ezq ,(IۥIWzď@S? 0(p"߁s _#uMغ&h]{>xa+H޾v^}ho{rGNA޾vVyd]:kK4Jr͋w3ᜱo*-oxU~_l+D ꣽJ(~_ʼ+B: R%z*g@Hb) 2&š@ mm~7 kS.4mo%)_&ـie5^x##B5E )\SMseM6\s 7v>9v/'S:GW"NvQ)DeFi~2 n=م+ nE=EX+˼{xmfcM@N v°ɟ.x SUTĚc|~ڰkǢu7(1~=g3#0xwßp\hwBݠp\h ݠs7(Aݍk'p {^~@gwE{Hk~ \Qyr װTC^u+Q| 86HM2mC}RAɀy]m'n/jgW3e^YQ*є24kX% R7 DW PߒlpODnIL*myRKA\@RK.z1<ʯm\]ܟ&76$~O%Re0y[( *߱#Һ&#(+DTl ^}c@ .1LM>^2hWB0KU@_k!][T-T`%Z#/'; g|fxOD5O=|D-RY'y{d,=J^Zd =TWx@M^sت _VC!b\.-DpW l*^wSGU0 _@s;oy ]vJ 2۠ʇY-.-;89u, gp~&&!JX8HkD+^`N=ۏi;('|ܞq6mq#"nOظ={`!8F30&L5> Wr?z^ӻw([J`.wzOhFAֺ7yEFR @V4o4RGϵ< !F 5B-f߀*FoG)y+{*0U)f)k ~P6Ia$mM1P*Qל wO9(/9~0e iv*Ջt r+!63VluUV(qp 5Xyi}5x#RY cEC,Ϛ1j!$!dPLA3i9S|X|OMyU*q(k4/J: fŏT=L<JpQVegL>wIgLWK+woOA=މ''c44p (BFD+l^4y9?Ƣ|')6  ,Aÿ(]It 8&8LH .3 LK "64~@ fp)9  0i򢜽E<|p">js1 B[5iɤlurP@11 2 z0 #GY9ͺiDq|Ux(#OD V/ux]h ΙoB(D݃݃݃t ==py!Polrot `% 7$!t,Z/Y.p'c AAWЫ$Gp0%0k-Y+AU)\oEyȏ':; ʞT=MAUIN#Z0ZzU@+#H+#d+#@++ET\iדt>Zq-.yx|ruq׍;FE*-US@sDb1jҳ7U;d,4!ٱ׌5#Awm6z‡V>LQl^߉jՠ26֕^ ?91`8񋈿?(D8VJ!vV~fo"JBOyoG?`@_PnIG%_/_béݧ(8ɶ]u2a)gǏRڶČ7s0ap%N"e}^'^4:DćM!)3sl0UkM3?7iyt+w`֏&yRߗ|ɓXy6n}г:ő5fD;~ z~e%D+| < o-DWbKaFϤ ^?D.IqH[ٱp&*JS9-ӊ䠈\\V~d0d3-}'|nmᙛ`<.k!kR%jxGS9fY;18?J".*GK2WA'uOɟӄؐ6p~!]B6hn[]bg٣ /¾Z]ϻ89nEcejLRR9ҫ,GNv6U,^:V9Y-k ;#k7ʳ'۫*#*Ц[=?^J؊jDIU=ۨ MGʤ|̫})jWN` T ?M!ENq^pN6`y!ʹNZcџ LR¨Vʿq~?IG<;F UswtRkKdd+(YEr /6&"5`x+.ӟ"@0G!Fo`$۲/Q {g@(MGG&`,DgҧM9ȨxQ3|K|${Kq! ew>?,\2x)wiGY].0U*KQz,h%ea`[=n n=V߃QjLovUxϐ~Bcd7?fe/:2$Ğ,t3BٸWc %jOaHSKJ t0ClTDENn:=oD&$_#rˋ4N(u*4*,%Pk'dkZq|R?{W]!+z,Ҡm2ozMFutiW3Ifu6!>{r=WˡG.4.ֳӬŭF΅tMU7&~ioږLz|EyLELW %( 98%ݺJsR9\[W/<y`EP݃}=C9T+vDPB1Fp@XbL>?I "pbP|ZDPQ@YdxfQed[WRC: ߯YYɸ=מ#;w7Svg$E4czٹL陼uw S!4$li֋R-l)xFZw-+>D[H\3oCA, A)9˛7P !)澟lBgA=9S+'#p6)/sUdsk}b#md{+ҩ2־W#kͭ\`:]ؘfCNo}HmPI:tC9~?KQ&F'yx |Vk)QꋺQA_MYG#[$!bzןțXWWG^dk[M*1;sy{u뼨s| ָobwaxjy6'lWeU|V3ek=e k7Q9J%|yI"͏>b^őd[-ǽ==OĘiToP"M=?A)JVfyRT|(ri39RkuNob@Y @^Ŵ]PTaQ3ͪoat@ߞbBqf,ot.(nsc%ԣ`ğjIƥKa)vL DP{0(5`v&m: Sek[uP5..}3=8?  +gT{,]n>4GWr^,Vn /u&aޯ{fZ@R5:tp"VR^}4% 6IS:|8IV%ʿDDk{k߮SQ0 \_׿89a@cι$8이Z7)}C+xYQ?}_J*颌=9S^f?ٛBpœuN&yH[H󷕄5_*Y`X_pb `t}?3i;hO=U\Ů<5a1  ᔯ3j/߆ @E:I~+"?<%}Ol#+uXiu?~ ^{:4ek9ޔ2Q<Ւ"՘6O/'o%]~"?AՄJWYRaOEpqL֦]{LS¡|_Bd^^$է7x͹ݷA1U1#Đ^q~gGwNxeNn\X庂NOAZRoO꿳.^e1Z1_]h~6D}">KAykՈr yS/MȞ>g_M^틧,`G3~"ȔF{7M,.2&$5Aa{gj??\cb'f3' qmblÈtyQ&Y++<3/sͧwL9VB<]܌sJ=mla5B*rkG]!+7D1J xtƦ0nfלAtfx);b8vO0N𦒥H|~KD\=uyR+i0GNXukC; #Mi%k {xWj3E(_`"Лxi輪#L-Ъ-gzlɱGSc39U}/N xoh:?:BU/boKI]uKwOgh5V: [y=emG)Dn[_YV9/,9|}:=.Ѿ ja[Y%䴙1F^I}voB'6RqO5G=l@[Qމmo8|GTQԐ4U# tXvk7|.uw#!f)aT~bT09u\$v{{qyg *ρlaՑeGv)8w YG~0]0s+lL^nw&^/ֿM=Ǔ.~wX~1@猁Z sO4W>$&Ezuݝ`L%ڃyd;5tap>ϫof/ Hj-†|50A$/ d(/69DGv{GmHE[C%F19$ !O<RzCԱ$l})(j3A 6 e&ޱT ZXR7~k_sx:k@Ns}y`@Gvۗ (\ ˁYb+֣ɺJK7H1J&TJ6VodM!D&}xǼ 2:<fL6ʷ uqv@2)sCyU㸁`!0XfeELJvr"Mhb5R4OyRP XgÉ$ 3-h '^s~+ȫ .Sq9Cf}e!P>0{%a:T |$*9? WFIk}:Pp`=`bN^A㜶vQQ>]m$a>OЮ`Nq~%\]K.5wWs3svEn<(r|`P l apﵾ7 R]rZvO¾jLN]qA`+a7(}֗ENܺZoDꫣMĕ4W+_>ֿ>^U&4&*&CF9q'~@Nifsw|?ؚSgFwӉ"[?QFr]g)w)^_U#[/6ӵw8AϪ( Af&? ҽkAa4{Q)Ag}ur[sA.b+ kaJ :(3n!X F}+s-2U5i$j_Y^X1J䴀sh|25FKtQ VR Bͮ:m*˦̊W? nO$N-kRk d_\۷25#s>@NT_7]V63U{_$]Cy޼vgqo\fP Ӕa\|VH9~:9T'j:r6SRZogjqI)ZX$5@VaQFؗ۬L,K%^e<*ЧcAt"O*Up|3ZCt:QB[Y 8>Je)O`3cV{Cy},q1aDkeވ_=RVUSwVnAD-1c۫ݻ[y:p`q|:sS5XlQN˶$ P}ᔙΐmpxǎ0%=zZV: v妈ONW*?xoo@x&)vᄔUH_1l?238FꂂP&_ֳ_§B ٝ` M1x>%7(jw% H3L- %Obk<%{Hbsto:Maf oݰw6߮[w8̥-Paf.JY_%"~G=b4sKjEX݁Dw҄D2y̺u49^+c0e3=ZVE5cyb k&d! fggB+="uj)ef.+N!m83y_jS B<+3#P:Vy7?±:2q[vQ,ʹb [ai1)+9>lȭj丑ܶmձl="YDﰷJ;UNO)h]BT7Jw; M-rfu'Ǯ;̣bMuq|Q\ܽ6@jZ "g@V~S`5ϋ:%6&r+}턖rG]"m&yR_xci @kn]A֩v@1J@#->T4 >仿8"EkA]|'ctbJuY]VWE@i:T6VW8haвiTnOJM\^Ya6w&~IFVEX (II]v8ߍLvc1b Jsdۃ82׈V3IY)+eqɈ,Z yp:9m l6"o,dF_Ϛ8Z0C1^ݠObh.^u}܅s5g]1X9`dAGt^,qbEׇN5ojMkXh!7 cBC`2 @U/HV8#o) O{z;w ۔LJ1`X0=3lm>ÁtUl%+RxWI +.ED]GYn-ÑDEFeQ,N3tAΥጠ\ %Tݘ?@쳾/p;C>8De^CTgdn?S`&/7=TԸ a<Ncp2uT!bMCp,Eοn5 (sj0T:o7HB%Q3A#;~<Ʉ}#RCր{%yaWq6 P%3de~jWOWnWI T!XU[n@HI廼TZO9U0QÐVs;5ٛYcWI y˒WkgCWǍ7\ cyU[R1Ad]MI*q9WN}EE:i9qO̳:H@s쒟(T&Q0.$";mvX'ty Q[x!&SF*ER b$cy#$^FG|`._" 瞔Zd_) ۺ}qLn8߬@H8Ax ס#C?K30r2w;0 FuX^(&szµ$ ucSms!;cl>.#aF3 ~/?80Ï|QX(3ڡ \^nڡt>H h7|>T `lc y'_A+hXY VM _ ޱIvJj=uzdUz~SaQ̳MUIM7}ȃ:4sJL4gH ~~>qSL37lMfU>CO΍]m.2] $mC0)zI3m~'* 4з1 kb6ߣ`T&~\oXE2jy^<8 pn[#R̊Zʘoߒ5&jy; 9իA>328`]Ct%+.D 9ng6)1kƫ>`M|# _8e7?vFytgu8lOe94F)xӡSqh?֡ Fpfj):=͟IP' Y5[E.X޲R!724{WӀ ՎM4F FQZֆ(mUo4rAfxj^}oΣ@kaetכ(]dV& wGi2}!k7I*>sJX_3~6VM_{%*cMdJSrlOZ$OEO(5z36n$'#2g/1V:P`f.13!a < GNz55;A^8De70Q;afF (LTl/I֧t}Kʗyz&Y&Yϖ飞[wS fvQcC,>E0E:Sljedd5n}2צj^dܛΤ(ˎaHv^;uqzqYYھY_Yźy]gX`hۈCZms,i{ 4K䂚s}Ps} heT6tM7 6i*w6l_ڞ&K|ixt8e<|Šg811ׇ|U}W>F~]ϩ_ois(,YyVDE'cTɇW4G]t>%ʶ"۵}^,xS|ax!:)lQzw0eIev+-y`,7Y$LQR, b d4BL41 2uv??=R/PUq^aLf^YlKGb!;' piz7Ӑ ^] N_267ɯP@_HIjVvfALЉ{е=.Lcp cI0ySޫMiZMĭzSL-!bm.Yʩ=}a sy> uxrݦ,auFMutYӁ{:2BWJ϶cU>@1%T<c;]HyfmQV!潅gz嚕N(4kOBq*w)([W/1CŠ'!sL[</փ<6=_s~+>}y&?ACm:)C-"3J灜MJ3ڗ 8gf%{5q<„ߩ Bƃy/t6b4"?MAsS4dF]z9`?v V_ښ[uD3} BLKciDcOlP 2 w!VA,iVEE./.]]9ݢRwublOA&>ފ;Kd'Ks>sXsLsbmsgA-d$Ͷ^Np;M!G|nwvoo"`SdkRTJ||| +ΜoWbdrv?ID l=#r RuNHaT/l @p`I4ȊjW3񈏌H}`ï?>r2"Ry1~Y '*i}Uiy=+`o;ն+![رf'jQ(vk~\${w& ];]yJ蛟5SY#mYH7 -e>մ] St=GO F5oéA'g5ddks,I[QηUf+83~y1Y@_J]:L[FGJhzP8!ӭ뫄ԙ'k$k.^$_މO"[VA k-gege ey@XAy>D-~Vy* :#ý؆]gq2NXPU?0&~%[A=֏҇,w̳?p 0Q߀9}\U aUlw;I*&K,>)ڎoUΊoׂ`bq.LM^\Y& }> Q62OTI"ƀ<)BT2/4!GB_i(Vqq K3*Tnh>R'n+a[g6c8Pighp2TnAcb7p͙IR9fU:[~uv;XPX28mVx(SoE?;ufcxUAi`/?k>C~PK5CDTqAx?Ǿmetrics_data.xmlUTRux PKVmxj-2.5.5/examples/order.go000066400000000000000000000046201402172443100156010ustar00rootroot00000000000000// Preserve list order with intermixed sub-elements. // from: https://groups.google.com/forum/#!topic/golang-nuts/8KvlKsdh84k package main import ( "fmt" "sort" "github.com/clbanning/mxj" ) var data = ` sadasd gfdfg bcbcbc hihihi jkjkjk lmlmlm ` func main() { m, err := mxj.NewMapXmlSeq([]byte(data)) if err != nil { fmt.Println("err:", err) return } // Merge a b, and c members into a single list. // The value has "#text" key; "#seq" has the list sequence index. // Preserve both and the list key if you want to reencode. list := make([]*listval, 0) for k, v := range m["node"].(map[string]interface{}) { switch v.(type) { case map[string]interface{}: // This handles the lone 'c' element in the list. mem := v.(map[string]interface{}) lval := &listval{k, mem["#text"].(string), mem["#seq"].(int)} list = append(list, lval) case []interface{}: // 'a' and 'b' were decoded as slices. for _, vv := range v.([]interface{}) { mem := vv.(map[string]interface{}) lval := &listval{k, mem["#text"].(string), mem["#seq"].(int)} list = append(list, lval) } } } // Sort the list into orignal DOC sequence. sort.Sort(Lval(list)) // Do some work with the list members - let's swap values. for i := 0; i < 3; i++ { list[i].val, list[5-i].val = list[5-i].val, list[i].val } // Rebuild map[string]interface{} value for "node". // Everything can be slice values - []interface{} - for encoding. a := make([]interface{}, 0) b := make([]interface{}, 0) c := make([]interface{}, 0) for _, v := range list { val := map[string]interface{}{"#text": v.val, "#seq": v.seq} switch v.list { case "a": a = append(a, interface{}(val)) case "b": b = append(b, interface{}(val)) case "c": c = append(c, interface{}(val)) } } val := map[string]interface{}{"a": a, "b": b, "c": c} m["node"] = interface{}(val) x, err := m.XmlSeqIndent("", " ") if err != nil { fmt.Println("err:", err) return } fmt.Println(data) // original fmt.Println(string(x)) // modified } // ======== sort interface implementation ======== type listval struct { list string val string seq int } type Lval []*listval func (l Lval) Len() int { return len(l) } func (l Lval) Less(i, j int) bool { if l[i].seq < l[j].seq { return true } return false } func (l Lval) Swap(i, j int) { l[i], l[j] = l[j], l[i] } mxj-2.5.5/examples/partial.go000066400000000000000000000020161402172443100161170ustar00rootroot00000000000000// https://github.com/clbanning/mxj/issues/53 package main import ( "fmt" "github.com/clbanning/mxj" ) var source = []byte(` c d x y z f g `) var wants = map[string][]string{ "one": { "a.b.c", "a.e.x", }, "two": { "a.b.d", "a.e.y", "a.e.z", }, "three": { "a.f", "a.g", }, } func main() { m, err := mxj.NewMapXml(source) if err != nil { fmt.Println("err:", err) return } n, err := m.NewMap(wants["one"]...) if err != nil { fmt.Println("err:", err) return } target, err := n.XmlIndent("", " ") if err != nil { fmt.Println("err:", err) return } fmt.Println(string(target)) // the rest of the wants n, _ = m.NewMap(wants["two"]...) target, _ = n.XmlIndent("", " ") fmt.Println(string(target)) n, _ = m.NewMap(wants["three"]...) target, _ = n.XmlIndent("", " ") fmt.Println(string(target)) } mxj-2.5.5/examples/reddit01.go000066400000000000000000000023151402172443100161010ustar00rootroot00000000000000// https://www.reddit.com/r/golang/comments/9eclgy/xml_unmarshaling_internal_references/ package main import ( "fmt" "github.com/clbanning/mxj" ) var data = []byte(` Hello!! `) func main() { m, err := mxj.NewMapXml(data) if err != nil { fmt.Println("err:", err) return } fmt.Printf("%v\n", m) type mystruct struct { FromUser string ToUser string Message string } myStruct := mystruct{} vals, err := m.ValuesForPath("app.users.user", "-id:1") if err != nil { fmt.Println("err:", err) return } if len(vals) == 1 { myStruct.FromUser = vals[0].(map[string]interface{})["-name"].(string) } vals, err = m.ValuesForPath("app.users.user", "-id:2") if err != nil { fmt.Println("err:", err) return } if len(vals) == 1 { myStruct.ToUser = vals[0].(map[string]interface{})["-name"].(string) } vals, err = m.ValuesForPath("app.messages.message.#text") if err != nil { fmt.Println("err:", err) return } if len(vals) == 1 { myStruct.Message = vals[0].(string) } fmt.Printf("%#v\n", myStruct) } mxj-2.5.5/examples/reddit02.go000066400000000000000000000024311402172443100161010ustar00rootroot00000000000000// https://www.reddit.com/r/golang/comments/9eclgy/xml_unmarshaling_internal_references/ package main import ( "fmt" "github.com/clbanning/mxj" ) var data = []byte(` Hello!! `) func main() { m, err := mxj.NewMapXml(data) if err != nil { fmt.Println("err:", err) return } fmt.Printf("%v\n", m) type mystruct struct { FromUser string ToUser string Message string } myStruct := mystruct{} val, err := m.ValueForKey("user", "-id:1") if val != nil { myStruct.FromUser = val.(map[string]interface{})["-name"].(string) } else { // if there no val, then err is at least KeyNotExistError fmt.Println("err:", err) return } val, err = m.ValueForKey("user", "-id:2") if val != nil { myStruct.ToUser = val.(map[string]interface{})["-name"].(string) } else { // if there no val, then err is at least KeyNotExistError fmt.Println("err:", err) return } val, err = m.ValueForKey("#text") if val != nil { myStruct.Message = val.(string) } else { // if there no val, then err is at least KeyNotExistError fmt.Println("err:", err) return } fmt.Printf("%#v\n", myStruct) } mxj-2.5.5/examples/x2jcmd.go000066400000000000000000000005411402172443100156530ustar00rootroot00000000000000// Per: https://github.com/clbanning/mxj/issues/24 // Per: https://github.com/clbanning/mxj/issues/25 package main import ( "fmt" "io" "os" "github.com/clbanning/mxj/x2j" ) func main() { for { _, _, err := x2j.XmlReaderToJsonWriter(os.Stdin, os.Stdout) if err == io.EOF { break } if err != nil { fmt.Println(err) break } } } mxj-2.5.5/examples/x2jcmd.xml000066400000000000000000000000571402172443100160500ustar00rootroot00000000000000is a test is another mxj-2.5.5/exists.go000066400000000000000000000005141402172443100141650ustar00rootroot00000000000000package mxj // Checks whether the path exists. If err != nil then 'false' is returned // along with the error encountered parsing either the "path" or "subkeys" // argument. func (mv Map) Exists(path string, subkeys ...string) (bool, error) { v, err := mv.ValuesForPath(path, subkeys...) return (err == nil && len(v) > 0), err } mxj-2.5.5/exists_test.go000066400000000000000000000020111402172443100152160ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) func TestExists(t *testing.T) { fmt.Println("------------ exists_test.go") m := map[string]interface{}{ "Div": map[string]interface{}{ "Colour": "blue", }, } mv := Map(m) if v, _ := mv.Exists("Div.Colour"); !v { t.Fatal("Haven't found an existing element") } if v, _ := mv.Exists("Div.Color"); v { t.Fatal("Have found a non existing element") } } /* var existsDoc = []byte(` William T. Gaddis The Recognitions One of the great seminal American novels of the 20th century. Something else. `) func TestExistsWithSubKeys(t *testing.T) { mv, err := NewMapXml(existsDoc) if err != nil { t.Fatal("err:", err.Error()) } if !mv.Exists("doc.books.book", "-seq:1") { t.Fatal("Did't find an existing element") } if mv.Exists("doc.books.book", "-seq:2") { t.Fatal("Found a non-existing element") } } */ mxj-2.5.5/files.go000066400000000000000000000143111402172443100137500ustar00rootroot00000000000000package mxj import ( "fmt" "io" "os" ) type Maps []Map func NewMaps() Maps { return make(Maps, 0) } type MapRaw struct { M Map R []byte } // NewMapsFromXmlFile - creates an array from a file of JSON values. func NewMapsFromJsonFile(name string) (Maps, error) { fi, err := os.Stat(name) if err != nil { return nil, err } if !fi.Mode().IsRegular() { return nil, fmt.Errorf("file %s is not a regular file", name) } fh, err := os.Open(name) if err != nil { return nil, err } defer fh.Close() am := make([]Map, 0) for { m, raw, err := NewMapJsonReaderRaw(fh) if err != nil && err != io.EOF { return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(raw)) } if len(m) > 0 { am = append(am, m) } if err == io.EOF { break } } return am, nil } // ReadMapsFromJsonFileRaw - creates an array of MapRaw from a file of JSON values. func NewMapsFromJsonFileRaw(name string) ([]MapRaw, error) { fi, err := os.Stat(name) if err != nil { return nil, err } if !fi.Mode().IsRegular() { return nil, fmt.Errorf("file %s is not a regular file", name) } fh, err := os.Open(name) if err != nil { return nil, err } defer fh.Close() am := make([]MapRaw, 0) for { mr := new(MapRaw) mr.M, mr.R, err = NewMapJsonReaderRaw(fh) if err != nil && err != io.EOF { return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(mr.R)) } if len(mr.M) > 0 { am = append(am, *mr) } if err == io.EOF { break } } return am, nil } // NewMapsFromXmlFile - creates an array from a file of XML values. func NewMapsFromXmlFile(name string) (Maps, error) { fi, err := os.Stat(name) if err != nil { return nil, err } if !fi.Mode().IsRegular() { return nil, fmt.Errorf("file %s is not a regular file", name) } fh, err := os.Open(name) if err != nil { return nil, err } defer fh.Close() am := make([]Map, 0) for { m, raw, err := NewMapXmlReaderRaw(fh) if err != nil && err != io.EOF { return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(raw)) } if len(m) > 0 { am = append(am, m) } if err == io.EOF { break } } return am, nil } // NewMapsFromXmlFileRaw - creates an array of MapRaw from a file of XML values. // NOTE: the slice with the raw XML is clean with no extra capacity - unlike NewMapXmlReaderRaw(). // It is slow at parsing a file from disk and is intended for relatively small utility files. func NewMapsFromXmlFileRaw(name string) ([]MapRaw, error) { fi, err := os.Stat(name) if err != nil { return nil, err } if !fi.Mode().IsRegular() { return nil, fmt.Errorf("file %s is not a regular file", name) } fh, err := os.Open(name) if err != nil { return nil, err } defer fh.Close() am := make([]MapRaw, 0) for { mr := new(MapRaw) mr.M, mr.R, err = NewMapXmlReaderRaw(fh) if err != nil && err != io.EOF { return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(mr.R)) } if len(mr.M) > 0 { am = append(am, *mr) } if err == io.EOF { break } } return am, nil } // ------------------------ Maps writing ------------------------- // These are handy-dandy methods for dumping configuration data, etc. // JsonString - analogous to mv.Json() func (mvs Maps) JsonString(safeEncoding ...bool) (string, error) { var s string for _, v := range mvs { j, err := v.Json() if err != nil { return s, err } s += string(j) } return s, nil } // JsonStringIndent - analogous to mv.JsonIndent() func (mvs Maps) JsonStringIndent(prefix, indent string, safeEncoding ...bool) (string, error) { var s string var haveFirst bool for _, v := range mvs { j, err := v.JsonIndent(prefix, indent) if err != nil { return s, err } if haveFirst { s += "\n" } else { haveFirst = true } s += string(j) } return s, nil } // XmlString - analogous to mv.Xml() func (mvs Maps) XmlString() (string, error) { var s string for _, v := range mvs { x, err := v.Xml() if err != nil { return s, err } s += string(x) } return s, nil } // XmlStringIndent - analogous to mv.XmlIndent() func (mvs Maps) XmlStringIndent(prefix, indent string) (string, error) { var s string for _, v := range mvs { x, err := v.XmlIndent(prefix, indent) if err != nil { return s, err } s += string(x) } return s, nil } // JsonFile - write Maps to named file as JSON // Note: the file will be created, if necessary; if it exists it will be truncated. // If you need to append to a file, open it and use JsonWriter method. func (mvs Maps) JsonFile(file string, safeEncoding ...bool) error { var encoding bool if len(safeEncoding) == 1 { encoding = safeEncoding[0] } s, err := mvs.JsonString(encoding) if err != nil { return err } fh, err := os.Create(file) if err != nil { return err } defer fh.Close() fh.WriteString(s) return nil } // JsonFileIndent - write Maps to named file as pretty JSON // Note: the file will be created, if necessary; if it exists it will be truncated. // If you need to append to a file, open it and use JsonIndentWriter method. func (mvs Maps) JsonFileIndent(file, prefix, indent string, safeEncoding ...bool) error { var encoding bool if len(safeEncoding) == 1 { encoding = safeEncoding[0] } s, err := mvs.JsonStringIndent(prefix, indent, encoding) if err != nil { return err } fh, err := os.Create(file) if err != nil { return err } defer fh.Close() fh.WriteString(s) return nil } // XmlFile - write Maps to named file as XML // Note: the file will be created, if necessary; if it exists it will be truncated. // If you need to append to a file, open it and use XmlWriter method. func (mvs Maps) XmlFile(file string) error { s, err := mvs.XmlString() if err != nil { return err } fh, err := os.Create(file) if err != nil { return err } defer fh.Close() fh.WriteString(s) return nil } // XmlFileIndent - write Maps to named file as pretty XML // Note: the file will be created,if necessary; if it exists it will be truncated. // If you need to append to a file, open it and use XmlIndentWriter method. func (mvs Maps) XmlFileIndent(file, prefix, indent string) error { s, err := mvs.XmlStringIndent(prefix, indent) if err != nil { return err } fh, err := os.Create(file) if err != nil { return err } defer fh.Close() fh.WriteString(s) return nil } mxj-2.5.5/files_test.badjson000066400000000000000000000001531402172443100160210ustar00rootroot00000000000000{ "this":"is", "a":"test", "file":"for", "files_test.go":"case" } { "with":"some", "bad":JSON, "in":"it" } mxj-2.5.5/files_test.badxml000066400000000000000000000002071402172443100156500ustar00rootroot00000000000000 test for files.go some doc test case mxj-2.5.5/files_test.go000066400000000000000000000072661402172443100150220ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) func TestFilesHeader(t *testing.T) { fmt.Println("\n---------------- files_test.go ...") } func TestNewJsonFile(t *testing.T) { fmt.Println("NewMapsFromJsonFile()") am, err := NewMapsFromJsonFile("files_test.json") if err != nil { t.Fatal(err.Error()) } for _, v := range am { fmt.Printf("%v\n", v) } am, err = NewMapsFromJsonFile("nil") if err == nil { t.Fatal("no error returned for read of nil file") } fmt.Println("caught error: ", err.Error()) am, err = NewMapsFromJsonFile("files_test.badjson") if err == nil { t.Fatal("no error returned for read of badjson file") } fmt.Println("caught error: ", err.Error()) } func TestNewJsonFileRaw(t *testing.T) { fmt.Println("NewMapsFromJsonFileRaw()") mr, err := NewMapsFromJsonFileRaw("files_test.json") if err != nil { t.Fatal(err.Error()) } for _, v := range mr { fmt.Printf("%v\n", v) } mr, err = NewMapsFromJsonFileRaw("nil") if err == nil { t.Fatal("no error returned for read of nil file") } fmt.Println("caught error: ", err.Error()) mr, err = NewMapsFromJsonFileRaw("files_test.badjson") if err == nil { t.Fatal("no error returned for read of badjson file") } fmt.Println("caught error: ", err.Error()) } func TestNewXmFile(t *testing.T) { fmt.Println("NewMapsFromXmlFile()") am, err := NewMapsFromXmlFile("files_test.xml") if err != nil { t.Fatal(err.Error()) } for _, v := range am { fmt.Printf("%v\n", v) } am, err = NewMapsFromXmlFile("nil") if err == nil { t.Fatal("no error returned for read of nil file") } fmt.Println("caught error: ", err.Error()) am, err = NewMapsFromXmlFile("files_test.badxml") if err == nil { t.Fatal("no error returned for read of badjson file") } fmt.Println("caught error: ", err.Error()) } func TestNewXmFileRaw(t *testing.T) { fmt.Println("NewMapsFromXmlFileRaw()") mr, err := NewMapsFromXmlFileRaw("files_test.xml") if err != nil { t.Fatal(err.Error()) } for _, v := range mr { fmt.Printf("%v\n", v) } mr, err = NewMapsFromXmlFileRaw("nil") if err == nil { t.Fatal("no error returned for read of nil file") } fmt.Println("caught error: ", err.Error()) mr, err = NewMapsFromXmlFileRaw("files_test.badxml") if err == nil { t.Fatal("no error returned for read of badjson file") } fmt.Println("caught error: ", err.Error()) } func TestMaps(t *testing.T) { fmt.Println("TestMaps()") mvs := NewMaps() for i := 0; i < 2; i++ { m, _ := NewMapJson([]byte(`{ "this":"is", "a":"test" }`)) mvs = append(mvs, m) } fmt.Println("mvs:", mvs) s, _ := mvs.JsonString() fmt.Println("JsonString():", s) s, _ = mvs.JsonStringIndent("", " ") fmt.Println("JsonStringIndent():", s) s, _ = mvs.XmlString() fmt.Println("XmlString():", s) s, _ = mvs.XmlStringIndent("", " ") fmt.Println("XmlStringIndent():", s) } func TestJsonFile(t *testing.T) { am, err := NewMapsFromJsonFile("files_test.json") if err != nil { t.Fatal(err.Error()) } for _, v := range am { fmt.Printf("%v\n", v) } err = am.JsonFile("files_test_dup.json") if err != nil { t.Fatal(err.Error()) } fmt.Println("files_test_dup.json written") err = am.JsonFileIndent("files_test_indent.json", "", " ") if err != nil { t.Fatal(err.Error()) } fmt.Println("files_test_indent.json written") } func TestXmlFile(t *testing.T) { am, err := NewMapsFromXmlFile("files_test.xml") if err != nil { t.Fatal(err.Error()) } for _, v := range am { fmt.Printf("%v\n", v) } err = am.XmlFile("files_test_dup.xml") if err != nil { t.Fatal(err.Error()) } fmt.Println("files_test_dup.xml written") err = am.XmlFileIndent("files_test_indent.xml", "", " ") if err != nil { t.Fatal(err.Error()) } fmt.Println("files_test_indent.xml written") } mxj-2.5.5/files_test.json000066400000000000000000000001731402172443100153540ustar00rootroot00000000000000{ "this":"is", "a":"test", "file":"for", "files_test.go":"case" } { "with":"just", "two":2, "JSON":"values", "true":true } mxj-2.5.5/files_test.xml000066400000000000000000000002111402172443100151740ustar00rootroot00000000000000 test for files.go some doc test case mxj-2.5.5/files_test_dup.json000066400000000000000000000001571402172443100162260ustar00rootroot00000000000000{"a":"test","file":"for","files_test.go":"case","this":"is"}{"JSON":"values","true":true,"two":2,"with":"just"}mxj-2.5.5/files_test_dup.xml000066400000000000000000000001731402172443100160530ustar00rootroot00000000000000for files.gotestdoctest casesomemxj-2.5.5/files_test_indent.json000066400000000000000000000002221402172443100167100ustar00rootroot00000000000000{ "a": "test", "file": "for", "files_test.go": "case", "this": "is" } { "JSON": "values", "true": true, "two": 2, "with": "just" }mxj-2.5.5/files_test_indent.xml000066400000000000000000000002141402172443100165400ustar00rootroot00000000000000 for files.go test doc test case some mxj-2.5.5/go.mod000066400000000000000000000000541402172443100134240ustar00rootroot00000000000000module github.com/clbanning/mxj/v2 go 1.15 mxj-2.5.5/gob.go000066400000000000000000000015051402172443100134160ustar00rootroot00000000000000// gob.go - Encode/Decode a Map into a gob object. package mxj import ( "bytes" "encoding/gob" ) // NewMapGob returns a Map value for a gob object that has been // encoded from a map[string]interface{} (or compatible type) value. // It is intended to provide symmetric handling of Maps that have // been encoded using mv.Gob. func NewMapGob(gobj []byte) (Map, error) { m := make(map[string]interface{}, 0) if len(gobj) == 0 { return m, nil } r := bytes.NewReader(gobj) dec := gob.NewDecoder(r) if err := dec.Decode(&m); err != nil { return m, err } return m, nil } // Gob returns a gob-encoded value for the Map 'mv'. func (mv Map) Gob() ([]byte, error) { var buf bytes.Buffer enc := gob.NewEncoder(&buf) if err := enc.Encode(map[string]interface{}(mv)); err != nil { return nil, err } return buf.Bytes(), nil } mxj-2.5.5/gob_test.go000066400000000000000000000025071402172443100144600ustar00rootroot00000000000000package mxj import ( "bytes" "encoding/gob" "fmt" "testing" ) var gobData = map[string]interface{}{ "one": 1, "two": 2.0001, "three": "tres", "four": []int{1, 2, 3, 4}, "five": map[string]interface{}{"hi": "there"}} func TestGobHeader(t *testing.T) { fmt.Println("\n---------------- gob_test.go ...") } func TestNewMapGob(t *testing.T) { var buf bytes.Buffer gob.Register(gobData) enc := gob.NewEncoder(&buf) if err := enc.Encode(gobData); err != nil { t.Fatal("enc.Encode err:", err.Error()) } // decode 'buf' into a Map - map[string]interface{} m, err := NewMapGob(buf.Bytes()) if err != nil { t.Fatal("NewMapGob err:", err.Error()) } fmt.Printf("m: %v\n", m) } func TestMapGob(t *testing.T) { mv := Map(gobData) g, err := mv.Gob() if err != nil { t.Fatal("m.Gob err:", err.Error()) } // decode 'g' into a map[string]interface{} m := make(map[string]interface{}) r := bytes.NewReader(g) dec := gob.NewDecoder(r) if err := dec.Decode(&m); err != nil { t.Fatal("dec.Decode err:", err.Error()) } fmt.Printf("m: %v\n", m) } func TestGobSymmetric(t *testing.T) { mv := Map(gobData) fmt.Printf("mv: %v\n", mv) g, err := mv.Gob() if err != nil { t.Fatal("m.Gob err:", err.Error()) } m, err := NewMapGob(g) if err != nil { t.Fatal("NewMapGob err:", err.Error()) } fmt.Printf("m : %v\n", m) } mxj-2.5.5/isvalid_test.go000066400000000000000000000032641402172443100153450ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) func TestXmlCheckIsValid(t *testing.T) { fmt.Println("================== TestXmlCheckIsValid") XmlCheckIsValid() defer XmlCheckIsValid() data := []byte(`{"":"empty", "$invalid":"hex$", "entities":"<>&", "nil": null}`) m, err := NewMapJson(data) if err != nil { t.Fatal("NewMapJson err;", err) } fmt.Printf("%v\n", m) if _, err = m.Xml(); err == nil { t.Fatal("Xml err: nil") } if _, err = m.XmlIndent("", " "); err == nil { t.Fatal("XmlIndent err: nil") } data = []byte(`{"$invalid":"hex$", "entities":"<>&", "nil": null}`) m, err = NewMapJson(data) if err != nil { t.Fatal("NewMapJson err;", err) } fmt.Printf("%v\n", m) if _, err = m.Xml(); err == nil { t.Fatal("Xml err: nil") } if _, err = m.XmlIndent("", " "); err == nil { t.Fatal("XmlIndent err: nil") } data = []byte(`{"entities":"<>&", "nil": null}`) m, err = NewMapJson(data) if err != nil { t.Fatal("NewMapJson err;", err) } fmt.Printf("%v\n", m) if _, err = m.Xml(); err == nil { t.Fatal("Xml err: nil") } if _, err = m.XmlIndent("", " "); err == nil { t.Fatal("XmlIndent err: nil") } data = []byte(`{"nil": null}`) m, err = NewMapJson(data) if err != nil { t.Fatal("NewMapJson err;", err) } fmt.Printf("%v\n", m) if b, err := m.Xml(); err != nil { fmt.Println("m:", string(b)) t.Fatal("Xml err:", err) } if _, err = m.XmlIndent("", " "); err != nil { t.Fatal("XmlIndent err:", nil) } ms, err := NewMapXmlSeq([]byte(`element`)) fmt.Printf("%v\n", ms) if _, err = ms.Xml(); err != nil { t.Fatal("Xml err:", err) } if _, err = ms.XmlIndent("", " "); err != nil { t.Fatal("XmlIndent err:", err) } } mxj-2.5.5/j2x/000077500000000000000000000000001402172443100130225ustar00rootroot00000000000000mxj-2.5.5/j2x/j2x.go000066400000000000000000000110531402172443100140540ustar00rootroot00000000000000// Copyright 2012-2014 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // j2x.go - For (mostly) backwards compatibility with legacy j2x package. // Wrappers for end-to-end JSON to XML transformation and value manipulation. package j2x import ( . "github.com/clbanning/mxj" "io" ) // FromJson() --> map[string]interface{} func JsonToMap(jsonVal []byte) (map[string]interface{}, error) { return NewMapJson(jsonVal) } // interface{} --> ToJson (w/o safe encoding, default) { func MapToJson(m map[string]interface{}, safeEncoding ...bool) ([]byte, error) { return Map(m).Json() } // FromJson() --> ToXml(). func JsonToXml(jsonVal []byte) ([]byte, error) { m, err := NewMapJson(jsonVal) if err != nil { return nil, err } return m.Xml() } // FromJson() --> ToXmlWriter(). func JsonToXmlWriter(jsonVal []byte, xmlWriter io.Writer) error { m, err := NewMapJson(jsonVal) if err != nil { return err } return m.XmlWriter(xmlWriter) } // FromJsonReader() --> ToXml(). func JsonReaderToXml(jsonReader io.Reader) ([]byte, []byte, error) { m, jraw, err := NewMapJsonReaderRaw(jsonReader) if err != nil { return jraw, nil, err } x, xerr := m.Xml() return jraw, x, xerr } // FromJsonReader() --> ToXmlWriter(). Handy for transforming bulk message sets. func JsonReaderToXmlWriter(jsonReader io.Reader, xmlWriter io.Writer) error { m, err := NewMapJsonReader(jsonReader) if err != nil { return err } err = m.XmlWriter(xmlWriter) return err } // JSON wrappers for Map methods implementing key path and value functions. // Wrap PathsForKey for JSON. func JsonPathsForKey(jsonVal []byte, key string) ([]string, error) { m, err := NewMapJson(jsonVal) if err != nil { return nil, err } paths := m.PathsForKey(key) return paths, nil } // Wrap PathForKeyShortest for JSON. func JsonPathForKeyShortest(jsonVal []byte, key string) (string, error) { m, err := NewMapJson(jsonVal) if err != nil { return "", err } path := m.PathForKeyShortest(key) return path, nil } // Wrap ValuesForKey for JSON. func JsonValuesForKey(jsonVal []byte, key string, subkeys ...string) ([]interface{}, error) { m, err := NewMapJson(jsonVal) if err != nil { return nil, err } return m.ValuesForKey(key, subkeys...) } // Wrap ValuesForKeyPath for JSON. func JsonValuesForKeyPath(jsonVal []byte, path string, subkeys ...string) ([]interface{}, error) { m, err := NewMapJson(jsonVal) if err != nil { return nil, err } return m.ValuesForPath(path, subkeys...) } // Wrap UpdateValuesForPath for JSON // 'jsonVal' is XML value // 'newKeyValue' is the value to replace an existing value at the end of 'path' // 'path' is the dot-notation path with the key whose value is to be replaced at the end // (can include wildcard character, '*') // 'subkeys' are key:value pairs of key:values that must match for the key func JsonUpdateValsForPath(jsonVal []byte, newKeyValue interface{}, path string, subkeys ...string) ([]byte, error) { m, err := NewMapJson(jsonVal) if err != nil { return nil, err } _, err = m.UpdateValuesForPath(newKeyValue, path, subkeys...) if err != nil { return nil, err } return m.Json() } // Wrap NewMap for JSON and return as JSON // 'jsonVal' is an JSON value // 'keypairs' are "oldKey:newKey" values that conform to 'keypairs' in (Map)NewMap. func JsonNewJson(jsonVal []byte, keypairs ...string) ([]byte, error) { m, err := NewMapJson(jsonVal) if err != nil { return nil, err } n, err := m.NewMap(keypairs...) if err != nil { return nil, err } return n.Json() } // Wrap NewMap for JSON and return as XML // 'jsonVal' is an JSON value // 'keypairs' are "oldKey:newKey" values that conform to 'keypairs' in (Map)NewMap. func JsonNewXml(jsonVal []byte, keypairs ...string) ([]byte, error) { m, err := NewMapJson(jsonVal) if err != nil { return nil, err } n, err := m.NewMap(keypairs...) if err != nil { return nil, err } return n.Xml() } // Wrap LeafNodes for JSON. // 'jsonVal' is an JSON value func JsonLeafNodes(jsonVal []byte) ([]LeafNode, error) { m, err := NewMapJson(jsonVal) if err != nil { return nil, err } return m.LeafNodes(), nil } // Wrap LeafValues for JSON. // 'jsonVal' is an JSON value func JsonLeafValues(jsonVal []byte) ([]interface{}, error) { m, err := NewMapJson(jsonVal) if err != nil { return nil, err } return m.LeafValues(), nil } // Wrap LeafPath for JSON. // 'xmlVal' is an JSON value func JsonLeafPath(jsonVal []byte) ([]string, error) { m, err := NewMapJson(jsonVal) if err != nil { return nil, err } return m.LeafPaths(), nil } mxj-2.5.5/j2x/j2x_test.go000066400000000000000000000027041402172443100151160ustar00rootroot00000000000000// thanks to Chris Malek (chris.r.malek@gmail.com) for suggestion to handle JSON list docs. package j2x import ( "bytes" "fmt" "io/ioutil" "testing" ) func TestJsonToXml_1(t *testing.T) { // mimic a io.Reader // Body := bytes.NewReader([]byte(`{"some-null-value":"", "a-non-null-value":"bar"}`)) Body := bytes.NewReader([]byte(`[{"some-null-value":"", "a-non-null-value":"bar"}]`)) //body, err := ioutil.ReadAll(req.Body) body, err := ioutil.ReadAll(Body) if err != nil { t.Fatal(err) } fmt.Println(string(body)) //if err != nil { // t.Fatal(err) //} var xmloutput []byte //xmloutput, err = j2x.JsonToXml(body) xmloutput, err = JsonToXml(body) //log.Println(string(xmloutput)) if err != nil { t.Fatal(err) // log.Println(err) // http.Error(rw, "Could not convert to xml", 400) } fmt.Println("xmloutput:", string(xmloutput)) } func TestJsonToXml_2(t *testing.T) { // mimic a io.Reader Body := bytes.NewReader([]byte(`{"somekey":[{"value":"1st"},{"value":"2nd"}]}`)) //body, err := ioutil.ReadAll(req.Body) body, err := ioutil.ReadAll(Body) if err != nil { t.Fatal(err) } fmt.Println(string(body)) //if err != nil { // t.Fatal(err) //} var xmloutput []byte //xmloutput, err = j2x.JsonToXml(body) xmloutput, err = JsonToXml(body) //log.Println(string(xmloutput)) if err != nil { t.Fatal(err) // log.Println(err) // http.Error(rw, "Could not convert to xml", 400) } fmt.Println("xmloutput:", string(xmloutput)) } mxj-2.5.5/j2x_test.go000066400000000000000000000010341402172443100144060ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) var jjdata = []byte(`{ "key1":"string", "key2":34, "key3":true, "key4":"unsafe: <>&", "key5":null }`) func TestJ2XHeader(t *testing.T) { fmt.Println("\n---------------- j2x_test .go ...") } func TestJ2X(t *testing.T) { m, err := NewMapJson(jjdata) if err != nil { t.Fatal("NewMapJson, err:", err) } x, err := m.Xml() if err != nil { t.Fatal("m.Xml(), err:", err) } fmt.Println("j2x, jdata:", string(jjdata)) fmt.Println("j2x, m :", m) fmt.Println("j2x, xml :", string(x)) } mxj-2.5.5/json.go000066400000000000000000000237671402172443100136360ustar00rootroot00000000000000// Copyright 2012-2014 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file package mxj import ( "bytes" "encoding/json" "fmt" "io" "time" ) // ------------------------------ write JSON ----------------------- // Just a wrapper on json.Marshal. // If option safeEncoding is'true' then safe encoding of '<', '>' and '&' // is preserved. (see encoding/json#Marshal, encoding/json#Encode) func (mv Map) Json(safeEncoding ...bool) ([]byte, error) { var s bool if len(safeEncoding) == 1 { s = safeEncoding[0] } b, err := json.Marshal(mv) if !s { b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1) b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1) b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1) } return b, err } // Just a wrapper on json.MarshalIndent. // If option safeEncoding is'true' then safe encoding of '<' , '>' and '&' // is preserved. (see encoding/json#Marshal, encoding/json#Encode) func (mv Map) JsonIndent(prefix, indent string, safeEncoding ...bool) ([]byte, error) { var s bool if len(safeEncoding) == 1 { s = safeEncoding[0] } b, err := json.MarshalIndent(mv, prefix, indent) if !s { b = bytes.Replace(b, []byte("\\u003c"), []byte("<"), -1) b = bytes.Replace(b, []byte("\\u003e"), []byte(">"), -1) b = bytes.Replace(b, []byte("\\u0026"), []byte("&"), -1) } return b, err } // The following implementation is provided for symmetry with NewMapJsonReader[Raw] // The names will also provide a key for the number of return arguments. // Writes the Map as JSON on the Writer. // If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved. func (mv Map) JsonWriter(jsonWriter io.Writer, safeEncoding ...bool) error { b, err := mv.Json(safeEncoding...) if err != nil { return err } _, err = jsonWriter.Write(b) return err } // Writes the Map as JSON on the Writer. []byte is the raw JSON that was written. // If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved. func (mv Map) JsonWriterRaw(jsonWriter io.Writer, safeEncoding ...bool) ([]byte, error) { b, err := mv.Json(safeEncoding...) if err != nil { return b, err } _, err = jsonWriter.Write(b) return b, err } // Writes the Map as pretty JSON on the Writer. // If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved. func (mv Map) JsonIndentWriter(jsonWriter io.Writer, prefix, indent string, safeEncoding ...bool) error { b, err := mv.JsonIndent(prefix, indent, safeEncoding...) if err != nil { return err } _, err = jsonWriter.Write(b) return err } // Writes the Map as pretty JSON on the Writer. []byte is the raw JSON that was written. // If 'safeEncoding' is 'true', then "safe" encoding of '<', '>' and '&' is preserved. func (mv Map) JsonIndentWriterRaw(jsonWriter io.Writer, prefix, indent string, safeEncoding ...bool) ([]byte, error) { b, err := mv.JsonIndent(prefix, indent, safeEncoding...) if err != nil { return b, err } _, err = jsonWriter.Write(b) return b, err } // --------------------------- read JSON ----------------------------- // Decode numericvalues as json.Number type Map values - see encoding/json#Number. // NOTE: this is for decoding JSON into a Map with NewMapJson(), NewMapJsonReader(), // etc.; it does not affect NewMapXml(), etc. The XML encoders mv.Xml() and mv.XmlIndent() // do recognize json.Number types; a JSON object can be decoded to a Map with json.Number // value types and the resulting Map can be correctly encoded into a XML object. var JsonUseNumber bool // Just a wrapper on json.Unmarshal // Converting JSON to XML is a simple as: // ... // mapVal, merr := mxj.NewMapJson(jsonVal) // if merr != nil { // // handle error // } // xmlVal, xerr := mapVal.Xml() // if xerr != nil { // // handle error // } // NOTE: as a special case, passing a list, e.g., [{"some-null-value":"", "a-non-null-value":"bar"}], // will be interpreted as having the root key 'object' prepended - {"object":[ ... ]} - to unmarshal to a Map. // See mxj/j2x/j2x_test.go. func NewMapJson(jsonVal []byte) (Map, error) { // empty or nil begets empty if len(jsonVal) == 0 { m := make(map[string]interface{}, 0) return m, nil } // handle a goofy case ... if jsonVal[0] == '[' { jsonVal = []byte(`{"object":` + string(jsonVal) + `}`) } m := make(map[string]interface{}) // err := json.Unmarshal(jsonVal, &m) buf := bytes.NewReader(jsonVal) dec := json.NewDecoder(buf) if JsonUseNumber { dec.UseNumber() } err := dec.Decode(&m) return m, err } // Retrieve a Map value from an io.Reader. // NOTE: The raw JSON off the reader is buffered to []byte using a ByteReader. If the io.Reader is an // os.File, there may be significant performance impact. If the io.Reader is wrapping a []byte // value in-memory, however, such as http.Request.Body you CAN use it to efficiently unmarshal // a JSON object. func NewMapJsonReader(jsonReader io.Reader) (Map, error) { jb, err := getJson(jsonReader) if err != nil || len(*jb) == 0 { return nil, err } // Unmarshal the 'presumed' JSON string return NewMapJson(*jb) } // Retrieve a Map value and raw JSON - []byte - from an io.Reader. // NOTE: The raw JSON off the reader is buffered to []byte using a ByteReader. If the io.Reader is an // os.File, there may be significant performance impact. If the io.Reader is wrapping a []byte // value in-memory, however, such as http.Request.Body you CAN use it to efficiently unmarshal // a JSON object and retrieve the raw JSON in a single call. func NewMapJsonReaderRaw(jsonReader io.Reader) (Map, []byte, error) { jb, err := getJson(jsonReader) if err != nil || len(*jb) == 0 { return nil, *jb, err } // Unmarshal the 'presumed' JSON string m, merr := NewMapJson(*jb) return m, *jb, merr } // Pull the next JSON string off the stream: just read from first '{' to its closing '}'. // Returning a pointer to the slice saves 16 bytes - maybe unnecessary, but internal to package. func getJson(rdr io.Reader) (*[]byte, error) { bval := make([]byte, 1) jb := make([]byte, 0) var inQuote, inJson bool var parenCnt int var previous byte // scan the input for a matched set of {...} // json.Unmarshal will handle syntax checking. for { _, err := rdr.Read(bval) if err != nil { if err == io.EOF && inJson && parenCnt > 0 { return &jb, fmt.Errorf("no closing } for JSON string: %s", string(jb)) } return &jb, err } switch bval[0] { case '{': if !inQuote { parenCnt++ inJson = true } case '}': if !inQuote { parenCnt-- } if parenCnt < 0 { return nil, fmt.Errorf("closing } without opening {: %s", string(jb)) } case '"': if inQuote { if previous == '\\' { break } inQuote = false } else { inQuote = true } case '\n', '\r', '\t', ' ': if !inQuote { continue } } if inJson { jb = append(jb, bval[0]) if parenCnt == 0 { break } } previous = bval[0] } return &jb, nil } // ------------------------------- JSON Reader handler via Map values ----------------------- // Default poll delay to keep Handler from spinning on an open stream // like sitting on os.Stdin waiting for imput. var jhandlerPollInterval = time.Duration(1e6) // While unnecessary, we make HandleJsonReader() have the same signature as HandleXmlReader(). // This avoids treating one or other as a special case and discussing the underlying stdlib logic. // Bulk process JSON using handlers that process a Map value. // 'rdr' is an io.Reader for the JSON (stream). // 'mapHandler' is the Map processing handler. Return of 'false' stops io.Reader processing. // 'errHandler' is the error processor. Return of 'false' stops io.Reader processing and returns the error. // Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized. // This means that you can stop reading the file on error or after processing a particular message. // To have reading and handling run concurrently, pass argument to a go routine in handler and return 'true'. func HandleJsonReader(jsonReader io.Reader, mapHandler func(Map) bool, errHandler func(error) bool) error { var n int for { m, merr := NewMapJsonReader(jsonReader) n++ // handle error condition with errhandler if merr != nil && merr != io.EOF { merr = fmt.Errorf("[jsonReader: %d] %s", n, merr.Error()) if ok := errHandler(merr); !ok { // caused reader termination return merr } continue } // pass to maphandler if len(m) != 0 { if ok := mapHandler(m); !ok { break } } else if merr != io.EOF { <-time.After(jhandlerPollInterval) } if merr == io.EOF { break } } return nil } // Bulk process JSON using handlers that process a Map value and the raw JSON. // 'rdr' is an io.Reader for the JSON (stream). // 'mapHandler' is the Map and raw JSON - []byte - processor. Return of 'false' stops io.Reader processing. // 'errHandler' is the error and raw JSON processor. Return of 'false' stops io.Reader processing and returns the error. // Note: mapHandler() and errHandler() calls are blocking, so reading and processing of messages is serialized. // This means that you can stop reading the file on error or after processing a particular message. // To have reading and handling run concurrently, pass argument(s) to a go routine in handler and return 'true'. func HandleJsonReaderRaw(jsonReader io.Reader, mapHandler func(Map, []byte) bool, errHandler func(error, []byte) bool) error { var n int for { m, raw, merr := NewMapJsonReaderRaw(jsonReader) n++ // handle error condition with errhandler if merr != nil && merr != io.EOF { merr = fmt.Errorf("[jsonReader: %d] %s", n, merr.Error()) if ok := errHandler(merr, raw); !ok { // caused reader termination return merr } continue } // pass to maphandler if len(m) != 0 { if ok := mapHandler(m, raw); !ok { break } } else if merr != io.EOF { <-time.After(jhandlerPollInterval) } if merr == io.EOF { break } } return nil } mxj-2.5.5/json_test.go000066400000000000000000000055451402172443100146670ustar00rootroot00000000000000package mxj import ( "bytes" "fmt" "io" "testing" ) var jdata = []byte(`{ "key1":"string", "key2":34, "key3":true, "key4":"unsafe: <>&", "key5":null }`) var jdata2 = []byte(`{ "key1":"string", "key2":34, "key3":true, "key4":"unsafe: <>&" }, { "key":"value in new JSON string" }`) func TestJsonHeader(t *testing.T) { fmt.Println("\n---------------- json_test.go ...") } func TestNewMapJson(t *testing.T) { m, merr := NewMapJson(jdata) if merr != nil { t.Fatal("NewMapJson, merr:", merr.Error()) } fmt.Println("NewMapJson, jdata:", string(jdata)) fmt.Printf("NewMapJson, m : %#v\n", m) } func TestNewMapJsonNumber(t *testing.T) { JsonUseNumber = true m, merr := NewMapJson(jdata) if merr != nil { t.Fatal("NewMapJson, merr:", merr.Error()) } fmt.Println("NewMapJson, jdata:", string(jdata)) fmt.Printf("NewMapJson, m : %#v\n", m) JsonUseNumber = false } func TestNewMapJsonError(t *testing.T) { m, merr := NewMapJson(jdata[:len(jdata)-2]) if merr == nil { t.Fatal("NewMapJsonError, m:", m) } fmt.Println("NewMapJsonError, jdata :", string(jdata[:len(jdata)-2])) fmt.Println("NewMapJsonError, merror:", merr.Error()) newData := []byte(`{ "this":"is", "in":error }`) m, merr = NewMapJson(newData) if merr == nil { t.Fatal("NewMapJsonError, m:", m) } fmt.Println("NewMapJsonError, newData :", string(newData)) fmt.Println("NewMapJsonError, merror :", merr.Error()) } func TestNewMapJsonReader(t *testing.T) { rdr := bytes.NewBuffer(jdata2) for { m, jb, merr := NewMapJsonReaderRaw(rdr) if merr != nil && merr != io.EOF { t.Fatal("NewMapJsonReader, merr:", merr.Error()) } if merr == io.EOF { break } fmt.Println("NewMapJsonReader, jb:", string(jb)) fmt.Printf("NewMapJsonReader, m : %#v\n", m) } } func TestNewMapJsonReaderNumber(t *testing.T) { JsonUseNumber = true rdr := bytes.NewBuffer(jdata2) for { m, jb, merr := NewMapJsonReaderRaw(rdr) if merr != nil && merr != io.EOF { t.Fatal("NewMapJsonReader, merr:", merr.Error()) } if merr == io.EOF { break } fmt.Println("NewMapJsonReader, jb:", string(jb)) fmt.Printf("NewMapJsonReader, m : %#v\n", m) } JsonUseNumber = false } func TestJson(t *testing.T) { m, _ := NewMapJson(jdata) j, jerr := m.Json() if jerr != nil { t.Fatal("Json, jerr:", jerr.Error()) } fmt.Println("Json, jdata:", string(jdata)) fmt.Println("Json, j :", string(j)) j, _ = m.Json(true) fmt.Println("Json, j safe:", string(j)) } func TestJsonWriter(t *testing.T) { mv := Map(map[string]interface{}{"this": "is a", "float": 3.14159, "and": "a", "bool": true}) w := new(bytes.Buffer) raw, err := mv.JsonWriterRaw(w) if err != nil { t.Fatal("err:", err.Error()) } b := make([]byte, w.Len()) _, err = w.Read(b) if err != nil { t.Fatal("err:", err.Error()) } fmt.Println("JsonWriter, raw:", string(raw)) fmt.Println("JsonWriter, b :", string(b)) } mxj-2.5.5/keystolower_test.go000066400000000000000000000020231402172443100162710ustar00rootroot00000000000000// keystolower_test.go package mxj import ( "fmt" "testing" ) var tolowerdata1 = []byte(` value `) var tolowerdata2 = []byte(` value `) func TestToLower(t *testing.T) { fmt.Println("\n-------------- keystolower_test.go") fmt.Println("\nTestToLower ...") CoerceKeysToLower() defer CoerceKeysToLower() m1, err := NewMapXml(tolowerdata1) if err != nil { t.Fatal(err) } m2, err := NewMapXml(tolowerdata2) if err != nil { t.Fatal(err) } v1, err := m1.ValuesForPath("doc.element") if err != nil { t.Fatal(err) } v2, err := m2.ValuesForPath("doc.element") if err != nil { t.Fatal(err) } if len(v1) != len(v2) { t.Fatal(err, len(v1), len(v2)) } m := v1[0].(map[string]interface{}) mm := v2[0].(map[string]interface{}) for k, v := range m { if vv, ok := mm[k]; !ok { t.Fatal("key:", k, "not in mm") } else if v.(string) != vv.(string) { t.Fatal(v.(string), "not in v2:", vv.(string)) } } } mxj-2.5.5/keyvalues.go000066400000000000000000000451751402172443100146720ustar00rootroot00000000000000// Copyright 2012-2014 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // keyvalues.go: Extract values from an arbitrary XML doc. Tag path can include wildcard characters. package mxj import ( "errors" "fmt" "strconv" "strings" ) // ----------------------------- get everything FOR a single key ------------------------- const ( minArraySize = 32 ) var defaultArraySize int = minArraySize // SetArraySize adjust the buffers for expected number of values to return from ValuesForKey() and ValuesForPath(). // This can have the effect of significantly reducing memory allocation-copy functions for large data sets. // Returns the initial buffer size. func SetArraySize(size int) int { if size > minArraySize { defaultArraySize = size } else { defaultArraySize = minArraySize } return defaultArraySize } // ValuesForKey return all values in Map, 'mv', associated with a 'key'. If len(returned_values) == 0, then no match. // On error, the returned slice is 'nil'. NOTE: 'key' can be wildcard, "*". // 'subkeys' (optional) are "key:val[:type]" strings representing attributes or elements in a list. // - By default 'val' is of type string. "key:val:bool" and "key:val:float" to coerce them. // - For attributes prefix the label with the attribute prefix character, by default a // hyphen, '-', e.g., "-seq:3". (See SetAttrPrefix function.) // - If the 'key' refers to a list, then "key:value" could select a list member of the list. // - The subkey can be wildcarded - "key:*" - to require that it's there with some value. // - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an // exclusion critera - e.g., "!author:William T. Gaddis". // - If val contains ":" symbol, use SetFieldSeparator to a unused symbol, perhaps "|". func (mv Map) ValuesForKey(key string, subkeys ...string) ([]interface{}, error) { m := map[string]interface{}(mv) var subKeyMap map[string]interface{} if len(subkeys) > 0 { var err error subKeyMap, err = getSubKeyMap(subkeys...) if err != nil { return nil, err } } ret := make([]interface{}, 0, defaultArraySize) var cnt int hasKey(m, key, &ret, &cnt, subKeyMap) return ret[:cnt], nil } var KeyNotExistError = errors.New("Key does not exist") // ValueForKey is a wrapper on ValuesForKey. It returns the first member of []interface{}, if any. // If there is no value, "nil, nil" is returned. func (mv Map) ValueForKey(key string, subkeys ...string) (interface{}, error) { vals, err := mv.ValuesForKey(key, subkeys...) if err != nil { return nil, err } if len(vals) == 0 { return nil, KeyNotExistError } return vals[0], nil } // hasKey - if the map 'key' exists append it to array // if it doesn't do nothing except scan array and map values func hasKey(iv interface{}, key string, ret *[]interface{}, cnt *int, subkeys map[string]interface{}) { // func hasKey(iv interface{}, key string, ret *[]interface{}, subkeys map[string]interface{}) { switch iv.(type) { case map[string]interface{}: vv := iv.(map[string]interface{}) // see if the current value is of interest if v, ok := vv[key]; ok { switch v.(type) { case map[string]interface{}: if hasSubKeys(v, subkeys) { *ret = append(*ret, v) *cnt++ } case []interface{}: for _, av := range v.([]interface{}) { if hasSubKeys(av, subkeys) { *ret = append(*ret, av) *cnt++ } } default: if len(subkeys) == 0 { *ret = append(*ret, v) *cnt++ } } } // wildcard case if key == "*" { for _, v := range vv { switch v.(type) { case map[string]interface{}: if hasSubKeys(v, subkeys) { *ret = append(*ret, v) *cnt++ } case []interface{}: for _, av := range v.([]interface{}) { if hasSubKeys(av, subkeys) { *ret = append(*ret, av) *cnt++ } } default: if len(subkeys) == 0 { *ret = append(*ret, v) *cnt++ } } } } // scan the rest for _, v := range vv { hasKey(v, key, ret, cnt, subkeys) } case []interface{}: for _, v := range iv.([]interface{}) { hasKey(v, key, ret, cnt, subkeys) } } } // ----------------------- get everything for a node in the Map --------------------------- // Allow indexed arrays in "path" specification. (Request from Abhijit Kadam - abhijitk100@gmail.com.) // 2014.04.28 - implementation note. // Implemented as a wrapper of (old)ValuesForPath() because we need look-ahead logic to handle expansion // of wildcards and unindexed arrays. Embedding such logic into valuesForKeyPath() would have made the // code much more complicated; this wrapper is straightforward, easy to debug, and doesn't add significant overhead. // ValuesForPatb retrieves all values for a path from the Map. If len(returned_values) == 0, then no match. // On error, the returned array is 'nil'. // 'path' is a dot-separated path of key values. // - If a node in the path is '*', then everything beyond is walked. // - 'path' can contain indexed array references, such as, "*.data[1]" and "msgs[2].data[0].field" - // even "*[2].*[0].field". // 'subkeys' (optional) are "key:val[:type]" strings representing attributes or elements in a list. // - By default 'val' is of type string. "key:val:bool" and "key:val:float" to coerce them. // - For attributes prefix the label with the attribute prefix character, by default a // hyphen, '-', e.g., "-seq:3". (See SetAttrPrefix function.) // - If the 'path' refers to a list, then "tag:value" would return member of the list. // - The subkey can be wildcarded - "key:*" - to require that it's there with some value. // - If a subkey is preceeded with the '!' character, the key:value[:type] entry is treated as an // exclusion critera - e.g., "!author:William T. Gaddis". // - If val contains ":" symbol, use SetFieldSeparator to a unused symbol, perhaps "|". func (mv Map) ValuesForPath(path string, subkeys ...string) ([]interface{}, error) { // If there are no array indexes in path, use legacy ValuesForPath() logic. if strings.Index(path, "[") < 0 { return mv.oldValuesForPath(path, subkeys...) } var subKeyMap map[string]interface{} if len(subkeys) > 0 { var err error subKeyMap, err = getSubKeyMap(subkeys...) if err != nil { return nil, err } } keys, kerr := parsePath(path) if kerr != nil { return nil, kerr } vals, verr := valuesForArray(keys, mv) if verr != nil { return nil, verr // Vals may be nil, but return empty array. } // Need to handle subkeys ... only return members of vals that satisfy conditions. retvals := make([]interface{}, 0) for _, v := range vals { if hasSubKeys(v, subKeyMap) { retvals = append(retvals, v) } } return retvals, nil } func valuesForArray(keys []*key, m Map) ([]interface{}, error) { var tmppath string var haveFirst bool var vals []interface{} var verr error lastkey := len(keys) - 1 for i := 0; i <= lastkey; i++ { if !haveFirst { tmppath = keys[i].name haveFirst = true } else { tmppath += "." + keys[i].name } // Look-ahead: explode wildcards and unindexed arrays. // Need to handle un-indexed list recursively: // e.g., path is "stuff.data[0]" rather than "stuff[0].data[0]". // Need to treat it as "stuff[0].data[0]", "stuff[1].data[0]", ... if !keys[i].isArray && i < lastkey && keys[i+1].isArray { // Can't pass subkeys because we may not be at literal end of path. vv, vverr := m.oldValuesForPath(tmppath) if vverr != nil { return nil, vverr } for _, v := range vv { // See if we can walk the value. am, ok := v.(map[string]interface{}) if !ok { continue } // Work the backend. nvals, nvalserr := valuesForArray(keys[i+1:], Map(am)) if nvalserr != nil { return nil, nvalserr } vals = append(vals, nvals...) } break // have recursed the whole path - return } if keys[i].isArray || i == lastkey { // Don't pass subkeys because may not be at literal end of path. vals, verr = m.oldValuesForPath(tmppath) } else { continue } if verr != nil { return nil, verr } if i == lastkey && !keys[i].isArray { break } // Now we're looking at an array - supposedly. // Is index in range of vals? if len(vals) <= keys[i].position { vals = nil break } // Return the array member of interest, if at end of path. if i == lastkey { vals = vals[keys[i].position:(keys[i].position + 1)] break } // Extract the array member of interest. am := vals[keys[i].position:(keys[i].position + 1)] // must be a map[string]interface{} value so we can keep walking the path amm, ok := am[0].(map[string]interface{}) if !ok { vals = nil break } m = Map(amm) haveFirst = false } return vals, nil } type key struct { name string isArray bool position int } func parsePath(s string) ([]*key, error) { keys := strings.Split(s, ".") ret := make([]*key, 0) for i := 0; i < len(keys); i++ { if keys[i] == "" { continue } newkey := new(key) if strings.Index(keys[i], "[") < 0 { newkey.name = keys[i] ret = append(ret, newkey) continue } p := strings.Split(keys[i], "[") newkey.name = p[0] p = strings.Split(p[1], "]") if p[0] == "" { // no right bracket return nil, fmt.Errorf("no right bracket on key index: %s", keys[i]) } // convert p[0] to a int value pos, nerr := strconv.ParseInt(p[0], 10, 32) if nerr != nil { return nil, fmt.Errorf("cannot convert index to int value: %s", p[0]) } newkey.position = int(pos) newkey.isArray = true ret = append(ret, newkey) } return ret, nil } // legacy ValuesForPath() - now wrapped to handle special case of indexed arrays in 'path'. func (mv Map) oldValuesForPath(path string, subkeys ...string) ([]interface{}, error) { m := map[string]interface{}(mv) var subKeyMap map[string]interface{} if len(subkeys) > 0 { var err error subKeyMap, err = getSubKeyMap(subkeys...) if err != nil { return nil, err } } keys := strings.Split(path, ".") if keys[len(keys)-1] == "" { keys = keys[:len(keys)-1] } ivals := make([]interface{}, 0, defaultArraySize) var cnt int valuesForKeyPath(&ivals, &cnt, m, keys, subKeyMap) return ivals[:cnt], nil } func valuesForKeyPath(ret *[]interface{}, cnt *int, m interface{}, keys []string, subkeys map[string]interface{}) { lenKeys := len(keys) // load 'm' values into 'ret' // expand any lists if lenKeys == 0 { switch m.(type) { case map[string]interface{}: if subkeys != nil { if ok := hasSubKeys(m, subkeys); !ok { return } } *ret = append(*ret, m) *cnt++ case []interface{}: for i, v := range m.([]interface{}) { if subkeys != nil { if ok := hasSubKeys(v, subkeys); !ok { continue // only load list members with subkeys } } *ret = append(*ret, (m.([]interface{}))[i]) *cnt++ } default: if subkeys != nil { return // must be map[string]interface{} if there are subkeys } *ret = append(*ret, m) *cnt++ } return } // key of interest key := keys[0] switch key { case "*": // wildcard - scan all values switch m.(type) { case map[string]interface{}: for _, v := range m.(map[string]interface{}) { // valuesForKeyPath(ret, v, keys[1:], subkeys) valuesForKeyPath(ret, cnt, v, keys[1:], subkeys) } case []interface{}: for _, v := range m.([]interface{}) { switch v.(type) { // flatten out a list of maps - keys are processed case map[string]interface{}: for _, vv := range v.(map[string]interface{}) { // valuesForKeyPath(ret, vv, keys[1:], subkeys) valuesForKeyPath(ret, cnt, vv, keys[1:], subkeys) } default: // valuesForKeyPath(ret, v, keys[1:], subkeys) valuesForKeyPath(ret, cnt, v, keys[1:], subkeys) } } } default: // key - must be map[string]interface{} switch m.(type) { case map[string]interface{}: if v, ok := m.(map[string]interface{})[key]; ok { // valuesForKeyPath(ret, v, keys[1:], subkeys) valuesForKeyPath(ret, cnt, v, keys[1:], subkeys) } case []interface{}: // may be buried in list for _, v := range m.([]interface{}) { switch v.(type) { case map[string]interface{}: if vv, ok := v.(map[string]interface{})[key]; ok { // valuesForKeyPath(ret, vv, keys[1:], subkeys) valuesForKeyPath(ret, cnt, vv, keys[1:], subkeys) } } } } } } // hasSubKeys() - interface{} equality works for string, float64, bool // 'v' must be a map[string]interface{} value to have subkeys // 'a' can have k:v pairs with v.(string) == "*", which is treated like a wildcard. func hasSubKeys(v interface{}, subkeys map[string]interface{}) bool { if len(subkeys) == 0 { return true } switch v.(type) { case map[string]interface{}: // do all subKey name:value pairs match? mv := v.(map[string]interface{}) for skey, sval := range subkeys { isNotKey := false if skey[:1] == "!" { // a NOT-key skey = skey[1:] isNotKey = true } vv, ok := mv[skey] if !ok { // key doesn't exist if isNotKey { // key not there, but that's what we want if kv, ok := sval.(string); ok && kv == "*" { continue } } return false } // wildcard check if kv, ok := sval.(string); ok && kv == "*" { if isNotKey { // key is there, and we don't want it return false } continue } switch sval.(type) { case string: if s, ok := vv.(string); ok && s == sval.(string) { if isNotKey { return false } continue } case bool: if b, ok := vv.(bool); ok && b == sval.(bool) { if isNotKey { return false } continue } case float64: if f, ok := vv.(float64); ok && f == sval.(float64) { if isNotKey { return false } continue } } // key there but didn't match subkey value if isNotKey { // that's what we want continue } return false } // all subkeys matched return true } // not a map[string]interface{} value, can't have subkeys return false } // Generate map of key:value entries as map[string]string. // 'kv' arguments are "name:value" pairs: attribute keys are designated with prepended hyphen, '-'. // If len(kv) == 0, the return is (nil, nil). func getSubKeyMap(kv ...string) (map[string]interface{}, error) { if len(kv) == 0 { return nil, nil } m := make(map[string]interface{}, 0) for _, v := range kv { vv := strings.Split(v, fieldSep) switch len(vv) { case 2: m[vv[0]] = interface{}(vv[1]) case 3: switch vv[2] { case "string", "char", "text": m[vv[0]] = interface{}(vv[1]) case "bool", "boolean": // ParseBool treats "1"==true & "0"==false b, err := strconv.ParseBool(vv[1]) if err != nil { return nil, fmt.Errorf("can't convert subkey value to bool: %s", vv[1]) } m[vv[0]] = interface{}(b) case "float", "float64", "num", "number", "numeric": f, err := strconv.ParseFloat(vv[1], 64) if err != nil { return nil, fmt.Errorf("can't convert subkey value to float: %s", vv[1]) } m[vv[0]] = interface{}(f) default: return nil, fmt.Errorf("unknown subkey conversion spec: %s", v) } default: return nil, fmt.Errorf("unknown subkey spec: %s", v) } } return m, nil } // ------------------------------- END of valuesFor ... ---------------------------- // ----------------------- locate where a key value is in the tree ------------------- //----------------------------- find all paths to a key -------------------------------- // PathsForKey returns all paths through Map, 'mv', (in dot-notation) that terminate with the specified key. // Results can be used with ValuesForPath. func (mv Map) PathsForKey(key string) []string { m := map[string]interface{}(mv) breadbasket := make(map[string]bool, 0) breadcrumbs := "" hasKeyPath(breadcrumbs, m, key, breadbasket) if len(breadbasket) == 0 { return nil } // unpack map keys to return res := make([]string, len(breadbasket)) var i int for k := range breadbasket { res[i] = k i++ } return res } // PathForKeyShortest extracts the shortest path from all possible paths - from PathsForKey() - in Map, 'mv'.. // Paths are strings using dot-notation. func (mv Map) PathForKeyShortest(key string) string { paths := mv.PathsForKey(key) lp := len(paths) if lp == 0 { return "" } if lp == 1 { return paths[0] } shortest := paths[0] shortestLen := len(strings.Split(shortest, ".")) for i := 1; i < len(paths); i++ { vlen := len(strings.Split(paths[i], ".")) if vlen < shortestLen { shortest = paths[i] shortestLen = vlen } } return shortest } // hasKeyPath - if the map 'key' exists append it to KeyPath.path and increment KeyPath.depth // This is really just a breadcrumber that saves all trails that hit the prescribed 'key'. func hasKeyPath(crumbs string, iv interface{}, key string, basket map[string]bool) { switch iv.(type) { case map[string]interface{}: vv := iv.(map[string]interface{}) if _, ok := vv[key]; ok { // create a new breadcrumb, intialized with the one we have var nbc string if crumbs == "" { nbc = key } else { nbc = crumbs + "." + key } basket[nbc] = true } // walk on down the path, key could occur again at deeper node for k, v := range vv { // create a new breadcrumb, intialized with the one we have var nbc string if crumbs == "" { nbc = k } else { nbc = crumbs + "." + k } hasKeyPath(nbc, v, key, basket) } case []interface{}: // crumb-trail doesn't change, pass it on for _, v := range iv.([]interface{}) { hasKeyPath(crumbs, v, key, basket) } } } var PathNotExistError = errors.New("Path does not exist") // ValueForPath wraps ValuesFor Path and returns the first value returned. // If no value is found it returns 'nil' and PathNotExistError. func (mv Map) ValueForPath(path string) (interface{}, error) { vals, err := mv.ValuesForPath(path) if err != nil { return nil, err } if len(vals) == 0 { return nil, PathNotExistError } return vals[0], nil } // ValuesForPathString returns the first found value for the path as a string. func (mv Map) ValueForPathString(path string) (string, error) { vals, err := mv.ValuesForPath(path) if err != nil { return "", err } if len(vals) == 0 { return "", errors.New("ValueForPath: path not found") } val := vals[0] return fmt.Sprintf("%v", val), nil } // ValueOrEmptyForPathString returns the first found value for the path as a string. // If the path is not found then it returns an empty string. func (mv Map) ValueOrEmptyForPathString(path string) string { str, _ := mv.ValueForPathString(path) return str } mxj-2.5.5/keyvalues2_test.go000066400000000000000000000020311402172443100157730ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) func TestSetSubkeyFieldSeparator(t *testing.T) { PrependAttrWithHyphen(true) fmt.Println("----------- TestSetSubkeyFieldSeparator") data := ` value 1 value 2 value 3 ` m, err := NewMapXml([]byte(data)) if err != nil { t.Fatal(err) } vals, err := m.ValuesForKey("elem", "-attr:2:text") if err != nil { t.Fatal(err) } if len(vals) != 1 { t.Fatal(":len(vals);", len(vals), vals) } if vals[0].(map[string]interface{})["#text"].(string) != "value 2" { t.Fatal(":expecting: value 2; got:", vals[0].(map[string]interface{})["#text"]) } SetFieldSeparator("|") defer SetFieldSeparator() vals, err = m.ValuesForKey("elem", "-attr|2|text") if err != nil { t.Fatal(err) } if len(vals) != 1 { t.Fatal("|len(vals);", len(vals), vals) } if vals[0].(map[string]interface{})["#text"].(string) != "value 2" { t.Fatal("|expecting: value 2; got:", vals[0].(map[string]interface{})["#text"]) } } mxj-2.5.5/keyvalues_test.go000066400000000000000000000254271402172443100157270ustar00rootroot00000000000000// keyvalues_test.go - test keyvalues.go methods package mxj import ( // "bytes" "fmt" // "io" "testing" ) func TestKVHeader(t *testing.T) { fmt.Println("\n---------------- keyvalues_test.go ...") } var doc1 = []byte(` William T. Gaddis The Recognitions One of the great seminal American novels of the 20th century. Austin Tappan Wright Islandia An example of earlier 20th century American utopian fiction. John Hawkes The Beetle Leg A lyrical novel about the construction of Ft. Peck Dam in Montana. T.E. Porter King's Day A magical novella. `) var doc2 = []byte(` William T. Gaddis The Recognitions One of the great seminal American novels of the 20th century. Something else. `) // the basic demo/test case - a small bibliography with mixed element types func TestPathsForKey(t *testing.T) { fmt.Println("PathsForKey, doc1 ...") m, merr := NewMapXml(doc1) if merr != nil { t.Fatal("merr:", merr.Error()) } fmt.Println("PathsForKey, doc1#author") ss := m.PathsForKey("author") fmt.Println("... ss:", ss) fmt.Println("PathsForKey, doc1#books") ss = m.PathsForKey("books") fmt.Println("... ss:", ss) fmt.Println("PathsForKey, doc2 ...") m, merr = NewMapXml(doc2) if merr != nil { t.Fatal("merr:", merr.Error()) } fmt.Println("PathForKey, doc2#book") ss = m.PathsForKey("book") fmt.Println("... ss:", ss) fmt.Println("PathForKeyShortest, doc2#book") s := m.PathForKeyShortest("book") fmt.Println("... s :", s) } func TestValuesForKey(t *testing.T) { fmt.Println("ValuesForKey ...") m, merr := NewMapXml(doc1) if merr != nil { t.Fatal("merr:", merr.Error()) } fmt.Println("ValuesForKey, doc1#author") ss, sserr := m.ValuesForKey("author") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { fmt.Println("... ss.v:", v) } fmt.Println("ValuesForKey, doc1#book") ss, sserr = m.ValuesForKey("book") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { fmt.Println("... ss.v:", v) } fmt.Println("ValuesForKey, doc1#book,-seq:3") ss, sserr = m.ValuesForKey("book", "-seq:3") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { fmt.Println("... ss.v:", v) } fmt.Println("ValuesForKey, doc1#book, author:William T. Gaddis") ss, sserr = m.ValuesForKey("book", "author:William T. Gaddis") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { fmt.Println("... ss.v:", v) } fmt.Println("ValuesForKey, doc1#author, -seq:1") ss, sserr = m.ValuesForKey("author", "-seq:1") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { // should be len(ss) == 0 fmt.Println("... ss.v:", v) } } func TestValuesForPath(t *testing.T) { fmt.Println("ValuesForPath ...") m, merr := NewMapXml(doc1) if merr != nil { t.Fatal("merr:", merr.Error()) } fmt.Println("ValuesForPath, doc.books.book.author") ss, sserr := m.ValuesForPath("doc.books.book.author") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { fmt.Println("... ss.v:", v) } fmt.Println("ValuesForPath, doc.books.book") ss, sserr = m.ValuesForPath("doc.books.book") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { fmt.Println("... ss.v:", v) } fmt.Println("ValuesForPath, doc.books.book -seq=3") ss, sserr = m.ValuesForPath("doc.books.book", "-seq:3") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { fmt.Println("... ss.v:", v) } fmt.Println("ValuesForPath, doc.books.* -seq=3") ss, sserr = m.ValuesForPath("doc.books.*", "-seq:3") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { fmt.Println("... ss.v:", v) } fmt.Println("ValuesForPath, doc.*.* -seq=3") ss, sserr = m.ValuesForPath("doc.*.*", "-seq:3") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { fmt.Println("... ss.v:", v) } } func TestValuesForNotKey(t *testing.T) { fmt.Println("ValuesForNotKey ...") m, merr := NewMapXml(doc1) if merr != nil { t.Fatal("merr:", merr.Error()) } fmt.Println("ValuesForPath, doc.books.book !author:William T. Gaddis") ss, sserr := m.ValuesForPath("doc.books.book", "!author:William T. Gaddis") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { fmt.Println("... ss.v:", v) } fmt.Println("ValuesForPath, doc.books.book !author:*") ss, sserr = m.ValuesForPath("doc.books.book", "!author:*") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { // expect len(ss) == 0 fmt.Println("... ss.v:", v) } fmt.Println("ValuesForPath, doc.books.book !unknown:*") ss, sserr = m.ValuesForPath("doc.books.book", "!unknown:*") if sserr != nil { t.Fatal("sserr:", sserr.Error()) } for _, v := range ss { fmt.Println("... ss.v:", v) } } func TestIAHeader(t *testing.T) { fmt.Println("\n---------------- indexedarray_test.go ...") } var ak_data = []byte(`{ "section1":{"data" : [{"F1" : "F1 data","F2" : "F2 data"},{"F1" : "demo 123","F2" : "abc xyz"}]}}`) var j_data = []byte(`{ "stuff":[ { "data":[ { "F":1 }, { "F":2 }, { "F":3 } ] }, { "data":[ 4, 5, 6 ] } ] }`) var x_data = []byte(` 1 2 3 4 5 6 `) func TestValuesForIndexedArray(t *testing.T) { j_main(t) x_main(t) ak_main(t) } func ak_main(t *testing.T) { fmt.Println("\nak_data:", string(ak_data)) m, merr := NewMapJson(ak_data) if merr != nil { t.Fatal("merr:", merr.Error()) return } fmt.Println("m:", m) v, verr := m.ValuesForPath("section1.data[0].F1") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("section1.data[0].F1:", v) } func j_main(t *testing.T) { fmt.Println("j_data:", string(j_data)) m, merr := NewMapJson(j_data) if merr != nil { t.Fatal("merr:", merr.Error()) return } fmt.Println("m:", m) v, verr := m.ValuesForPath("stuff[0]") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("stuff[0]:", v) v, verr = m.ValuesForPath("stuff.data") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("stuff.data:", v) v, verr = m.ValuesForPath("stuff[0].data") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("stuff[0].data:", v) v, verr = m.ValuesForPath("stuff.data[0]") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("stuff.data[0]:", v) v, verr = m.ValuesForPath("stuff.*[2]") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("stuff.*[2]:", v) v, verr = m.ValuesForPath("stuff.data.F") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("stuff.data.F:", v) v, verr = m.ValuesForPath("*.*.F") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("*.*.F:", v) v, verr = m.ValuesForPath("stuff.data[0].F") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("stuff.data[0].F:", v) v, verr = m.ValuesForPath("stuff.data[1].F") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("stuff.data[1].F:", v) v, verr = m.ValuesForPath("stuff[0].data[2]") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("stuff[0].data[2]:", v) v, verr = m.ValuesForPath("stuff[1].data[1]") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("stuff[1].data[1]:", v) v, verr = m.ValuesForPath("stuff[1].data[1].F") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("stuff[1].data[1].F", v) v, verr = m.ValuesForPath("stuff[1].data.F") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("stuff[1].data.F:", v) } func x_main(t *testing.T) { fmt.Println("\nx_data:", string(x_data)) m, merr := NewMapXml(x_data) if merr != nil { t.Fatal("merr:", merr.Error()) return } fmt.Println("m:", m) v, verr := m.ValuesForPath("doc.stuff[0]") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("doc.stuff[0]:", v) v, verr = m.ValuesForPath("doc.stuff.data[0]") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("doc.stuff.data[0]:", v) v, verr = m.ValuesForPath("doc.stuff.data[0]", "-seq:2.1") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("doc.stuff.data[0] -seq:2.1:", v) v, verr = m.ValuesForPath("doc.stuff.data[0].F") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("doc.stuff.data[0].F:", v) v, verr = m.ValuesForPath("doc.stuff[0].data[2]") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("doc.stuff[0].data[2]:", v) v, verr = m.ValuesForPath("doc.stuff[1].data[1].F") if verr != nil { t.Fatal("verr:", verr.Error()) } fmt.Println("doc.stuff[1].data[1].F:", v) } func TestValueForPath(t *testing.T) { m := map[string]interface{}{ "Div": map[string]interface{}{ "Colour": "blue", }, } mv := Map(m) v, err := mv.ValueForPath("Div.Colour") if err != nil { t.Fatal(err) } if str, ok := v.(string); !ok || str != "blue" { t.Fatal("wrong value") } } func TestValueForPathString(t *testing.T) { m := map[string]interface{}{ "Div": map[string]interface{}{ "Colour": "blue", }, } mv := Map(m) str, err := mv.ValueForPathString("Div.Colour") if err != nil { t.Fatal(err) } if str != "blue" { t.Fatal("wrong value") } } func TestValueForPathError(t *testing.T) { m := map[string]interface{}{ "Div": map[string]interface{}{ "Colour": "blue", }, } mv := Map(m) _, err := mv.ValueForPath("Color") if err != PathNotExistError { t.Fatal("no PathNotExistError returned") } } func TestValueForKey(t *testing.T) { m := map[string]interface{}{ "Div": map[string]interface{}{ "Colour": "blue", }, } mv := Map(m) v, err := mv.ValueForKey("Colour") if err != nil { t.Fatal(err) } if str, ok := v.(string); !ok || str != "blue" { t.Fatal("wrong value") } } func TestValueForKeyError(t *testing.T) { m := map[string]interface{}{ "Div": map[string]interface{}{ "Colour": "blue", }, } mv := Map(m) _, err := mv.ValueForKey("Color") if err != KeyNotExistError { t.Fatal("no KeyNotExistError returned") } } mxj-2.5.5/leafnode.go000066400000000000000000000064131402172443100144270ustar00rootroot00000000000000package mxj // leafnode.go - return leaf nodes with paths and values for the Map // inspired by: https://groups.google.com/forum/#!topic/golang-nuts/3JhuVKRuBbw import ( "strconv" "strings" ) const ( NoAttributes = true // suppress LeafNode values that are attributes ) // LeafNode - a terminal path value in a Map. // For XML Map values it represents an attribute or simple element value - of type // string unless Map was created using Cast flag. For JSON Map values it represents // a string, numeric, boolean, or null value. type LeafNode struct { Path string // a dot-notation representation of the path with array subscripting Value interface{} // the value at the path termination } // LeafNodes - returns an array of all LeafNode values for the Map. // The option no_attr argument suppresses attribute values (keys with prepended hyphen, '-') // as well as the "#text" key for the associated simple element value. // // PrependAttrWithHypen(false) will result in attributes having .attr-name as // terminal node in 'path' while the path for the element value, itself, will be // the base path w/o "#text". // // LeafUseDotNotation(true) causes list members to be identified using ".N" syntax // rather than "[N]" syntax. func (mv Map) LeafNodes(no_attr ...bool) []LeafNode { var a bool if len(no_attr) == 1 { a = no_attr[0] } l := make([]LeafNode, 0) getLeafNodes("", "", map[string]interface{}(mv), &l, a) return l } func getLeafNodes(path, node string, mv interface{}, l *[]LeafNode, noattr bool) { // if stripping attributes, then also strip "#text" key if !noattr || node != "#text" { if path != "" && node[:1] != "[" { path += "." } path += node } switch mv.(type) { case map[string]interface{}: for k, v := range mv.(map[string]interface{}) { // if noattr && k[:1] == "-" { if noattr && len(attrPrefix) > 0 && strings.Index(k, attrPrefix) == 0 { continue } getLeafNodes(path, k, v, l, noattr) } case []interface{}: for i, v := range mv.([]interface{}) { if useDotNotation { getLeafNodes(path, strconv.Itoa(i), v, l, noattr) } else { getLeafNodes(path, "["+strconv.Itoa(i)+"]", v, l, noattr) } } default: // can't walk any further, so create leaf n := LeafNode{path, mv} *l = append(*l, n) } } // LeafPaths - all paths that terminate in LeafNode values. func (mv Map) LeafPaths(no_attr ...bool) []string { ln := mv.LeafNodes() ss := make([]string, len(ln)) for i := 0; i < len(ln); i++ { ss[i] = ln[i].Path } return ss } // LeafValues - all terminal values in the Map. func (mv Map) LeafValues(no_attr ...bool) []interface{} { ln := mv.LeafNodes() vv := make([]interface{}, len(ln)) for i := 0; i < len(ln); i++ { vv[i] = ln[i].Value } return vv } // ====================== utilities ====================== // https://groups.google.com/forum/#!topic/golang-nuts/pj0C5IrZk4I var useDotNotation bool // LeafUseDotNotation sets a flag that list members in LeafNode paths // should be identified using ".N" syntax rather than the default "[N]" // syntax. Calling LeafUseDotNotation with no arguments toggles the // flag on/off; otherwise, the argument sets the flag value 'true'/'false'. func LeafUseDotNotation(b ...bool) { if len(b) == 0 { useDotNotation = !useDotNotation return } useDotNotation = b[0] } mxj-2.5.5/leafnode_test.go000066400000000000000000000053041402172443100154640ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) func TestLNHeader(t *testing.T) { fmt.Println("\n---------------- leafnode_test.go ...") } func TestLeafNodes(t *testing.T) { json1 := []byte(`{ "friends": [ { "skills": [ 44, 12 ] } ] }`) json2 := []byte(`{ "friends": { "skills": [ 44, 12 ] } }`) m, _ := NewMapJson(json1) ln := m.LeafNodes() fmt.Println("\njson1-LeafNodes:") for _, v := range ln { fmt.Printf("%#v\n", v) } p := m.LeafPaths() fmt.Println("\njson1-LeafPaths:") for _, v := range p { fmt.Printf("%#v\n", v) } m, _ = NewMapJson(json2) ln = m.LeafNodes() fmt.Println("\njson2-LeafNodes:") for _, v := range ln { fmt.Printf("%#v\n", v) } v := m.LeafValues() fmt.Println("\njson1-LeafValues:") for _, v := range v { fmt.Printf("%#v\n", v) } json3 := []byte(`{ "a":"list", "of":["data", "of", 3, "types", true]}`) m, _ = NewMapJson(json3) ln = m.LeafNodes() fmt.Println("\njson3-LeafNodes:") for _, v := range ln { fmt.Printf("%#v\n", v) } v = m.LeafValues() fmt.Println("\njson3-LeafValues:") for _, v := range v { fmt.Printf("%#v\n", v) } p = m.LeafPaths() fmt.Println("\njson3-LeafPaths:") for _, v := range p { fmt.Printf("%#v\n", v) } xmldata2 := []byte(` Item 2 is blue `) m, err := NewMapXml(xmldata2) if err != nil { t.Fatal(err.Error()) } fmt.Println("\nxml2data2-LeafValues:") ln = m.LeafNodes() for _, v := range ln { fmt.Printf("%#v\n", v) } fmt.Println("\nxml2data2-LeafValues(NoAttributes):") ln = m.LeafNodes(NoAttributes) for _, v := range ln { fmt.Printf("%#v\n", v) } // no-hyphen PrependAttrWithHyphen(false) m, err = NewMapXml(xmldata2) if err != nil { t.Fatal(err.Error()) } fmt.Println("\nno-hyphen-xml2data2-LeafValues:") ln = m.LeafNodes() for _, v := range ln { fmt.Printf("%#v\n", v) } fmt.Println("\nno-hyphen-xml2data2-LeafValues(NoAttributes):") ln = m.LeafNodes(NoAttributes) for _, v := range ln { fmt.Printf("%#v\n", v) } // restore default PrependAttrWithHyphen(true) } func TestLeafDotNotation(t *testing.T) { xmldata2 := []byte(` Item 2 is blue `) m, err := NewMapXml(xmldata2) if err != nil { t.Fatal(err.Error()) } fmt.Println("\nDotNotation-LeafValues:") LeafUseDotNotation() defer LeafUseDotNotation() ln := m.LeafNodes() for _, v := range ln { fmt.Printf("%#v\n", v) } } mxj-2.5.5/misc.go000066400000000000000000000047571402172443100136160ustar00rootroot00000000000000// Copyright 2016 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // misc.go - mimic functions (+others) called out in: // https://groups.google.com/forum/#!topic/golang-nuts/jm_aGsJNbdQ // Primarily these methods let you retrive XML structure information. package mxj import ( "fmt" "sort" "strings" ) // Return the root element of the Map. If there is not a single key in Map, // then an error is returned. func (mv Map) Root() (string, error) { mm := map[string]interface{}(mv) if len(mm) != 1 { return "", fmt.Errorf("Map does not have singleton root. Len: %d.", len(mm)) } for k, _ := range mm { return k, nil } return "", nil } // If the path is an element with sub-elements, return a list of the sub-element // keys. (The list is alphabeticly sorted.) NOTE: Map keys that are prefixed with // '-', a hyphen, are considered attributes; see m.Attributes(path). func (mv Map) Elements(path string) ([]string, error) { e, err := mv.ValueForPath(path) if err != nil { return nil, err } switch e.(type) { case map[string]interface{}: ee := e.(map[string]interface{}) elems := make([]string, len(ee)) var i int for k, _ := range ee { if len(attrPrefix) > 0 && strings.Index(k, attrPrefix) == 0 { continue // skip attributes } elems[i] = k i++ } elems = elems[:i] // alphabetic sort keeps things tidy sort.Strings(elems) return elems, nil } return nil, fmt.Errorf("no elements for path: %s", path) } // If the path is an element with attributes, return a list of the attribute // keys. (The list is alphabeticly sorted.) NOTE: Map keys that are not prefixed with // '-', a hyphen, are not treated as attributes; see m.Elements(path). Also, if the // attribute prefix is "" - SetAttrPrefix("") or PrependAttrWithHyphen(false) - then // there are no identifiable attributes. func (mv Map) Attributes(path string) ([]string, error) { a, err := mv.ValueForPath(path) if err != nil { return nil, err } switch a.(type) { case map[string]interface{}: aa := a.(map[string]interface{}) attrs := make([]string, len(aa)) var i int for k, _ := range aa { if len(attrPrefix) == 0 || strings.Index(k, attrPrefix) != 0 { continue // skip non-attributes } attrs[i] = k[len(attrPrefix):] i++ } attrs = attrs[:i] // alphabetic sort keeps things tidy sort.Strings(attrs) return attrs, nil } return nil, fmt.Errorf("no attributes for path: %s", path) } mxj-2.5.5/misc_test.go000066400000000000000000000125311402172443100146420ustar00rootroot00000000000000// misc_test.go package mxj import ( "fmt" "testing" ) var miscdata = []byte(` sub_value_1 sub_value_2 element_2 `) func TestMisc(t *testing.T) { PrependAttrWithHyphen(true) // be safe fmt.Println("\n------------------ misc_test.go ...") } func TestRoot(t *testing.T) { m, err := NewMapXml(miscdata) if err != nil { t.Fatal(err) } r, err := m.Root() if err != nil { t.Fatal(err) } if r != "doc" { t.Fatal("Root not doc:", r) } } func TestElements(t *testing.T) { m, err := NewMapXml(miscdata) if err != nil { t.Fatal(err) } e, err := m.Elements("doc") if err != nil { t.Fatal(err) } elist := []string{"elem1", "elem2"} for i, ee := range e { if ee != elist[i] { t.Fatal("error in list, elem#:", i, "-", ee, ":", elist[i]) } } e, err = m.Elements("doc.elem1") if err != nil { t.Fatal(err) } elist = []string{"sub1", "sub2"} for i, ee := range e { if ee != elist[i] { t.Fatal("error in list, elem#:", i, "-", ee, ":", elist[i]) } } } func TestAttributes(t *testing.T) { m, err := NewMapXml(miscdata) if err != nil { t.Fatal(err) } a, err := m.Attributes("doc.elem2") if err != nil { t.Fatal(err) } alist := []string{"name", "seq"} for i, aa := range a { if aa != alist[i] { t.Fatal("error in list, elem#:", i, "-", aa, ":", alist[i]) } } a, err = m.Attributes("doc.elem1.sub2") if err != nil { t.Fatal(err) } alist = []string{"name", "seq"} for i, aa := range a { if aa != alist[i] { t.Fatal("error in list, elem#:", i, "-", aa, ":", alist[i]) } } } func TestElementsAttrPrefix(t *testing.T) { SetAttrPrefix("__") m, err := NewMapXml(miscdata) if err != nil { t.Fatal(err) } e, err := m.Elements("doc") if err != nil { t.Fatal(err) } elist := []string{"elem1", "elem2"} for i, ee := range e { if ee != elist[i] { t.Fatal("error in list, elem#:", i, "-", ee, ":", elist[i]) } } e, err = m.Elements("doc.elem1") if err != nil { t.Fatal(err) } elist = []string{"sub1", "sub2"} for i, ee := range e { if ee != elist[i] { t.Fatal("error in list, elem#:", i, "-", ee, ":", elist[i]) } } } func TestAttributesAttrPrefix(t *testing.T) { SetAttrPrefix("__") m, err := NewMapXml(miscdata) if err != nil { t.Fatal(err) } a, err := m.Attributes("doc.elem2") if err != nil { t.Fatal(err) } alist := []string{"name", "seq"} for i, aa := range a { if aa != alist[i] { t.Fatal("error in list, elem#:", i, "-", aa, ":", alist[i]) } } a, err = m.Attributes("doc.elem1.sub2") if err != nil { t.Fatal(err) } alist = []string{"name", "seq"} for i, aa := range a { if aa != alist[i] { t.Fatal("error in list, elem#:", i, "-", aa, ":", alist[i]) } } } func TestElementsNoAttrPrefix(t *testing.T) { PrependAttrWithHyphen(false) m, err := NewMapXml(miscdata) if err != nil { t.Fatal(err) } e, err := m.Elements("doc") if err != nil { t.Fatal(err) } if len(e) != 2 { t.Fatal("didn't get 2 elements:", e) } e, err = m.Elements("doc.elem1") if err != nil { t.Fatal(err) } if len(e) != 4 { t.Fatal("didn't get 4 elements:", e) } PrependAttrWithHyphen(true) } func TestAttributesNoAttrPrefix(t *testing.T) { PrependAttrWithHyphen(false) m, err := NewMapXml(miscdata) if err != nil { t.Fatal(err) } a, err := m.Attributes("doc.elem2") if err != nil { t.Fatal(err) } if len(a) > 0 { t.Fatal("found attributes where there are none:", a) } a, err = m.Attributes("doc.elem1.sub2") if err != nil { t.Fatal(err) } if len(a) > 0 { t.Fatal("found attributes where there are none:", a) } PrependAttrWithHyphen(true) } var whiteSpaceData = []byte(" hello world ") func TestPreserveSpaceDisableByDefault(t *testing.T) { const ( path = "doc.elem3" input = " hello world " trimmed = "hello world" notTrimmed = input ) tcs := []struct { name string args []bool expectedOutput string }{ { name: "Default Preserve Space disabled should trim values", args: nil, // nil will result in the `DisableWhiteSpace` to be skipped expectedOutput: trimmed, }, { name: "Single true is passed should not trim values", args: []bool{true}, expectedOutput: notTrimmed, }, { name: "Single false is passed should trim values", args: []bool{false}, expectedOutput: trimmed, }, { name: "No args are passed should not trim values", args: []bool{}, expectedOutput: notTrimmed, }, { name: "Extra arguments should be ignored", args: []bool{true, false}, expectedOutput: notTrimmed, }, { name: "Extra arguments should be ignored with false", args: []bool{false, true}, expectedOutput: trimmed, }, } for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { if tc.args != nil { DisableTrimWhiteSpace(tc.args...) } m, err := NewMapXml(whiteSpaceData) if err != nil { t.Fatal(err) } s, err := m.ValueForPath(path) if err != nil { t.Fatal(err) } if s != tc.expectedOutput { t.Fatalf("expected '%s' got '%s'", tc.expectedOutput, s) } }) } // Set it back to false after all tests are done DisableTrimWhiteSpace(false) } mxj-2.5.5/mxj.go000066400000000000000000000063601402172443100134510ustar00rootroot00000000000000// mxj - A collection of map[string]interface{} and associated XML and JSON utilities. // Copyright 2012-2014 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file package mxj import ( "fmt" "sort" ) const ( Cast = true // for clarity - e.g., mxj.NewMapXml(doc, mxj.Cast) SafeEncoding = true // ditto - e.g., mv.Json(mxj.SafeEncoding) ) type Map map[string]interface{} // Allocate a Map. func New() Map { m := make(map[string]interface{}, 0) return m } // Cast a Map to map[string]interface{} func (mv Map) Old() map[string]interface{} { return mv } // Return a copy of mv as a newly allocated Map. If the Map only contains string, // numeric, map[string]interface{}, and []interface{} values, then it can be thought // of as a "deep copy." Copying a structure (or structure reference) value is subject // to the noted restrictions. // NOTE: If 'mv' includes structure values with, possibly, JSON encoding tags // then only public fields of the structure are in the new Map - and with // keys that conform to any encoding tag instructions. The structure itself will // be represented as a map[string]interface{} value. func (mv Map) Copy() (Map, error) { // this is the poor-man's deep copy // not efficient, but it works j, jerr := mv.Json() // must handle, we don't know how mv got built if jerr != nil { return nil, jerr } return NewMapJson(j) } // --------------- StringIndent ... from x2j.WriteMap ------------- // Pretty print a Map. func (mv Map) StringIndent(offset ...int) string { return writeMap(map[string]interface{}(mv), true, true, offset...) } // Pretty print a Map without the value type information - just key:value entries. func (mv Map) StringIndentNoTypeInfo(offset ...int) string { return writeMap(map[string]interface{}(mv), false, true, offset...) } // writeMap - dumps the map[string]interface{} for examination. // 'typeInfo' causes value type to be printed. // 'offset' is initial indentation count; typically: Write(m). func writeMap(m interface{}, typeInfo, root bool, offset ...int) string { var indent int if len(offset) == 1 { indent = offset[0] } var s string switch m.(type) { case []interface{}: if typeInfo { s += "[[]interface{}]" } for _, v := range m.([]interface{}) { s += "\n" for i := 0; i < indent; i++ { s += " " } s += writeMap(v, typeInfo, false, indent+1) } case map[string]interface{}: list := make([][2]string, len(m.(map[string]interface{}))) var n int for k, v := range m.(map[string]interface{}) { list[n][0] = k list[n][1] = writeMap(v, typeInfo, false, indent+1) n++ } sort.Sort(mapList(list)) for _, v := range list { if root { root = false } else { s += "\n" } for i := 0; i < indent; i++ { s += " " } s += v[0] + " : " + v[1] } default: if typeInfo { s += fmt.Sprintf("[%T] %+v", m, m) } else { s += fmt.Sprintf("%+v", m) } } return s } // ======================== utility =============== type mapList [][2]string func (ml mapList) Len() int { return len(ml) } func (ml mapList) Swap(i, j int) { ml[i], ml[j] = ml[j], ml[i] } func (ml mapList) Less(i, j int) bool { return ml[i][0] <= ml[j][0] } mxj-2.5.5/mxj_test.go000066400000000000000000000022301402172443100145000ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) func TestMxjHeader(t *testing.T) { fmt.Println("\n---------------- mxj_test.go ...") } func TestMap(t *testing.T) { m := New() m["key"] = interface{}("value") v := map[string]interface{}{"bool": true, "float": 3.14159, "string": "Now is the time"} vv := []interface{}{3.1415962535, false, "for all good men"} v["listkey"] = interface{}(vv) m["newkey"] = interface{}(v) fmt.Println("TestMap, m:") fmt.Printf("%#v\n", m) fmt.Println("TestMap, StringIndent -") fmt.Println(m.StringIndent()) fmt.Println("TestMap, StringIndent NoTypeInfo -") fmt.Println(m.StringIndentNoTypeInfo()) o := interface{}(m.Old()) switch o.(type) { case map[string]interface{}: // do nothing default: t.Fatal("invalid type for m.Old()") } m, _ = NewMapXml([]byte(`HelloWorld`)) fmt.Println("TestMap, m_fromXML:") fmt.Printf("%#v\n", m) fmt.Println("TestMap, StringIndent -") fmt.Println( m.StringIndent()) fmt.Println("TestMap, StringIndent NoTypeInfo -") fmt.Println( m.StringIndentNoTypeInfo()) mm, _ := m.Copy() fmt.Println("TestMap, m.Copy() -\n", mm) } mxj-2.5.5/namespace_test.go000066400000000000000000000012431402172443100156410ustar00rootroot00000000000000package mxj import ( "fmt" "testing" ) func TestNamespaceHeader(t *testing.T) { fmt.Println("\n---------------- namespace_test.go ...") } func TestBeautifyXml(t *testing.T) { fmt.Println("\n---------------- TestBeautifyXml ...") const flatxml = `123John Brown` v, err := BeautifyXml([]byte(flatxml), "", " ") if err != nil { t.Fatal(err) } fmt.Println(flatxml) fmt.Println(string(v)) } mxj-2.5.5/nan_test.go000066400000000000000000000026511402172443100144650ustar00rootroot00000000000000// nan_test.go package mxj import ( "fmt" "testing" ) func TestNan(t *testing.T) { fmt.Println("\n------------ TestNan ...") data := []byte("NAN") m, err := NewMapXml(data, true) if err != nil { t.Fatal("err:", err) } v, err := m.ValueForPath("foo.bar") if err != nil { t.Fatal("err:", err) } if _, ok := v.(string); !ok { t.Fatal("v not string") } fmt.Println("foo.bar:", v) } func TestInf(t *testing.T) { data := []byte("INF") m, err := NewMapXml(data, true) if err != nil { t.Fatal("err:", err) } v, err := m.ValueForPath("foo.bar") if err != nil { t.Fatal("err:", err) } if _, ok := v.(string); !ok { t.Fatal("v not string") } fmt.Println("foo.bar:", v) } func TestMinusInf(t *testing.T) { data := []byte("-INF") m, err := NewMapXml(data, true) if err != nil { t.Fatal("err:", err) } v, err := m.ValueForPath("foo.bar") if err != nil { t.Fatal("err:", err) } if _, ok := v.(string); !ok { t.Fatal("v not string") } fmt.Println("foo.bar:", v) } func TestCastNanInf(t *testing.T) { data := []byte("NAN") CastNanInf(true) m, err := NewMapXml(data, true) if err != nil { t.Fatal("err:", err) } v, err := m.ValueForPath("foo.bar") if err != nil { t.Fatal("err:", err) } if _, ok := v.(float64); !ok { fmt.Printf("%#v\n", v) t.Fatal("v not float64") } fmt.Println("foo.bar:", v) } mxj-2.5.5/newmap.go000066400000000000000000000133441402172443100141420ustar00rootroot00000000000000// mxj - A collection of map[string]interface{} and associated XML and JSON utilities. // Copyright 2012-2014, 2018 Charles Banning. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file // remap.go - build a new Map from the current Map based on keyOld:keyNew mapppings // keys can use dot-notation, keyOld can use wildcard, '*' // // Computational strategy - // Using the key path - []string - traverse a new map[string]interface{} and // insert the oldVal as the newVal when we arrive at the end of the path. // If the type at the end is nil, then that is newVal // If the type at the end is a singleton (string, float64, bool) an array is created. // If the type at the end is an array, newVal is just appended. // If the type at the end is a map, it is inserted if possible or the map value // is converted into an array if necessary. package mxj import ( "errors" "strings" ) // (Map)NewMap - create a new Map from data in the current Map. // 'keypairs' are key mappings "oldKey:newKey" and specify that the current value of 'oldKey' // should be the value for 'newKey' in the returned Map. // - 'oldKey' supports dot-notation as described for (Map)ValuesForPath() // - 'newKey' supports dot-notation but with no wildcards, '*', or indexed arrays // - "oldKey" is shorthand for the keypair value "oldKey:oldKey" // - "oldKey:" and ":newKey" are invalid keypair values // - if 'oldKey' does not exist in the current Map, it is not written to the new Map. // "null" is not supported unless it is the current Map. // - see newmap_test.go for several syntax examples // - mv.NewMap() == mxj.New() // // NOTE: "examples/partial.go" shows how to create arbitrary sub-docs of an XML doc. func (mv Map) NewMap(keypairs ...string) (Map, error) { n := make(map[string]interface{}, 0) if len(keypairs) == 0 { return n, nil } // loop through the pairs var oldKey, newKey string var path []string for _, v := range keypairs { if len(v) == 0 { continue // just skip over empty keypair arguments } // initialize oldKey, newKey and check vv := strings.Split(v, ":") if len(vv) > 2 { return n, errors.New("oldKey:newKey keypair value not valid - " + v) } if len(vv) == 1 { oldKey, newKey = vv[0], vv[0] } else { oldKey, newKey = vv[0], vv[1] } strings.TrimSpace(oldKey) strings.TrimSpace(newKey) if i := strings.Index(newKey, "*"); i > -1 { return n, errors.New("newKey value cannot contain wildcard character - " + v) } if i := strings.Index(newKey, "["); i > -1 { return n, errors.New("newKey value cannot contain indexed arrays - " + v) } if oldKey == "" || newKey == "" { return n, errors.New("oldKey or newKey is not specified - " + v) } // get oldKey value oldVal, err := mv.ValuesForPath(oldKey) if err != nil { return n, err } if len(oldVal) == 0 { continue // oldKey has no value, may not exist in mv } // break down path path = strings.Split(newKey, ".") if path[len(path)-1] == "" { // ignore a trailing dot in newKey spec path = path[:len(path)-1] } addNewVal(&n, path, oldVal) } return n, nil } // navigate 'n' to end of path and add val func addNewVal(n *map[string]interface{}, path []string, val []interface{}) { // newVal - either singleton or array var newVal interface{} if len(val) == 1 { newVal = val[0] // is type interface{} } else { newVal = interface{}(val) } // walk to the position of interest, create it if necessary m := (*n) // initialize map walker var k string // key for m lp := len(path) - 1 // when to stop looking for i := 0; i < len(path); i++ { k = path[i] if i == lp { break } var nm map[string]interface{} // holds position of next-map switch m[k].(type) { case nil: // need a map for next node in path, so go there nm = make(map[string]interface{}, 0) m[k] = interface{}(nm) m = m[k].(map[string]interface{}) case map[string]interface{}: // OK - got somewhere to walk to, go there m = m[k].(map[string]interface{}) case []interface{}: // add a map and nm points to new map unless there's already // a map in the array, then nm points there // The placement of the next value in the array is dependent // on the sequence of members - could land on a map or a nil // value first. TODO: how to test this. a := make([]interface{}, 0) var foundmap bool for _, vv := range m[k].([]interface{}) { switch vv.(type) { case nil: // doesn't appear that this occurs, need a test case if foundmap { // use the first one in array a = append(a, vv) continue } nm = make(map[string]interface{}, 0) a = append(a, interface{}(nm)) foundmap = true case map[string]interface{}: if foundmap { // use the first one in array a = append(a, vv) continue } nm = vv.(map[string]interface{}) a = append(a, vv) foundmap = true default: a = append(a, vv) } } // no map found in array if !foundmap { nm = make(map[string]interface{}, 0) a = append(a, interface{}(nm)) } m[k] = interface{}(a) // must insert in map m = nm default: // it's a string, float, bool, etc. aa := make([]interface{}, 0) nm = make(map[string]interface{}, 0) aa = append(aa, m[k], nm) m[k] = interface{}(aa) m = nm } } // value is nil, array or a singleton of some kind // initially m.(type) == map[string]interface{} v := m[k] switch v.(type) { case nil: // initialized m[k] = newVal case []interface{}: a := m[k].([]interface{}) a = append(a, newVal) m[k] = interface{}(a) default: // v exists:string, float64, bool, map[string]interface, etc. a := make([]interface{}, 0) a = append(a, v, newVal) m[k] = interface{}(a) } } mxj-2.5.5/newmap_test.go000066400000000000000000000055101402172443100151750ustar00rootroot00000000000000package mxj import ( "bytes" "fmt" "io" "testing" ) func TestNewMapHeader(t *testing.T) { fmt.Println("\n---------------- newmap_test.go ...") } func TestNewMap(t *testing.T) { j := []byte(`{ "A":"this", "B":"is", "C":"a", "D":"test" }`) fmt.Println("j:", string(j)) m, _ := NewMapJson(j) fmt.Printf("m: %#v\n", m) fmt.Println("\n", `eval - m.NewMap("A:AA", "B:BB", "C:cc", "D:help")`) n, err := m.NewMap("A:AA", "B:BB", "C:cc", "D:help") if err != nil { fmt.Println("err:", err.Error()) } j, _ = n.Json() fmt.Println("n.Json():", string(j)) x, _ := n.Xml() fmt.Println("n.Xml():\n", string(x)) x, _ = n.XmlIndent("", " ") fmt.Println("n.XmlIndent():\n", string(x)) fmt.Println("\n", `eval - m.NewMap("A:AA.A", "B:AA.B", "C:AA.B.cc", "D:hello.help")`) n, err = m.NewMap("A:AA.A", "B:AA.B", "C:AA.B.cc", "D:hello.help") if err != nil { fmt.Println("err:", err.Error()) } j, _ = n.Json() fmt.Println("n.Json():", string(j)) x, _ = n.Xml() fmt.Println("n.Xml():\n", string(x)) x, _ = n.XmlIndent("", " ") fmt.Println("n.XmlIndent():\n", string(x)) var keypairs = []string{"A:xml.AA", "B:xml.AA.hello.again", "C:xml.AA", "D:xml.AA.hello.help"} fmt.Println("\n", `eval - m.NewMap keypairs:`, keypairs) n, err = m.NewMap(keypairs...) if err != nil { fmt.Println("err:", err.Error()) } j, _ = n.Json() fmt.Println("n.Json():", string(j)) x, _ = n.Xml() fmt.Println("n.Xml():\n", string(x)) x, _ = n.XmlIndent("", " ") fmt.Println("n.XmlIndent():\n", string(x)) } // Need to normalize from an XML stream the values for "netid" and "idnet". // Solution: make everything "netid" // Demo how to re-label a key using mv.NewMap() var msg1 = []byte(` no default:text default:word `) var msg2 = []byte(` yes default:text default:word `) func TestNetId(t *testing.T) { // let's create a message stream buf := new(bytes.Buffer) // load a couple of messages into it _, _ = buf.Write(msg1) _, _ = buf.Write(msg2) n := 0 for { n++ // read the stream as Map values - quit on io.EOF m, raw, merr := NewMapXmlReaderRaw(buf) if merr != nil && merr != io.EOF { // handle error - for demo we just print it and continue fmt.Printf("msg: %d - merr: %s\n", n, merr.Error()) continue } else if merr == io.EOF { break } // the first keypair retains values if data correct // the second keypair relabels "idnet" to "netid" n, _ := m.NewMap("data.netid", "data.idnet:data.netid") x, _ := n.XmlIndent("", " ") fmt.Println("original value:", string(raw)) fmt.Println("new value:") fmt.Println(string(x)) } } mxj-2.5.5/readme.md000066400000000000000000000264261402172443100141100ustar00rootroot00000000000000