diff --git a/go.mod b/go.mod index da66317..9de96e5 100644 --- a/go.mod +++ b/go.mod @@ -1,26 +1,20 @@ module github.com/diamondburned/cchat-gtk -go 1.14 +go 1.16 -replace github.com/gotk3/gotk3 => github.com/diamondburned/gotk3 v0.0.0-20210223232102-0ce0ad615fb2 - -// replace github.com/diamondburned/cchat-discord => ../cchat-discord -// replace github.com/diamondburned/gotk3-tcmalloc => ../../gotk3-tcmalloc -// replace github.com/diamondburned/ningen/v2 => ../../ningen -// replace github.com/diamondburned/arikawa/v2 => ../../arikawa +replace github.com/diamondburned/cchat-discord => ../cchat-discord require ( github.com/Xuanwo/go-locale v1.0.0 github.com/alecthomas/chroma v0.7.3 - github.com/diamondburned/cchat v0.3.17 - github.com/diamondburned/cchat-discord v0.0.0-20210107014523-4fefdf1b9332 - github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db + github.com/diamondburned/cchat v0.6.4 + github.com/diamondburned/cchat-discord v0.0.0-20210326063953-deb4ccb32bff github.com/diamondburned/gspell v0.0.0-20201229064336-e43698fd5828 - github.com/diamondburned/handy v0.0.0-20201229063418-ec23c1370374 + github.com/diamondburned/handy v0.0.0-20210329054445-387ad28eb2c2 github.com/diamondburned/imgutil v0.0.0-20200710174014-8a3be144a972 github.com/disintegration/imaging v1.6.2 github.com/goodsign/monday v1.0.0 - github.com/gotk3/gotk3 v0.4.1-0.20200524052254-cb2aa31c6194 + github.com/gotk3/gotk3 v0.5.3-0.20210326060404-6328e5470ece github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 github.com/peterbourgon/diskv v2.0.1+incompatible github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index 8c68a87..1cb53fc 100644 --- a/go.sum +++ b/go.sum @@ -6,16 +6,24 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.53.0 h1:MZQCQQaRwOrAcuKjiHWHrgKykt4fZyuwF2dtiG3fGW8= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0 h1:sAbMqjY1PEQKZBWfbu6Y6bsupJ9c4QdHnzg/VvYTLcE= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/datastore v1.0.0 h1:Kt+gOPPp2LEPWp8CSfxhsM8ik9CcyE/gYu+0r+RnZvM= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0 h1:9/vpR43S4aJaROxqQHQ3nH9lfyKKV0dC3vOmnw8ebQQ= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0 h1:RPUcBvDeYgQFMfQu1eBMq6piD1SXmLH+vK3qjewZPus= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Pallinder/go-randomdata v1.2.0 h1:DZ41wBchNRb/0GfsePLiSwb0PHZmT67XY00lCDlaYPg= github.com/Pallinder/go-randomdata v1.2.0/go.mod h1:yHmJgulpD2Nfrm0cR9tI/+oAgRqCQQixsA8HyRZfV9Y= @@ -27,19 +35,26 @@ github.com/alecthomas/chroma v0.7.3 h1:NfdAERMy+esYQs8OXk0I868/qDxxCEo7FMz1WIqMA github.com/alecthomas/chroma v0.7.3/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM= github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721 h1:JHZL0hZKJ1VENNfmXvHbgYlbUOvpzYzvy2aZU5gXVeo= github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0= +github.com/alecthomas/kong v0.2.4 h1:Y0ZBCHAvHhTHw7FFJ2FzCAAG4pkbTgA45nc7BpMhDNk= github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE= github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897 h1:p9Sln00KOTlrYkxI1zYWl1QLnEqAqEARBEYa8FQnQcY= github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ= +github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 h1:y5HC9v93H5EPKqaS1UYVg1uYah5Xf51mBfIoWehClUQ= github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk= github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= +github.com/dave/jennifer v1.4.1 h1:XyqG6cn5RQsTj3qlWQTKlRGAyrTcsk1kUmWdZBzRjDw= github.com/dave/jennifer v1.4.1/go.mod h1:7jEdnm+qBcxl8PC0zyp7vxcpSRnzXSt9r39tpTVGlwA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -60,12 +75,28 @@ github.com/diamondburned/arikawa/v2 v2.0.0-20210105213913-8a213759164c h1:6n1EqF github.com/diamondburned/arikawa/v2 v2.0.0-20210105213913-8a213759164c/go.mod h1:e+lhS20ni2luFEU06Pc8paCxgZL99/RZb77dOC82CF0= github.com/diamondburned/arikawa/v2 v2.0.0-20210106050916-771591e5eb65 h1:foJMpT+BAoASVzDj9WDxNp6/OxnWnQ/uUHk2DXARP/Y= github.com/diamondburned/arikawa/v2 v2.0.0-20210106050916-771591e5eb65/go.mod h1:e+lhS20ni2luFEU06Pc8paCxgZL99/RZb77dOC82CF0= +github.com/diamondburned/arikawa/v2 v2.0.5 h1:X/jPfeEFj/Hzk26kudNJqtVkQb3vnh3tAjEF1mY7GK8= +github.com/diamondburned/arikawa/v2 v2.0.5/go.mod h1:e+lhS20ni2luFEU06Pc8paCxgZL99/RZb77dOC82CF0= github.com/diamondburned/cchat v0.3.11 h1:C1f9Tp7Kz3t+T1SlepL1RS7b/kACAKWAIZXAgJEpCHg= github.com/diamondburned/cchat v0.3.11/go.mod h1:IlMtF+XIvAJh0GL/2yFdf0/34w+Hdy5A1GgvSwAXtQI= github.com/diamondburned/cchat v0.3.15 h1:BJf8ZiRtDWTGMtQ3QqjNU0H+784WSrkJEpFGkKY5gEw= github.com/diamondburned/cchat v0.3.15/go.mod h1:IlMtF+XIvAJh0GL/2yFdf0/34w+Hdy5A1GgvSwAXtQI= github.com/diamondburned/cchat v0.3.17 h1:pGwas8Y0SBU7yg4EQ/MvrbqZhrnRhPBYm1AiRsL147s= github.com/diamondburned/cchat v0.3.17/go.mod h1:IlMtF+XIvAJh0GL/2yFdf0/34w+Hdy5A1GgvSwAXtQI= +github.com/diamondburned/cchat v0.5.4 h1:0N/H+zs4T6YBOP5dtUnJ+paZfq06772b5CXRw7bWx7U= +github.com/diamondburned/cchat v0.5.4/go.mod h1:IlMtF+XIvAJh0GL/2yFdf0/34w+Hdy5A1GgvSwAXtQI= +github.com/diamondburned/cchat v0.5.5 h1:YgI98ID9UQAgHbLFEyHQ2qcAJ5A2HcVZaq+A26njAQo= +github.com/diamondburned/cchat v0.5.5/go.mod h1:IlMtF+XIvAJh0GL/2yFdf0/34w+Hdy5A1GgvSwAXtQI= +github.com/diamondburned/cchat v0.5.6 h1:U6f41fEtXgs+fdmk0q9ouQsfzY7nQzp9N8fV0FfEbv0= +github.com/diamondburned/cchat v0.5.6/go.mod h1:IlMtF+XIvAJh0GL/2yFdf0/34w+Hdy5A1GgvSwAXtQI= +github.com/diamondburned/cchat v0.6.0 h1:XVql8slOho9FUxuJm/I7/XWr5l1XgxLc5SvcvI+ybp4= +github.com/diamondburned/cchat v0.6.0/go.mod h1:IlMtF+XIvAJh0GL/2yFdf0/34w+Hdy5A1GgvSwAXtQI= +github.com/diamondburned/cchat v0.6.1 h1:BFpY2Nvnut1/X+0dhL8STK80RVmfEJLmf4ppTJX2ADg= +github.com/diamondburned/cchat v0.6.1/go.mod h1:IlMtF+XIvAJh0GL/2yFdf0/34w+Hdy5A1GgvSwAXtQI= +github.com/diamondburned/cchat v0.6.2 h1:H0Hyd2irpKlTR03ulm6IMy7RVorPtvQS5X0kTn26Up8= +github.com/diamondburned/cchat v0.6.2/go.mod h1:IlMtF+XIvAJh0GL/2yFdf0/34w+Hdy5A1GgvSwAXtQI= +github.com/diamondburned/cchat v0.6.4 h1:CFh6eFNE+SQ7IOjb1QDcgTgv/I7W2k6E7d3n8qJ+ZrQ= +github.com/diamondburned/cchat v0.6.4/go.mod h1:IlMtF+XIvAJh0GL/2yFdf0/34w+Hdy5A1GgvSwAXtQI= github.com/diamondburned/cchat-discord v0.0.0-20201220054426-918719599f2d h1:n61DxLdX7nPj7KA1N/azaR8wa0pnDBDT6Yi1seOsBWM= github.com/diamondburned/cchat-discord v0.0.0-20201220054426-918719599f2d/go.mod h1:pvp1TOHK7NUM+GDRPixQGsKyCSbGYhiseK2jM+1I+ms= github.com/diamondburned/cchat-discord v0.0.0-20201220081640-288591a535af h1:pTdxsrVSYCdraGormbu1t8uQJMe/OD/ZIz9KljDWAvc= @@ -98,6 +129,22 @@ github.com/diamondburned/cchat-discord v0.0.0-20210107010729-8edbbcc24992 h1:njL github.com/diamondburned/cchat-discord v0.0.0-20210107010729-8edbbcc24992/go.mod h1:g+RqSLt/ccZZVZbsukOiCwQCqKM/9HfHMJVboIUW+tU= github.com/diamondburned/cchat-discord v0.0.0-20210107014523-4fefdf1b9332 h1:nGOfPHgujDdvltCkzMiKhldlo9qLyflT8weG+xWOi2E= github.com/diamondburned/cchat-discord v0.0.0-20210107014523-4fefdf1b9332/go.mod h1:g+RqSLt/ccZZVZbsukOiCwQCqKM/9HfHMJVboIUW+tU= +github.com/diamondburned/cchat-discord v0.0.0-20210318171231-71f2e1570400 h1:RwU9SqiWT/iqrosB0Nz54t1CRjMTP/XhZYUIT+jirgE= +github.com/diamondburned/cchat-discord v0.0.0-20210318171231-71f2e1570400/go.mod h1:OoF9yCU2eZmC8fNh7rJ+xaANLPsH8EWzFR7QG13UWLM= +github.com/diamondburned/cchat-discord v0.0.0-20210318194307-9dc28023dac5 h1:Zh3qkQmJowAdE6G8/hQJ8TLnTo03IDbCW9Lq/mIV4Ko= +github.com/diamondburned/cchat-discord v0.0.0-20210318194307-9dc28023dac5/go.mod h1:hkAXdLdcTYb87ZTBvfEopEavbs8x7xPygJGpK5Z2Es8= +github.com/diamondburned/cchat-discord v0.0.0-20210318212724-ba43f691bccc h1:sRXWos0PGQ7JrASu35AnF6tsT0wN3ZC9r5OTVNusr5k= +github.com/diamondburned/cchat-discord v0.0.0-20210318212724-ba43f691bccc/go.mod h1:ZFzQ34q1tr3ci5HRyqzbmoth7HMsXO9iTXImc112Yeg= +github.com/diamondburned/cchat-discord v0.0.0-20210320000032-f3e0d38c382d h1:tBcY8AqCXDq+hicxQGuFj8HTWt+3YnjfinexNbniWSA= +github.com/diamondburned/cchat-discord v0.0.0-20210320000032-f3e0d38c382d/go.mod h1:H5UuKeE097pqWKvWwdwEBIByO6chZgTva1qsiE8Jm4Q= +github.com/diamondburned/cchat-discord v0.0.0-20210320051719-18eb6081460f h1:alREboGThGvNzYFq+bqdhrntYvpClvkMAsnc3xblMZU= +github.com/diamondburned/cchat-discord v0.0.0-20210320051719-18eb6081460f/go.mod h1:yn0CA0/JyIs3U8v+B487DQWg2037ePvqcTZS1CZQGVA= +github.com/diamondburned/cchat-discord v0.0.0-20210325233237-f9814bf4101b h1:l35x20NdcMWnEbGyNSS0K+PDXbTclCMCK2n0hU8pV/U= +github.com/diamondburned/cchat-discord v0.0.0-20210325233237-f9814bf4101b/go.mod h1:zbm+BpkQOMD6s87x4FrP3lTt9ddJLWTTPXyMROT+LZs= +github.com/diamondburned/cchat-discord v0.0.0-20210326063215-9eb392a95413 h1:r6PAQX0PhUXVB7Uuxd9BNNOvNXBs73DUIlNSjDXHqFk= +github.com/diamondburned/cchat-discord v0.0.0-20210326063215-9eb392a95413/go.mod h1:zbm+BpkQOMD6s87x4FrP3lTt9ddJLWTTPXyMROT+LZs= +github.com/diamondburned/cchat-discord v0.0.0-20210326063953-deb4ccb32bff h1:p5XYPavnJ89wrJAf4ns6f1OfHQz5NMU9uXlX3EiKdfU= +github.com/diamondburned/cchat-discord v0.0.0-20210326063953-deb4ccb32bff/go.mod h1:zbm+BpkQOMD6s87x4FrP3lTt9ddJLWTTPXyMROT+LZs= github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db h1:VQI2PdbsdsRJ7d669kp35GbCUO44KZ0Xfqdu4o/oqVg= github.com/diamondburned/cchat-mock v0.0.0-20201115033644-df8d1b10f9db/go.mod h1:M87kjNzWVPlkZycFNzpGPKQXzkHNnZphuwMf3E9ckgc= github.com/diamondburned/gotk3 v0.0.0-20201209182406-e7291341a091 h1:lQpSWzbi3rQf66aMSip/rIypasIFwqCqF0Wfn5og6gw= @@ -138,6 +185,10 @@ github.com/diamondburned/handy v0.0.0-20200829011954-4667e7a918f4 h1:qF5VHC35+Gy github.com/diamondburned/handy v0.0.0-20200829011954-4667e7a918f4/go.mod h1:V0qyhW4v6KPFwtDpXdBm5aWH7zWEyrzZpcB6MPnKArQ= github.com/diamondburned/handy v0.0.0-20201229063418-ec23c1370374 h1:1KLPz5mbYF7t3ajrK55alkDcbjWc+7aQFjKzV9qJRN4= github.com/diamondburned/handy v0.0.0-20201229063418-ec23c1370374/go.mod h1:9EiMOAKWhEFoVnFLTco2v0v0rJn855YAHDDa2bL8urU= +github.com/diamondburned/handy v0.0.0-20210317194712-ec07079c938b h1:vcu2dF4RyJM+w3nRgNsbOnGjdf/Bxd5etjyNJJ8trvY= +github.com/diamondburned/handy v0.0.0-20210317194712-ec07079c938b/go.mod h1:WsMP6/3+U5b8ZmIn7MilCXHhhph1uvqkBRr86Fubm+k= +github.com/diamondburned/handy v0.0.0-20210329054445-387ad28eb2c2 h1:fIQVMaOTWAcv6nThIyzKuyAO/GccwtVYDovnEpFFXGs= +github.com/diamondburned/handy v0.0.0-20210329054445-387ad28eb2c2/go.mod h1:+edD3Anr1+QF0HjgOUFJRkPiVAt0mj3IczvZc+yIuvo= github.com/diamondburned/imgutil v0.0.0-20200710174014-8a3be144a972 h1:OWxllHbUptXzDias6YI4MM0R3o50q8MfhkkwVIlfiNo= github.com/diamondburned/imgutil v0.0.0-20200710174014-8a3be144a972/go.mod h1:kBQKaukR/LyCfhED99/T4/XxUMDNEEzf1Fx6vreD3RQ= github.com/diamondburned/ningen/v2 v2.0.0-20201219070301-15610044db9a h1:w8CWPYiwH9p2XGlHHeTqRWx7e8CJJLN8i4orAkOa27Y= @@ -160,25 +211,33 @@ github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473 h1:4cmBvAEBNJaGARUEs3/suWRyfyBfhf7I60WBZq+bv2w= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72 h1:b+9H1GAsx5RsjvDFLoS5zkNBzIQMuVKUYQDmxU3N5XE= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/godbus/dbus v4.1.0+incompatible h1:WqqLRTsQic3apZUK9qC5sGNfXthmPXzUZ7nQPrNITa4= github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0 h1:Rd1kQnQu0Hq3qvJppYSG0HtP+f5LPPUiDswTLiEegLg= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/goodsign/monday v1.0.0 h1:Yyk/s/WgudMbAJN6UWSU5xAs8jtNewfqtVblAlw0yoc= github.com/goodsign/monday v1.0.0/go.mod h1:r4T4breXpoFwspQNM+u2sLxJb2zyTaxVGqUfTBjWOu8= @@ -188,13 +247,18 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12 h1:TgXhFz35pKlZuUz1pNlOKk1UCSXPpuUIc144Wd7SxCA= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -202,12 +266,21 @@ github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gotk3/gotk3 v0.4.0/go.mod h1:Eew3QBwAOBTrfFFDmsDE5wZWbcagBL1NUslj1GhRveo= +github.com/gotk3/gotk3 v0.4.1-0.20200321173312-c4ae30c61acd/go.mod h1:Eew3QBwAOBTrfFFDmsDE5wZWbcagBL1NUslj1GhRveo= +github.com/gotk3/gotk3 v0.5.3-0.20210311170413-be85685ca6db h1:6DrB5/BH3GK8Wg6VZ+C2NqQQdMof0iHifNqxixBKefk= +github.com/gotk3/gotk3 v0.5.3-0.20210311170413-be85685ca6db/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q= +github.com/gotk3/gotk3 v0.5.3-0.20210326060404-6328e5470ece h1:97BTiWMRSBA/fkg4irBHzQPv8E30dIUThuAtQn/MK6Q= +github.com/gotk3/gotk3 v0.5.3-0.20210326060404-6328e5470ece/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -215,9 +288,11 @@ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= github.com/kawasin73/umutex v0.2.1 h1:Onkzz3LKs1HThskVwdhhBocqdRQqwCZ03quDJzuPzPo= github.com/kawasin73/umutex v0.2.1/go.mod h1:A02N2muKVFMvFlp5c+hBycgdH964YtieGs+7mYB16NU= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= @@ -225,11 +300,13 @@ github.com/lithammer/fuzzysearch v1.1.1 h1:8F9OAV2xPuYblToVohjanztdnPjbtA0MLgMvD github.com/lithammer/fuzzysearch v1.1.1/go.mod h1:H2bng+w5gsR7NlfIJM8ElGZI0sX6C/9uzGqicVXGU6c= github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.7 h1:bQGKb3vps/j0E9GfJQ03JyhRuxsvdAanXlT9BTw3mdw= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= @@ -238,8 +315,11 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd h1:CmH9+J6ZSsIjUK3dcGsnCnO41eRBOnY12zwkn5qVwgc= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= @@ -261,11 +341,14 @@ github.com/twmb/murmur3 v1.1.3 h1:D83U0XYKcHRYwYIpBKf3Pks91Z0Byda/9SJ8B6EMRcA= github.com/twmb/murmur3 v1.1.3/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/yuin/goldmark v1.1.30 h1:j4d4Lw3zqZelDhBksEo3BnWg9xhXRQGJPPSL6OApZjI= github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.2 h1:YjHC5TgyMmHpicTgEqDN0Q96Xo8K6tLXPnmNOHXCgs0= +github.com/yuin/goldmark v1.3.2/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zalando/go-keyring v0.0.0-20200121091418-667557018717 h1:3M/uUZajYn/082wzUajekePxpUAZhMTfXvI9R+26SJ0= github.com/zalando/go-keyring v0.0.0-20200121091418-667557018717/go.mod h1:RaxNwUITJaHVdQ0VC7pELPZ3tOWn13nr0gZMZEhpVU0= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go4.org v0.0.0-20200411211856-f5505b9728dd h1:BNJlw5kRTzdmyfh5U8F93HA2OwkP7ZGwA51eJ/0wKOU= go4.org v0.0.0-20200411211856-f5505b9728dd/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= @@ -273,6 +356,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -281,6 +365,7 @@ golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm0 golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd h1:zkO/Lhoka23X63N9OSzpSeROEUQ5ODw47tM3YWjygbs= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -294,12 +379,15 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367 h1:0IiAsCRByjO2QjX7ZPkw5oU9x+n1YqRL802rjC0c3Aw= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -314,11 +402,13 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0 h1:MsuvTghUPjX762sGLnGsxC3HM0B5r83wEtYcYR8/vRs= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -383,9 +473,11 @@ golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56 h1:DFtSed2q3HtNuVazwVDZ4nSRS/JrZEig0gz2BY4VNrg= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -394,11 +486,13 @@ google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEn google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0 h1:0q95w+VuFtv4PAx4PZVQdBMmYbaCHbnfKaEiDIcVyag= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -412,6 +506,7 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce h1:1mbrb1tUU+Zmt5C94IGKADBTJZjZXAd+BubWi7r9EiI= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -419,11 +514,13 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -433,7 +530,11 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/icons/cchat_256.go b/icons/cchat_256.go deleted file mode 100644 index fb7723a..0000000 --- a/icons/cchat_256.go +++ /dev/null @@ -1,6 +0,0 @@ -// Code generated by file2byteslice. DO NOT EDIT. -// (gofmt is fine after generating) - -package icons - -var __cchat_256 = []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01\x00\x00\x00\x01\x00\b\x06\x00\x00\x00\\r\xa8f\x00\x00\x1c\xbbzTXtRaw profile type exif\x00\x00x\xda\xe5\x9bY\x92\x1c;rE\xff\xb1\n-\x01\x93cX\x0eF3\xed@\xcb\u05f9\xc8*\x0e\xfd(u\xab\xd5?2\xb1HV132\x02\x80\xbb\xdf\xc1\x01\xba\xf3\x1f\xff~ݿ\xf1\xab\x86\xec]\xb6\xdaJ/\xc5\xf3+\xf7\xdc\xe3\xe0\x87\xe6\u007f\xfe:_\xdf?\xaf\x05\x9f\xdf\xdf߿\xc2\xd7\xdf\xc1\xfd\xf1\x8d\xc8\xf7\xc4\xf7\xf4y\xb1\xe6\xafw\xd3\xd7\xeb\xdfח\x1f߹\xd1\x1f\xde\b\xf67\x1fH?\x1e\x13\u007f}p\x1d_\xafG\x1f\u007f\x1bQ\xc9a\xfa_\u007f\xb5\x9f\u007f\xee\xdd\xed\xde\xf3\x99\xddȅe(\x9fI}\x1e\xe1\xbeoÅ\xdc$\xa7\xf7\xb1\xc2W\xe5\x8f\xf1s}_\x9d\xaf\xe6\x87_\xac\xeb\xf6\xcbO\xbeV\xe8!\x86\xe4o\xc8a\xbb0\xc2\r'l\xbe\xaf\xb0\x18c\x8e'V\xbeǸbz\xaf\xb5Tc\x8f+\xf9\x14R\xd6W\xb8\xb1\xa6\x9evj)\xa6\x15OJ)\xbb\x14\u007f\x8c%\xbc\xe7\xf6\xf7\xbc\x15\x1aOށKc\xe0f\x81\x8f\xfc\xb7_\xee\xef]\xf0\x8f|ݻ\x06\xcf\x1c\xd9\r\x1b|zp\xc5\x183\xce4\xf3\xb4Yf\x9dm\xf69\x16\xe9\xb3\xf2\xb2UV]m\xf55v\xdci\xe7m\xbb\xec\xba\xdb\xee{\x9cpH%w\xf2\xb1SN=\xed\xf43.\xb9v\xd3\xcd\xd7n\xb9\xf5\xb6\xdb\xef\xf8\x11\xb5\xaf\xa8\xfe\xe5\xeb\u007f\x10\xb5\xf0\x15\xb5\xf8\"\xa5\xebꏨ\xf1j\xad\xbaѻE\x10ΘbF\xc4b\x0eD\xbc*\x02$tT\xcc|\v9GEN1\xf3=R\x15\x16\x19\xa4)6;\xf8\xe1B!\x84\xf9\x84h7\xfc\x88\xdd\xcf\xc8\xfd\xc3qs\xac\xf5ߋ[\xfcG\"\xe7\x14\xba\u007fA\xe4\xa2;\xe9o\xe2\xf6\x87\xa8m!\xe1z\x11\xfbT\xa1\xd6\xd4'\xaa\x8f\xf7O\x1b\xb1\r\x16;~~\xf8\xdf~\xff\xbfz\xa3q\xac\xaf0wKeǵȖ\xecC_\x9de\uf5aaE[n\x10\xbe<\xbb\xd9ʭ\xac6A\xd8\x18\xf6H\xdbW\x1b\xa7\xcd|.\xb99&Y\xe0\xebL\x1b`\xe9\xe6o\xae\xc5V\xecw\xd9l\xe3r\x91\xf30\xad/\x9b\x9f[\x8c\x1b\xe4\xb0\x06\xef\xce\r\xe7u\xf22tk\xf3\xfas\xea\xedV\xeb\xa1z@\xb7\x16\xec\xb4U\x02C\xbb~\xa4v\xaa\xb9\x98\xd7\xf5v\te\xb3J\x1d\x03\xc0\x83k\xef\x9dg\xa7\xbb\nd֬\xdc\xf7\x86\xf7\x9f\xb7\xa8\xbfϛs\x9f[-\xcc1\x8e;sRN}\xe4\xdab\xbd+\xcez\x83H·VナDI\xf9\x977\xbc\xff\xed-;\x97\x9cm{\xbb|t\xabPSn\xd7\xe7\xcf\xc84\x80\xf0_\x8d,\xfcyd\x8e\xa1\xc5sF\xfc'o\xf7&\xacѹ\xcf\xf0\xea\x1c\xbd2\xdbQ\vL[{8\xbe\xeb\x12?6\x98ħ\xb2/\xf6\xd7\xdb\xf9\x9f\xb7s\x9f\xfb\xfdv;\xb8\xf8\x8dn1\xba\xf4st\xfe\x8dN\xc4\xfc\xb7+NJy\x17z\xbd\xe7\xce7\x9d0n]{\xe7R\x9a\xee\xe5?C\xab\xbc\xf5=0x\xeb\r\xed\xc7\xea\xb4\xef\a\xb9\xef'\xfd\\\x87\xb9\xaf\x92\xb5\x1c\b\xe9,0\xed\x10\xd1w\x93_\x06\xf0\xf3\xf9a\xf8\xbbRu\u007f\r\xf6g\x8eD4\x0fE\xe0\xd7q\x9d\xbar\xfa\x8c\xcbޭ\xeb&g\x9a\xfer<\xa5\xffv3]\xd1v\x9d@\xd4\xc8\xdc\xcd6\x01\bgGe\xda\u05f8\xfe\xf0\t\xb7?iؿ\x87\xfc\xde\xca\xdf#\xeb\x83Yr\xbb_\xee\xf5\x87\xcbu'\xa2\xd6v\xf8\x1e\xf6\xf7r~\r\x9b\xb8|\xdf/\xaf\x1dO\xb1\xdd\xec\xf7\xb1\x8d\xef;\xba\x9f#\xf8\x84s\xfcqh\xd6\xdf4g\xef\xb5x\x962\xa6S3%\xbe\xc2\x1d}C8\xd5\u0379c\xa9\xad\x83\x1a\xc5\xf2\x1a\x8d8\xd7`\vܖ\x86\f\xa5\xb5\x03)\xb7:\x00z+\xf9\xa0A\xdbj\xe3\x10\xabbǧ\xc9ȣﮐ\xb5\x13\xe4\x88sQ\xc6}\xc0\x8e\xb0T\x059H\x84\xd4\xc1\x8a\xb8\x11\x98\xa8\x99\xd5SZ\xfe\x0exo0\xd8=ˊ%\xfb9\xad\x85\x95\x1c\xd2s\x00 ~\x9d\xb0\xc6Yu\x88G;S\xf4\xe0\x95\xbf\xad\xd4AN\x8dt\"\fv\xccЕ6b\xe8\xadQ\x00\xb5f\xbb;\x03V\xde1\xc6PA\xc1\xcb\xd0Ǭ+p\xb3\xcdSr\xda+[h\\\xb7k.a\xe6\xbc\x1b\xf4w\xdae\xbdY.@(\xbce\x13\x8e\xf6\xe5\xce\xf1zQ5\x96\x81%[\x14Gg\x98z\x91\xa4D\xb8\x9d\xd1N\xee(\xe7\x93\xf5^Z\xc3:ah\xc5X\xa0]\xd3e][s\xe0\xf7\xa2@\x13\xeb<\xea\x8c\xd7H\x14r\xc1\xc6M\xab\x96\x95{(\x84p\xd5[!\u007f\xc6\x17\xdb)\xdc2\xed\xb06\x12\xfc(\xb0\xa5\xe7\xeb\f\xf8M\x1b\x90Ms\"\xaf!\xfeZPI\xfa\xf1\xdah\xa1.\xf8?\x81)(\xff\x1c\xeb\x19\x88\x16 z\xaf\xb4Y\xfc\xcd\xfa\xc2\x01\u070eZC#\xec3W=T\xb8\x84Cn+\xcf\x02u\xef4\x94vi\xec\xc5P\xc3^%sc\xc9\u007f\x12\x15\"bD\xa3\xe7\xd6ɨ~\\\x9b\xf3h\x81J\xd8\r݀,\x98\xe4b+ET@\x10\xad(\xady\xc9\x17&\x15\x03\x0fI,\xa9*竴k\xf2ce\atwD\x99\xd5\x1ey/@z\xab\x10\v\"\x86\xc4\x01\xd7\xe02\xb0o\xf7\\c\xbe\a\x03v\nyR.l\xe8\x99\x11\x00\x02\x1f\xb1\xe6\xaeo;\x95g\xe5\x98۬\rҺ\xe4z\xaa\x17\xd9\xd6f\xba\xed\x10\xde\xc0 nܸ\x97\xd3һY2?\xfb\x01\xbaJC\xba\x8c\xea\xb9Q& 7\xb0\xf0\xa4\xc5*L?\xc7\x04b\xb3\xd0F]L\xad?\xd1+\xbb\x97}L\xd3\x05\b\xaf\xa5\xa3`\x06(\xb9\x10ʹ\xdd[\xa0JM\x11\xbc\xd6v\xfbe9Q?\xe4<\x99d\x03f\xdeT\x19\x04*r\x0f$\x1f`Pao\xb2\x15\\ \xd7\x1ceF\xda\xe3\xa8\xd2L\xa4\xe9\xea\xd3+q\xb5t$\x1fjQ\x9f\xf0iY=1\x95nĤ\xea3\xc0\xba\x8f\xbcZ\x1a\n\u009f\xee\xc8\xd4Dv\xa4$X\xec\x14=\xa8\xc1\xd4\x03>\xf3\xcer:Y\xda\xdb&9\x06eK\x8a+!\xec\xa5\xc5\x01\xae\x17U8\xfb&\xe0\x0e\x83\x8bJ@vnP\x9f\x99K\xcd]\xb0ǘ\x1c\x03\x04\xa3\xf6\x98\xc8\xc6\x1f\xf5\x88\x02\xf9\xd0#i\xce\a\xbe\xafr\\\x96\xe1\x81\\\xc8\xd6W\x91\xfda\xe1H\xef\x1b\x82\xb4w֎\xdb1\x0e\xe9\xd7F\x1dR\x9eRȐ\f\xb5\xd2\b6\xe1p\x1duY^\xff \xa8\xce\xe1\xb6s۲\xde\xc0'`\x8cX\xd7}:\xf4\xf5\xc5|\x0fP(\x87\xba\x87\x1d*\x17\x05^\xf6\x8cՑ\t\x9ea\xd7\xcf\xdc\xe7ړ\xb5Ǐ\x13\xf68\x10`-\vs\x8cY\xe5|\xa4\xe1x\x93\xb2'yp\xd7!\x94\x1e@\xbcX\x8c\x111\x9b\xb0\xc0\xa6\xbb\x91\xf0x\xe7ch\xea\xc0{(r\x10\x16\x1c\xbe \x83\x1f\x13\x1c\xc0\x06\x84j\xf7000\xf6\xf24\xb2\x8dJ\x14\x1e\x150\xb5\xf5\x98ɾH\x980\x18\x17\xbfQY\x9aK\x1e\x8fi\x85\x05\ra\xd8fU\x17\xd2۔\xa47\x02rm\xf1HB\xc9ط\xb3y\xc4]\xca\xdd\xd5\x01Ћ^\u0081N\\\x05\xb7L~!\xf9\x12l\x86s\a\xd7\x13\x01X<\x8dr8\xb7$\xa4\x06\xa3J=\xe4\xee(\n\xd6$\x9e\xde7\x13&\xeb\xc0\x04\xd0a\x9f]\x90\x00\x80\x00\x94\x03z\x93~\x15\"\x98\xbc\xe9\xa9E\xea\xf0z\xd1y\xab\a\xf4\xb0\x13\x1c\xae\xa3\x03V'\x8f\x82\xbbY\f\x960\x1c\xab`\xd6ĠX\xe7c\x8c\xcebg\x96P)qO\xa9u\f߂΅_\x1d \x9cɥ\u05c9a\xe1\xf3\xcdc!\x10\x89ZI\x03\xfc\x8d\x191ý\x8f\xc0t\x901\x8b\xf9p\x19F\xb0\xe3\xd32|\xd4\xc3\x05\x12\xe0\xa6d\xb8\xa3N\n\x02\xe8gW\x06\xefo,\x10\x1d\x1c\t\x84%\x00g\xd4;\x00\xab}\x06\x15\x9b\xa3H\x1b}\x91U\xb0\xdd.\x1f\xa5\xdaqX\xc3e(\xe8\x98\f\x1bT-l\xb9\x15C\x87L\x00\x98\x8d\xca\x1b\xa8it\x94t\xfa\xb9\xcaj2\x1a\xa68,bg0\x90\"!ۃ\xcc\xee\xa0\bqe\xbc\xbbK\"\x1doe2\x98 \xe1\x81#\x03\x8f\x0ee\xa0\xac\x9a\x90nV\x86\"\xbe\x18\x85\tn\x81~t\xcaB\xd5\xcev\xc7a\x15\x8f\xba\v\xe5\xfa\x95\x9a\u007f\b\n\xb81CJ\xb3\xb4I\xa4\b3u\a\xba\x8dA\xce\x0e2\x1aǺ&\x95[\x0f\xab\xee2\xd8~\xf1\x97\xbe\x1b\x84\x10\xc6fQ\xa8\xaf\xa3\xba\xa6\xca\xc0\x909\xb8O\x9f\x8aՈ\x18\x92\x02h7\xa1\x8e\x15\x922o\x9f\a\xf4\xe9\x1e\t\xd7J\xb4\x96\x81Q\x18߈p\xccT\x8eh1\x97\x8fH&\xab\x00\xe3\x8c[\xc2\xc2tPQ\"$e\xe4\x8dA*`\xa89\xa8\x8e!\x89&\x0f\xc2\x01\x9b\x93\xc8M\x16\x17!\x02d\x16O\xa54`\xaa$䄧\xd0@\n\x00Ƣ\xfe\x1c\x18:1\xbb\x13\xe7u\x90\"0\x01\x98\x19\ts\x8f\xe4M\x1b\xf6;\x0eR^\x97\xb2G\xc1\xc2\x13o\x8c[\xad1 }\xe8\x89Ĥ&\xf74\xb3\x10\x13U\xb1\xceZ\xc9oS\xfd\x9c\xa9\xfc\xb8\x88*\xea\x98\xf0<\x8d\u007f\xea\xc3\xc6\x04\x1cS\xf3߸\xaa\x10G([z\xff\xeb)O~\x03\x83\x8c\x11\x98\x90s\xa4\xd8\xcb\x0f\xc8\fz稥$\x18\xe0_\x10\x1d\x058`\f\xa4\x1f\xf5\x9b\xa4}zD\xc8\xf5\xb0{\x857\xf1\x97U\x8b\xdeH\xdd\xda@\x1d\xaa\xae\x94\xce]\x80\x1d\x9fX\x8dĘ\xeaY(\xfc\x9b\xc8+\xa3hQ\x11}\xf1HbQjoh\x154Li\xb5+\xc7\xfb\x14w\x1f\xc4\rv\xb2S\x04Uѓ\x04\xb4\xc4\xec\x06\vK\xd2\xef\x94\x1c\x1a\x00҃\xf8\xe1lB\x8a\x91!\xc1X\x1f\xd2'\xc1\xe0$\xbf\xf1\xeeM\xe0\xee\x1e\f\x1a\xb8\x1b\xe8\x8e@검]:\xec\x04\x82瀮Az-\xffl\xc8,xj\xcb\xf6rg\xb4\xac6J\x0f!&P\x005@Π\"cl!\xf0L\xccŻ+\xa8߮\v\x8d\a\r\xe4!\x19\x825\x05\x1d\x02\xfc\xd2q\xbd\x92/\x16\xd1\x16!\xa8\x8a\x10[\x8bD\xf7\xbb 4\xf1\xc1\x03\xcb=<\x88\xb8\x0f\x94\x8d\xa9A\xebR&\x05\xb4\xd1ŀ\xe6\x04s\xfa)8.DY\xcfT\xcfE\xd40\xa5\xcc:__\x06\nd\x0e\xc8\x03\xdceRq\x1dr\xd1;J4j\xf6(\u007f\xd8\u007f\xf6\xbaw\xa4@381\xd6\x00\x85\xe1\x93N\xb6\x94\xe4Q`\xc8pbh\xcc0\xa3\xae@\xf9\xa4[v\xb0ԭ\x1a6\x10\xbd\x03^M\x02x!\x15\x94\xb2\xc0ȝ\x1f\xb6C\x17n\xe2\a\xb1\xa1{\xc8\xfd\xb6\xc9\xc5\x14\xc4\xd4\xf0\t\x0f!q\x83Kg \r\x99\n\\\x81ؘDyb\xa1t\x03\xc4_\x80\xc1\x8fm\x8f\xe2e\xd1\xd0^\x1b7\x81O\f\xea'S\xa5\xa1 ]'\xb1\xa3D\xfa\xc7Lf\x9c`\x01\x0ejGB\xb1ƈ|\b\xdbK4Pt@0\xc4\xd40PH\x8e\x1a\x12Q\x01Mz\xe8\xa2<\xe3\xe3\x06\x8c\xa8\xbcyE-\x84L.\f\x8cm%\xb4\x18\x90\xabpQ\b\xb3\x00\x19A].b\x9f\x14{\x14 \xe5\x92\u007f\xe6Jw\xa3U\n\xb8\r\xf8\x00f;\t\xaf@\xaaL\xe2\v\x953xD>2\x83\x1anX*\xe2\xcf\x10\xc1$>$\a\x85\xd0&\x19\"\xec<\x1c\x01@h\xf6\tg\x06\xc86Q\x92\x04\x8cԮH\x9aCA\xae\x05\xf1H\xd9`i\x10\x8d`\xcfi\xbds\x9f\nP\x0eD\a\xdcI\xa582\xaf.q\\\xd2\xc3\xe0\xb4A\xbdQP\xa9\x9d\x19p\x11\t\x8b\xe4\x15\x9dx{\xa5\xe2\fӽ\x10}\x1eYLހ\xeb\b,8ڕ\x1aP\xb1\x80q\xb3ap)Y~p\xfe\xfc\xbbk\xa9#Z\tUc\x88\xe9\x00{s\x13\x92\xe6\x9ce\xafW\x98\x9f\xecl\t\x18\xc3\xf7\xab\x19+\x94\x9c\u007fB\xc9\xf5\x13%\x11`\xaa\xca\x1dɷ\x0f\xcc\x01\x96\xf0X\xed~\xed\xeb@\xea\x87~\xb5}|\a\xc6\x02!̪\xc2H\x16\xc6\x0f\x18\x94\xb6\x81\x9d\xf0\xc9]JJ\x18\b\x02\"W\xbe\xf0ԙ\x86\x82[D\xea\xe1\x1c$-\xe1#\xb0t\xab[\x8b}D\xaf\x19p\xc3{\x9f\x8eSR\xcb\x03\x80\x9b\x15c\x86n\x8e\x14)\xdcS\x90~X<\xbc\xb1z\xb9,\xb2\xb2\x8f\x1c*\xe8*\x8c\x1c\x11\xac\x8d\x8b\xab\xe6FR\x02\fj\xe5.\xc4Q\xc3_\x83\xfd\xc0\t\xf7GĹDEx\xe4W\x812S\xc2\xccft\x03\xacqE\xcdh\x1c݀pS\x12\xc1\x13\x065\xdb\x1e\xbecӌ\xc8\xe3\xf4\x02\x19W\x83S\x92\xb1\x06\b\x9a\xe0\x11rybΘ\xf7j_\x05ۡ\xaf\x01x\x8f-XCʀ\xc5Q\x8f\xde\x1ec\x13\x95\x04#\xfb2]\x01\xab\xd0+,\x9cr(\xa9\u07bc,o\x00\xada]j~}\xbd\x964&\x0f\xb2\"\xcf1B\xbex\x99\x90\xd0\x02\"\xedl\x17\x90\x97\xc1\xd0\x02haЀ\x14GwR\xffV\x8cUإ\x9c\x9c\xd1y\x14\xa3H\xc8\xc6\xc1\xfb\xa8\xbf\xc7\xedB2L\x18V\xb9\x81\xbd\x0e\xa9\x86\x90Af\x15\xe4\x02T\u009aIx\xa3z\xe2\x86M\x17\xb1,\x04\xea\x92\xffa`6 \xaa\x06\xa9\xa4M\xb2E\x9eIv3\xd8@Ԡ~?\xbc\xb8\a\xf9\xc1ڢ\x8eJk\xe8FOb\xb6~=\xb2\v\x8b.CZՆ\xc7%\xbf$\x85\xfd\xaapG\xf5\x86Dv\xb9\xa0\x1aJ\xff\xfa7&\x8b\xea\x8fh\n\x980\x03/ٞa\x8c\x90\x9fJb\xe0\xb8}\x88P\xc0\x97\x8a\x90\xbcM\x91\x9cw\xf5wiP\xbf*\x04Ʌ\n\x8c\x0fL\xa5c&\xea\xd8pE\xf8\xc4Q\x9fj\xf8q%wh\xb7\xe1מ0}H\xe3\xcf\x11(5\x16\x05\xcb~\xe7\x99\xca\xcf\f4\"~lKT\xbc\xfa\xa3^^y\xe4\xafk\xd0Dݡ\xef\x99a<\xaf-E\x1d\xc2^(U\xccuF\x1b.\xe9A\x15\x88\x04\x89W\xa3\xb8\xddO\x1f\x0f\xdb\xdd\xc0%\x9cvEG\x10\x15\xe4q&a\xe1\v\x89\x1d\x94}&\x13G\x99HK\x9e\x83p\x05O2\x9e\xb9\x9b\xb6]\xb4\x85I\xb9\"\x13\x1a\u0383\x18Nu\xbdL4\xa5^-f\x1d\x99x\xd5r\x8e>\xc9\xd8D\x84,B\x83\xb5\x19\xf2?P\b\x8e\x8cU%\xdf\xfd\xbero`hE\xaec\\\xf7Q5\x99KA\x05\x91\x99\x0f±\x13P\xbc8%K\xe9'\xb2d\x8c\xa26\x0f\xf5\xfe\n\x01\x04\x9fk\x05|IB\xfa\x032\x87\x9c\v\x91\x9a\xe8\x0e\xe3\x9d3\x1e[\xe9\x06\r@W1\u007fj\x828\v'\xf0&\xa8b\x94\xf7d\x10\x11\x91\x1eQ\xe4q3A\xb5[!\xa6\xc1t\xd2r\x19\xf5\xcae(\\\x90\x84\xe80r\x1e\xe7\x19D\x81T\xfc|m\xfdm\x80\x14\xa9}q\xb6\xd9XB\xd6\r\xa7\xb2\x1f\x18\xc2]\xe0\x1fP\x9b\x1a\xf0{\x84\xee\x05\xe0\xc0h\xc5\x19\xc8\x01\xa4=\xf4b\x96\xe4`\x9e\xe4\xc0\x1eAɧ\x1fh,C\xa4\xe0\xd5\x06\x1c\xc1A\x18\xd8Ὠ\xb5\xdaE\x8f\xa8\x03\x83\x9c\xa8\x8bZB\x14\xb4r\x15\xf1\x95,E17D`\x001p\xae\xed\x18\xea:R\x12\xda\x1e\xeaX\x02\x17\xf7\xa7(\xb4q\x80\xfd,^\x068\xb3^<\xa6}\xb64\xfa\xfb9?\xce\xc8ڲXYE\xb9\xb0\xc7\xe44p.\x84v\"\x0f@\xff\xf5\xb5\x92\xf8d\t\xb9\xb5'T\x99/E\xfa\xb2\xf9\xc8q\x9d߸\xa3ae\xaa\xae_\xefz\xa7\x0f\xb0j\xb9R=\x10\a\x89PdѸ\x85 9SEȱ\x80S$wP\xc6Ⅳ\xde\xd9\xcfK*\xe2bTG]aѮ\x00\x83\\\xaa9\xf7=\xf8\xb8\xfavM\b=^c[=*\xa8z_c\x86\x95\xc03ϢF\xcf*:\u00a0\xeeq\x9b\xf9\xaas\x81\xd3\xf3D\x01\x83v$\xa7'N\xb1\x91\x03@\xd2\xeb@\xf0)ȩy#\xebXZ\x10r\xf8ZM\xaa\x13]R\xf3\xa4\xd6\x0elo\xa6\xdd><\xa0\xecU'\t0\x00\x80\x99J\x00\x02\x00\x89\xbb\xbc\x1cu\x1dS\x85\x0f\f\xc1\xbbnĵa\x9a\x11\x9agmD\x84z\xd3$^k9\xbc\xfd\xe4\xfc\xfa\x12\xed\xb5yY\xec<\xc2R9\xa0n\xb6\xb4c\x81\x83p#\xa8Ԑ\xef\x1aTFE\xb85\x16;\x1emn\xa6\xa9V\x01\x01\x10,5u\xa4\x87-\xf4&\x02\xac?\xc1\x97\xe5\xf2\xc8\"T\x0fv\x02<\xcb\xf2\xe6*\x8f\x8d\\V'\" gH\x87\x15g\xfa*\xb6\xdbt\xce`\x90\x90\xb1L\x9cMb=\xb1\xb3$\x1c\x9f\x04\x92,\xaaQ\r\x90\xcc\xc3\xcbj\xb4\xc9\xf7\xa3\x11\x81\xf3\x1cd\xfb\x91(pA\x13\x0e\xc9\xe2'\xdc$\x8cB\xba\x1f4c#\x06\x01\u1a1dxaW\x99\xa8\x14\xc9\x1fV\xebV\xe7\xa1j\xe9K\x16\x0e\xf9\xd7\x1a,%b\xdf\xe0-\x1a]i\x85:-\xa2@\u0081-0\xf5\xbd\xd1\xf7\x1e\x14k\xcd/f\xb2\xa5\xce\xddz\xd4\f\x144Th\t0\"\xa6F\xbe\x977!\xf1K\xdeBu\xac{oe\xa6\aq\xea.#\x94pCa\x8d;5\x97\x89\x86\x04\xba\xaf\xfaM\xb6g~[\x02\x94\x99\xc5\xcbs\xf0kg\xb7S\x11-5m\xaf\x8e\x04d\xa2\xb7\xb7\xe1\xbe\xf9HD\x96\xc3\xc8X*s\xeaf\x92ԁ\\\r\x1e\xb2O\xac\x81U5\x93*\x19\x10\xa1:\xcc4\x9a}E\xd6\x00_\xd9\xc0ګ\x9e\x1dűQҘ\np\u07ba\xdb\xea\xc0x\xe2\x03\x1c\xfb\xc6X\n\xb0\x05m@c\x05\xf3\xa3~\xf2\xd5NOŻK\xb5\x91\xdaj9\xe1\xf6\x17f4b\v\x03I~\x8a\x9b\x8d@bW\x8e<$6\x95\x8a-\xb8\x04H\x139\x0f8\xed\x12a\x19B\x9f\xa4\xe5\xc9\x19\xad\xe2\x04VP\t\xa4\xb8'CX\xe03\x1c\xae\x0e\xb1\x066#\xca\xf0\xd3Fe[\x02\x1c\xc9\xff\x80\xfe\xbf\xe0\x1e\xa2\x8e\x04\xfel\xa9\x18\xceհ\xe2H1\x11\x8ah\x940AUn\x8d\x82[\x00֙Ԗ\aD\xa9O\xb5N\xe5N\x11\x12\x03oمV\xf5\x04\xe5\xcd$ul\x8a\x8a\x00HH:g5\xbd+6\x8bA.O\xe9\xe7\xca0\xa1kʊZ\x83\x01gB\xc3>\x1b$\x91\x01\xb1\xa5\xa7\x18(\xc3\xfe\xe4\xb1$\xc3\xeb\x15>\x19\xe0\xa2D=\xe4\x0f\x06j\a\xae.Q\xcc-j\xbc̿^\xfe\xb9Z[JG\xba\xe3\xebjX8:\x86\x9b\xd4\xe5\xe1\x02l\xd3K\xce'\xab\xda'\x03\x02\x12\x17\x87\xc8\a\x80ɏtXP\xf5\x16\x8c\xaa<)\x13\n\xb9\xac\t\xb0\x91\f\xd9x\x1aN\x90ܝ)c\xe3\xf1/\x01A\xc1\xcfU\x9e\x10\x1f\xa2\xae\x10*\xe1\xea\xd4\x03\x81\x1b\xa5\"\x15\a\xd2\x04NjuDC\xcas\x90?,#\x9c\x17\x86\xec}\xc0\xb6\xaaQU\xd5\xc3&c\x1e\xf8F\xaa\x0e\x1f\xa2=N\xfc\x96\u007f[_\x18\x1f\xf4bi\x88\x0f\xa7\rn\xf0\x1c\xbf̒\xa7\x012\xd9+\xef\b`\xe1\x14\xd1\x10Ȅ$}\x86\x81\xbem]\xc3q\x81R\u061c\xa1\xb5\a\x03\xd4-&!Ֆ\xa3H\xc1\xea;\xf0h\xe4\xee\xac/g\xaa:\x94`\x94T.Q\a+\xe2X\x89\xa4\xac\xa0\xc8\b\xa0L̄\x1a\xdd\"\xad\x05\xb0\xc5\x0e\xcfW\x00}\xd44\n\xaa\x84\x89\x1e\x0f\xf0F\xa4\x142\xadmp\xad\u009a\"\xb2M\xda\x01\x92]\x9c\xd0v\x85VA\xb9\x8c\xabp\xfd\x02\xc2]Xњ\x0ec\xcd0'*\x10\xe9\x81\xc9Sp\xd4\xf5\xf6j\x87\xa8?{\x04݈\x9b\xac>9\xaa\xfd\x9d*ʋٸ\xf6\xda&\x98?d}\xee\x18\b\xed\xd7@\x95j\x8fU\xf4K>\xac\x18e\xa2\xb3\x04\xea\xe9\x98\xf6rբ\b\xf0\b\u007f/\xf5qy\xc9]\xe6\x81y\f\x12\x9cm\xaac\x93\x11}\xa8\n\x16U\xdbP\xda\xd7jhyJ[\xa7]\x8a\xb6^:ʟH\xae\x87\xef\xa4J#z1_\xd0$\xe4\xc9PXѩ\xcf\x1f\x04\xa0\x91\b#\xbd\x8e\xa9\xbd\xa2\xec\xbaO\x8aj\x1f\xa4\x81\xfe\xe4z\xb4ԘG\x89^'\t\x06\x18.\xa2\x00\x1b\x90(ށ\xb2\xa4\x93HY\xcc\"I\x8cE\x8b:5\xa8\x83{\xe1-R\x122\x15ki\x90f:\v\x8a\xd2a\x1e\xe8v\xdc\xf0\xe4\xad\x18\x82\xd3\xe9\x19\x10je!\x06ʃ\x04\xa1\x80\x97\xf6\xc4\xe2w\xdf\xc2\x16\xaa̓\x04\xd0<$\xfe%A?\xf6\xef[\x83:\xc1zM\x1fP\xc5f\xea<\xc33\xde\xda\xd90\x89M<\xaa\u07bd\xb8\xab׀\x95~\x90\x02\u007f\xfbY\xba\xcf&[N\xe5F,\xcb8o:\x8fp2\xf6P`Z\xe3\x17\x986u\xdd\v\x02\xe5\xa9\x04д\xfa\v\xec\x8e\xf3\xd5\n\x11\xe3\x9c \xa1Utۭ\xfe\x99\xba\x91 m\xbdڃ\x87\xe36\x1f\x1eb9Ӟ\xd2PjuR\n\x1d\xd4Pj\xf87\x00\xaba\xe8\xef@C\xe2C\x80s\x8a~\x14\t\u007fƓ\x8f<\x91\xba\xb5H3\xcf\xe2!*\x8b\xbc;9E\fՔ\xec\v\xd7\v\xbb\x13\xa3\x86\x9bF\xe7\"\"\xd4\x17@\x1f\xc0\xfd\x10\xb9\xdf\x18\xcf\x04tPs\xd8'L\x9b\x0ejȞ\xed\xa9L\b>\xa8\x97w\x86p\x15\x9c8x\r\xccG\xa4D\xd2ڤ\xb6\x12\x12ۮ\x8e\xb3`\xf2\xad\xd6\xd7i\x91\xf9\x14\xbf\xb2\xea\f\xac\xbe\x11\\\x8c\xa5W\x11\xa6\r\xe0\x9d\x1a\xb3\xaa?\xad\xa5s*\x01\x0e:\x01D\xd2\x16ۃ\xdb\te\x1c\x8c%\xdeS\xcdk/|\xfc\x8cmp\xc3!\x85\xbbF\xd3q\xa9E\xc19$WoI\xfd\x98QQ\xb3\x05\xce\xf2,\x0e\x8aYĵ\xb4w\xb0\x8b\x8eI\x90\x88ب\b\xeaEuWM\x9d\x81\xb2y-run.\xf6%^\aW\xb4!\xc4\xec\xd4\xf9\x85g\x04.g\x16\x9cg/myR\x05\xa0\x82T\t\xb7N?\xc0\x02\xe9\xe3\r\t\xb2\x9d\xe0\x1d\xd20kw\xf1(\x05\xba'\xf5\xe1SO\x15\xa1\xbcgƑ\xe39\x87\x1c\x1d\xea\x89H\xe3w\x8b\xb6\xfe\x11\x81\xf02\x84\x9e&\x06\xb4\x8d\xe3\b2+遰\xb7\xc0\x80\xed\xcb\xf2\xf3\xd5\xff\x00,\xca\xc5\xf1#́\xa9\xe0\x01w+ں\xb3\x14H\xaa\xa3-p\x0fom\x87G\t`ה\xbaC\xad\xa2I\x10PJ\xd5\xf0Y\xe5\xfc\xb5\xca\x03W\xb3Ԫ\xae3\xbdF\xeb\x92\xe4\u05f6\x00\xfa,\xf9\xe4\xa6\xc1ը\xab\x0e\x8fig\x16\x9d\x1a\x11\x97h:\b,/\x006\xc8#a\xd0I\xb7\xa5C\xae\xfd65%\xc3Z1-\x9e\x1c\xe5$3\x94\xed_+\xe3ML\xc6p\xd9~\xb5\xaa\x1a\xa5j\xe6k#\xbc\x837\x90&6a[3\xc8\x0e\xe1\x9eq5\xacZ|[y\x0e5\fzK\xda\xe3Β\xb6\xe8\xed\xe6\xe7\xaaH\xbb\xa1\x86\v^\x06^{\x8f{\xdem\x9f\xd7\xfd%\x9f\xbc\xb6\x8a\x8b\x04W6\xc0\xdf>G\xb6\x00\x99\xfb}\x8d\xaa\xb6\xe9\x8c\xcef}\bI_\xf2\xf3\x1b\xc8\x03\x90\xe1\xe7\x17\x18\xa2\u007f\"\nB\xee\r:b\xb2\x99l\x918\x86>u\xb4\xa3\x90\x19\xa4\xa5\x9cvІ\xe2Θ)\xb2\xf0xX\x13\xb4A\xfa\x15u\x9f\x06\xd2!\xf6\x81\xfa\x98\x1d\xa1\x95u\xee\x8f\xf1S࠶\x05R\x98\xc7f\x9d\xeff\xa5&\xb4\b\xfa\x80j\xea\xe8N\x16\xf0s2I\x9bH\x181\xfc\x14\xb8/\x05\x8eЊ^g>\xabx*/\xf5\xb1U\xa9\xf0\xfc\xd1q.\xfb\xda\xdbǗl\x1dÎ`\xf0\x87a\x12\x93\u007f罒\xba\xcb\xc8c\nT-\n\xaa\xedH*\xc4烼4m\xd5&6T\xad\xd3X\b\x10\xf0\a\xc0f\x01?\x87\u0a8eO\xb1\x96:\x1a\x82\xa8<ج\xb8\x0e\x81#C\xf9mR\xc0W\x9b\x03/\xb3\x9b\x98\xe2\xeb6\x9f\x9b\xd7\xcf\xe1+٬7\x1a\x8a\x02\xa4\x9ca\xb9M\xd5fi\xd5\xcfm2\t\xf6\x10\x16\x03<\xdeٶ\xb5\x93\xda\x13K\x12\x99\x81\xac\xf0\xbdJ\xc8+X\x80q\xbf}P\xa7\x19E\x80\x8a2\xffq\xfd\x1b\xba>\xa1\xebkc(\xa8\xe4\xfb\xce5\xfd:\x10\x1d\x9ea\x9d\xb5\xedz\xba#\xe5\xe1\x85>\xfep\xb9\xce_\xb2\xe8\x97\u007f\x81\x95o\x8e\b\xec\xc08\x86\xb6\xe8\xdfy\x1c\x04\x1bꖹ8*\x91j\xb1\xcfd\xce\xf7d\xb4\x952\xfe2\x19$\xa9\xa9\xfd\xb4\xb6\x14P\x95\xab\vYgF\x93\xda\xd0@\x1f+\xfb\xcb3\xbbn\x9d\xf7\xef\xb7\xce\xe9\xc5fe\xac\aR\xa2S-\xf9;WȎX\xdc\xef\x03W\ue112\xd5\x18\xff\xba\xcb'\x87\x14c\xd3}\xe6\xf7}vC\x14j\xdb]\x16\x00>s\xa4\x05%\xf4\xbd*J\x92)\x85\t\t\xaf\xf8=\x9a\v\x01\x11\x9eX\x91s\x9f\xdb@\xdc\xeb\x9d\xc3nM'`\xe3\xcc\x0e\x1d\xcc\xf2\xbfͪ\xa9cB\xe3\x9d\x12н0\xf2C`\x8b\x8e\x81\xe36\xe2\f\x13\x91\x9f\xfb\xe1\xd3\xc0\x185\b\xce\xd7\v8/\x14[\xbaQx\x8a%\xdf\xeb\x1d4\x03\xe4\xb5\x17&\xff\x05\x17\xae\xab\xdd\xfc\xc1\xac\xc0T\x00{\xe9p\x87\xb4\x18\xe0\b\xa5\x02\x9b\xe8M\xa8\xd9͎\xec\x8b:?\x05\x93\xa3a\x10\x97X\xc7\xf4\xe2\xdatp\x82\xe5\x88\x06\x17B\x06\x8c\x0eY\xf8v\x1dX\xd5\xdf\xc1G\xe7j\xdbߠ\x0f\x99\xf2\xba\xc4j\x80\xcdO\xa7U\x8c\x83\xf6\xed\x1f$\x05\xc7JjSMM\x1dȻR\xe9\xce.&}\xeb\f\x17\xb2\xadg\xed\xbaš\x16\xc9\xd6\xf7\x93\xf1\xc8ܳ\x00\x98\xc8݂\x8a\x03\xd8!A\xd0B\xfdc\xd2\xeb\xf5\x1eG\x80 Q\t8Ta\xac8M\x8d\xd9M& pp\x94`\xd5\xd1\x1e`y\x87G\x8b\xf6\xf4\xb0\xa4rqj\x14P̱\x1cE\xe2\x1d\xac\x94o\x1f\xf7\x1d\xd5\x02ɖ\x9ah\xb9\xadŅ\x8c\xf0\x1a\xb6\xa6L\x9d\xa9P\xdb읍+\xe4Rl\xda\xcd\xd0q\xbb\xba \xe7\x99\\Vg\xbcJk`\x86\bά\xb8\x17\b\x13̟利\x05\xe3\xda\x13\xb8\xb0\x86\xa9\xdb\xdb\xc9\x11+:\x83\xd7q\xf4|\xd7\xe1&wtn\n\xff\x15\xc1n\x12\x14\xb6\x8c\xfag\xe82\xe4\xfa\xbc\xd7\x19G\xedh\xb20[;\xd4\xcd봽\xden\xe2,5\xfa\xb1c\x8eσ`\xfb|\xbf\x82tJ\x9f\"\xc5\f\x0eTB\xc6E\xf1\xec\xf6N\xf8jpu\xc9\x12H\xb4\xf6\x9d\xb49Q\xc8\xec\xe8\x90\xefp\xf8Ca\x1dBM襇\xd6U;\x05\xa4\x04\xd6:\x1b\xe5\xc7\xef\x8cJÿ\u07b4\xed\xb3}\x87 \x01xP\v\xc8Jmg\xa8\xe5\xa9sO\xba|a:\x11s\xdfoˍ\xbc\xeb\xf7\xd0\x06G?:=\xab\xdb\x0fD|\xd3q\x1f\xc3/jk\xd7}\x9a\xba\x98\x9f\xef\xcf`\xb2\xda\x1b\xe1\xd1N\x84P\x12G\xc1W\xea\xea\xf1\x10\x8e\xd4\xfb~\xfbɍ\xa8\x10\"r\x86\x9b:\xf5\xdd\xc6k7\xfb\xbf\xa4\xbdN\f\xef\xa8\xdbϐ\xa4\xb81\b\x88\xbd\xa1\xb3k\xc4<\x04J\xb4\r\x80\x8e\x81:\xfc#$\xa4}\xbb\xf7?B\x9aN\xdf\xd7\xcaU(}m+\xf6\xb7A\xb2\xb5\xd5Mѓ\u0383\xb0\"\xc3t8\t\f\x9d\xd5\xeb\xecH#\xb31'\xfa\xf3qC,\v8\x93\x16\xa5\x8cҌ\x97\x18\x0f\xb51\x93\xda{\xfd3\x19M\x05\xdc\xd1\xd1B\x14\xb7\xfe?\x15\x06\xbe\xb9V\x0eS\x84\xfa>\xddt\xf2-\xe5\u007f\xe6?\x1f\xb8\u007f\xc1\xff^\xf8\u007fy#Ҩ\xbb\xff\x04\xe48d]\xd02נ\x00\x00\x00\x04gAMA\x00\x00\xb1\x8f\v\xfca\x05\x00\x00\x00\x06bKGD\x00\x83\x00\xe5\x008\x88.\xdb\xe8\x00\x00 \x00IDATx\xda\xec\xbdY\x93\\[v\x1e\xf6\xad}\x86\x1c+k\x1eQ\x98/p\a\xdc\xdb\xf3%\xbb94\x9b\xdd\"%\xca\x1c\x9a\x94\xbaI\a#(\x85\xfc$\xbd\xf8\xc9/~\xf3\x8b\u007f\x80\x1d!\xfb\xc5֓\xc40)\x9b\xc1AA\x99\xea\x96L\xa9\xc5n6{\xb8\x13.\x80\x8b\xa9\x00\x14P\x85\x9a\xab\xb2r:\xc3^~8\xd3>\xfb쓙\x05\x80\xa4\xec\xc8\x1d\x91QU\x99Y\x99yv\xee5}\xeb[k\x01\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x935Y\x93U\xba\xe8o\xf6\xed^'TWj\x98]\xac\xa2Rs }\x1b`ze\x1f\x8b\xe8\x15o\r\x9d\xf1#\xd1\v^\x06\xbd\xfcW!^ѵK~\x89\xa3\xc2\xf1\xed,\xdbl\x85\xd9K\xf3\xe8\x97O\xffO\x9a\x9f>\xeek\x95>\xae^ø\xd7\\\xf69\xe4\xe8\u007f#b\x00\x12\xbdS\x0f\xed\xe3>\xdaG}\xf0\x87\xff\u007fQ\x00\x9f\x02\xe6\xd6j\xa84/\x03\xf2]\xb8\xb5\xaf\x82\xf92H\x9c\x83\xb0\x9a#O>\xfdu^\xc6\x10\xe1\xa6Q\xffC/\xfe\xf9\xe8E\xbf\x9e\xbfa]=\xf6\x81\xe7\x17\xfb\xb7\xecN\x1e\xef\xffx\xb4\xe0\xd2(\xd9嗸\x96\xb3>6\xb6\x02b\x00!dx\x04`\x13\xc0#\xf8\xfd\u007f\a\xa2\xf7\xe0\x0f\x1e\xe3`\xbf\x8f\xfe_\xfd\u007fL\x01X\x9f&,\\\xbe\b\xdb\xfd\x05\b\xfb\x1f\x83\xc4\xdb j\x00\xb0ʅ\x8d\xce\xfe\xd1\xe8U_\x16\x9dA\xfe\f\x0f\xd2\vn9\xfdu|u\x84\x97\x90̳\v\xf8x\u008e\xb3\t\xfb(K}\xd6\xfbx\xcc-\x1a\xe7=_\x95\xb20|&\xe6\x10\xe0\x130\u007f\x8c0\xf8\x17\b\xfdoa\xf7\xf9c\xf4~\xc0\xffe+\x00\xeb\v\x84\x85\xf5\x8b\xb0\x9c\u007f\x06\xdb\xf9&\x88\xce\x03$^\xf8cQ\xd9C\xf4r\x97\xf1R\x8a\x83\x8c\xce\xc0X\x9a\x83^\xd1W\xf37\xed\f\xf0+R\x10|Va\xe2\x17\x14Η\xf0T\xd4\xe7ҋ|N~y\xa5@\xac\xde\x1d\x82y\x13\xa1\xff\u007f \b\xfe9\x0e\xf7\x1e\xe3\xf4\xfb\xfc_\x98\x02X\x06f?;\x8dj\xe37a;\xff=H\\\x18絉\b\x8d\x8a\r\xd7\x16/v\xbc\x86\xc6\xfc\xa3\x04\xefE\x94\x06\x8d\xbf\x95tFמ\xfe\x96\xbf\xc2Wa\xf9\xcf`\xc5Cɐ\xccŇ\x88\x8b\xaf\x97\b\xe2\xb0צ\xf1>\x18\x8f\xa3X\xc8p\x1dc)\x83\xf1\x95\x0e\x83\xe1\a\x12~\xc8\xd15\xf3\x18;\xcb\xf2\x11\x82\xe0\u007f\x84\xd7\xfb=<\xbb}\x1cE\f\u007f\xeb\n`\x0eX\xfa\xd9\xeb\xb0\xdd\xff\t\xc2\xfa*@\x8e镫\xae\x85\xf3\xcbSX?\xbf\x8c\xd5\xf3kX\\]Ekv\x0en\xa5\x02a\x89\xf1\\Z:\xebQ=\x9b\xbb\xcdg\x12h\x1a\xf3-ͯ\xc3/\xac\x88\xe8oG\xbc\x99\xcf\xf8z<\xf4O\xc9RyM\x1e\xea)\xf0\v\xc6ڜ\xca\xf2\xb8\x82\xc9%\u007f\x8d\xb6\xf0|\x86P*QB2\x94\x18\xf4\xbah\x1f\x1ebok\vϟnaks\a[\xfb\xa7\xf0\x82\xb0\xecu|\xc8\xf0\xdb\b\xfd\xff\x16\x1b\x1f\u007f\x02<\xfe[T\x00\xd5/\x10\xa6V\u007f\x11N\xf5\x9f\x83\xc4\x15ӫ^??\x8b7\u07be\x8a\x1b\x9f\xff\x1cV\xd6/\xa0\xdah\xc0\xb6\x1d\x10\x91\xf10\xf3K\b2\x8f-\x94\xe5\x97\xceg\x15j:\xc3v\xc6\xd7˯\\\xb8\xe9\x15\v>\xbf\xd83F)\t>;\xe8f\xb4\xd8l\x8a\x9b1\xbe\x857=N\x86\xcfG\xc1í#\xf3u0߇?\xf8\xa78>\xf8\x16\x8e^\x1c\x1bx\t\x05p\x9e\xb0\xf4\xb9_\x87\xe5\xfc/ \xb1\xa4\xbf⥕)|\xe5\x17\u007f\x1a\x9f\xfa\x89\x9f\xc4\xd4\xf4,,\xc79\x93U\xe3\x97\x10\x10\x1e\xdb\xf2\x97\xbc\xefY1\x02\x1a\xad\x1c\xf8\f\n\xe2\xec\xdf\"\xbdZG\x9e\xf9\xc5^\x8bG\x1e\xf5\xb1b|>#V0\x9eЏ#\x94<\x862\x1aﳍ\xb7\x13\\\x1a:\x85A\x80\xf6\xe1\x01n~\xff/\xf1\x9f\xbf\xfd\x1d<\xddk\x9b\xf6{\aa\xf0O\xb1\xf1\xe0\x0f\xc0w\xf9oL\x01P\xe5]⩕_\x83\xe3\xfeo \x9aS\x1fs,\x81\xaf\xfc\xec[\xf8\xea/\xff2\x96\xd6\xceA\b+\xafe\xcf\xf8\xf6<\x8eP\xbc\x8c'a\xb8\x9b_D؇\xbe\x1e\x9d=\x94xI\xe5\xf0*\xe1b>\x83\x95/u\x89\xf9E\xac=\x0f\xb9 6\x8b\x95\xc9\"S\x99؍\xa74xL\xc55R\xf0\x99\xc7\v\xf5\xd5P)\f\xb1\xbf\xf5\x14\xff\xe9\x8f\xff\x04\u007f\xf1\xfd\x9b\bB\xa9\xbf\xe6\x01\x02\xff\xbf\xc1\xd1\xfe\x1f\xe2\xe8\xc7g\xfeڭ\x17R\x00\xadO\u007f\x15\x8e\xfb\xbf\x03\xb4\x98\xf2&\x18X\x9c\xae\xe0\xeb\xbf\xfe\x15\xfc\x9d_\xfb:f\x17\x16\"7_\xfb\x12\xa9\xa0\xddy\x84\x10\x8dA.a\x1e\xf3`rvHFjE>\xbbd\xd1\x18O\xe71^\x90\xce\xf6Ư:7t\xe6wb\x8c!X\xda\x13)\xb1\xf6<\x96\x87\xc0\xb9\xb3\xc0\x863ĥ\xe7\x85s\xcfўO\xf1\xef\\|\x8d\xe8\xff\xa4\xf9\xff\n\xcf\xe3\xa1\xcf\xe3\xd2Ϭ\xff?\x94\xcf\xc2\x11P\xdej\xe1қo`\xbaJ\xd8~\xf4\x04=?P\xcfr\r\x82\xbe\x02\xdb\xfe!\x8ei\x038\xfakV\x00\xb3\u007f\xef2\x9c\xea\xbf\x02\x89K\xeaA=\xbf\xd4\xc0o\xfd\xceo\xe0ݟ\xfd\n*\xd5\xeaP\x00,c\xff\x8cF\xce\t\x94g\v\x8d\xe9\xcaӋX\xd03Y\xd9\xe18\x00\x8f|\xb9q\xb2\x06\xc3=\f>\xcbg<\x13\xe85\xaeF`\x13f\x97W\xde\xf3yX\xb6\xad\x1c\xbb\xe1\x16\x97\xc0 \xdd\xcd\xe3\x12\xab\r%\x13\xc3\xe3\x9dм\x00\x8eCD\xe11\xdd4\f\xb9\xae\xec\xb3\x16\x9d\x92\xb3R\x85K\x8e\xe2\xd8&\x9fG\xdcƉ\xeb\xc7t\xf1\xcf$X\xba\xc76\x8e\x80\x95\t\x87n\x89M\xe7\x8e3\xc5A(\xd9\x03.\xd93\xa9Y\xeba\x1e\x81\xc1+`Ӟ\x97\xff?\xebצ\xfc\xbf\x10\x02\xf3\xab\xabX^[ē;wp\xda\xcf)\x81y\x80/\xa0\xb6\xf0'ho\xfa\xaf\\\x01\x10\xae\x80\x1a˿\x0e\xcb\xf9\xef\bp\"\xa5Ř\x9br\xf0\x9b\xbf\xf3u\xdc\xf8\xec\x17`YV\xeel\xa7\x96{\x84{N్\xefجyz\xd1\xe7И\xafO#li\xf9\xe1ȹ\xc2\\\fuI\xe3\x06\x9c\xddŧ\xb1\xd5\xc3Yޡ\\\xefriX\xc7c\x92g\x98\xa3-ͅ\x04\x05-jp\x9b\x89G\x84\x02l\xf8\xdf\xec+d\xa3\xd5\xcd{\x18\xacz5\\\xfe\x9d\xf2P\xc5P\x9e\xd1\xe0\xa1!F^-\x92 \xcc,.bf\xa6\x81\a\xb7nc\xe0\xfb\xc9\xff\x11\x04]\x06\xe1&z\x95\x9b\b\x0f^\xad\x02\xb0\x1a\x9f^b\xa7\xfa/@\xb4\x9a\xdcg[\x84_\xfd՟\xc1\x97\xbe\xf2Uض]z\x0e\xe9e\x8f-\x8dr\xf1i\xa4\u00a03\xba\xdc#y?\x85/\xfd\x8c!\x05\x8d\xe1\x8c\x1b\xcf\x12\xbd\x94\xec\x9f\xdd\xcd?#hƬ)..\xf5\xe8\x12wf\xbc\xd7\xe7!\x01\x8b\xf6;\x8d\x1f\u007f\x9b\xad\xb9\xae,F+\x93R\xa1g6\xb8\xf8\x99w\xc1C>K\x99b A\x98[^\x86\x15\xf4p\xef\xeeCE\x89\xb1\rA7Pu\xff5N\x9ev^\x99\x02\x10\xb8\x02\xaa\xce\xff\x13\xb2\x9c\xdf\x06C$\xae\xf2\x97\u007f\xea:~\xe97\xfe!j\xb5z,d<\xdcʏqX\x8d\x16\x9eG`\xfa\xf4\x92\nfԣ#\xb1\xca\x17\xad\x02|\x11,\xc2\xf0a\xe8\x05\x04~\x84\x96\x18\x0f\b\xe43\"\xe1l\x0e$\x86ľo\xf2\x99ǰ\xc0\xac\xff_\xee\x16\x1fv\xe6R\x10\v\xac\x15\xb7(\xff\v\x86\x11=\xd6/\xa0\xdc\x1a\xbd\x02\xab?\x14uLjظL@5\x8fBs\xe5\xa9\x14!7YvY\x8aғ\xfa|\x1a\x1d\xe7\x9b>\u007fQ\xa9ȼG\x90S\xea\xe3|\xde\x11\x9e\x02\x9b\xf0\x84ѯCDhδ\xf0\xc9\x0f\u007f\x88\xee`\x90|>\x1b\xcc6*\xee\x1f\xe0tw聰G\x1a9a\xcdC\x88/\x022=˯\xbfq\x01s\xf3\x8by\x81!\x03\x02\x90@\xbb&\xeb\xa4\x14\x95l&\x97\x89\x06\x9b5\t'\xf8\x89\xe1y\xc4f\xe5\x10\xa7\xfbr\xae6\xebD\x9a\xf8Q\xc9C2\ae\xf4_\x8a\xd3y\xb1\x8f\xa1m\x1d3\x95\x17\xfe\xa4g\x83\x15*\xfb\xf02_\xe3\xf9)\x13\xf2au\x17<\x86\xa9a\xc0\xa9\xb8\xb8\xfa\xf6[\xf8\xfe\x8fޏJ\xac\xa3\aV\xe1ڗ_Z\x01P\xe8\xbf\v\xe1:\xc9\a\x9d\x99\xae\xe0ҕk979\xe3\xeb\xe7\xdd\xec\xf4~%\x91J\xfa\x05\x9aR|\xcc\xe55\x00%\xff\x03]~\x8c\x9b>\xb2g\x94Q\x19\xb3\x1a\xbf+\xc85\x17,\x02\xa7\xcf\x19~L4A\xa78M\x99\xfe\x1d\v=Ź\x15\xfd\xf1D1\xf0p,\x82\x87\xe9=\xd6\x04\xffL\x84\x1f\x1e\x81\xba\xa3\x04\x03@\xd1MV\xc2\x1df\x8d(\x93(\x05V\xf7\x9c\x8d\xe1\"\xc7\\\x12.1\x18\xfa\x96\xb3\xb2o\x91^5\xe4\xacI\x8bř\xcc\x1e\xc1\x88\x93\xc4Ø\x82<\xcens\xf9\xe1\x8c\xd7ڕ+hV\x1d\x9c\xf4\xfa\xc9C.d\xf8%\x00\xdf\u007fa\x05`\xa1EdU\xbe\x00\x96\x82\xe2(mmm\x06\xad\xa9VN\xba\xa8\xa0\bL\xf7\xebe@\xa4h\xfe\xa2@Rr\xbf\xe9p3\xe7\x15L\xc1%\xa5\x12\x8f\x82s\xb8\x01\xab\xa6\x9f\rG\x96\xd9\xf03:\xa8\xa92P\x1f\xcb\x1d`\x93v\xd7,?\xa5;\x11\tt,\xf0\x91\x0e \xed>\xca\xee3(\x83R`\xd2dET\x85=\x96\xfbi\xb2\xae\xac\x11\x98x\x84p(\x96\x9c\xf3\xac\xb8\b/\x91\x8a\xb0s\x8a\xa1\xb0\xa2\x1c\xd4dz\xf7\xd7\xdeCNJ\x89\x90\xdf.B\xb6͔=N\x9a\xc7E\x8a\xf3\x90\xee\xb3\x1c\xea\xdc\x0fU\x9f<\x1a\xf8\xe3\xb2\xfd\xe3\x11*\x82\x81\xe6t\v\xab\xcb\v8\xd9x\x9cȕ\x80#>\a{\x81\x10\xec\xf1\v)\x00\x81\x86\r\x96\xf3\x99\xc82\x96V\xe6Q\xa9T\f5ٔ\t\xedX\xf7\xe7\x01\xf0\xf4\x19:b\x9f\nU\xe1\x9b\xcd\x01\x90\xac\x1e\xeeq\n\x83\xa8\xecK\xe1\x18\x8b\xcb\x1f\xc2\xfcM\xa6\xbfKV\x9e\x87\xec9f\r\xaf^_r\x10I9\x88\x91\x90G\x82.\xd2ߣ\x9b\x00D\xf6;\x11\x81Ue\x90\xfc>\xccC\x1au`i\x1c\xe4_\x13\xfcR\x1c\xa0H\xfde\xc3\xcf\xfc~\xcaH\x110\xa7\rC\xa2Dz\xfd.\xbc\xce0\xecB\x11\xe6D\x91\xa6{.\xe2\xc7\x04\xe5\xf69\xfb\x0e\xd4T\x14\x95\x9f\x1f*\xb8\x8bCT)\x97D\x9bl\x88\x98x4\xcbB\xf9խ\xb8XX^\xc0\x9d\x8d\r5\xacZ@\xd5up\n\xef\x05\x15@\xcd!\x19\xce&Z\x12\x00\xe6\xe7\xe7`\t\x01b\xa9\xe1\xee\xaa\x1d\xa7B\x1c\xa3Ƹ\\b\xadM\xf7\x17\xae6\xf5\xf3JzB\xe7\xfe\x9fKK{3w\x94\x14+\x83\x9c\x10'\x87R\xca\xe4\xa7\xcc\xfd\xcdRB*\x87\x97\xa5f\xbd4\x81ah\a\v\xa6\x83\x17\t\xbf\x10\":\xa4d\xc5?\x05H\xc4\xf7S|\x8b\xefO\xfe\x97\r\xde\x01\x91A\xe32\xc6\xec\xae\xc4#\xd2\u007fl\xf02\x940\x88\x91C\xb1\x8b\nT\xa6\xfb\x98\xedo\x18\xed\xab\x94\x85=\x86\xa2\bX+\x9eI\xbfi\xca\\yJ]\xfc\xcc\xcaS\"\xfc\x89\x82\x15\x04\x12\xc9\xef\xca}\xcas9\xf5\xc0\x14\xa5\xc2\xe3\x86Kf#\x93?\x8b\xa3;\x111\x0f\u007f\x17\x12\x84\x99\x85y\xa4\xad\xc8\x19\x00\x87\xb3\xa8Y/\xae\x00\b\x96 )\xab \x19\x87?\x84\xe9\xe9\x19%ŧ}\xc0\x1c\x16P\x9e\xa0\xa6! a\x19>@\xa3p\x03h\x13\x06ؤm5\xbc9B\x95\n\x16^\xa6\a\x8f\xc12\x84\x94\x122\xf9\x19*\u007f'ϓ\xb1ՒRQ\x1aRS\x04\x99\a \xd2\xc3&\n\u009f\xde/2\x81\x17\xc2\x02\t+V\n\xd1OaY\xe9sS\xa5 b%\x90Z;R\xbe\x17.ן4\f!\x1c\xb3>\xde\x04ڱI\xf03\xa1\x962\xcc\xefo\x18\x16\xeeK\x95\x83\xa2(\xd2\xef&\xf1\x12r`\x1f\xe2\xfd\xa0ة\xd2\xf77\xdbg!\x94}\xb6\xb2\xbf\xb3\xfb\t\"\xdeW\xa4\nWS\xe4ü,2\x00\xe2\x18\xee!\xe4\xbe\x02\x1a\xd6\x1c\x05\x85\xb4jkf\x06@\xa8|\xa7\xb2\x96o\xc8qv\x10\x90\x88YdM\v\x19\xb5Z͘\xfbO\xdcu\x15\x104\xfd\x96\xf3\x11J\x8c9a\xc4̇!\x8f\xb3\x11\xe3+\xa2\xae\x1c\xff\x9e\xb7\xf4\xd1\x01\vC\t\x96!\xc2\xf8@f?\x83\xf4\x90\x86a\x880\b\xe0\xfb\x1e<\xcfG\xaf\xdbE\xaf\xdbE\xb7\xd3\xc7`\xe0!\xf0\x03\xf8Ab\xcd\xf2\x8a\xa7Z\xab\xa0Rq!,\x82m;p\\\a\xd5j\x05\x95j\x05n\xb5\n\xc7q`\xbb\x0e,ˆ\xb0,X\x96\x05!\xa2߅eA\b\v\"~,\xfa]\x80(\xf9YT\x06\xa4\xc0\xde\\\xf0]\xb9\xc4#\x18\xa3\xf7\x1d\xe9\xfb\xaa\xc6\xf5E\x17>\x11\xe8P\x86\x902\xde\xcb0\x84\f\x83\xe8\xbex\u007f\x93\xdf\x03߇\xefy\x18x\x03\xf4:]\xf4z]\xf4z}x\x9e\a?\b\x10\x84A\xf4\x9d)\xd7@\x044\xebuXv\xa4(\x1dǁ\xeb:\xa8T+\xa8T\xabp]7\xda_G\xddO\x11\xff.r{\x9a\xda''\xd8\xdez\x8e\xdd\xfd\x03\xb4\xbb=x~\xa0Ѐ\xb8\xf8و\xc7\xe4\x00dgX\xc6?{^\x88\x9e\xef\xe1\u0d0d'{;\x10D\xa8\xba\x0e\xa6\x9bM,\xce\xcfaii\t\x8df\x13NŅm\xdb\x10\xb6\x1d\xefq\xe61X\x96\x05\xb2\x04\x04\x8b\x147ȓ\xd6)\xe5\x1e\x8c\x03\xc0\x12\x8dn\x98JC\xab!U?[Q\xe4$\x87\xf3\x1b\xc6\"\x02\x81s\x02G\xb9\xe6\n\xa4\x80\xbf\x9cG\xfe\r\xf7e\xc6ƀ\xf8\xeb\x9dV\x15\x01\xca\x14G\u07bf/\xbe\x87\x0e\xba)\xa8~\x89\xc5O\x0ef\x10\xfa\xd1\xcf\xc0\x87\xef{\xe8u\xbb8\xd8\xddÓG\xcfp\xb0\u007f\x02\xdf\x0f\xf2\x9e\x19P\x1ckH\xaa\rM\x82bɜ\xd4}\x12\x88H\xd8\xcc\xe6\xffM\x8a\xa5X\xd3\x1f\x9e\x17\x85\x19\x87\x87m\xf0\x11x\x03tNO\xf1\xf4\xf1&\x9e>y\x8e\xf6IOaV\xa9\x1fS\rg\x98Yʀ\x99{\x1c\x06'\xd2\ufd43\xc0\xdf\r\xa4\xbf-\xfd\x81ǁ\xe7\xcb0\xf0\x99eH\xc2\x16v\xadՄe\t\"r-\x12\xf3B\xd83\xc2v[®T!D\x93HTI\b\x1b\x80`\xb5\x8bj|\xf0e\xc889\xe9\xe2䤋\x8d\x87\xcf07\xd7\u0085K簸\xb2\x84j\xbd\x0e\xc7qce\xe0\xc0r2π-\v\x82-\x10g\xd9\x03\x82\x01\xd0b.\x01W\v;\xab\xa0\xf2\t\xa8'\xe38>\xb3\xf4A,\xf8A\xe0\xc1\xeb\xf7qrt\x88\x8d\x8d\xc7\xd8\xde\xddG\xd7\xf3\n\x1c\x01\xf5\\\xc5gA\xb2\x94\x1eCv\xa4\ufde5\xe7\x1d\x87\x81\xf7,\f\xbc#\xe9\xf9\xbe\f|O\xca0`\x96\xa1]\xa9\xd5\xecj\xa5\nA\x82H4H\x889a;3±\x9b¶\xaa\x10b\n\x82\\\"\xb2\xa0\xb6\x88PX~^\xe8\xe3\xf9\xd1!v\x8e\x0eQ\u007f\xf8\x00+\xf3\xf3\xb8x\xe1\x02Z3\xd3p+UX\x8e\r\xdbq2E`NJ@(\x18\x8cP\b]\x06\xc5j\x02\xa6\t\xa3\xe7\x10p\xcePh_U\xe2U\xaa\x16\xffe=\x00J\n+\xa4\xcc\xdc\xed!\xd3\\r\x03N\x88\x86\x93z\x86\x84\x040<\xb7\f\t4\xb6egM\xf8cw4\x94!\xc2 \x8c\xdd\xfb\xe8`\xfa\xbe\a\xdf\xf7p\xda>\xc1\x93\x87O\xb0\xf9x\x1b\xdd\xee@\xfb\xb2\xf2\xe9\x05\x0eÁ\f\xfc\xa3\xc0\xeb=\x19t\x8f6z\xbd\xa3G\x83\xd3Ón\xef\xe0D\x86\x03\x9f\xd9\v\x98\xc30\x86dU\xb5\xac6J\"\"\xcb\"\xb2,\x12\xaeMµk\xb5\xb9\x96ۘnV\xaaS\xcb\xd5\xfa\xf4\x15\xab:\xb5.lw\x81\x84U\a\xa8`\xd9B?\xc4\xce\xce!\xf6\xf6\x8e\xd0j=ĥ\xab\xebXY[E\xadр㸰\x83X\x19H\a\x96\xe5d\xf1,[\x10\x82\xf3\xe9Cb\x15|)\xe1\x06dh\u007f\x92\x96K\xd0|\x99*\xd6\xcc\xda\a\xbe\x97\xba\xf9\x87\x87\axp\xff!\x9e\xef\x1db\x10\x0405\xee\x88M\xb2d\x0e;\xa1\xef\xed\xf9\xdd\xee\xe3\xc1\xe9\xf1'^\xfbdo\xd0>:\x0e;\xc7]\x0e\xfd\x80C?\x88\xe6\xe7A\"\xab\xd2An\u007f\x89\x04Q\x84\x94\x92eYT\xadW\x9c\xd6̴\xdbl4\x9dz\xf3\x92\xdbj\x9e\xb7\xdcʺ\xb0\xedi\x12T\xd5\x13\xc7\fFg\xd0\xc7\xfdgO\xf1dg\x1bK\xb3\xb3\xb8z\xe9\x12f\xe6\xe6Q\xa9V\xa2}u\x1cXN\xa4\b,\xdb\x06s\f\x1e\xb2\x00D\xc2\xd5@\xc1\x1b`\x1d\x84-\x01\xad\teT\xe1a\xbd\x02\xa4\xd9c{\xd1\x10\x80\f\xee`\x01\xceS)\x92&\xb6\xe4\x99\x04|\xcc\xf0\xc1\xa0\rXqMS\xc1g\xc5\xd5O\x90\xe58\xfe\xf4c\x8b\xffx\xe316\x1fm\xa1s:(þ\x999\xec\x87^\u007f\xbb\xdf9|\xafs\xb2s\xef\xf4x{\xaf\xdf{\xdef\xc8\x01\x00?\xbe\x05\xf1-\x11~iP\x00)\xbe\xca\x1c\n\xe6P@z\x16\x00\xbb\xed\x1d<\xc71l\x00\xb7\x01\xfc\x85\xe3\xcc6j\xd3+Ӎ\xa9\xa5\v\xd5\xe6\xfc[N\xbduUX\xf6\fHت\ue552qt\xdc\xc1\xfb?\xbe\x83\x8d\aOp\xe9\xf2:V\xd7\xd7Pk4`\a\x15\xc8Ѕ\xe5\x04\x91\"\xb0m\xb0\x15{\x04I\xba\v\n\x03\x91\xb5\x14\x96F\xdf͑w\x14p/\t\x9f\xc2 R\xa8\x81\x17\t\xfe\xf1\xe1!\xee\xdf\u007f\x80\xad\xdd}xA\x90\x9d\x1fU\x18\x98\xa5\f\xc3v\xd0\xeb<\xea\x1f\x1f\xbe\xd7;\xda\xdd\xe8\xef\xed\x1c\x85\xbd\xa3\x0e\x00O\xdb߰d\u007f\xf3\n\x80Y0\a\x022\xb08\x80\x85A\xd7\n\x8f\xf7\xec>\xe0\x00\xb8\t\x12\xae=3߬\xcc\xcd\xcfW\xe7\xe6.WZ\xadO[U\xf7\x9c\xb0D\x9d\x11\xbbG\xf1\xcbza\x80ͽ\x1dl\x1f\xeccun\x0eW._\xc6\xec\xdc\x1c\xdcj\x15v\x18)\x02\x19\xdaQ\x98 㽅\xbe\xb7z\xeb\x18Y\xb0\xfb4\xb4\xe6\x82\v\x00{\x11;\xd0*,_\x1e\x03\x90i\xa3\x05\xd2r\x8e\xd1wH\x1a\x12K\x99\x17@\\\xb4\xd4\x06\xa1/\xbd\x9fȘ?Ms\xdb\xc8\xe7I\v.\u007f\xce\xeaG\x873\b\xa2\xb4\x92\xefGh\xf3\xd6\xd3g\xb8\xff\xc9#\xb4O\xba\xe6\\\x06s\x18\x06\xde\xee\xe0\xf4࣓\xa3\xa7?<\xdc\xdf\xd8\x0e\x82v\a\xe0>\x80A|8\x93\x9bI\xf8\xa5A\r\xab^\x80PnV\xfc}$7\xd7\xf7\x0f]\u007f\xef\xf0\xf9\xc9ޭGD\xf6\x0fj\xcd\xf5驹\xf5\v\x8d\xd9\xd5/\xda\xd5\xe6\x15a\xd9S\xa0\x1c\xab\x1aGG\x1d\xbc\xff\xfe\x1d<\xda\xd8ĵ\xd7/cqe\x05\xd5z\rNP\x81t\xddX\t8\xb0\xd8\x06,;\xb2VV\xe2\x11\x93\x81\x12\x9f\xcf\xeb3\xb2||\x18\xa7\xf0\x02\x05\xd4\xf3\xbd\x01|o\x80\xf6\xc91\x1e\xde\u007f\x88\xc7϶\xd1\xf7=s\xeaP\x86\xfd`0\xd8\xec\x1d\xec\xfe\xd5\xe9γ\xdb\xfd\xdd\xcd}\x0e\xbd^\xbc\xb7\xea\xfe\x8e\xa3\\\xf5\xfdM\xe6\xcdY\x86\xfdu\xc0\xd2\r\x0ew\xdd\xe0pw\xabs\x1fwɭ~\xa7\xb2\xba\xb6X_\\|\xa3:?\xfb\x05\xcbu\xd7HPE=\x15\x81\f\xf1xo\x17ۇ\xfbX\x9b_\xc0kW\xafbzv\x06N\xa5\x02;\xf6\xb4؉\xf66\xf2\x06\"%\x8b\x84\xb0\xc5\x19\xdeZV-B\x1a\xfaO\x86\x8bSk\x03\n%\xd4\n]9\xdak\xf9r\x1e\x80\n$\xa4T\xd3\\w\xd5\xe2lCʑ\xce(\xfd\xa4\xa4\xd3z\x13\xadh \xcb\xe4B\x04\xf5~)\xd5\xfa͜\x82Ȅ?\"\x92$q~\x10x\xf0\xfd(\xcd\xe4\xc7\xee\xe8'\x1f\xdf\xc5\xce\xf6a\x9a\xa3\xcfa\x19\x1c\xfa\x81\xd7{\xda9\xda\xfa\x8f\a{\x0f\uf71en\xee\x03\xdc\x03\xd0\x03\xd0\xd7\x0e\xe8\xb0\xc3)\x87P\x16ʔ\x80\x95\x1e\xd2\xe8\xe6\x02p\x99\x83j\xb7\xbdq\xd8mol\x8b'\xeeͩ\x85\xeb˭\xf9\xf3\x9f\xaeM-\xfe\xa4p\x9c\x85\xc8协\x81\x04\x0e\x0fO\xf1\x83\xef\u007f\x84\x95\x95\xa7\xb8\xfe\xe65L\xcf\xcd\xc2\r\xab\x90a\x05\xb6\x13\x82\xa5\x038\x1c[+\x8e\x0f\xaaP\x98\x84\xf9\x9ax5\xb5's8\x8a\x8f V\xaa\xbe7\xc0\xa0\x17)\xd6;\xf7\xee\xe3\xa4\xd3\xcd\x1f\xf4\xe4uð㟶\xef\xb4w\x9f}\xa7\xfd\xe4\xc1F\xd8?>\x89\xf7U\xdd_o\x88g\xc5%\xcaU\xd5]\xeaޒ\xb6\xb7\xa9\x92\x8do\x15\xf6\xfa\x95\xfe\xa3\a\x87\xfdG\x0f\x1e\x8b\xa9\xe9\xef5ί_\xac/-\xfd\xb4\xdbl\xbcN\x96h\xaa\xb1\xb7'%6v\xb7\xb1s\xbc\x8f\xcbk\xeb\xb8t\xe9\x12\xea\xcd&d\xe8B\x86!l7\x02d\x99m\xc0\xb6 `!\xa9݇\xa2d\xc7a\v\x0eE\xfes@\xc0覢/\x06\x02*-\xbeҬ|\x99{\x9e+\x82\xd7sƆԞZ%Hd$:\x98\xee'\xadyB\x0e叁\xbeT\xf8}/\x12|o\x80n\xb7\x83'\x1b\x8fq\xef\xf6\x06\x06}_\vO\x00 \f\x03\xaf\xff\xf8\xe4\xe0ɷ\xf7\x9e߽\xdd\x1f\xec\x1e\x01\xe8Ʒ\xe4\x80\x0e\x86\xb8\xa5\x12\x18\xd97Z?\xa4\xaa\xb5\x12\x8a\xc52\x1d\xd4*\x80\xaa\x94^\xedx磣㝏\x9f\xd4Z\xe7\xbf7\xb7\xfcڧ\xebs+?k9\x95e\"\x12\xac \xdc϶\xf6qpx\x82+W\xd6q\xf1J|Pe\x18Qn\x99a;N\xfc\x1dG\x874R\x02zmD^\xf8\xc38֏\xe2\xfcho\xbdA\x1f\xed\xa3#ܾ}\a\x9bۻ\b\x99\x15W?\x06\xd9°\xebw:\x1f\x1f?\xdb\xf8\xf7\xa7\x9b\xf77\xa5\xdfkk\xfb\xdb?\xa3b\x1dV9\x9e\v\xb7\x86x[\x8e\xb6\xbf5\xd9>>i\u007f||pz\xf7\xee\xdd\xea\x85\xf3kS\xeb\xeb_v\xa7\x1a\xef\b[\xb4\xd47\xe9z\x1enn<\xc0\xf3\xfd]\xbc\xf9\xda5,,-\xa1\"\xab\x90\xb2\x02v\x1d\xd8\xc9G\xb4\x19\x82\xa2T,%h#\xe9\xb46\x1aCx\r\x80\xa1\xd6\xd7\x10:`+\u0097\x01\x01\xf3-0(\x85\xc4\xd8LT2\x95\x053\x19B\x02CjO\x05\xf6\xcb\xf0\x81\"f\x9c\x1dP\xa9\b\xbf\x92\xce\xf3\xe2\xc3yr|\x84[\x1f\xde\xc6\xf6\xb3}\x8d\xba\x1e!\xf9\xd2\xf7v\xdbG[\xdf\xdayv\xf3\xbd\xde`\xf7\x00Q/\xa5N|8\x13ˤ\xbb\xa4\xc3\x04\xbf웤!\x8a@\xf7\nt\x8f\xc0\x05PI\x14\x01 뽓G\xa7OO\x1e\xed֧/\xbd?\xb7z\xed\xf3\xf5ٕ\x9f#ۙW\xcfU\xbf\xef\xe1֭\a\xd8\xdf;\xc0\x9bo\xbf\x81\xd9\xf9y\xb0\f\xe3\xf8Q\xc6։!\xc8J\x952\xa9Q\u007fJ\x89VҦA\xe4\xee{^\x1f\x83^\x0f\xbb\xdb۸y\xeb\x0e\x8eڝ8\xe4\xcd\x0e\xabd釽\xde\xc6ɳ\xc7\u007fz\xf4\xe0\xe6]\x0e\xbd\xb6\xb2\xbf=E\xb1\x0e\xc6t\xf7_f\u007f\x87)\x82\x8a\xb2\xbf5\xf6\xbdv\xef\xfe\xfd\x93\xdeÍ\xcd\xfa\xd5\xcb\x17\xa6έ}\xd5m5\xde&K\xd4\xd43\xb4wz\x8c\xbf\xfc\xf0=\\][\xc7իWQ\x9f\x9a\x02XqT\xc8\x01\x10yZ\t8\x98e\xd7\bz/L\xd5\xf6\x93\xa1ò\xce0̇\x01\x8a\xd3I/\xe9\x01P֛*O\x1b\xcd\t+\x1b\x8c=\x15?\xa0\x9a\xe0'\x15\xe5,\x02\x88\xc5l\x02k\t\x14Rjȑ\xb7LA\x00?\xf0\xe0{^t8\xfb=\xec\xee\xec\xe0\xe3\xf7o\xe3\xf8\xc8\xd0#\x91\xc3^\xbf}\xf0\x83\x9d\xad\xdb\xdf::y\xb0\x05\xe04\xbeu4ˤ\v\xbe\xd4P~\x8c\xc1`Ƙ\x87W?\xb0\xba\"H\x0ej\"D\x8d\xee\xf1F\xa7{\xfcx\u007fj\xe1ڇ\xf3k\xaf\xff\x82;5\xfbY\xb2\xac\x9a\xea%=\xdf9D\xfb\xbb?\xc4\x1bo\xbd\x86\xf5\x8b\x172\x0fO\x19\xd4,\xc0 !\x94\xe8\x8a\xc1\x9c\t\u007f\xea\xf2\xc7\xc2\xdf\xeb\x9cb\xe3\xe1C|ro#\xeaQO\xf9́\f\xfc\xbd\xf6\xf6\xd3\u007f{\xb8\xf1\xc9{\xc1\xe9\xfe\x81\xb6\xbf\xba\xcb\x1fh\xfb+\xff\x9a\xf7WW\xb4\x8e\xb2\xbfU\x005\x00\x1dȰӽ{\xef\xb4\xf7x\xf3i\xf3\xb5˯M\x9d_\xfb\xaf\xac\xaa{9\n\xec\x91\x02\x85\xb777ppr\x84w\xde|\vs\v\xf3\x19(\x17+D\x12v\x9c\xd5&\fk\u007fS\x9a\x12d\xb3\x92ȧ\x01\xa5\"g/\r\x02\x0e鬚5Z)\xe8\xae\xccCл\xda\xe8\xf5\xcdd\xc8\x1c\xe8y~\x15<\x97\x9a[\x9aY\xa7H\xf8}\xf8\xbe\x0f\xdf\x1fD\xb4\xd2^\a\x9b\x8f\x9e\xe0\xf6\x87\xf71\xe8{Y\xa5X\xfc\n\xa17xv\xb8\xfb\xe0\x8f\xb6\xb7?\xf88\x94\x83c\x00m\x83\xf0\xab \x9f)\xb5\a-\xe6\xd4]P*9\xa8\x80\xa9\x0fV\xf1\xb5\x13ECJh0P\x0ej/s\xa3e\xaf\xbdw\xa7wz\xf0\xe0w\x17\xce\u007f\xf6\xbd\xe9\x95+\xbfl\xb9\xd5u\xf5\xa0v\xfb\x03\xbc\xff\xde-\x9c\x9c\x9c\xe0\x8d\x1bo\xa2I\x88\u0602\x94\x90\x05-Hbų\x949\xe1\xf7}\x0f\xfe\xa0\x0fo\xd0G\xa7}\x82۷nc\xe3\xe9vT\xbe+\xd4ݕ\x81w\xda~\xffp\xe3\ue7de>\xbd\xf7\x04බ\xbf\xc3\x14\xab\xd4\xf6Ew\xe7\r$둊\xc0\xb4lj\xb4\x04\xf1k\xfb\xb1\"\x18(\x9eI\x12\xa2ty\xd0\xef\xb5o\xde\xeat\xb7\x9f?\x9d\xb9~\xf5\x8bՅٯ\t\xdbj\xe5\x94\xec\xc9>\xba\xef\xff\x00\xef\\\u007f\x13\xe7Ο\x8f\xf7\x94 \x92\x9f\x00\x98Đ\x8am\xb3\xebO\xd0\xfb\x91\x98\x86\xaf\xaa\xfd\n_\t\x158\x11f\x89\xa4\xf5f\xda\t(\xf3\xe15O\x80\f\xbc\xf7(\xca\x00\x00 \x00IDAT\x9c\xf1|\xac\xcf:}\x91Uea\x1a\xadeț\xaan\u007f\x9c\xe2\xf3c\x14z0\xe8\xa3\xd7\xed\xe0\xc1\xdd{\xb8\u007f\xfb1\xfc@j`\xa1\xf4\a\x9d\xc3\x1fm=\xfd\xe8\xdf\x1c\xb7\x1fm\x01Ѕ_\x8f\xf5C\x83\xb5Wcwݵ\xd4\x1f\xa3\x11\x1aVbX\xa7\xcb\xec[L\x94A\x82?x\xf1\xe7\xec+\xb7\x1eK\xbf\xb7\xfb\xe8\xfb\xbd\xd3íg\x8b\x17\xde\xfeZuf\xe1\x8b$bo\x80\x81P\x86\xb8w\xef1X\x86x\xe7s\x9f\x8e+\xe1\b\u008a\xf8\x00\x02\x16 (&PeH\xbf\xefy\xf0\xbd>\xbc~\x0f'\xc7G\xf8\xf0\x83\x8f\xb0\xbdw\x10\x91\xa5\x94+\x94\x81\u007f\xdc\xd9\xd9\xfaӽ;\x1f|?\x1c\xb4\x0f\x00\x9c(\xfb\x9b\x84T\xbab\x95%\xfb+J~\xa7\x11\xfb[6\xe3k\xd8\x1e\x87\x8a\"\xb0\xe3\xcf\xd7W\xf0\x9f\x1e\x80~\xb8\u007f\xd0\xdf\xff\xdeΎ_\xbbr\u007f\xfa\xea\xf9_\xb3k\x95\xab \x88\xc40\xb6\xfb]\xfc\xf0\xe3\xf7a\xdb\x16\xd6ίDžEI\xe9q\xe4UE:\x99Ƌ\xf3\rӊ\xf4\xf2\xf9\xac̈́\xc2\xfe\xa3\xd1t\xf51=\x00(\xb1?\x1b\xa9\xa3ɨ@ι\xf2d\x00+`\xac\x15H\xbd\x06\xce\x17ɰ\x9a#\xd5\vy\xa4L-\u007f\xa0\b\u007f\xb7s\x8aOn\xdd\xc1\xa3\xbb\x9b\x90\xb9l\x02\x81\xc3\xf0\xf4\xe4\xf0\xe9\x9fl>\xfe\xab\xef\xfb\xb2\xbb\xaf\b\u007f\xdbp8u\xc1/C\x96--\xddd\x19\x0e+\f~\x1f+\x16Oj\xa1\x85\x8e/H\xc3\xf3\x13\x97\xd9W>s\xeaR\xf7N\x9e\xf8\x9b\xb7v\xffp\xe1\xc2g\x1fN\xaf\\\xfa\x15ḋP\x0eʣ\xc7[X;\xbf\n\xa7\xe2²\xe2B\x978䊾;\xa9xV\x99\xe5?><\xc0\xfb\xef\u007f\x88\x9d\x83\xa3\xec{\x8a\t\x04\xe1`\xf0\xec\xe8\xf1\xfd\xdf?\xbc\xff\xc1\x9dxoO\xe2\x9b\xeeU\xf9\x06\xc1/ˊ\xe8\xfb\xab+[*R\xc4r\xb7\xf0\f\xfb\x1bj\xfb\xebk\xfb\x1ba\x15\xcc^\xf7\x93\xfb\x9ewxt8\xf3ƕ\x9f\xab\xceO\xff,YTK>E?\xf4q\xfb\xfe\x1d\xcc\xce\xcd\xc6\x14b\x01\x96\x02,\t\x10\x89\rUb/*\xe9ՠ1h\xb9\x10\xfb\x1b.\x99\x94\xa3\xf5\xb2!@>/I\xd9g%\x1d\xb1W)\xbbd\xd0T\xf9X\xbf8\xe6\x16\xe6\xe3\u0097\xa8\xf9\b\x10\xb9\xa8\x92e\x04\xf8\xc5\xca\xd5\xeb\xf7ptx\x80\x1f\xff\xf8}\xec\x1f\x9fhW\xc4\xd2\xef\x9e\xdeڻ\xf7\xf1\xbf\xeel=|\x12\xefm\xa2\\\x13\xe1Wc}i\xb0\xf6\x96\x16\x8fۆ}\xd6\x15\x82\x18\xa2\x00\xa4A\xe0\xf5}\rJ\xf67\xd4\xfe_U\x04\xe9\xfe\x06\xbb\xfb\xe1\xfe\xd1ɟ5o\xbc\xb6ݺ\xb0\xf2+±f\x93\v\xda==\xc2\xce\xce6j\x8d\x1a\xc2 \xa92\xa4hvǰ\x88P\xa7\xf8\x8e5p\x85\xb5\xe8\tI\u007f\xfb\x97\x05\x01%D\x84_\xe6{\xe1\xeb\xa7Y\xe1\xfb\x93։G-\xfaUC\x87\xe2t\x19*\x99\xaa\xab\x02Rq\xa5Y\x92\x87N\x0e\xe7 \x02\xa4\xee\u07bc\x8d'\xf7\x9f\x82\xa5Z\x96\xc9\x1cx\xbd\xcd\xe7\xcf\xee\xfc\xee\xf3\xfd\x9b\xf7\x01\x1c\x1a\x84\u007f\xa0Y}(q\xa7~(]\xe5\xe6(?\x1d\xc3A\x15%\n@w=\x03\xcd\xe2\xf8\x1a\xd1\xc8/\x01\xcaX\x11\xa8\xb0\x84-\x87\x93\x9dOh\xd0m\xff\x9fko\xfc\xc4o\xb8ͩדõ\xbbw\x80\x93\xa3CTjU\xc8\xc0B\xd4\xfd1J\tF\f??Τ\xf4p|t\x88\xf7\xdf\xff \x13\xfe\xd4k\x93\xc1\xe0\xe4\xe8{;\xb7?\xf87\x83\xa3\xe7ۚr\xed*!\x95j\xf5u\xc17\xa5\xe5\xca\xf6\xd72xZ\xa6\xfdU-y\xa8\xed\xadi\u007f}-䓆[AY\xb0\xef\xa3\xfdޭ\x0f\xc2\xc1\xc0\x9b\xbd~\xe1\x1b±\xa6\x93\xf3\xfa\xe0\xc9C\xac\xae\xad\xc1q]H\x19\x80YĽ\x12\bJsB#\xb4I\x86\x9e\x02\x05\x00\xb0\xd0\x01W+%#\xf9*B\x00Vf\xff\xe9!\x00\x95V\xf8\xe9}\xe3M\xde\x01\xb4L@\xbe\x85>\xe5.,M\xf7i\xc2\xef\x0fz\xe8w;\xb8\u007f\xe7.\x1e\xddی\x84?\xe3\v\xb0\xdf\xef\xdc\u007f\xf6\xf4\xa3\xdf\xdd?\xbe\xff(\x16\xfe#\xcd-\x1d\x18\xac\xbeP@75\x05\xa7\xa6\x8a\x92\x9f\xc9cNՙk8\xd5V\xb5RmN\xb9Nm\xcev\xaau\xb2]\x87,;i\xff\x03f\xc9\x1c\x06\x92\xfd\x81\xe7\xfb\xfd\xce \xe8\xee\xf9\xbd\xd3\xee\xa0w\xd0\xf5\xc3Ӟ\xe6n\xaaģ\xber\xbf\xaf\t\x94,\x89y\x13\x89\xb6\a\xa7[\x95\xfd'\xb7\xbf\xbdr\xfd3\xe7ȶ\x9b\x00\x10\x84!\xf6vw1\xbf\xb8\x80ж@!\xc54{F\x18\x86\x11\xc1\xa7\xdfG\xfb\xe4\x18\x1f\xbc\xff\x01v\x0f\x8f\x14\xd5\xc8`)\xfd\xfe\xc1\xfe\xff\xb3\xfd\xf1\x8f\xfem\xd0=ލ\xf7\xf6H\xb1\xfc\xc9\xe7\x0f\xb4\xcf$\x86\xa48՟\xc9\xcd%!\\gv\xaea7\xea5\xa7V\x9b\xb6\xab\xd5\x19\xe1:U\xe1\xd86\tJ\xcd*K)\xa5\x1f\x84\xa1\xe7\x0f\x82\xc1\xe0\xd8\xefu\x0f\x82\xd3n?8<\xeep\x18\fr\xae|q\x8f\aC2>\xb2\x84\xdem\x01p\xba\xb7\x1f>\xa8L7\xbf\xd7<\xb7\xf0\v\x11&\x00\x1c\x9e\x9e`\xd0\xef\xa2֨\x81ى\x84?\x1d3.T\xdbg\xa8\xbd(\x86\x03\xe5m[c\x00PH\xdde~\xc9\xc1 \x1a\x18\x9b\x8c\x05\xd7[K\xa5\xe0\x9e\x89\xe2\x9b#\xf6\xa8\xffG9n\xb8\xdec\x91\xf3\xc0\x1d\xc0\x9c\xf1\xfa\xe3B\x13\xdf\x1b`\xd0\xef\xe1\xc9\xc6#l\xdc~\x04\x19\xca\x1c\x8f5\xe8\x9d\xde{\xfa\xe4\x83\u007fyp\xfa\xe8\t\x80\x03E\xf8O\x95x\xdf7\b\x8c\xa5\x13pⴐr\xa3\xaac7\x1b\xadֹ\xc5Fs\xfeb\xb5>{\xddr\xab\xe7\x84\xe5̐\xb0\xaa\x00\x9c\xaci_^\xd5g\r\xb19\x04\xd8\xe30\xecK\xe9\xef\x05\xfd\xd3\xcdn\xe7\xf0f\xa7\xbd\xbbuz\xf2t_ʁ\xca@\xec\xa9`\x94!}\xc6\x06\xef\xc5V\xae\xa1q\xba\xb7\xb1믿\xf6\xacҚ\xbe\x9e<\xa9\xd7\xed\"\f|\xc8І\f\b,\"+\x15ĥ\xbb\x9d\xd36n\xdd\xfc\x18\xbb\aG\x99/'\x00\x96\xd2\xef\xee\xed\xfc\xd9\xf3\x9b?\xfaV88\xddS\x94\xab*\xfc\xaa\xcb\x0fM\xf0\x93\xfd\xad\x19\xf6\xb7Jª\xdb33S\x8d\xc5\xc5\xe5\xea\xf4\xf4\xeb\xceT\xf3\xa2p\xecU\xe1XM\x10* \xb2)\x92\"\xca{\x92Q\xf5Fą\xe2\x00\xe0\x81\fî\f\xfc-︳\xd1?>\xb9\xdd\xdb\xdd\xdf\xf1\xf7\x0fO eO\xdbW\x13\xdb3P\xf65\x8c\xefK\x94X\x92\x8d\xa9\x81\xb9\xd1y\xb6s\xa7\xbe2\xfb3¶\x1a\x00#\xe4\x10\x83\xc1 \xa2Oˤ\xe9i\xbe\x0e\x80\x86LS\x1e\x1e\xf7\xab\u07b6\x96<\xa2HA\xbf\x02\x0f@\x82 \xf2\x1f\xc2\xc4\x03\x88\a\x83\xb0F\xf1͜\x11SÐ\xbc\xb7\xa2\xaa\x80\"\r\x95\xd3\x16R\x19\xe8\x17!\xd2Ϸ\xb6p\xf7\xc3{\b\x03\xa9\x86\x10\xec\x0f:\xf7\x9e~\xac\b\xff\xb1\x86\xf4\xeb\x87S\xb5Hɡ\xacǷ\x06\x80\x86%\xdc\xc6\xec\xecյ\xd6\xf4ʛ\xd5\xfa\xec\x17,\xb7\xba\x02!\xaaq\"\xcd\x1c\xadq\x9e\x98A)4A\x02 \x87\x1c\xd1\x10p\xe6\xedJ\xed\xf5jk\xe1\xe7fV\xae\x9c\x06\x83\xee\xe3^{\xef\a'\x87\xcf>99\xda\xd8\x058II\xa9\x04\xa5\x9e!\xb6\x86\xe2\xaez*\xaf^\x86\x83\x81\xefu\x1eT\xd0J\x15@\x94E\xf1\x11\x06vZ\xb7\"\xc3\x10A\xe0\xa3\xdf\xeb\xe2\xee\x9d;x\xba\xbd\x93em(\x12\xfe\xde\xde\uedf7?\xfa\xc1\xb7\xa4\xd7\xddU\xf6W\x15~_QL\xa4)\xa4\x8a\xb6\xbf\x8d\xf8V\xb7[3\xd3S\xe7\xd6.\xd6\xe7\xe7?\xebN5\xde$ۚ'AN\xcaF7\xe5\xc0\v\xd6\x10\x04\x82E \v\xa0\x8ae\x8b\x96U\xb1W\x9cz\xf53\xf5\x959_^]?\xf0\xdaݏ\xbb\xfb\a\xefu\x9f>\u007f\x14\x1c\x1c\xab\xacώ\x92\x02\xeck\xa00+\x8a@\x0f#<\u007f\xef\xf0\x98e\xd8\x06Q#\xf9\x1a\xa4\fR\xe7!#_\t\xe5'F#\xff9|\x8c\r=6\xf5qk\x18\xc2D\x1f\x1b\x03\x90Eͣv|\xa5bN\x9fL\xbd\xfe\r\xad\xba\x136T\xbe\xc1\x81\x81\x0e\x99 \xffi\xbb.\x1fa\\\xc6\xeb\r\x068>:\xc4\xed\xf7n\xc3K\xa8\xbd\xf1\xab\xf8^\xef\xf1\xd3\xcd\x0f\u007fW\x11\xfeC\x83\xf0\x87J.X\x18\x04?9\x94M\x00\x8d\x8a=33\xbfp\xe5Jk\xf6\xdc\xcf;\x95\xfakd\xd9\xcdT\xdb%\r2(\x0f\xe3\xe6ʉYgD\xb2\xe29)\x8f\x11l!\xac\x19\xb7>5\xe3Ԛ7\x9a\v\xe7\x0e\x17:\xaf\u007fx\xb4\xff\xf8;ǻ\x0f\x9e\x86\xb2\x9f\x84/\xa7\x1a\x9b.\xf1fX\x8b\x8d\xd5x\x98e\xe0\xfb`\xe6\xd4\x03M*&\x03?=H2\f\xe1y\x03<}\xf2\x04\x1b\x9b\xcfb\x975yE\x19\xf6\x0f\xf7\xff|\xfb\xe3\x1f\xfe\x99\xf4\xba{\x9ag\xa5\n\u007f\xa8\b\u007f\x12\xe3W\x14+\xdfT\xf7\xb7\xba\xbc\xb2\xd8:w\xeeS\xf5\x85\xf9\x9f\x11\x15\xa7P\x8c\x93\xef<ͥ\xca5m\x00B\x06\xc0,\xaa\x80v\xad\x8a\xb5R\xadL\xadT\xe6\x1a?պ\xb8\xb2\xd5\xdb=\xfen\xfb\xf1\xb3\xf7\xbc\xed\xbd=0'd\xa5\xaa\xa2\x14\x06\x9a\x12\x10ʁ\xcdB\x03)%\x87a\x90\x8dݤ\xb47b9\xcdcx\xb7\xcb\xd4ʛ\xca\xee1b\xba2\xbdt90\x176^\xe5\x01\x14*\x02\x99\f\xde\x01\x86\xb7\x03\x83B\x14\"䪜\x92\xb8\x9fe\b\x19\x04\xa9\xf0\xfb\xde\x00\xdd\xd36n\xbd\xff1:Z5_\x18x\xdb\xdb۷\xfe\xd5~\xfba\x12\xf3'¯\xba\xfd\x81\xe6\xf2\xbb\xca\xe1\xac\x03\x98\x8aoM\x8b*3+\xcb7^\x9f\x9e[\xff\xbbv\xa5q\x99\x84\xa8\x98\x87\x8dd\xed\nmdž\xe3X\xa8T]T\xaa.\x1c7jD\xc9\xcc\b\x82\x00\x9e\xe7c\xd0\xf70\x18x\xf0\xfd\x10~\x10\x1a\x0f\x00\x11,a9\v\xd5\xe9\xf9\x9f_nN\xbf;\xbbx\xf1ã\xbd'\xff\xe1\xe0\xf9\xc7\x1b̲\xae\xe4\xd7+\x9ab\x03\xf2EE\t0)Ȳ\x9c4o\x1b+\x80\xc8\v\x10is\x8f0\fp\xb0\xb7\x87;w\xef#\x94\xa1j}\xd8k\x9f\xfcx\xfb\xd6\xfb\u007f\x16\xf6O˄\xdfS̏\x1e\x86$\x8a5\xd9ߩ\xca\xfc\xe2\xe2\xec\x95K\x9f\xad\xcd\xcf}\xcdr\x9dE\x10\xacaV^\x10\xc1\xb5\x1d\xb8\x8e\x8d\xaa[A\xc5u\xe0\xd8\x0e,K \x94!\xfc \x80\x17\f\xd0\x1b\f0\b|xa\x10u\x1c\xa2b\x9b-\b\xaa:U\xf7\xb2\xbd\xbep\xb1\xb1<\xf3\xb5\xde\xfe\xf1\x9f\x1fo<\xfb\xa1\xf7tgG\xdbۮvmB\x01'ӽ\x85E\x82,\xb2\xf3\xec\xbc\xd80\x82A$\v\xd4_\xa3\xb0\xa3\f\xfc+\x01\x03\xd3PZj<\x9c\x97\f\x01(\x0e\x01dV\"kl\xd01\x9c\aP\x92\xfa\xa3\xb2|\x1f\xb2\x9c\xbfTQ\xff\xb8\x91G\x1c\xf7o\xdc\u007f\x80\xbd\xad\xfdT\x111\x00\x19\xfa'\xbb;\xf7~\xef\xf9\xe1'\x0f\x15@\xea\xa4D\xf8\x85\"\xfc\xd5X\xf0\x9b\x00Z\x00\xa6\b4=?s\xed\xc2\xe2\xf2k\u007fߩM\xbd\x9d\x91i\xb4V\xa5\x82`;6\xa6\xa6ꘙ\x9f\xc6\xec\xfc,\xea\x8d\x06\xdcj%J\xaf\xc5\xddb\xd4\xc1\x99I\xb9\xb2\xef\xfb\x18\xf4\xfb8m\x9fb\u007f\xef\x00\xc7G'8=\xed#T\xb0\x8c\xe4P\x90e5+S\xb3_Z\xaaO\xddhͭ~\u007f\xf7\xd9'\xff\xfe\xf4\xe8\xd1v,T\xa7\x9a\xf5\xe5\xf8\xda*J\x8c]%aW*\xd5\xdae\x95\x0f\x10\x19\xae\x00A@\x10\x14u\xda\xed\xf5:\xb8s\xe7\x13\xf4\xbcA\xce\xc2\x04\xbd\xee\x83\xe7wn\xfe\xa1\u007fz\xb8\xa3(\xd6v\x89\xf0[\x8aկj\x82\xdf\x12\x95\xea\xec\xec\xb5ko\xb6\xd6V~Ū\xb8\x17\xa2\x8a\x19\xed\x80\x13G}\xfb\x9c\nf\x9aM\xcc\xcf\xcebzz\x1a\xd5Z\xd4\xe1\xd7\xd2Zr\xe9\x1c\x11\xcf\x1b\xa0\xdf\xeb\xe1\xe8\xe4\x18{G\xfb8\ue722\xe7\x0f\"\xe6\xa2*\x80\x82\x85\xa8Xˍ\xd5\xd9\u007fX\x9d\x9f\xfa\xe9\xd3\xd5\xf9?=\xbe\xf5\xf0}\xd9\xe9\x1fş]\xcd\x16%\n\xd6Q1\v\x00\x15gnzZ\xd8\xd4T'\b\vAȥ\xfc\x89s\xe1\x94\xde\xe1jd(@\xc5t!\x956\x04yi\"P\xf4Să\x97\xf5\x90+7\x12*E\xf8L9\xfd\"\xe0g\xfe|yE\x93\xa3\xa2&4_\u007f\x80\xbd\x9d\x1d<\xba\xf38\x1fdK98>\xdc\xfc\xc3\xcd\xdd\x0foih\u007f\x99\xf0\xdb\n\b\x95\x1c\xcei\x00\xd3\x15{z\xfe\xdc\xea\xdb_lά\xfe=a9s\x11\xba̹\xa1\x1b\xb6cafn\nKk\x8bXXZD\xad^\x8f\xba\xc4Xv\xae3o6\xbc#\xdb3\xbd\x1d\xf9\xfcb\x88\xf5\x8b\xe7\xe1y\x03tڧx\xbe\xf5\x1c;;\xfbh\xb7\xbbH\x8c\x17ǩ!XV\xab6\xbd\xf0\xb5s\x8d\xa9\x1b'\xbbK\u007f\xbc\xf3\xe4\xc3\x0fð\u007f\x1c+\xb0\xaef\xa5*\x8aRkL-^Xr\xea\x8du\xf5\xbbq]\x1b\x1c\x86\b)\xcem\x05>6\x1en\xe0\xe0$\x9f\xee\v}\u007fg\xef\xe1\xdd\xdf\xeb\xed?{fȦ\xa8\xc2\x0f%mZQb\xfcV\xb2\xbf\x8ds\xeb\xe7\xe6\xae\\\xfe%wz\xea\vdQU?oD@ݭ`af\x06\xab\xcb˘\x9e\x99A\xb5Z\x8ds\xe9J\x8bn!\xb2\xfe\xff@65H+\r_\\^\xc2\xe5\xe02\x06\xfd>\x8e\x8e\x8f\xb0\xb5\xb3\x85\xbd\x93Ct\xbc\xbe\x12|2@\x10V\xc5>\u05fa\xb4\xfc\x8fj\xf3S\x1f\x1e\xdd\u007f\xfao\xba\xf7\x9e>\x89\xaf!\t\xb7|E~\xaa\x89\xc1\x00Po\xae/\xbc.,j$\xcdS,!\xa2\x16\xf0iOVV\x94\x80fE\r\xed\xf7\x98ˇ\x8a\xe4\x1a\xe6\xb2\xd2\x12,\xd7\xea\xec\xa5=\x80\xcc]\x11)\xb0dž\xb6|j\r\xbf\xd6 \x84h\xa8\x96\xcbO\rPg\xedIp\x18\x82\xd5\xfer\x9e\x87\xeei\x1b\xf7n~\x82\xc0\vr\xf3n\xba\xa7\xfb\xdf{\xb4\xf5\xe3\x1f\x18H>e\xc2_Qb\xd1\x16\x80\x19\x00\xd3sS\x97/\xac\xac\xbe\xf9u\xa7\xda\xfc\x14\t\xe1\xe4[4\x11*U\x1b\xcbk\vX\xbf\xb4\x8e\xe6\xf44*n%ב7\x13~\xa1M\xfeQ[\x18\xc8\\\x88\x13\xc6qx\xa5RE\xbd\xd1\xc0\xec\xc2<.\xf7{8<8\xc4\xe3\x8d'\xd8\xdf?F\x10\x87\t\xf1\x1e\x91師3+\x97\u007f\xa7ڜ\xfe\xde\xf3G\x1f}\xab\xdb\xde\xde\xd7\u0080\xc4M\xad\x03h9\xd5\xd6\xec\xc2\xf9\u05fe,,+w@\xa7[SQ\x89p\x10\x81TG\x87\a\xd8\xdc\xdaξ\u007f\x02X\x86\xdd㧏\xfe\xaf\xe3'\xf76\x94\xfd\xd5\x01?\x15Lu\x14\xafjJ\xd9ߙ\xf97\u07fc1}a\xfd\x1fX\x15w\xdd0>\x033\x8d:ί\xaea9i\xca\xe98i\xef=\x910\x16\xb5)>j\f\xa6*\x81txK\x18\xedo\xb5VA\xb3\xd5\xc4\xf2\xf2\x12z\xdd\x0evvw\xf0h{\x13G\xbdN\xae\xfb\x11\t8\xeet\xeds\vo_>\u007f2\xdd\xf8\xa3\xe3\x8f\x1e\xde\xe4\x81\xdfV\x14\x9d\xeaa5\x01\xb4j\xd7V\xd7\xeb+\xd3?\x11\xb9Ñ\x9c\xcc6\x1a\xa8T\xabqwf(\x85W\x9cOy\x95̱\xc83\xe4\xb5ٓ\xd0k\x03\xd8\x106\xbd\x04\x06 \x14\x0e\x00\xab\xf1\xbf\xd6R\xbaX\x15H\x1ah\xa1\xa2\xfb\x06\xc0\x834\r\xc8j\x89o\x985\x98\xf4\xa3\n\xbf\xc7\x0f\x1e\xe1h\xf7$\x87#\xf8^\xf7\xd1\xe6\xd6\xcd\xff;`\xff\xb0D\xf8C\x83\xf0'.\xfft|8g\xd7\x16\xde~sq\xe9\xb5߲\x9cʹh.J\xb6\x85\x96%\xb0\xbc\xbe\x80\xcbׯ\xa05݂\xe3V\xe2\x96\xdcN\xae/\xbf\xb0\xacܨ\xa9\xfc\xf0Ih\xad\xb4\x95\x16\xe5\t\x18\x17_\xb3\xebVPk4\xb0\xb0\xb8\x80\xa3\xc3C\xdc\xfb\xe4\x01\xf6\xf6\x8er5\x12$\xa8Zk\xcd}y\xfd\xfa\x17.\xee=\xbb\xfbG\a[\x9f<\x05\xd8S\x14\x80\r\xa0V\x9dZ\x9c[\xber\xe3\xa7+ͩ\xd7\xd3\n5\x003\xad:\xea\xf5jT\x1e,\x01\xcf\x1f\xe0\xfe\xc3G\xf0\x83@m/%\xbb\a\xfb\u007f\xbe\xf7\xc9G7\r\f\xbf\xbe\xb2\xbf\xba\xf0'^\xd5\f\x80\x19\xe1V\x16\x96>\xf5\xf6O5\x97\x17~\x95,\xab\x99u\xeb\x8dާ\xeeVp\xf9\xdc:\xd6ϯ\xa3V\xafÉ{\xeeY\x8a\xf0g\x93{(\x9e{@\xf9)\xc0P\xabD\xf3#\xdcd(\xd3\xf6eN%\x1a\x16\xd2lMauu\x15[\xdb\xcf\xf0\xe0\xd9c\x9c\xf4;9k+\\\xb18}y\xe9\xb7ݩ\xeaw\x0e>~\xf4\xdd`\xe7\xf8H\x03Z]\x10j\xf5\xebk\xe7g^_\xffe\xe1X\xb3ɾ\t\x00\x97\xd7/\xc4C`D\xac\x04\xa2z\v\"\x06\x8d\x1aY\xaf\v3\x97\xe1\x05\x9c\xe7\x02\x14\x8a\x83^\x02\x044\x81\x10\xb9\x16\xde\t\x05\x98\xb5Y@d.\xf2\xc9\x17\x06\xa1\xd0\x18\x849_\xdfϡ\xd2\xd2\xcb\xf3\xd0>>\xc6\xe6\xfd'Qۛ\xf8\u007fd\x18\x9c\xec\xee=\xfc\x83\x93\xc1\xces\x83\xf0\xab\xa9>R\xb4v\"\xfc3\x00f\x01\xcc^X\xf9\xdc\xe7\xe7\xe6/}Sؑ˟}zBs\xba\x8eko]\xc1\xe2\xcaJړ\xdfNZp[\xf1\xa4\x1eeT\x97:t2\xbdX\xd2\x02\xa7dN\x81\xd2\xc30mY.\xa3\xa1$A`öm\xb8\x15\x17\xad\xe9\x16\x9em>Ž\xbb\x0f\xd1\xeb{\xe9\xbe2 \xecz\xfd\xf2ҥ\xb7\xfe\xf1\xd4\xec\xf2\x8fO\x0e\xb6o\xf5N\x0fOe\x18\xc8jc\xaa٘]\\o.\xac\xbckW\xaa+Q\x9c\x1d\x1d&\xcb\"\xac\xaf-òDj)w\x9e\xef\xe0\xf8\xf4T\xcdH\xc0\xef\xf5\xef\xefܻ\xf3\x1f\x99\xe5\xd1\x10\xe1g\x83\xf0'.\xff\x9c\xd3l--\u007f\xea\xc6/W\xe7f\xbeL\x82\\\xf5LXDX\x9e\x9b\xc3\xeb\xaf]\xc3\xf4\xcc\f\x1cׅ\xed\xd8Y+\xeeܔ\x1eu\x86b6\xf7O\x17\x9a|( s\xb8\x8b\f\xedȨ86\xec\xc0\x82\xedX\xa8֮`a~\x01\xf76\xee\xe1\xf1\xfev\x0e4$\x8b\xaa\xf5\xa5\xd6W\xdd\xd6\xeb\xd7;[\a\xdf\xed\xee\x1co\a\xedn\x8fl\xcbvg\x9b\xad\xc6\xea܍\xea\\\xe3\x1dr\xac\x96\x1a\x83/4g\xb0\xbc\xb4\f\xcb\x11\xb0\xec\xa4 (#\x00\x82\xa4V\xa1:\"\x05Xv\x1f\x99x\x00\xfc\xf2\x1e@\xc4\x01\x90i\x1fyR\xd3\v\\D\xf4a\x18\xee\x91u\xffQH\xc1\xb9\xec\x00\xe5\x89\fqO+N\x84?\xb5\xfe><\xaf\x8f\x87\x9f\xdcG\xbf\xd3W\xf3\x9f\xb2\xd3~\xfe\x9dg\aw\xee)\x85'e¯\xbb\xfd3\x00f\t4\u007fi\xf5ݟ\x9c\x99_\xff&\t\xbb\xa9*$!\b+\x17\x16\xf1ڛ\xd7\xd1l\xb5\xe0\xb8.\x1c\xa7\x12\v\xbf\x9d\x8e\xef\x12\xc2R\x06v\xaa\xe3\xbcQdH\x92\xdaS_\xf7\x06,XRBJ\v\xa1\fa\xd96\xec\xc0F\x10w\x9e\xbdt\xf52f\xe7gq\xfb\xe3\xdb\xd8\xdd=\x8c\xbf\x86\xe8ՄmO7\x16\x96~\xae>7\xff%fًx\xdcT\x15BT!\x92NA2u9\x17\xe7\xe7КN\xaaY%\xfa\xfd\x1e\x9en?\x8fRVY\xfb\xae\xd3\xc3͍?\x1e\x1c\xef\xed\"_5\xd9+\x11\xfe\x8a\xe2\xf6\xcf\x00\x98ugfWW\xdey\xeb7*3\xad/\x82`\xa9V\xa9\xea8\xb8v\xf1\"Ο\xbf\x10\xf5.tݨ\xbf^l\xf9\xa3\xfe\xfb\xb1\xe0\xe7B\xaaܠe\x83\x02P\x14,\v\x05O\x12q{x\x01\x19\x84\bC+\xf20\x9cH\x11|\xaa\xf1\x0e\x16\xb7\xe6q\xeb\xd1]\xb4\a]\xd5E\x17v\u0379к\xbc\xb4>ua\xa1\xc7\xcc\x03\x00\x82\x04\xd5Ɋ9\nJ\xf0\xebX\x16\xae_~\r\xf5F\x1d\xb6c\xc5J\x8c\xb2\xd2k\f\xf3\x00L\x05@::h\xea\r0\x1a\xf5\u007f\xa14 i\x9b\x9a\xb8\xeay\xd7\xdeأ\x17j\x1f\xa1\xb2RG}Xh6Y&HKQ\x03\xdf\xc3\xf1\xe1!v6\x9f\xe7\\\x9e\xd0\xebo>۹\xf7\x9f$\xa4\xa9\xb0\xc77\x80R\xaau\x9a\x010wy\xf5\xdd/\xcḓ\u007f\x83\xc8jdc\xc7\x18\xb6k\xe3\xca\x1b\x17q\xfe\xf2\xa5\xc8%u+Q\xbbm\xdb̈́_\x19\xd8\te\x00%rS\x80M\xf9\x9ex.\x82P\xb3\x1e\xd1a\x15BB\xb2\x80\x90\x16,+DhY\xa9\x1bl\xd9\x16l\xc7\xc6g\xbf\xf0\x19ܿ{\x0f\x1b\x1bO\x11\x84\x81\xe2Q1\x91%*\x04Q\xc9#\xfd2\xf5\xb8\x88\x80\xf9\xd9\x16\xae\\\xb9\x04\xd7qҞ\xfe\xbb\xbb\xbb\xe8\xf6\xfb\n\xb8IJ{x\xf0\x9dÍ{\x0f\x91/\xe9\xedi\xc4#\xd2\x00\xd54\xacr\xa7gVV?u㛕\xe9\xe6\xbb \b\xce\xc5\xfa\rܸ\xfe:\x16\x16\x17\xa3\x99\x88\xae\v۵#\xe1\xb7l\b[\x1dةN\xe8͇T\xc69\x11ȷ\x8cLf,\b&HI\x10\x92 -\x01+\x14\x106\xc1\xf2\x05,+\xba\x9d\xbfp\x01\xad\xa9)|t\xf7&\x9e\xb7\x0f\xf4\xe13\x82lj\x10b\xa2\x0f\x15\xfbe\xb8\x96\x83\x1b\x17\xafamm\x15N%2\x14ѵP\n\x04\x92\xa1\x88\x99\x14!/\x95\x0fR\x1b\xec\x18\x94\x80\xfey\xc4K(\x002\xb4,&u\\\x98\xda\xf0\x13z\xab@*\xd4+\xb3\x86y䊈\x12b\x90\x9a\xf7O\xe6\xf2\xf9>\xbcA\x1f\x8f\xee=\x80\xdf\xf7\xb3&J,\a\a\x87\x9b\u007fz\xec\xed\xee\"_o\xae\x13Qʄ\u007f\xf6\xf2\xf2\xe7\u007fbf\xf6\xdc7HX\r\x95\xa0SmT\xf0Ƨ_\xc7\xf2\xea**\xd5\x1a\\\xb7\x12\xb9\xfd\x8e\x03\xdbr\xd21Q\xe9$_\xd5\xe2Sv\xfdjK\xf8B\xa7$\"\x85\xacB\xd9\xd8\x05\x16\x10 H\x11\x1fV!`Y\xc9O\x01?>\xa8o\xbe\xfd\x16\x16\x96\xe6q\xff\xde\x03\xec\x1f\x1c)\xa5ό\xb2~\xf3S\xf5\x1a\xd6V\x97\xb1zn\x15\x8e\x13s\xd3%\xa3\xdf\x1b`{wWq\xfd\x19\xa1\xe7=?x\xfc\xf0\xbb,CSᔯ\x85U\x8e.\xfcN\xb3\xb9\xbc\xfa\xa9\xb7\xfeAu\xba\xf1nč\x97\xa9\xf7\xb743\x8bw\u07bc\x81\xd6\xf44\xdcj\x05N\xc5\xcd\xc5\xfcQ\xccl\xa5\xb1~:\x9a{X\v\x10M\xa8\x12\xd06\xc5\x19bl\x8aDT\x96+\x98 -\x02\x85\x94\x96C[\xb6\x80\xb0\x05l{\x1e\xefֿ\x80GO6\xf0h{\x13\xc7\xfd\xd3\x02z\xaf\xfff\x91\xc0\xf2\xf4\x02\xae]z\r\x8bKK\xa8ԫp\\;\xf2\x00\x12\x05\xa0\xd6/\x9ag\x8cc\xf8\xb4 ]\xd9\rk\n\xfa\xd2\x1e\x00\xc7l\xc0hgE\xacES%\xa0\xf1\xfa)!\xf2\x94\by\xa1zP\r\x1f\x92\xd1P2O\xfc\x89\xday{89:\xc2\xeeӽl.!\x80A\xbfs\xfb\xe9\xfe'\xb7\x90\xd5\xf3wF\xe4\xfa\xd5<\xff\xcc\xf9\x85w>5;\xb7\xfe\r!\"˟l]\xbdUÍϽ\x155y\xacT\xe1\xb8\xd5\xc8\xf2;n4iGE\xfa\x89\xd2x_\xb7\xfaY\x9b-%\x85\xa7\r\n\xa5\\\x8dD|X)R\xaf\x16G\xaf+(R\x06$(R\x04\xb6\x88<\x02\xdb¹\xf3\xe71\xbf0\x8f\xbd\xbd]<\xdax\x84\x93\xf6)<\xdf\xcf<0\x8a\xc0\xcbF\xbd\x8a\xd5\xd5e,\xaf,\xa3R\xad\x82\x88b`,\x80\x94\x01vvw\xd0\x1b\f\x14pW\x86\xa7;Ͽ\xdd\xd9\xdd\xda\xd6\xf6v0D\xb9&\xae\xff\xb4\xb0\xec\xf9\x95w\xde\xfc\xc5\xea\xcc\xd4\x17\xa3\xa3#SC\xb2:\xb7\x80\xb7ߺ\x81\xa9V\vn%\x12~\xdb\xcd&\xf6F#\xb7H\xb1\xfa\x94mkA\x01\f\x99\xa2\x03\x80\x84\xa9p-\x1e\xd9\xc8\xd1\x14\x1f\x12\x80\xb4\xa2\xae=\xa1E\xa9\"\xb0\x1c\v\xaf\xd7\xdf\xc0\xf9\xf5u<}\xb6\x89\xcd\xdd-t\x06]\x04a\x98\x82\xdc\x04B\xc5v0\xd3h\xe1\xd2\xfaE\xcc\xcf/\xa0Z\xafFį\xf8\x9alGi\bBZ}\r\x99c|}\x06F\xa1W`\x92\x9dᢱ.U\x90g\xcf\x02\x18\xb8\xc6i\b@\xe6\x89=\xc3\xea\xfe˼\x00\x05\xb5L\xdc\xffP\x89\xff=o\x80\xc7\xf7\x1f\"\x18\xf8Y\x98 \xc3\xee\xde\xc1\x93oy<8\xd6(\xb1\xbak*4\xa2O\v\xc0\xccr\xeb\xea\xe5ŅK\xbf%,{Zmz\xdah\xd5\xf0\xf6\x17\xde\xc6\xdc\xc2\x02*\x95\xc8\xf2'Sy\xad\x84\xd4#\xac\\\x1ajx\xd7/\xc5\vO\xdc;*~iz\xa3\xd8$}*\x88\xa2\x16R\f\x90\xb0!E|@\xe3\x9b\x1dF.s\xadQ\xc7\xea\xda*\x06\xde\x00a\x10\xe4\xbc\x00!D\x1aW\x93\xa0x@j\xc4\xf6\xf39\x84\xe7yx\xbe\xbb\x97\x03\xfe\xc2\xc1\xe0\xe9\xfe\xe3\x8d\x0fQ\xec\x94dʨ\x14\\\xff\xa5O\xbd\xf5\x93\xb5\xf9鯁\xd8R3<\xe7\x16\x16\xf1\xf6\x9b7\xd0h\xb5b\x86\xa4\v;\x01\xfdlu\x1cw\f\x98\x81\fͿ\xd8\xc0\x8f\xd7cc.\xb8\xcdZ\x04\x06\xe6\xb86\x9f\x12.\x81\x1da\rV\xa4h-[\xc0v,\xb8\x15\x1b\xcd\xd6\x14\xae\\\xb9\x02\xcf\xf3!e\x98e\xac\x88`[V\xe6\xc1\xd8v\x84'ض\xe6\xcd\x10H(\xfd\x17\xf5\x19\x8cơ\xa1\xf9\x16z\xc3\a\x84F\x99\x85\x82\x82|\xb9\x8e@R\xed\x04\x80\xb4\xdcG\x1fԑ\xa3\xf6*\x93\x84u\xf2\x8f\n\xfa\xe9\xbcf-\xf5\x97\x16\xfd\x04>:'m\xec>\xdb\xcb%\x11\xfb\xfd\xf6\x9d\xe7'\x1b\x8fPl\xe3\xe5+))2\x00S\xad\x96\xbb\xb8\xbc\xba\xf4\xda7-\xcb^b\x05ǨMU\xf0\xd6\xe7\xde\xc4\xfc\xc2\x02\xdcJ\r\x15\xb7\x02ۭD4\xd38ϟΉ'\xbd\x9b\v\x15\xbf\xa0\x92\xe1\x90Ć٠\x94\xaf\x88Hp\x88dX\as\xa4\x04\x04\x01R m\xe1%\xc3\b\x13\b\xc3\x00\xb2RA\x95\xeb)ꭾ\xa1J\x94I\x1a\xa8r̆;88@w\xd0W\xea\x1498\xdd\xdd\xf9\x0f^\xfbH\xed\x8e\\\xa6\\\x1d\x85H\xd5\x02К\u007f\xfd\xb57\xa6V\x17\xbe\x1eq\xf9\xb3\x02\x96\xd5\xf9\x05\xbc\xfd\xe6\r4[Sp\xab.\xdcJ%\xb5\x92Y\x9aOu\xf9\x91\x8d,3\t\xbeʡ1\xb8\xbf\xa4\xc6謜bE_')\xeb$m+d\xbcDZ\xa7%C\vah\xc3\tCTj.d(\xd3}K\x94v\xd4\xf3/R\\\x96%b\xceB\x9c\xb9\xb0\xa2\xfbE\xe2)\x1a\x8b\x97L\x8d>M\x93\xb3\xb9| \xaeI\x19\xbe\xac\a@i\b \xf2\xb3@\x98\v\xe3\xc0Պ\xbf4Mh\x9c\xf2\xab\xf4\x01$\xb5\xe6\x87\xd3RI\x0e\xb3\x91ҁ\xef\xe3\xd9\xe6&\xbc\xde \xfbT2\xec\x1f\x1co\xff\xb9Ϟ\xdam\xc6T}\xa6[\xa7\x96E\xf6̹\xa5\xeb?︵\xebi8C\f\xb7\xea\xe2\xadϼ\x81ŅET\xdcjd\xf9\xd3T\x9f\r+\x87\xf2\xab\xa9\x1c\xcd\xf2h\xf4f\xe6\x02\xd3\t%\xa8i\xd6\x04\u00948\x88C\x04f\x02q\x1c\x1bK\x02[\x02\x96\xb4 َ\xfb\xfd\xcb\x14PT\x85$I\x8bE<\xffh\x92j\x10D\xac\xbf\xad\xed\xad\\\xfaHz\x83\xadç\x9b\xb74\xe1\xd7]\u007f#\x99\xaa\xbe\xbc\xb8:{q\xed\x1b\x96mM\xab\xb4\xf0\x85\xd6\f\xde~\xe3\x06\x9aSM\xb8\xd5\n܊\v\xc7\xcd[I\x12\x91ǓC\xf8K\t-<\x94+\x9f\xe7\x95+\xe0Y\xaee=\x83\x13\xef@\x10D\xecu\x11Y \x8e\x15\xac$X\xa1\x80\x94V<\x11\x89\x95\xfd\x85\x82M\xc4\b\xbf\x95\a.I!\x00\xe5\xbcbC\t\xe0(\v_(:Aq\x92\x90q\x94\xd0\xcbQ\x81\xa3,\x80P\xb4,\xa51{\x1e\xd8҇\x80\x9a\xbf\x14*y\x9b8\xf6\x0fe\xae\xff\xfc\xa0\xd7\xc3\xce\xe6\xf34\xe3\xc0`\xf8~\u007f\xe3\xf9ɣGȷ\x96\xf6\fl\xb4\x02\xd5wm\xe6\xda\xf5Fs\xee+\xd1\xe31xcY\xb8\xf6\xf6U,.-\xc1\xadD\x1cs\xc7N\nL\xa2\xd1ډ\xd5ϵr\xd2ӟ\\tKɤ\x04\xa0t;\xa7\xfc\xa8\xa7\xecPAﭜy\\\x04\x10\v\b\x01H&\x88Dq\xb2Ȳ\t9\xcf-ˇG\x96?\x8c?\x98D\xbb}\x82v\xa7\xa3\b\x11\xcb\xee\xc1\xe1\xf7\xfbG\a\a(\xf6\xf1\xd3\xf9\x14jh5%,kz\xe1\xcaů\xd9\x15\xe7|\xe2\x922\x80V\xad\x8e\xb7\xdfxS\xb1\xfcN\f\x8eE\xe8\xb8e\x912^;W\x15Y\x92\xf7\xe6\xe1\x022\xa4\x90\xc8\x14\x1a\xb0\xc2x$N\xf67\x0e\xbd\x04 ,Q\x14~\xe5\xbbW9\t);1w=\x19^\xa0*\x01(\xf5\x0ezz\x0fC\n\u007fr\x13\x9b\x19\xe5]\x82\xe8\x95(\x80\xfc!$\x15\x03\x806\xa5G\xef\x0e\xa4\x96\xbb&@ \x19\xaeU\xe1\xfd'迌Gw\x1f\x1e\xec\xa3s\xd4Q]\x85\xf0\xf8d\xe7/\x06QIl\xb7\xc4:\xa9\a4\x15\xfe\x963\xb7\xb88w\xfe\xeb\x82D\x03J\a\xa3\xf5+kX[_G\xb5RE\xc5q\xe1\xd8n*\xfcV\x12\xef'c\x1eI/[\xa6\\9*\x1b\xf0\x91\xf4ϒa0\xba\x9b\xa7\x96V\xa8\x95\x96\xa4\xf9\x8c\x94\"\xdc\"\x8agS5\xcdE\xb2\x11KH\t0\x87\xe9t')Clmm!\xe40\xbb\x94\xd0?>\xdez\xf6\x01\xf2\x13{\xf4\xbe\t\xa4U\xf85\x014\xe7\xae]\xbaV\x9b\x9b\xfa\xa9\xb4C.\x18\x15\xdb\xc1\x8d\xebo`fv\x06n\x1c\xf3;N\x9c\xea\xb3E\xe6\xf6'\xee~\x8a\xf4\x17]\xfc<#\xb5\b\x02\xe61\x15.A\xda\x19z\xff)2\xb8Ω\"@\xacT9\xcbR\x15ȸ\n\x1bQ'(\xe5\x80K\x83\xe2\"\xed\xb3\x16:|\rSl\\\xe2\xf1\xbc\xaa,\x80\x885c\x96\x02T\nu`h\xf5]\xd2\r(9p\xac\xcd\xfcS[\x1b'\xe0_\xaa\x00\xe2\xfc\xff\xce\xd3- \xcc\xc8\r2\xf4\x0f\x0f\xda\xdb\xf7\x91\xef\xdeb\xea:\x93\xeb\x84\x03\xa0\xb9:\u007f\xe5s\xb6S\xb9\xa4~\xf6\x99\xc5\x16\xae\\\xbb\x82j\xb5\n\xd7q\xe18.\x1c\xdbN\x85_\x90f\x99X\x19\x86\xa0\xd6\xff\xb2\xc6v4\fG1\xccU\x1e\x12\x03*\x1a_\xf5\x14(룔\xf32T1\x88\vC\x92\xbd\x95,c\xc0+y\xd5h\x9f\a\x83\x1e\x0e\x8e\x0es\xff\xed\x9dv\xee\x9c\xee\xef\xee!\xdf\x19\xc7\xd7\xf6\xb7P\xe8c7\xea\xb3\xd3k\xcb\u007f\x9f,\xd1L\xad\x1c\x01\x97ϝ\x8f\xf3\xfcQIt\xe2\xf6'\x9c~!\x90\xb9\xfc\xa4\xa6\xd9\xd8(\xb4\x89\x81!cc\x90\xbc\x95\x84\x89*\xab\x83n\xba;M\x19\xef%\xe9\xda\u009c\x17J.\x19A\x90\xe3&P\x1e\xdbѹ1Å\x96\vyuS\x16\xa00'\x80xؼ\x91\x17g\x02\xe6\xc8\xc2ڧ\xbd&\x14\xb79\a\x0e\x926w2}\x1f\xc3\x1c\xccB\x03\x12*IK\x9a\xb8\xfb\x04\xbdd\xd7\x14*\xeb\xf55&~\x00)\xd7N̚\xb7Q\x0eB\x9f\x01\x04̘\x80R\xf9;\xf1\x00(W\xe0S\xd6\x11X\xab\xf2S\x8c\x17+\xb5\xff)\x00\x98\x0e\x9f\fqzr\x82A\xbb\x97\xbd\x82\f\xbdv\xe7ঌ&\xf5\x96Y'\xbd\xedT\x1d@cy\xe6\xdcOX\x96\xbd\xa8\x12\x93֯\x9c\xc3\xec\xec\x1c\xdc8\u07b7\xe3\xa2\x1e\x8b\b\x82D*\xfc\x84|\xcfv\xe2lFb\xd6Ɍ4mL\n\xda_l\xe1dJ\x91\xaaXJZ\x14\x95+\xed\xe4\x82\xdbH%q1Qn\x92{\xdc(B\r\xb3\x02\xec\xee>\x8fC\x82赤\xef\x1f\x9e\xee\xed=A~P\xa7I\xb9\xaa\xe0_\xddi5g\xa6V\xe6\u007f\x81\x04\x9c\xc4\xf3pm\x1b\xaf_\x8d\xa8\xb09\xe1\xb7\x04,\x11O\xcaIy\xf1\x067Wo\x10I\xe6\xd0\xd4\b\x84\xc1L\r\xceu\xd6aS\x0e^\xf5\xb0\xf2\xff\x97\xcft\x97\xbfG9?\x81b\xa5\xc29\x16\xdfX\x18\x86\t\xdc3>\x9f_-\x0f \xf3\x00\"fZ\x02~\x10\xe7\xe3\xdd|\xeaO=\xa0\x84\xfc~\xabTG\x85\xf3\x98\xb2\xff\xb2\xf2_\x19\x068\xd8\xdd\x03'}\xfe\xc0\x90\xa1\u007f|\xd4\xdd\xdbD\xb1{k8\xc4\xfd\xaf\xcd8\xf3s\x8d\xc6\xdc\x17U\xe0\xaf9\xd3\xc4\xf9\x8b\x172\xc0ϲa[Vd\xf9Ed\x9d2\xa7\x9d\xcc_hNX\xf5V\b2U\x02\x05\xa0Ϩ\x9d\x95CI(?\xe0\x9c\xb7\x98\xb9\x06,J,\x99\xd5\bD\xdfW2\xe3/\x19\xf2\xe9\xfb\x83\xcc\xfd\x8f\xff\xc7\xef\xf6\xee\xf7\x0e\x0f\x8fQl8\xaac+j\xeb\xb4\xfa\xec\xf9\x95\xabvž\xa8\n\xd2\xfa\xd2*f\xe7f\xe1\xb86\x1c'ʍ\x17b~Ma\x99\xc5I\x1f\x98aN\x05\x96#\xe8J\x9c\xaf\xbe\x06\x95\x83ly\xeb\xcc\x05|\xa6\xaca\a\x19\x846\xf5\xf2X\x16gjr\x91u\xcb&|@ǒ\x86`\b\xaf4\v@9W#k\rN,#\x84T\x01\xfc\x88\x15%\xa0\x83\x81ƾ\xc7ʸ.\x96i\x01PR\xb1\x15\xf8>\x8ev\x0fR\xb7\x99\x00\xf4\xfd\xfe\xe3#\xff\xe0\x18\xc5I\xb2z\x9f\xf9\x9c\x02X\x98Z{\xdd\x12\xce2%\r=\x04\xe1\xc2\xd5\v\xa8\xd7\xebp\xec\xa8\xda\xceJ\x84\x9f\x84\xd2fVAn\x15^/\x13\xb4\x92h%\xbf\x9cKo\xaa\xad\xd3L!\x01̱\xacrPI'\x85hʂ\n\"ù\xef\fI\x13\xca\xd4Ê<\x80~\xaf\x8fN\xaf\xa3č\x1cvO\x8e?df\x93\xf0K\x8dU\x99v\xc2%\xcbj4\x17f\u007f\x8a\x04U\x12K^\xafTp\xf1\xfc\x05\xa5\xaa/\xaecHF\x90Qf\xf9\x89\f(\x06\x15Ga\xf1\xa8ԘQ\x90\x8b\xf8\x00\x19I7\xac\xed#\x97\x80\x86\x995#\x05?(N\xbf\x86!Enp\xdf\r\xe7\xa4L\x81\x9d)\xdb1\x86\xe5\x1f\x9b\a \x94\xf6\xe7Y1P\xd404\x15\x0f\x9d֫\xd0u3\xe0/\x03\x01s\x92\xc3y\xfaob\xa1\xbcA\x1f\xbd\x93N\xf4>\xd1N\xc9n\xf7\xf8\xb6\x04\xab\xae\xa9?\xe2\x80V\x1dr\x1b\xad\xfa\xec\x97(\xb9V\x06\x1aS5,.-\xc4n\xbf\x1d\xc5\xfd1\xe0'\x94\x98?\x8b\x13\x15\u007f\x9d4,\x90\x8c\x9e^Q\xd8s\x04\xa0\xbc\vJF>\x18\x17q!\xd2@-.!Ǩ{\x1b\xa7\x00\x13\x05 \xe3\xfdm\xb7\x8f\xa3\"\xa2\xf8\xffe\x18t\xbb\a\x87[(\xb6\xc36\xf5\xf2O[\xa5\xb7\xd6\x16\x97\x9cF\xe5u\xf5s,\xcf-\xa09Հ\xe3X\xb0m\v\xb6-`\xd9YN\xf4\x15\xc5\xeb\xa22\x81`\xa3\xbbMC\xf7qD\xc8@0\xb7\xd2'\x95\xfa\xae\xbdo.\x94\xe3\xf4\xda\xca3je\xdf/\x9b\xad~\xc1\vД\x14\xa3X\xff\U0006a600\xa4\xf0\x00҂\x95$\xfe\xcfyfj\x96@\xcb\xfa+܀,e\xc8y\xbes\xdc\xf3_\xed\xff\xd7\xefu\xe1\xf7\x06\xa9\x16\x95\x1c\xfa\xa7\x83\x93M\xe4'\xb9\x84\x86\x03\x9ak\xeb=WYXt\xdc\xeaEu\xca\xca\xe2\xea\x02j\xb5\xba\"\xfc\"\x8d\xf9\x85\xe2R\x1a\x85,\x96\xfc\f\a\xa0<\b\xc5P\xfa#\x14[\x1f\x11\x17\a#\xe9Y\x85bڐ\r\xae\xa2\xaa\bԃ\xc8Z}xҎ:V\xb0\xf1\xb0ϣ\xa3Ü\xe0\xb1\x1f\x1cv\xa2;MC1P\xb6\xbf\xcdř\xeb¢fƩ\x10X_]\x8b\xdc~;s\xfbEں+\xf1\xe8\bЀ\xccR\x12\x8f\x96\xaa+\xb5\xf2ZښQ\x1e6\x90)v\xe7<\xae\x92\x02\u05cc!JG\xef\xed?d\xba\xef\xd0\xcfh\xa01\xb3Y\t`\xd8\xf5\xbf\xda,\x00\xa7\xfd\x00T\xfd\x9a\xb8\xd2\xf9F>\xa45\x04\xcd..\v\aȐ\x02\x94J\x05`\xe2\x05H\x9c\x9e\xb4\xa3A\nI\xe2Jʓ\x93\xc1\xd1>\xf2c\x9cB\xcd|\b-F\xadL\xd7\xe7\xaf\n\x12\xcdĂZ\x8e\x85\x95\xb5\xd5X\xf8#\xb7ߢ(\xe6/\xb8\xfe̅\tE\xac\x9a\xff\xf8\xf3G\xcd(U%\xc0\xc5.G9\xb6\x9fv\x90\vހ\x92*U\x81\xc0\u00812Ǭ9jlJ\x12R@\xd6 @\xa7ӆ:v\xda\xef\xf7\x9f\x84\x9e_6\x15G\xf5\xaeR\x80U\xd8V\xbd67\xf5\x19\x12I\x99/c\xba\xde\xc2Tk\nvl\xfd\xa3\xa6\x9d\x11\xe8'DJ\x9fσ\x96\xa5\x80\x1f\x1b(\xc0\xe3*\x03\xf5\xb5G\xa4܆\xe4\xe8\xf5\xf0\x83P^\r\x98G\xfa\xb9\xe4\xb12<\x81\r\x1f\x8b\x87\xf2rT\x05G\xaca\x00\xf4\n\x14@\xe4A\xc8x\xcaQ25\x963V\x9ejyr\xaeP6#\x80\xd5F \xfa\a\xe4\x8c\x04\xa4ƨ2\f\xd199\x89نѕ\x84~\xff\xb0+\xbb]E\xf8Up*9\xa09\x05 \xaa\xcdj\xeb\xad\x14\xfcc\xa01]G\xa3\xd1Є?v\xfdɐ\xe5e5GǙ+Δk\xbeH:\x10Ȝkz\x9c\xbfv\x95\x14\xa5\x8dz&*X\xa9\xb2C\x92/M\xd5-\xa72\x1d\x8c\xf3\x18@\x18\xfa\xe8\xf6\xba\xd9s%\xb3\xd7\xebm\xb0\x94\x9e\xb6\xbf\xa6\x01\x9e\xa9\aP_\x9a\x99\xb6]k=\x02\x8b#E\xb5<\xbf\x00\u05cd\x19\x94v\xbe\t\x86\xfa\x99\xc9`\xb5ʬ\xa7)\xd4\xc9t,\x97\xc6\xc3F+\xaf\"椇V\xe3b\v%\xa1H\xaeO\x06J\xf1\x84\xa2\x12(\xbe\xbf\x8e\r\xe9=\x00\x8c\xbc\x01\x9d\t(^\x9a\t\bm&`\x96KF\\\xaa\x9a \xfa\x89\xa5\xd2g\u007f\x92\x92DT\x9d樞\x82\xd3\xfc?s\xfcSF%\xaa\xbd\xd3n\xc69 \xc0\v\x06O\x02\x0e\xfd\x12\xeb\xa4\x1fP\x1b\x80;eM5\x1d۹\xa8\xb2\x15\xe7\x16\xe7\xa2\x03\xaa\b\u007f\x9a\ue2d9\x8b)Y\x89\x8aJ\x80\xd4x\xdc\xc0\xed\xcfQ\u007f\x99\x8b\xa0h\t{-_qi\xce\x04\x14b[VYB\xf9\xfezy\xc2V<\x8b.V\x02\xbe\xef\xc1\v<\xf5=\x02\xaf\xd3=0\xec\xad\x1a^\x11\xb4Y~\x8d\x99\xe6*%\xee?1laa~~>u\xfd\xf3\xe9>Θ~%\xc5+\xb9\x8e\xd1&j\xab\xd65\xd8(P4\x8cN\xcb%\x82c\xb6\xce\xc3B\x8c\x02\x00\xcb&\xcbmhTB\x86\x82\x9e1\x15Ct4K\xf0\x01V\xaa\x01\xcf@\b\x1c\xa3'`\xde\xed\x89<\x00\xa4\x94\xd3<9\x85r\x99\x16.q\xdf8\r\x11\x94\xf2\xe2\x94k\x1dy\x00^\xaf\xafR\xaf\xd8\v\x06\xdb\f6Mn5\x8d\x98\xb6\x018\r\xb75-\x845\x05\x8e\xc2\x18a\t\xcc-\xcc\xc1\x12j\xba/C\xa5u\xf7_%V\xb0\x9e\x8abd\xae\xbf\xe6ِ\xd1\xe2\f\xa1s*\x18@\x14adB\xad\xc4\x02\x19\x10\xc5ڈ(R\xbc\x8d\\\xb5f\x86\xaf\xa4\x1c\x00\x0e\xe1\xfb^\xdcE(\xe6\x16H\xd9\xef\xf7\xba{0O\x1eVë\xdc\xfeV\xa6j\xcb$\xe0$QX\xbdRE\xa3^O\xd1\xfe\x84\x0f\x9f\xeeob\x95ɜ\xf1Ё<\f+\x8ea\r\x84+\f\xad\x1d\x01\xfe\xd10K_\xc250\x81{\xac1\xf3\x8a#\xe049\x18\x06\x10\x8eQ\a@(T\xdf\x02\xda\x14\xa4W\x95\x05\x10@\xca\x03H\a}\xe7ƃg\x11\x0f⃙a\x01\x84|\xb6,\xc9\x02h_`2,1\xf5\x00\"\x8e\xba\xdf\xf7ҋ\x93̡\xe7\xf5\xda%\aT\xb5P\xb9Q\xd3\r\xa7\xb6BQ6\x00\x00é\xdah4\x1a\xb1\xe5\u05ed?\x8au\xe3\x85v\a\x9cor\xca\\d]\x99\xf2\xfc\x9ab0N\u007f!V\bB<\x04\xf41猋\xb1\xaeb\xfds\x18@\xe4\x01\xa4\xf3\xea\x18\xe00\xf4\x82\xbe70\xec\xaf\x1a\xff\xe7\xf6W\xd8\xc2u\xaa\xee55\x0f2Uo\xc0u\x9d\xd4\xedO\xac\xbfޱ7u\x15it\xaa\xab\x1c\xe1\x1e\xe2\xa6\xd3h덡.\u007f\xbe`H\x85\tLY\x80\xdcg \x8c\x1d\xfb\xe7҃zÜQ\xd8\x06\x99p\x02C\x16@\xbc\xa4\a\x90\xe0\x00)\x84\xc7\x11\x0f \xe9iG\x8a\x13\x9bq\xa93\xd0/\a\x1ej\x13\x00\x13eB\xac\x1eҸ\rX\x10(\xe9D\xf6\a\xa1w4\xc4\xfa\xab\x97\x9b\x1eҊ[\x9f!\xc0Nr\xb5\xd5z\x05\x15\u05cds\xd1Q\x87\xa34+E\n\xf0\a\x94\x96\xed\xa6\xa0\\\x92\rP\x9e\x93+\x06\xa4|\x99\x80Z\xee\x1b\x85O漾~\xa0\t#FB\x97Y9VG\xd6ɔ\v\x000\x82\xc0\x87\xe4$ngH\x19t\x83\xde`\xa0\xed\xad\x84\xf98Y\x00lr,ۮڋ\xaa \xb6\xa6\xa6`\xdb\t\xe8G\xb9\"\x9f\xd4\xfa\x83\xb4\x0e\xd1\xc8s\xd8QV\xeb>\n\xf9\x1f\x96\x02T\tCŸ\xbc \x98\xc4J\x9f\x8aEC\x93\x03t\x14K\x9dx\x1dE\xcc@;#&K\xc9\xd9\xe77\x1dx\"\x8e&\x191k\x9c\x80\xc8\x03H8\xfb\xf1\xf7s\xec\x0f\x06ސ\xfd%]\xc1:5\xb7&lQO\xdeO\x10\xa1՜\x8a\xcag\xd3\x1axU\xf0\xe33\xa0\xd7\xe5\xebc\xaeH\a2\x91\voX\a\xf2\f\x96\xb1T\xc8yL!f\x1e\xa1\x80ʕq\x19\xc7`h\xc3\x0f\x8d\xed\x97v\x8b6\xcd\xd64\x95\x04\xeb\xfc\x85WW\x0e\xac*\x00%.e\x1daU)\xaf\xc85\xfeȣ\x04jP\xcdy&\xa0rH\xa5\x94@(#O#b\xa9\x84\xa1\xf4C\xe8\x93X\xf3\x19\x00\xb5E\x87\x10D\x96Mּ\xe0t\xae-\xea\x8dZ\xe4\xfe#s\xfd\x85\x02\xb8\x10K\xe5%\x94\xb4e!\xc7>\x86\x96\xcd\xd5u\xe6\x89D\xfat\xe5\x02\x1bP\xfd\x1f\xa5\vL\xc6\x0f\xd0&\fC\xef\x1a\xa3\xf2\xcd5%\xc0\x8c0\xf0s\a\x91ð'Ce\x86\xb5Y\xbaT\x0f@T\xea\x95:\xc0\xb5d\x82\xb4 B\xbdV+L\xc0I-\xaa\x9a\xae҄t(Ǟ\xcc]~F\xa2\xf2C-\xee(4\x1fcҋ\xc7\x15\xf6a@\xa4i\xc0\x87F:\x1a\x89\x0f\x94\xf4\x04|U\x18\x80:\xec\x9a\xd4Z\x80t_\xa3\xf8>K\x0f\xaa\xd5r\xaa\xb5Ӽ\x82X\xf8I\xc6§T\x05\xb2\x94\x19[X\x86A\xac\x00t\xc17}d\x81\xa8\xbf\x8b\x10BT\x11W\xc9\x03\x84Z\xad\x96\xa6\xfb(\x17ƕ\x8f&OJB\vᕚ\xe23y\x01\xf9\x16J\xf9V\x00\\\xcc\xd7\x16j\xd9\v\xfc\x00\x1ey\xb8\x90#Z%ݜ\xb2\x1b\xc7?\xa5\fs[\xc8A\xe0\x1b\xf6\xd6\xe4\x01\xa4\n֮\xd8n\x04\x00FO\xb1-\v\x8ec\xa5\xa5\xd3i\xef{\xa5\xbc\x96\n\x85\xcbڡgU\t\f'\xbe\x14B#*\n\aF\xb2\x02\xd9\f\xd8\xd20\xa1\x1d\x06\x1c\x1a>\x9f\xaa\xf8\xd5\xec\xd1\x18a]\xf9Xp.\xe72\xd0+T\x00\xd0B\x80\xbcE\xc9\xd7\xfdga\x01k\x1d0X\xeb\r@J{qŻP\xf9\x00R\xa6\x8a&\xe6\xddK\x86,;\x9c\xba\xcdM\x9b4\t\x12N\x8a#\x10P\xa9\xb8\xca)\xe6\\ucd\xfdEfAs\x89\xfd<\xa8Y\x14\xde\\\x88A\xc5Ԝ\xaeL\x86\xb2\xfc\xa8\xbc\xbe\x80s\xbc\xa0\xf2\xd1\xdeC\x15\x89\t\xc3`\xad$X)\xc5~%!\x80*,j\xfcOiW\x94\xd8\xea\xab\xe3\x8dt\xcao\xeeo\xa8L\x804\xe6\x87\x02\x06f\xe4\xa0\xc8ZEs\x16Y2\xcbq\x1a\x9f+aw6\x98+\x01+m\xdb\xd2p\r}V{F<\xca3\xf0(\xab\xee3)\x016t\xfd\xd1b8=\xc6O\x0f\x9d\x89\x13Ne)\xa4\xfc\x81,\xb2\x04\xb5\xb9p\x86[\xae\x9c;y\xff\xc8%\xd0\x03\xeb\xe1\xfbLIϛ\xc8M\xb3D~\xf0E\xfe}3\xe5:Vjt\xa4\x823\xb8\xe14\x9a9\x872kNf\xf2MyF\xa2\\\xd9\xe8\x98\x03\xeb\xafKz&\a9\x83jR4E\x10P/\xb4+\xf9\xba\xe8\x95x\x00q\x0e])\x06J\x05\x95t\xa4\x9a\xf2\xdc\u007f\xc5-ͺ\xd2\xe6\x0f*嬿&\x94\xe9A\x96\xf9V\xc4\xe3\xac\xc8BP\xc4\x01\x88\xee\x10DY^\\a5\xe6&\x80\x9a\xc2x\x13\x03\x8f\x95#h\x18\xdcX\xf0\x06\xf4\xb2R\xd6\x01B\xdd\x1dVJ\xad\xd9\x00\x8e\x91\x9e\x95P\xd1kVR\x89\x9a7\xc0\xba\x1e\x8d\xd8\x17g\x8d\x1d\xa3Ac\x8a\xc24\n\xbe\x9a\xa5\x950\x03(z\xf8\xc5Ō˘\x84\x1c\xb3+?\xaa\xce~\x1c.\xc0h\x80ј\x81P\xb9%4\xc4}7\xa6\xf4F\xfcMZ\xe8\xa4w\x04\x1aS\t\x8c\x81\x01hM)\x13\xeb\x9c2沘?9䅂72\xd7\x02$\x1e@&\x84y\xa1\xcc\nrX\x90\xa1\x0f\xef\x90\xdcK\xc2+\xe0\xf4?\xa4\x8cR\x8b\xaa\xc2QX\x8dʌ\xae|s\x8f\xdcL\xcfb\n\x90\xf5\xd2\\=%\xa8\xe1 l8\x94j\x87\x99\x02R\xacR\x8a\x87\x1d\xce\x02:\x9e\\[\x86\x9b\xa6\xc5]\xa4z=L\x82`\xe1\xac\xf6Cf\xaf\x15\xa9\xe8 n\x97m\xc2he\x11cѹ\x014FH`\xca\x00\xf0\x10W\x9f˽'\xa61ˊ\r\x13x\x86\xf7\x0f\x18\xeeE\x94~w9\x82\x99r\xcd<\xc68=\xe2\xdc\xf8\xf0W\x8a\x01 \x87\x01$h\xb9\xae\x193N@\x1e\xfc\"\x85\xad\x9a\x15\v\xa9\xb3\x00\x12K\x9cy\x03\x9a;\x1ce\x18\x04E\xa8\xe28\t\x8e\xa4\xc5\b\xb3\x94!\x89\xc4\x12\n\xf8\xbe\x976uT\x19rP\xaeI\xa1\xe2\xe7c7\xd5\xd8\x17\x98{0\xa7\x04\xf5\xea,2\xb7D\xcfy\x10\xa6\xbe\x83\xd0{\x10\x16\x85$_\x95\xa9v\x05f\x8dz\xcbE\x0e\xbdE\x96\x06\xf2aDb\x9b9\x94R-\x03\ve\x10\xb7%\xe7\\\b\x97\xc0\x06f\xee\r\x1b\x1b\xa0\xe4-\x9cޯ\xaf\x8c*̥\xa4\x1b\xa3\x90\x1b\x95\xb19\xddZZ(T\x9a\x05(\x8b\xe7G\xf4\x1a0)\xc2!3\x01\x86\x03\x94\xaf,\r\xa8\xa1\xb5\t8\a\x13\xe1\x8d\x15z,\xe5\xb8\xddj\x86 \x9bϔ'\x03Af-\xc8I\x01\xe0\x04\xc1\xb2`\x8d:\xa49\x93ÐRJ\xdf\x03\x9c\xb8\x8dy\x88A\xaf\x97\x82\x8c`M\tp2\xaa\x99\x14\xe1V؋jzH\x13z\x95\xb9k\x04\xebJ\xb8\xfd\\Ұ\x02\xd0\xe7*\x14cGp\xbe\xab\fQ\xb1\xf2M\x1d\xecJ\xca\xdf\xd1ȭ\xecy\xc2\"[\x05\xf8\f\xfb\xabS\fe\xe8\a>X\x06\x80pA\f?\xf4\x10\x86AJ\xe8ʈG\xda˩=TI\xa1\x85\xd3h\x02\x10\xb1\xc1\r/+\x99\xa6ᄟ|\xd9o\xf9k\x00/V(4\xfa\xfe3z\t\xac\xa0\xfc<\xc4\xf3\x13\xaf\x98\b\xa4\x17\x14%!@\xd46Y-r\xc9~O\x1axfJ\x9e\xd2/<\xd2!d\x88\xfd\xb3/9M%q2O\x8el\x8bla8\xa4\xa4\x05\x96鍙C\x19\x06\xa7i\f-\x81^\xa7\x03\x19\xf7\xc5O\xfa\xbcGJ ~Y\xd6O\xa8\x01\x81W+\x9e(\xdf)H/\x10J\u009cB+t5\xadc\xc8\x12\x14\xac\x14\xab\x9af\x88\xb5$\x13\x10(A$s\xf1\xae%D\xe6%\x10@\x0eU\x88`\xc5_\x9d(Q\xb49j\xa1\xdf\xf7\xfb\f\xe9\x11\xa1\x0e\x02B\x19`0\x18\xc4\xfb\x9a\xf5\xd0\xcfB\x10*\xa4j\xd4\xd89_w\xc5g \xe1\xb09\x1d6\xccBҸ\xe0^\xd9\xeb\x8c\x13\x12\f\x0f\x15\xc6y\x8f\x9c\x82\"-\xe3\xa0\xf7\n0\xd5\x02\xd0+P\x00\x05s\xc0j\b\x90\x95\x03\xa9\xb1s\xc6\t(\xf3\fd\x8e\r\x98\x84\x15\xc9\x05[ɰ\xcdL\xb1X6Y\x95\x84\x84b\xd0KZ\xa9\"\xa2\u0382\x1cn\xab.s\xef\xb4\x13Y)\xa5\xfbP4;>\x06\xb3\x85\x80\xce\xe6\xd0*x\x95\xa2\x9c\x04\xfb\xe0\xbc[&T\xd6\x1f\xe5\x0f\xa3!UE9l\x01\xf9\xbcb\x81C\x0fs/;6\x95\xb6\xca\x02\xfa\x9f\xe4\xe5\xff_\xf6\xde,F\xd6,9\x0f\xfb\xe2\xfcKn\x95\xb5ު\xbbv\xdf\xee\xdb\xdb\xf423\xd4\fE\x0e\x01\x99\xa2 \x896%Y\x00\x01\x1b\x06lA\xa0!?\x19\xf0\x93\x01?\x18\x06\xf4h\x18\x86\xfd\xc07\xfb\x850\x04\xd9\x16iӀH\x8329#\x92\xb3p\xc8i\xceLO\xafwߗڗ\xdc\xf3_N\xf8\xe1\xdf\xe2\x9c\xff\xfcYu\xbb\xef\xf8\xc1\xe8\xbaHTݪ\xac\xac\xcc?OD|\xf1\xc5\x17\x11A\xe0\xe7\x9c@\xc9R\xf7\xfd\xc0\v\xe2(m\xba\xbe\xb0\x12\xfat6\x99\x8d\xc1<\x06\xb0Zt\x1b\x8e'#\xb0\xde(g;\x94\xfcJ\xbe\xf1\xb8\xb6\x13\x8fٹ\"{!Yf)\xe1\x9c\xf7\x97NV\n\x9e\x1a\xafm\xbdӮq\x02\xefY\xf2\xf9\x85\x82$9\xfb\u007f\x11\xdb\xdf\x04\xf5\xb9\x99\x0f\xa0\x9fC\n\x00\a\x02\x90)@\xe9\x04$\xd1W\b\x83j\xe5\xadJ\x17PM\x16\xd2%\v_\x8c6\xf6T\xd6JZ\"\nFІ\xb7\x9a;\x80EN\xa0\x88P)\x83\x938\x9d\xef\x02\x9a\x89\x89\x98\x80\xe9p\x84$\x8e2\x14P8\x00\xede\xcb\xe0\x98J\xc8j\xafn\"\xc9\xd8[\x93{j\xba~9:\x80t\xb3GgS0`H;\xad\x92i\x8d t\x8c\x197\xb9\x84J\n\\\x8d\x0f\xaf\f\xa7(\x87\x16\xd5\x02E臽\xa0\x15G\xa9\x92b*\a\xba\xd2\xc8\xfb1\xf4\\\xc7:JF*\xacN\xc1`tR\x8e\x1c\xcbP\x96\x97/\xd4 A\xb6\xa29\xef7\xa6\xeb\xc8\xe8Ǎy\xbc;%\xe0S\x8dpq\xae\x8fSJl\ry\xbf\x8b\xe0ł1\xefT\xef7\xa8;\xa2ӝ\xa1QQ{\x91\xbd\x00\xaa\x01\x01@\xebl\xc7:\xa3\xa6\x9d\x97\x06\u03a2D\xc4\xc6\xf3\xae\xa6\n\x93D\x01\x00\x143\x9bB\xf7z\xd9!\xd5:?\xa8\x04VT\xeaZ\x8c\x91\xe7V\x95ʞw\x00GO\x801\xa2\xcbU\xdf7f\x03rm\x1a\x90I\x12jQ~\xb4ˮf\x03\x8b\xa4^\xb3k\xabkџ\b\xb9h\x87\x90\xe6\x13\x97\x94Gm\xaf퇨f)x\x8e\xeb\xab\xc5\xf5Mt\xccq\x12ŏ\x03\n\xde*\x9e\xcdpr\x82$\x8e\xa1u\x989\x02N\xf3\x8dEŵ\x15\x17jѤ\x1e\x1b\x1907\x8e\xf0\xae\x89yN\x89\xbc\x8b\xeb\xfc̓<\x1a\x8d\xb9\xb6\x8c\xc4=\xfa\vh\x1eFʮ\x91\xee\x0e\xfe\x83\x9b\x82\t`Tv^X;0\xac\x8a\x96!\xa2\x11\xbb\x01M\xe5@\x13\xcaa\x8bM\xd1\xd49\xf6\x1be\xc7\xe2\x99\xf2\xe9\xda\xc6 v3\xe9\xb6\x13\xa5\xd3`\xb74N~\x8er\xeci%\xc2fy\xb7\xf1\xfe[\x1a\x8f\xc5\xfc\xec\xf3\xa5\x00\xea,\x1c\x80\xc1\n1g3\x01\xf3v\xd2\f\xc2\xe70>g\xd7I4\xf7P\xf1\xff\xd2\xd0\xc5}\x98A\x85\xecWh\x0e\x94\"\xb4;\xad\x9c\xa0\xcbZ\x00\xda\xf0^\xf1A\x818\xa4\x9e\x03\xa6\xea\xdc\xf8c\x00\xd1(\x1d\x0fS\x1d\x1f\x94\xf5pf\x1c\xec\xee\"I\xb2\xcd\xc3Z'9\x0fP\xcc$\x10\xb3\tJ&[\x88\x95\xb4\xa9\x1f q\x9f\xec\r\xd20\x86\xa8\xb2)w6\x842\xe5߰\xf8K2\xeb\xe8\xe4T\xe82\xea}Q\xe2k\xae\xe7\xff\x05\xe4$U9\x00q\x9f\xb0\xdd\r\xb7\x84s\xf5\x1bҀҹ\x02\x88''\xd3'\xcczV<\xafy2\xc3p4\xc8W\xbbe\xc3G\xcbt\x80u\xedyթ\x1bIVV\xff7e\xe3p^'\xf3\x9aiԻ\xfbdD\xd6\xd5\xfbA͌:\x19\xef\x89\xfd\x18\x8bՖT\xd3A\xd8ύ\xad\xbf\xe5~-\xf5\xdfǂ\xfbq\x9d\xb8\xfb\"\x0e@V\xa2\x94\xbc\x98\xac\xb3h\xad\xa5\x80G:\x04aض\x13\xb0\xbf\x16\xc4b\xd9kJ\x84n\xafg\xa4\f\xa1\x17l\x06\xf0Z\xc8\xc6Q\xb9\"\x95\x8d\x00\xe2\x11\xc7\xe3Y4\xbd[5\xfc0\x06\xfb\x87\x98ϧ\x99\x03\xc8\x0f)\xa7i\xee\xbc\x1c\xe5A\xe9\x04\xec\xbe\x05y0˼M8\x05C}\xa7\x1b$\xba\xb9\xf3,\x96\xb0\xb0\x10\x00\x95rh\xbb\xb7\xdfu\xc8,\xb2\x0f\xba$V\xcbI\xbc\xf9g\xdf\xf7\xd0i\xb5\xcb\xd5\xe8\xa4\xe0\x85\xbd\xf0\\~m\x03G\x1a ^X\xe5`\xc7\a\x93\x03\x9d\xa4\xc7\xe5\xca1\xa4\xd89\xd8F\x92Ĺ\x83MEU kFb\xa1\xc4̂\x88\xb6rZv\x8b\x99\xc8e(\xf6\xe1g\x87S\xd05\x87R{_\\NT^\xe7\xe2\xef\x93t\xae\xe2\xb9\xc3\xed\x8c\xears+@8\xfeV\xfd\xbd\x14ϟ\x8a\x1b\x97\x9f\x8ds@쮏\xbd(\x04\xa0\x04\t(\xbb\xf7J)m\xf9\xb5.\t>Y\xea#\xeb\xeb\x02=(A\x00\x16\xb2\x91\xfe\xd2\x12<\x95)\xf8H3<\xd0\xea:\xb5W\x1d\x87\xd4F\x00iq@\x01\xcc\a\xd1\xf0Cp\x1a\x17b\x9f\xf9`\x82\x93\xe3#\xa4I\x8c4\x893'P\xa6\x03\rN \u007f\xadT\x1a\xa3\\\x8f&\x0e\xa6\x94\x19\xcbCB\xb6\xfcX\xd7<~\x15\xe5t]\x12M\x96\xe7\xe7\xe6\xe8g\x18\x83@\x1c\x85\xf1+\x02|O\xa1\xd7\xe9\x1aQ\xaf\xd5\t\xde\xf0\x02%\x1d\xac\u007f\x1a\u009a\x1dF\x83x\x1cݑ\u007f\xff`\xb0\x87\xd9tV\x0eu\xc9\x1clVu\x91\xc6SC9\xac\x17\xbf\x16i(\xd4\x10a\xd9]\xf5p^\xab܈h\x81\xa1V\x8e\xad:\x03\xb6\x93Y\xe8\x90\n\xe3%\xc7\xfbb\x19\xb2\xfd\x1a\xeb\x8e\x01\v\xfe\xa6k>\xce\xd9>\xce\xe4\x00\xc8N\x01X\x8b\b_|\x9d\xdf4\x9b7\x96?\xb3\u007fO\xca~3\x02\xb0\b\xe9\xbdn\x17^\xa0J\xa7\xa1\x88:}\xaf\xbb\x8el$u\x98\x1fTW\x94*\x1c\xc0\x1c\xc0\xfc0>y\x92\xea\xe4\xb00\x1a\xd6)v\x1e?\xc9\xe7\xe2\xc5H\xd28;\xa4%s-\x0e\xaa\x11\xad\xaa\x88QEfmD|2&\xef\xe8\xf2`\x1b\xf7\x13p\x92\x9c\xb0X\xdeGW\a\xcf@\x02V\x04e\xe1\x80$\x02ai\b\x99\xf1+\x02\x94GX\xee\xf7Q\x8d}\xd7\xf0\xda\xea\\k\xc9_\x12\xd7W\xa2\x00\x9b\x03\x88\x00̙1\x1b\x1d\x8c\u007f\xcc\xccIq\x80'\xf1\x18\x87\xc7\xfb\xb9\x83\x95\xa9\x96.IWy`\xd9@5v\n\xd3l\x94U\x04\xd6\xee\xebV\x18\x1f\xebz\xc4u4+5:\x02\xb2u\x14\xbc\xf09U\u007fCF\xe8\xfc1H\x1bϝ`=7\xd2yZR\u007flr \xc0\n\x15\xf0χ\x03p9\x01C\xbcS\x1c\xee\xa22\xc0&7\x00\x96\x8e\xc0D\x06d\xd5\xffU\xa9BɚvZA\x88\xd6r\aĹc`x\xcb\xd4~\xdbr\x00.\x14\x90\b\x040;\xd2\xd3\xe3\xc9|\xfc!\xa1z\xae\xc7;{\x18\r\aH\xe2\xe2\x90fN \x13\t\xe50Uk\xb7\x91\x96\xaf\xdb\xce\xe5-hn\xe5\x9drE\x973\xd2\xc9\xc7`G\xfeo\xfc\xbe;ǯ\xe5\xa9$r\xff\"\r\xc8\xc7u\xad\xae\xacd\x8a\xc0\xfc`+\x8fV\x967\xbb\x9b\x8e\xebk;ؤp\x00\x00f'O\x87\x0f8N\xf7\xcah\xc9)\x1e\xef<\xc6|>\xcfR\x81\x02\t\xe4RaC\x89Y\x8c\x13\x97\xcf\xd5\x05\xc5\xe5\xf5'\xed`\xee\x1b\"\xa8\x95:P#w\xd2\x1c}\x8d\xd5\xdb\xec\xfe\xbd\xda\xf5'\xd7cj\xeb~\xcd\x11\xbd\x82\xfd\r\x88\xc8\xf1}j\xe2\x00^8\x02\x00W\x11_KH\xcbn2\xb08̺\xe2\x06\xa4\xf4Wr\x01\xf9$\x0fx\x94\xb5\xee.\xad\xf4+\xa7\x01\xa6\x9e\xdf~m\t\xde\x12\xb2A\x9f6\n\xb0aj\x04`\xa6\x81\xe9\xe1|\xf0\x13\xad\xf5\xa4\xb8\xb8\xf1d\x8eg\x8f\x1fe( \x89LR\xb0\xd0\b\x18N@@@\t\rkP\xbeB\rd\x19+QQ\xe5`+U\xb0#\x81\xe4\x03\xea\xf9\xa2\xdc\xcfh\x1cf\xb6\x1d\x89\x16\xe9C\xfe{\xf9r\x0eO\x11\xba\x9d6\xdaAX\x1d \xc5Ao\xb9\xfd&\xb2\x95_6\np9\xd89\x80\xd9\xf4 >\x99\x1eO\xffZ\xd4tq0\xda\xc3\xd1\xd1\x11\x92(Μl\x9a -S-m4\r\xb1q\xad*\x87%\xbf&\xb2\x9b\x9b,\x92\x90\xb4ct=[\x88@\xa6\x1b8\x05nׯ\xedb\xa3\xd4b\xecy\x93CA\x83\x01\xbb\t\xbf\n5\x88t\xc5B\a\x06j\xa1\x9f\x03\x02P\x8d)\x00\u05cdX\xe8\xeb\xcd\xea@\x06\xfb\xa5\x88\x88\x84\x83P\x05\x01(\xe0\xbf\x02\xc1W\n뛛\xe5\xdf\x043|\xe5mm\xa8\xdeF\xee\x00Z\x8eC\xcaV\n0\x030}\x16\x1d=\x8c\x93\xf9\xbd\xaa\xa6\xaa\xb1s\xff1\x06'Ǚ\x13\x88\xa3lPf\x9aVpը\n\xe8\x8a\fb\xfb0\x99\xf5\xf6\xdaab\aJ ǰ\x0e\xc8\xfc\x9f\x1d\xe8\xa0!\xf7gW.\xac\x05\aQq\x00*\x13\xfd@)B\x18\x86X\xee-KC\xa2\xf6j\xeb+A[u\x85\x13\x90(\x00\x8e\xeb;e\x8d\xf1ɳ\xe1O8M\a\x85#Ku\x8c;\x8foc6\x9dVN I*\x01V\xb9\xa4\x94\xdd\xcc?WF\xc0v\x8aD\r$\xa1\x98\x80D\xb5\xfb\xc1\xe4S\xa8\x89\x8c\xb3\"\xb5\xccם)\x82\xc9?\xb0L7\xb8ɰݎ\x81\x1a\x9c\x02\xb9\xaa\bĎ\xe7\xab\xdd;\t_x\n \f^\x96\x00K\xe6_\xdc\nf\xbdt\x02ں\xaf\xd5\xfa\xab\xc0Y}\x8f\x00\x8f\x14V\xfa}\x04\xbd\xa0|\f\x0f\xe8m\xa8\xdek\xf9\x01m7\xa0\x00-\xf2\xd4\x19\x80\xc9\x14\xe9\xc9\xfe\xe4\xe8;\xacuTD\xced:ý[\xb70\x9dM\x05\x12\x88\xf3H\x95#\x81\x1c\x05d\x9f\xd3굔\xa9\x8f\x88\x10\x9c\x1a\x86W\x1cdr\xc1Y;W\xb7\xbf6\x1e\xdb~\x8c|j\x12\xcc\xfbp\xfe\xf7\x8b\x83W\x96ݸ:0E\x19Py\x80\xef+lnlf3\xfb\xf3\xc7\xf5Z\xea\xe2\xca\xc5Ζ\xb8\xbe-\x87\x83-\x10V\xe9`\x8f\xeeN\x9fD\xa3\xe8\xe3\xd2\x19\x11\xe3p\xbc\x87\xa7;O\x11E\x11b\xe1\x04\xb2t \u0379\x80\xb4DR\x06\xdfBҩV\x88\x81\\y?\xeaQ\xb1\xe2g\xac\xdc\xdc\xca\xc1ٙ\xf3\x8b\x12\xa3\xdc[i\x97\x88Y\xec\\\x14\xe3\xd6\xd8Yy\xd0n\x83\xb5n\xe4\x84\xf9\xda\x11XDE\xc0v.\xcaRȼx\x12\xb0\"\xf2\xe0\x80\xf5%:ж\xa1\xcb\xdf\xd1\xc6}\xf3\x1c?\xbb\x01\xf0@\xf0A\xe8\xb6;\xe8\xad/K\xc4A+\xaa\xfd\xcd.\xd4\x12\x80\x8euHU\x03\n\x98\x00\x98<\x8a\x0eoF\xf1\xec\xb6l?>z\xb2\x8d\x9d\xa7O\x10\xc5\xf3\x12\t\xa4IT欜7\x0e\x99Q\xdcl\xb5u\x12Zl1҂\xac3Xj\xf9}v\xe4\x83\xdc\\:\x92Z\v\x16\b!\xab\xb9\xa7F\xe9\xadtLe%\x80\xe0y\x84\xf5\xd5U\x04^ \xba\x04\xd1[>\xd7}Ӻ\xb6\xa1\x85\x02d\x8a5\x050\xd6)\x0f\x0f\x1f\f\xbe\xa3S=(R\x0e\xcd\t\xee>\xbb\x83\x93\x93\x13\xc4Qd!\x81$K\x05D\xcf\x00˨m\xeb\x18\x84\x813s\xa3\xf1/.\t\xc2\xf1\xd8\x0e\xe3\xcf\x1b\x99\xe4\xcf%\x1a4\xaemAh\xca\xf4\xd05ئ\xe6\b\xb4\x83\xbb0\x1d_\xb3\x16@\xd7\xf9\x06\xc3ٜ=\xfa\u007f.\x04 \xcbw\x86A\x97\x11?w\bB\xddW\x8d\xfd\x12\xa4\xa1-\b\x12<\x80\x97\xf3\x00\xa1\xefcc\xeb\x1c\xa4ц^p\xf9\x02\xf5.\xe6\a\xb4c\x1d\xd2\xe2%\xa7\"JM\x01\x8c'\x9c\x1e\xefN\x8e\xfe\x8d\xd6\xe9\xb84\x9c$Ń\x1b\xb7pr|\x8c(\x9a#\x8a#\xc4I\\\x91\x82e:\x90\x1aFfV\x01جۻ\x18y\xe2z>ώ\x03\xc2V5\x81\xb4\xc5-T7F\x8eND\xf5B\x17\xeb\xd5S\xf3\xffeJS8\x9e|tw\xb7\xdb)Ӏ<ߤ\xeeZ\xebo\x86=\xd5\x17N@\xa2\xac&\a;>\xbc;}4;\x9c\xfd o\x01\x04\x811\x8e\x06\xb8q\xff\x06\xa6\x93)\xa2y\x8e\x04DyP\xbbDXN\"\xaeI\x00\xa3\x17\xd6\xfdk\xa4\x1f[\xa5Q\x17\x8c\x17\xefO\xb5QYCs\xb5\xb8\xb6(\x1b\xebT\x97ed\x96\xb72h\xe8f\x83-G\xa6[\xa8#OQ\xca|\xbf\xf6Z`j\x04\f\xde\x04\xcf\xcd\x01x\x8b~x\t\b[\xc0o)\xe0R\xf1\xbdw\xdf\xfa\x05\\Z\xdd0\xb5\xebRG-\xc4=\xe5\xf7\xa9\xde\xfd\xe6\xd49\xe7F\xae\xb3n~h\xadA\x9e\x87ݧO\xa0\xe7I\xfe\xa2\xc9\xf7A\xf3'zx\x1b\xd5\x1e{\xb9\xcb\u07b5-\xd8\x03\xe0\x0f\xd3\xd9\xfc\x9c\xdf9\x17\xfa\xc1\xcbD\x99r9\x8db\x8cgc\xac\xae\xafgK-\b\xe54\xc1rz\xb0\xf0\x80\xc6\xeb\x11=\xe5\xe5\xc6[27'W\xca5!\xcd54\xe4\\\x9fuD\x95&\xa28\xb0ESL9ȓ\xb9\x84\x9eeN\xcd\x1a\xbaX\xafV\x1cV\xd6\xe2\x00g\xceLk\x8d4Oq\xe2y\x8c\xfd\x93\x9d\xea`)\xear\x9a\xde\x1a\xedG\a\xe2\xfa\xba\x96\x85\x1aח5\xfc\x94\x93a\u007f\xab\xf5\x8e\xf2\xd1/\xae\xcdd>\x84b\x1f+\xfde(\xaf\x90#\x93q\x8dH\\\xdb\xf25\x93ݼS\xef{p\xb5\x00\xcb>\x01\x86=.{\xb1\xf2\x8f\xa5\x13(Z\x9a\x8b\xcdJ\xc5\xde\xca|\x93\xb5\xd6r\x9d\x9d\\cf\xaa\xf2\xe4\\\x81ơ\xa5\xa7\x8e-\x83\xb8^\xcd\rJ\xfb\xbb'x\xff\xb3[\x92\xb2\xddA\x8c\xdf\xc1C\xcc?\x97\x03\xb8\b\x84\xa1\xed\x00\xde\xfc:.\xae\x9d3T|\xa5F\xddn\x82`\xcb!\x18\xb0\xb8\xfa^\xd55\xcb\xe5~\xc0\xecbg\xb3*\x8fGǘ\x1e\f\v-6\xf9P\xcbS=\xfdx\x88td\x1dЅ\x87T\x03\x9eN\xe2õ\xf6\xd2;JQ\xbf8p\xf3\xd1\x04\x11\xc7XY[\xcb[\x91\vçR\xb7OBgO\xb5\xe6\rm\xb2\xd7d\x93Hh\x10\xe9T\x87\xbd\xa6\xe6\xca5\xf0.1L\x115\x8b\bZ8K\x9df\xdfKuŸ\xeb2b9\"\x98\xd6PJa{\x99)\xcdd\x00\x00 \x00IDAT\xef\x19R\x1d\xe72lx~\xe8\xf9\x87\x8fǟ\xb1Ƣu\xe1\xd2m\xf9\x00\xfc\xf9I\xaa\xc3%\x1awV\x83\xaf\x92b\xbfx}\x83\xc91:~\x0f\xbdN7[\x17&{\x13\x94\xc3P\xa4#@\xbd-\x9a\\\n8\x87\x1e\x9e\xec\xef\x93\xc3\xe0\xadr_a\xd0\\\x1azZ][\x11\xf1\x8b\x14\xa6\xb8\xc6幵\x11\v\x99;&ͳ`53\xb9\x06\xb8\xa2A!\x99\a\x1c)\x8a\xda\xdf9\xc1\xfb\x9fݖ\xcd\f_\xcc\x01\\\x02¶p\x00\x04\xe0ݷ\xbe\x86K\xab\x1b\x867\"^\x10\xfd\xad)7\xb2Á\xac\xef\xe5豌d:\xf7\xb8P\x84\xfdGO\xcb\x06$\xa5\xd0V\x8c\xfdm\x9e<\x165\xff\xa6\x95\xd6\x10BFo\xc4I\xda\xd5\x18.\x85\xedw\x89\x10\x14\x87g|<\x84\xf6\x80\xfe\xcar\xb5\xd2J\x18|1\xeaڌ\xd2b\xb5\xb5\xbd+\xceX\x88i\xd6g\xe5\xe10\x1a\x80\xc8>\xf4\xc5d \x11\x89\x84\xf1\xeb4E\x9a\xa6Y\x99-I\x91\xa4I)\xbeI\xf2\xd2[*\x94\x8e\x95SH\xcb\xdf'f\fGc\f\xa7\xc7\xe5s\xf7|\xea'qt}r\x94\x9cX\b\xcb\xe5`\x8d\xbd\x8c\x93\xfdx\xdc?\x1f\xae\x06\x1du\xb5\xe8\x0e\xd3Hq4\xbb~\x1ai\x92f\xd77I\xf2\xaf3\x04Uܧp\xbc\xac\x8b\xc7A\xfd\xdc\xcb\xea\x0f\x9d\xbd\xe5\x98\x1c-\xc4D\xd6\xf7\xf3kp\xb0s\x82\xf7\xafߖw\xff\xe2\x0e\xc0N\x01\xdey#w\x00֓\xaaE\xf6\x06\x87\xc0\xd6\x19w\xad\xb3.\xe7`\u007f\xe7\x04\xef\u007fzG\xbe\xf8\x1d$/\b\x01\x14O\xe2\xdd7\xbe\x8aK\xab\xeb\xa8m\nv\xe4\xf55'\xc0\x96W\xb6g\x9b\x89|\xaa`\xb7u\xde1\x97\x12\xe3\xf0ɳ\xf21\x94\xa2\x9e\xc78y\xc6\xd3G\xe2\x80&0\x17\x88\xba\x90\x001\xa0F\xf1to=h\x9f\x0f}\xff\x02r>\x00Z\xe3\xe4\xf0\x00\b<\xf4\x96z\xc2@\x9b\x0e\x19\xd7s<\xb2\x14Y5f\x1a\xe6!\x14\x8e\xa5\xa8.0U\x1at\x99\xbf\xa7:7\xfc$\xc9\r=F\x1cg\xe4\xda|>\xc7d:\xc1h4\xc2x4\xc2x2\xc1d2\xce\b\xb8(\x12i\x82\x95\x1a\xa4\x1a\x8a\x14\x86\xa3\x11&\xf3a\xe9\x90\xfcP\xad\xeb$\xbe9>J\x87\r\u05f7is\x90\x8a\x06:\x85J\xb7{\x1b\xc1\xdb\xe4Q\xafx\xbdq:\xc7\xd1\xc9\x11\xfa\xed>ZaX\xcb\xe7\xeb\x90݄\xc6$\x11\x80\xc5\x11\xb0\x93\x13`g\xcb,C\xaeK\xaf\xa2~\x9a\xea\xcca\xe6\x86\x1eG\t\xe2(F\xfd\f:M\xf0ʵky^\x97\x829\x00\xb3\x0f/\xff\xc7^\xbecP\x11\xa8\xe8w\xd7\xd9^\xbc\xc6R\x8c\x01\x9cͱ\xd6F\xec\xe7\xe2\bU\x0e \xcd\x0fW\x92&e䏓\x04Q\x1cc8\x1c\xe1\xe1\xe3\x87\xd8?\xde\xc5<\x9eel\xba0I\xe5yX^Z\xc5\xd5\xcbW\xb1\xb2\xb2\x82 \b*'\xc4\x1a\x9e\xa7py\xeb2\x0eG\xdbY\xe5\x03\x80\xf2\xd0\xdfx\xa5\xf7w\x0f\x1fGϒ9\x17\xd7w.\x9c\x00[\x9a\x8b)\xc4j\xf6\xbdϢ;Ag\xfc\xbf\xaf\xbf\xd6\xfd\xa7ʧ\x95\xe2:\x8c\xe3c\xfc\xec\xee\axO\xbf\x87\xad\xcds\xf9uM\xc1\xec\x83ك\xe7+x\xbe\x97][\xa0\"c\x95訷W\xaf9\x86\xae\x1aו\xb8Z\x9b\xc6\x05\xaaBe\xfc\xa9F\xaa\xb9\x82\xfaqZF\xfb\xf9,\xc6\xfe\xd1\x11\x1e\xec<\xc6\xd1\xf4\x10I:\xcfޗb\xc2\x12\x11Z^\a\xe7\x97/\xe0\x95K\x97\xd1\xefw\x11\xa6>\x82\xd4\aZ^EA\xf9\xf9^\x8a\xd2f`\xb6+\x93k\xd8\a\xd7S\x17qv\xc8~\x8d\xf6\xd0\xd0/Z\x05\xb8bq\x00\f\xe0\xdd\xd7\xdfå\xd5u\xb3\x02\xc0\xf5\xa8\x0f\xa1\xe03\xab\x01\xe6t\xe1\xbaÑKCM\x14\xa0}\xc2\xe1\xe3\xed\xf2\x82)\xa2n\b\x95l\xeb\xc9}]\x8fP\xf2\x90:}ۘ\xd3D\xc7ѣ\xe5\xa0}\xcd\xf3h\xb5<\\Zcpp\x80Y\x1a\xa1\xb7ܯ4\xf35\xf2\xa82T\xb2\t\x9a\xa6vU2\x17vԙg-\x88\xbd\f\xb2\x170>NbDq\x9cG\xfc\b'''\xb8q\xeb:\xae\xdf\xf9\x18\a';\x88\xe2)\xb4\x8e\x90r\x02]\xdct\x8cTG\x18O\a\xd89x\x8a\xe3\x93\x13\x04^\x80 \br\x8d@\xe1\x04|\x8cFcL\xa3a\x19\xa5\xfc@\xad+\xa5\x1f\rv\x93\x03\xc1\x01$X\xbcE\xb8\xc2\xde\xd1\x0e\x14\xfb\xe8uz\xd5lA0\x02?\xc4\xfe`\x17\xcciqP\xfdV\xd7\xdb\x1a\x9d̯\xc7\x13\x9e;\x1c\xacn\x10\xbc\x97o\xf3h'9i\xf51h\xf5\xbd\xd7\xc9C\xab\xb8k\xca\x11\xf6\a\xbbH#\xa0\xd7\xee\xe5CVu\xe9\fY\xf0A\x95\xc8J\xd6\xeaQ\xb1\xee\xa2)˸\xbe\x06\xa3\x9fV\xa5<]\xe4\xf9:\xe3Pⴄ\xfa\xd1<\xc6d4\xc3\xddG\x0f\xf0\xd1\xe3\x0fq2\xdf\x05#5a9\xb9\xf2r \xd1s\x1cNv\xb1\u007f<\xc4Jg\x19\xedVP6_\x91B^b\x96\x9c\x12[c\xf7\x9b\xf6\x0f8*l\x0e\x1e s\x00\xf7\xaa_\xd49\a\xf0y\x1d\x80\x8d\x00\x00\xe0\xed\xd7\xde\xc1\xa5\xe5\xf5*Z\xb3;GY\xc4\x01\x98|A>\xea\xc8r\x1a\xd2\xf8\x8b\\\r\xc4@\xe0\xe1\xf0ٳL\x9a\x9b\xb5\xb7\x86]\xf27\a\xe9\xf4\xc6\x14\xb4\x11\xf5\x19`\x8eg\xe3\xf8\xfa\xc1\xd3\xf1\x1f?{8\xfa\xee\xee\xc3\xc9_\x1fnO?\x98\x0e\xa3\xebJa\x16\xb4\xbduR\b\v\b\xa9\x91b\x16ͱ\xb1r.\x9b\x12\x9c\vt:\xad\x0e\xf6Ov\x91r\\h\xcb)쨋\xca\u05cf\x86\xbb鉐\x02놪\x80\x13\xf6\f\x9f\xa5G^K?k/{ה\x87^\xf9\xdc\x15c\x12\r\xb0{\xbc\x0f\x1d\x13\xdaA+\x1b\x1c_\x94\xe34\x8b\x92\xb0.\xc5M\xd9\xd7\\\xfd_\xb2\xf0Z\x1b\xa4g\xc1\xeag\xcc~e\xfc\xf1I\a\x87\xdb\xf3\xc7:\x8d\x1f\xf6\x96\xfd\xcbʧ\xa5\xe25E\xc9\f\xbd\xce2\x96\xba]x^Fh\x06\xbe\x0f\xad\x15\x8eG\xfbUީ(l\xf7\xbd˳q|k>\xe4\xd9s^ߢ\xa4\xa1G\xcf\xf41sz\xb7\xb3B\x17T@\x1b%\xd3\aF\xa2\xe78\x18\xed\xe2\xe0\xe4\x04>B\xf8\xcaC\xb1\xb8\xb8\xac\\\xa4E\x8d\xbe\x12=U_\x179}\xf6\xff\xd2\xe8㴄\xf9U\xc4\xcf\xd8\xfdh\x1ec:\x9ea\xef\xe0\b\x9f<\xbc\x8e\a\x87\xd7\x11\xe9\x89M\xder:Ń\xfd\x8f\xf0\xbb;\u007f\x8e\x1fϞb;9\xc6q:\xc2 9\xc6h\xfa\b\a\xc3Ǹ\xed\xb50h\xad\xe2%R\xf9**\x02fQ\x8c\v+[h\xb5\x03(/\x1b\xc4R\xa6\x03J\x96\xbc\xfc\x80vZm\fF#\xcc\xe2q\xa9EW\x01\xfa\x9d\xbeZ\x1a\xec'\xf7\xd2y-\rЎ\xf4J\xbb\xae\xf1d\x9fǓaz\xb3\xdd\x03\xfc.]\"\x85@\x96\xedf\xc9\b\xdb\xc7Oqx|\x828\xd2\xf0)w\x04ie\xe0iR8\xd0*\xc2\xeb\\\x9c\x93\xd5\xe6\x13\x83\xc9O\xa2\xca\xf0\xa3y\x82\xf9,\xc2h4\xc1\x93\x9d\x1d\\\u007f|\vw\xf7?\xc38>\xaa\r\xd4`\x8d\xd9l\x1f\u007f\xb9\xf3>~\u007f\xf01\xee\x83q\x9c_\xdfa~}g\x00b\x9e!\x99<\xc6Q\xb0\x8e\xb8\xb5\x86W\x89\xb2\x1e\x9bHO\xd1\xf5\x97\xb1\xb1\xba\f/P\xd9\xf5\xf5(\x93D+\x8b\xab!swC}ЈH\x1b\\%C0\xf6wF\xf8\xd1\xf5\a/\xd6\x01\xd48\x80\xabo\xe1\xd2\xf2\xaa\x98ao\x8a}\x8c\xd9\xff\x0eG\xe0\xd2\x04ԝ\x88\xf9\xe2I\xe8ߋ\xdfiw;8\x99\x0e1?\x19\x95\x17\xd1#\xea\xf7\xc9;?\xd4\xd1\xedIV\x15ЧD)\xd7!M5\x90\xeeE\xf1^\x1aE7:\xbe\xea\xf9\xbe\xda \x05\x1f\x82\xbcI\xe29\x86\xc7\a\xd8\xd9y\x8c\xfd\x83\x03\xccf3\xa4\x05TM\x13\xa4Z#I\xab\xba}\x92\xab\xf3Jx\x9f$\x88㬌\x17\xc5\x11f\xf3\x19\xc6\xe3\t\x0e\x0f\x0f\xf1\xe0\xe1\x03ܹw\x13\x8f\x9e\xdd\xc1h|\x98\x93|B\xf9F\f\x9d\xea\xc1\xf0h\xf6\x9d\a\xb7\x86\xff\xe7\xdevr\x1f\xc0\x11P\x1e\xd0Qޤ3Cu\x1dh|\xa2\xe3\xde\n\x05\x9d\xbe\xf7J\xa1}\x88\xd3\b\x176.\xa1\xddn\x95\a\xd4\xf7\x15:\xad.\xf6O\xf6\x90rTNH\xf7[t\xbe\xdd\xc3\xecx;}\xc6\x1a|\x86\xebZ\xbb\xb6\x00\xd2x\x88\xf9\xf1\x83\xf4\x9e\xd7\xe2Ga\x8f.\xa8\x00}\x90hL\xa3\x14\xb3d\x88\xbd\xd13<=\xd8\xc6\xe1\xc9\x00I\x94\x82S.\r\xdf\x14\xeb\x88(\x9f$\x88\xa34\xaf\xe1\x8bH?\x9dc0\x1ccg\xff\x00\xb7\x9e\xdc\xc3\xcdg7\xf1\xe4\xe4.&\xc9I\x89,\xa1\xaa\xe5V\xe9\x1cO\x8fo\xe3w\xb7\u007f\x80?\x9b?\xc3v~}\v\xe7Z\\ߢ\xe4\fh\xd0l\x88q\xff*\xaez-\xac\x966\xa8=\\\xd9\xdcD\x10*(_\x95N\xd6\xd4\x05|\xfe\x85$r\xe0\xed\xfe\xce\x10?\xba\xf1\xd0L\x01R\xfc\x0e\xee}N\x1d\x80k8|\xd1\xf9\xc7\xc4eݟ\x89ʚh\xe1\xbbj\x9a\x00\x12|&U\xfa\x81Z\xb1\x9cH\x1c\xf6l\x1c\x18\x83\xe1\x11\x10\x10A+B\xea)\xf4Zm\xbc\xf6\xd6[\xf8d0@4\x18\xe7\v\x16\b\x1d\xcf\u007f\xe3m,\xfd\xa3\x9fƣ\xdf\x1f\x99\xedX\xf2#\xb6j\xd8\xc6ҋB^\xfc(\x8a\xe7{\xfb\xc7\xff˫K\xadw\xce-w\u007f#\b\xbc\x97\x89ȗ\nF\x9dD\x18\x1e\xedbx\xbc\x8b\x87w=\x04\x9d\x1e\xbaK}\xf4\x96\xfaX\xea/\xa1\xddm#l\xb5\xe0y\x1e(_ʩ\x99\x91\xa4\t\xe6Q\x84\xe9t\x82\xe1x\x88\xd1d\x88\xc9t\x88(\x9ed|\x87\x92\rG(\x97\x81\xb2\xc6l>\x8d?\xdd۞\xfe\xf1\xd3\xc7\xf1=\xad1\x10\x11i*\x0e%\xe5]|Q\xfeH\x01\x80\xf6\xe1\xb3\xf9\xf5\x95\xf3\xc1\xb7\x94OK\x99\xff\xce\xc4DJ\x01\x9e\x9f\xbdo\x9e\a\xac\xaf\xae\xe0\xea\x85\xd7p\xfb\xe9\xc7\x19\v\x0e\x80\x14\xfb\xcb\xe7\xfd_\u007f\xe9k\xfa\xe8\xe1O\xe2\xf7\x99\x9d\x1c\x00\x04G\x90\xc0\xbd\xb3!\xd6\t\xe6O\u007f\x94N\a\xcf\xf4\xa3ͷ\xbco\xf5\xb6ԯ\xa9\x00\xeb\xf6r\x89y:\xc0\xcep\x80\x9d\xd1=\x04\xaa\x8dN\xd8G\xbf\xbd\x8c\xa5\xce\x12\xfa\x9d\x1eڭ\x10a\x10d\xf95\x15\xd3\xdb5\xe28\xc1,\x9ac4\x1dc0\x1ba8\x1b`\x12\x0f\x11\xa5\xe3\x9a\x04[\xc2}\x1d\xe3d\xba\x87\xef\xef\u007f\x8a\x1f\x8coa;7\xf6\x91\xb8\xbe\xc5\xd9Qy'j\x9c\u007f\x1d&\xbb\x18\x8c\x9f⧫o\xe1\xa5¡\xcd\xd3\x19\x924\x81\xd6A\xd6\xa0\xc8[z\xa7\x00\xe6\x83\x03}\x92\xc6\xe9@\xf9\xdeR\x99\x8a\x11g\x0e\xc0\xa3\x8c\xe0D\x96\xa7^\xbdt\t\xa3\xc9\t\xb6\x8f\xefU\xc2\x17\x0f\xdd\xf5\x97\x83\xdfL\x12=y\xf2\xb3\xf4\xa3\x06E ,\xa2p\x8e\xfaX\xf19\x80\xd9\xe8\x11O\xc7O\x92\xc3\xd5\xd7\xe8\xa7\x1b\xaf\xa9\u007f\xa7\xbdN\xdfT\x01֡\x8aU\"\\Φ\x8f\xf5\x04\xf1|\x8c\xc1|\x1b8\x01\x88T^_\xf7\xe1\xab\x10J\xf9`N\x91\xe89R\x8e˒\xad\xb16̽W\x9au\x82\xa3\xf9!>8\xba\x8d\xef\x1e\u007f\x8c\xc7Х\xe1\x8f\x1cε@\xcfi~\x9dۅ\bmz\x80\x9dU\x8d\x04^\xa6{\x90KRY\xecJ\x04*\x96ٹN\xdc\xe8\xb51\x17\x82\xd6W\xa1\xb3ѻ\xf2<\xf3\x00\x9ek9\xa8B\xbe\v@k\xb1\x9d\xb1\xdc\xf5\\)\xfe\fc\x17\x0eA\xec<\xe2\x82f'\xc9\x10\x92XrY֊2'\xc0\x99\x13\xf0\x15eN\xc0S\xd0\xec\xe3\xf2\xf9\v\x18\xbdq\x82\xed\xcfn\xa2\xdaBK\xfez\xd8\xfa{_\x8d\xd2\xe8gi\xf4\xa7\x91\xbby\x85\xac\xe8\x1f\xbbP@1\xf5\xe6$\xe5\xf1\xc9\xf1\xf4he8\xfb\xf0b?|c\xad\x17\xfeJ\xab\x1d\xbc\xae\x88L\xf8*\xfc:s\x9a\xb7\xa13\xb4\x9e\xe7G\x87\xc0\xcaq \xa9\xbaƺj,Mt\xc2\xc7\xd3q\xfc\xd1\xd1Q\xf4\xa3\x9d\xed\xe4\xc1<\xe2\"\xbf/n\x13\xcb\xf8S\xf1\xdeRn\xfce\xceΌ4\xa3\xf8u\xf9\x87I\x01\x9e\x02\xd6\u05ed\xeb\xaa\xf2\xe7(\x9d\x80t\xb2\xd2\xc1\xce\xcb\xd7\xc5\xe8\x1e\xdf\xc2\xe0\xf86?\tW\xf9/V_\xc1\xa5\xa5-|\xad\xb5Foz!Γ\xe2.\xbc\x824<\xc3\xc1\x85\x19\x87\xa0\x91\xb0\xc6$\x8d\xb0\x17\rpk\xb4\x8d\x0f\x06\x0f\xf1t\xfe\f\x03qM\xed\xebkϛ(\xa2?;\x1a͔\xdfE(ˁU\x17i>\x8b\xb0\xe8f\xb3\x05Ed5\xcca\xd1\x1a1\xb3\xa7\xa4 \xd3?\xcfL\xc0ϱ\x1e\\\x83Ҵ\xa4/\x8d\xfc\xbf!\xef7R\x03\xe1\x10*$`\xe6\xfe\f\xcavi\xe4\x0f\xa9ċ\xf5\x88\xc1*\x9f\x87\xc2\n\xda\xf3\xb0\xd4n\xe3\xcd7\xdf\xc4'\xf3)\x86O\x9e\x95\x97L\x11\xb5\xb7\xc2ֿ\xff\xf5\x88\x83\x8f\xd2\xe4Og\xf5C\xaa\xc4!\xb5k\xdbv\xa4*\x0eG\x1b@'a\xb4\x9fLӣ'\xd3\xf4\xa1\xb77\xff\x8b\xf5\x96Z\xeew\xe9\\\xb7\xe3]h\x87ޕ\xc0W\x97\xbdP-)\x856\x13B0<\xa2|\xf5 A3\x902a\xa65ϒ8\x1d\xc4)?\x9c\xcd\xd3g\xe3\x89~6\x1c\xe9Ó\x11\x0f9s<\xf26\x15_G\rm\xd0J\xf4\xe8\a9\x02(\xa6&\x85\xab[j]\xf9\xbcR\xac\a'p\x16\xf9\xf3\x14\xa0(\a2\x17\xa5*\x8d\x8d\xb5e\xbc\xf3\xea\xbb\xf8\xf0\xceO0OG\xe5\xe1\xf0B\xda:\xff\xa6\xf7O\x88\xf8_>\xfd\x88\xaf\xc3\xdc!c__\xe9d\xe5\xf5\x8d\xc4k\x1b\x03h\x83щ\x8ep\xb2{\x84\xfd]\xe0F\xb0̽\xdeE\xact\xd7p1\\Ź\xa0\x8d\xd7\xfc6\xceQ\x886\x11\xda \x849\n+\xb6\"j\x0013f\x9c`\x96\xceq\x18Oqw~\x82\xbd\xe9!\x9eNvq\x12\xeda$\x9c\xbb}mg\x02Q\xc9.H\xf9ڊ\xeb\xdb\x12\xb7\xb0\xbb\x89\xab\xe4e\x84qƛ\x14\xb5\u007f\x167\r\xab\x9c\x03ג\xd2\xc6\xfd\x84N^@\xac\x9a{Q\xcbA\x95\x03\xa5\x96\b\xa0\xe8z)\x8d[\t#7\x1b\x83J\xa3w9\x06\x96\xedR\\9\x02e\xe27%z\xe3\xbd._\u0604\xd6_ŧ\x0f?@\xa2\xa7e\x14\xf2\x02\xac\x9f\xbbF\xff\xb1\x17`\xe9\xd1\a\xfc\xa3tf\\[\xb9\xcc5\xb2\xd0@\xea@\x03\xbe\xb8\x9e\xf2\x1a\x17\xdf\xf7u\x04\x1f\x11T:\x82\x177o2v=\xbe\xbc\xb6\xb6\xb3u5;\xb1\x95B\x15\x11\xbf\x93\x1b}q}\x97\xfdu\xac\x9d\xff\x06~\xd5oc\xab2k\xc2\xe5\xf5s\xf0}Y\xfb\xe7ڀ\x19\x02\x9b\xb1\x9eL\xc3&1\xbb@6\n\xc9ܿ\xac\xb1)Ǥ\x86/\x9a\x02(yҴ\x06\xd2T@~ʍ\x91\xac|\xdf4\xf2\x1a\xfc\x97\x89q\x99N\xe4?R$\xf8<\xaaj\xb4\xa8\xd2\x01\x06\xc3/\xfe\x96\xca\xcf?3\xd6\xfaKx\xfbk_\xc5\xf5\x8f?\xc6xg\xbbl*R\x04\u007f9\xf0\xbe\xf55\xc2\xe6\xdd8\xf9\xbd{\x9a\xef;\x0e\x9a\xddRl\x1f\xd4\xe2\xf0\xc8\xe8\xe67|V\xe2\xe0\xb8\xde\ng\x8d\xdc:\xac\xf2\xff\xbaa\u0381\xb2\xe0~a\xfc\xfd\xfcp\xae\x06\x016\xae\xbe\xa3~q\xed\xa2\xff\x0f\x94\x87v\xb6F\x9b\xe1\xa9\x10\xaf^y\x19a\xe8\xe7Ɵ#\x80ܜ\x14\n\a\xe0\xe5\x87\xcc\xc7K\x97\xb6@\xf4u|\xf6\xf0CDzT\xa5[>\xf7ׯ\xe2?\b{\xd8|\xfc\x11\xbe3٭\x19\xf2\xd8\"+etM\x05\xa3^\x18\xa4\xbc\xbe\xf6\xb5\xf5\x1ci\x06Y\xa1T[\xc4c\xd3\xf5mj\x1e\x83\x05\xf7\vd\xd2\x15\xd7w\x15\xc0j\xe75\\<\xff\x8b\xf8w\xdb\xe7\xf0M\x19\xfdW;\xeb8\xbf\xb1\f/w\x00J1H\x99[\x89\xc90t\x94ӄ\\ў\xc8L\t(o\x1d\xafM\x0f\"\x91'\xd0⅁g\xe6\x00\n\xc7R\xa5\x00T\xd5\xfb\x8dh\xdfP\xfa+\xf3|\xd1GH\x15\v\x8d\xa2\xa7^\xa6\x05\x16\x8b\xa3\n\x9f\xc10\x14P\x99\x03 \xb0\x97\xd9\xdb\xfa\xd2\x12\xdey\xef=\\\xf7\bçO\xb3\xfbd Eu|z\xe3M\xcf\xffg\xbdy\xf2\xfb\x9f\xa5\xfcIZm\xc1\x91+\xb1f\xa8\xcf³#\xb6\x9d\xefڇ\xd2u8\xe1\x88R.E\xe2i*;;*\x05\xe2pv\xf3ù\f`em\x13\x17_zC\xfdFgE}\x83<\x0eY<̹\x95\xcbX_]\x86\x1fPvHs\x89\xaa\xf2\xca\x02L\xf9\x9e\x12rG@\x01\xae\\ڂ\xe7}\x1d\x9f<\xf8\x10\xb3\xe4\xa4z\x9b<\xb4\xfa[\xf8\xbb\xd7~\x19W\xb6o\xe2\xffڿ\x81\a\xa8_\xdf\t\xcca\xa3\xa9\xe5\b\x8a\xd7os\t\xa7]_8\xb04;\x1c\x81n\xb8\xb1C\x02S8\x9f\x96e\xfc\xcb\x00\x96\xc9\xc7\xea\xda/ⵍw\xf0\x9b~\x17W\xcb\xca\x1e2\xe7ym\xf3\x02\xba\xdd\x00~P\xa5V*\x9f\x83HFK\xb0\x88\xe4r\x14\x9cC\bd\xe7\xffDr&\x80vU\x01\xe8\v9\x00e7z\xeb\xb4\"\x01\x8d|\xdf\xfa\xbf\x8c\xea6\xdcG5p\x13D`-\x9c@q\x9f\xd2\xebX$\xa1$\x06e\xbe\xa4\n\x04\x92\x9d\x95\xb5~\x0f\xef\xbe\xf7\x1en\xb5B\x1c>\xb8\apZ\xa6!\x81\xc2\xf9\x97\xdb\xdeo\xf5c\xfd\xdd۱\xfe\xb3=.s\xe6b\x16\xfeD\x90A\xb1\x15\xb1\n0\x94:\xfc$9\xfc&\xeažE\xd3\x1e\x1b\xbb\x16mgcG\xfd\x8e\xc8G\x97=\x0f+W^\xc7W6\xaf\xa8\u007f\xec\xb7\xe9\n(+@\x17\xc0\xab\xdbZ\xc7[\xd7^C\xbb\x13\xc0\xf7\x15\xfc\x02\xfe+\xce\x06W\xa8\xaa\xcf\b~^\x96)\xfe4\x05\xb8tq\x13A\xf0\r|r\xffc\f\xe7{2\x9d\xf5Z}\xbcs\xe5k\xd8\xea\xad\xe1_?\xf9\x00\x1f&3\xb4ĵmY\xa5\xb5ؑ\xd6h\x11\xc5\xe1\xa8ܸ\x96`ӂv9\x97R\x11p\x97\x87=+\x9dj\x89뻔;\xd7~x\x19綾\x81o-]\xc1\xdfS>\x96\xed\x8c\xf5R\xff\"\xae\x9c_GТ\xdc\xc1\"\xef\b,*\x02.\x02\xd0\x1a\f\xc2|J\xfe\xcf\xf5\x14\xe0\xb9j\x00\xcf)\x04\xca\x15) \x9d\xd6\xd5~\xe4\x9a\xf3\xec\x88\xfc\xf6gU9\x0e\xa8\x8c\xfd/\t\xc0\xdc1\x14\x93\xe6\xa9b\xf7\xa1\v\xa1PI\x0e\x8a\xfc\xc0\xf32\x0f\xdb\xed\xe0+_y\vw\xdb-\xecܽ\t\x1dG\xe5\xf0\x15E\xd4\xd9h\xd1\xdf_\n\xd4\x1b\x8f\xe7\xfa\x0fn'\xb8\x1dWN@ր\xe7\xd6A\xb5\x11\x81<\xa8M\xd5\xe7\xa67b\x91\xe6\x93\xce`\xf8\xc5\xe1\xec\n\xe3_\xda\xd8\u0085\x8b\xaf\xe0\xd7zk\xea[\xe4\xa3gN\xcda\xf4\xdb\xe7\xf1\xee\x1b\xefbmu\ta\xa0\x10\xf8\xd9\x01\xf5\x94\x8cP\xd95U\x06\xb8S\xf9\xe1U \xf2p~s\x15a\xf8u|r\xef\x06\x0eG\x8f\rA\x93\x17\xe2\xdcƫ\xf8Oz\x1bxo\xfb\x06\xfe\xe8\xf0\x0e\x9e\x82\xcb]\x0e#Qf\x93)W\xech5\x86\xe5t\xe9LU\xfe\xc5\xd7ו\xe5ڈ\xaa\b\n\xc5\xf5]\x02\xb0D\x1e\x96\xd7\xff&\xae\xad\u007f\x05\xff\xd0_\xc2\xeb\xa4L\x1b\"\x10.\xf5/\xe0k\xd7^F\xb7\xe7\xc3\x0fUf\xfc\x1eCy\\\xf6\x00\x98\xb3\xfc\x1dB \x98\xcd>l\x8d\xdd\xe7\xc6\xf6`<\x97\x18\xe8\xb9ˀ\xa45(I\xb2R\x91k\xfa\x04\xe5\xa5A\xa3\xbcg\xa7\x06V\x8a\xa0\xf2Ӧ\x01.\x9c@\x1e\x85XW\xd3T\n\xc7P|O\x89\x1a\xaa_xA\x95\xe10\"\x05\x82\a\xa2\x16\xde|\xedU\xf4\xfb=ܿq\x1d\xf3\xe1Q\xa9\xbe\x02\xa0Z\x1e\xae\xbdң\xffl#\xe6\xf7\x1f\xcd\xf1\xdd\a)\x9e\n\x85\x9d-\x04q\r\xc8\\4tD\x9f\xb1\x1ac\x1fj倿\xd2\xf0\xed\xc3\xd9\x03\xb0\xd4\xe9b\xed\xca5\xbc\xb7\xb6\x85\u007f\xcf\vi\v\x8aU\xe9\xf1r\x03\xde\\\xbb\x86\xb7_{\x03++Kh\xb5<\x04\x81\x82\xef\x8b诤\";?f\xaaBu\x04\x02)/s\x12\x8a\xb1\xae\x96\xf0\x8d\xf0]\xdc|\xd0\xc3\xe3\xa3;Y߂H\t\xdak\xf8\xa5\x97\xbf\x81WW/\xe1;;7\xf1\xd3\xf16\x0e\xf2\xe7,EL3GZ`\xcfv\xb4\xa3\xb6>\xc35e\x879\xb8J\xc1\xbeñ\xb6EJ\xd5\x03a\xa9\xff\x15\\\xd8x\x17\u007f\xab\xb3\x89_\xa1\x00K\xf6\x1f\v\xbc\x00\xaf\x9f{\x19\xaf]>\x8f\xeeR\x88\xa0\xa5\x10\x84\x80\x97\xa7\x00\x85c%\xc7\xde\b9\x1f\xd1]\xffg#3&\xb6\xd3\x04^\xe0\xe7\xbe`\x19\xd0 \x16\xd3\x04\x94&\x19l/Ӏ\xeapԶiPE\x12\x92U\x15(#>\x1c\x0eB\x92\x87\xc5L8\xce\xe7t\x942\x1b\xebm.<\xabB\x99\xb7\x12yP\x14\xe0ʅ\xf3\xe8\xf5\xba\xb8s\xeb\x16\x06\xcf\x1e\x95\x8cj.\x1aꭶ\xf1\xb7{-\xbc\xb75\xc3\xf7\x1f\xce\xf1\xfe\xae\xc6>ם\x80]\x1fNpzo|S\x04\xa2\x86H$\xf3{\xcfb\xc5mH\xda\x05\xd0\xedt\xb0r\xe1\n^۸\x88_\x0f\xdax5kI5cD\xe8\xf7\xf1\xca\xe57\xf1\xf2\xe5\x8b\xe8v[\b\xdb\x1e\xc2P!\b\b\xbe\x8f\xdc\xf8I\x94\xaa\xaa멨b\xa0)\xc8߷\x1c\x05d\x9cA\x1b\xef\xbeq\r\xeb\xbb˸\xf9\xf8V\xd6Y\x14=z\xec\x00\x00 \x00IDAT'\x10\xae\xd7\xc2\xe6\xeaU\xfc\x87\xbd\xf3\xf8\xa5\xe3G\xf8\xe3\x9d\x1b\xb8\x15\x1d\xe1X\\[\xdb\xc9ڬ|S\xbe\xee\x1e\x8f\xdbl\xf4.4\xe5[\xba_}\x17\x8f6\xd6\xf1\xec\xde\x1dēaՖ\x00P\xa0pn\xb3\x87\u007f\xbc\xd6ů\x1c\xcd\xf1\xfdg3|\xf8$\xc1.\x9b\x91j\xd1AM\x1dun4\xe4\xf3g1|_\x10\x93\xf6\xe1\xec\xf4zX\xb9p\x19o\xaco\xe2ׂ\x0e^!\x0f-[aH\xe4a}\xe5\n\xdex\xe55\xac\xad\xf6\x11\xb6}\x84\xa1\x8f \xf4\xe0\x87E\xf4/JTZp32S˞\xbe\xf22\x89M6^He\x87Y1\x94\xf2\xa0T\x80\x97.mb\xa5\xdf\xc3͇\xf7\xb1}\xf2\x10Zhs\x89\xe0\x85\x1d\\;\xf7\x06\xfe\xd9\xca\x15<\x1c<ş\x1e\xdcí\xf13\x1c\xa1~}#\a\xdajr\x04\xb6u\xb8\xd0T\x93\xe1\xbb\xc4<\x1d\x00\x1d\xf2\xd0]z\x13\x9b\xab\xaf\xe3\xbd\xdeE\xfc\xaa\x17b\xab\xe8O\x90q'T\x01^^\xbb\x84\xd7.mai\xa9\x95E\xfd\x96B\x10\x8a\xdc߫\x9c\xab\xbd\x01\xca\xed\xbf\xdc\xc6\xdf$\x00\xaa\xaa\x03|\xb6\xc4\xf3yI@\xb3\x17 \x05%\x95\x03`\x12H\xa0,\x05\x8a\x9f\x19\xa8@\t\x92\xb02z\xd6E5\x80J\"\xd0 \x14\v\x82\xb0\xb0\xf6\\Q\xc9*wŪ\xe2\x05\x94\x18\x1bMT\xa5\x03\x8ar\xbd\xbbj\xe1\xf5\xabW\xb0\xb1\xbe\x8a\xfb\xf7\xef\xe1x\xe7\tt\x9a\x94(\x82\x00\x15x8\xbf\xd9\xc3o\xaew\xf1kW#|\xb4;\xc5\xfb\xcf\"<\x1d1F\v\x9c@\xd3A\xe5S\x1c\x80Zp8CK\x18\xd3\xf6\x14:\x1b\x1b8\xb7\xb1\x85w\x96\xd7\xf1\xcbA\x80K\xf0\x10\xb2\x1c\x98\x9b\x1f\xd3nk\x03\xaf^\xb9\x86\v\xe7ϡ\xdbi!hy\b\x02a\xf8~U\xf6#c~\xbdKN\x9b\x0f?UՖa\"\x02)\x95\xa3\a?+#\xfa=|\xbd\xf3\x06\xce\xefm\xe0\xf6\xb3\xfb\x18\xcd\x0f\fn\x80\bA\xd8\xc3k\x1b\xaf\xe3\xe5\u0557\xb1=\xdeŏ\x8e\x1e\xe3㓇\xd8Og\x18\v\xc1U\xe4@[\xaeԠ\xe9\xfa6A}Oh6B\v\xf2\xb7\xfd5\xf4V\xdf\xc0\xa5\xe5\xab\xf8\xa5\xd6:\xde\xcb;\x14\x95K\x93\xb2\xd5\xdd\xc0\x9b\x17/a}\xb5\x87V\xdbC\xd0Rٵ\r\xb3\xa8\xef\x05\x10\xe5?\xb3\xf7\xbf\x16\xa8ɚ\xa9a숐\x8dA.\xe8\x0f8\xe7\xdfJ\x1a\xfa\x8br\x00%\xd2N\x12 M\xb2,:Ϸ+\x06\x9e\xa0-d \x1d\x04PU\x0f\xe0\tc/r{\xa8\n!\xe4F\xcf*\x0fϖ@\x88\xf3\xafe\x83\x91\xa2\xe2{,\xd2^\u038b\x04\x05\x12\xc8\x1c\x81\xbf\xd6G\u007f\xe9m\xec]\xbe\x88G\x0f\x1e`t\xb8\x03\x9d\xcbc\xcbҶ\xc2\xc6j\x17\xbf\xd6\xef\xe1[/\xa5xz\x12\xe1\xc7GS\xdcٛcw\xa8\xcb\xc3\x1a5\bu\xd2\x06\xc8\xea\x8a\xfe\x9e#\x17-\xf3}_\xa1\xb3\xb6\x8e\xd5\xd5U\\]Y\xc5/\xb4\xbax]\xf9X\xcer\x1cqn\xf2Gl\a˸\xb4\xf52^\xbe|\x01\xbd^\aA\xe8e\x11?\xf0\xe0\xe79\xbf\x12\x91_\xe5k\x99\xc9\xd6\xce\x1b\x11\xa6\xea6S2\xd8\x10J'@\x9e\a\xe5\x03\x9e\x17\xe2\xe5p\x13\x1bk}<|\xb6\x83LJ\x8f1\x89\aU\xe4\xcc\x1d\x81\xdf\xc6K+/\xe3J\xff2\xfe~\xf4.\xee\x8e\x0f\xf0ӓg\xb8?z\x82\xa3db\xe8\xf0\x17!-\xdd\x00z\x17\xa1*#\xa5\nΡ\xb7\xf4\x126\xfa\x97\xf0Fg\x13\xdf\xf4\xbb\xb8D\x1eڥY\x92i\xf8k\xad\x15\xbc\xb2y\x1e\x17ϭ\xa0\xdd\x11h* \xf8\x81\x82\x17PY\xf6˸\x12\xca\xd8\u007fk\x89\xa7k\t\b\x13/\x8e\xfcd\xd6\xfcY4\x05\x19\xcbk\xf8\x05\xa4\x00N\x120M@q\\\xf5\xea\x96\x11^U\x10\x9fTC\x8a \x85;y\xc47\xfeB\xde\a\xcf\xf9\xac\xfd\xb2\x05*w\b\xa5@H\xa2\x02\x12\"\x85\xcc\xd0\r\xb2\xa4X\x89\xcdEg.\xc1\xd3\n\x1e3|/@x~\x1d\xebkK\xd8;\xba\x8c\xc7\x0f\x1fa|\xbc\afm\x18\x81Gh\xb7\x03\\k\x85x\xf5\xdc\x12&\xafh\xecN\"\xdc=\x89\xf0\xd9p\x86\x83\xc3\bG\x11#J\xd8\x10\x10\xa5\v\bBW>\xea\x01\xf0\x14!\xf0=\x84Km,-\xafb}i\t\xd7z\xcbx+\bq\x99|\xf4\x89r\x9d9Y\x85k\x02\x82\xb0\x8f\v\xe7\xae\xe0\xa5\xcb\x17\xd0_\xea\n\xc3W\xf0}/\x9bJ\xe3\x17z\xff\xa2,\x95\xc3~\x98K+Ȋ?e\x93\x8a\xe0\x05\xf2qaY\x87\xa8\xcaЀ\xe7q\x86\x04\x02\xc0\x0f\xdax\xabs\x05\x97\xcfo\xe0\xf1\xee\x1e\x1e\x1f>\xc64\x1e\x99я@\xca\xc7r{\r\xbf\xd0Z\xc5WW\xafb\x98Fx:=\xc2\xed\xf1!nM\x0ep4\xdeÀ\xe7\x88t\\+\x19\xa6\x8eT\x8b\x16\\__\xb5\x10\xa8%\xb4z\xe7\xb1\xda\xdd\xc4Fg\x03\xef\x84+x\xcdk\xe1\x1c\xf9蚃I\xa4S$\xac\xb4\xfax\xf5\xdc\x05\x9c\xdfXF\xb7\x13\xe4\xd1^e\xd77 xA&\xf8\xf1\xfcʱ\x96\xfb\x0f\x01kY\fp\xfa\xc0\xcf\xd3\xf4\xff\x15ڭV\x92\x9fU\x04\xfc\x9cJ@\x96\x0e \x89r\xc3\x13\xb8\xc66z\xeb\x969\a%\x9c3\xaa\xe6w;\xd7\xe7\xfcD\x17\x06\xafT\x99&\x94\x91\x8a\x85c`\xa1,\xa4J\x11Y\xb9[\xc1\xbe2\xf21\xae\n\x1eg\xba\xdd\xc0k\xa1\xd3>\x87͍\x15\xec\x1d\x1e\xe1铧\x18\x1d\xef\xe5\xcb7!\xd3\x03\xf2\x14z\xcaë\xad\x10\xaf\xac\x02\u007f;\x05f)\xe3x\x9e`o\xaeq\u007f\x1e\xe3x\x9e`0Kq\x12\xa7\x98%\xf9\x14+\xe6l\xb17\xe5\xe9\xb3\xf2@\x9e\a\xcf\v\xe0\xb7|\xf4\xc3\x10+\xad\x0e\xfa\xad\x10\x97\xc3\x16\xaex\x01V\x95\x87><\x04R`¶>\x8a\b\x9d\xd6\nΟ\xbb\x88˗\xceci\xa9S\x1a}P\x1a}n\xf8~\xe6\x00\xab\xc8\x04k\xae\x9c8_\xcaVְɱ\x14\xff\xe7rn \x141\x94\xa7r#`$>\xe0\xfb\x84 \xecbi\xe9\n\xae\x9c?\x87G;\xbb\xd8>\xde\xc1(\x1e\b\x01K\xc5\x13x!V\xbd\x10\xab\xc1\x12\xde^\xba\x82\x84S\x8ct\x8c\xe3x\x8a\x9dx\x8a\a\xf1\x18\xa3h\x8a\xe3h\x8a\x81\x8e\x11\xa7q>X9\xcd\xd6H\xe6\xcaeE\x01\x94\xf2\xa1\xfc6Za\a+A\x0f+\xfe\x12\xfaA\a\xd7\xfc\x1e\xb6\xc8NJ*\f\x9e\xac\xb5\"\x12\x06\x92\xc2jk\x19W76q\xe1\xdc2ڝ\x00\x81a\xf4ŵ\xcd\xc7}\x15z)\x92%?\xd4\x06w,\xee\xf6[\\\xebgWu\x00\xae\xbd\x83_\xb0\f謧\xc8f\xa0\x9cAcR\x80⌴+\xfeoq\x03D\x94M\x11R\xa5\xc4,{I\xe5L\x81\xaa\x8d8\x83\xb4\x95#\xa7³\xe5F_\xe6\xbb\xe5\xd4\f\xae\xfa\x11\x98\x8c\xde\xfa\xe2\"Q)@\xcaTZ\n*k\xe6f\x82_\xdc|\x85Ng\v[\x9bk8\x1e\x8e\xf0\xe4\xe96\x06G\xfb\x88\xa2\x89ch\x03\x88\xb2_Y\xf2\bKA\vWz\x84\xbf\xc1Y\x9b]\u0084\x98\x19\xa9&$\x9a\x91\x80\xf2%\xef\x04p\xd6\x14䑂O\n^>H҇\x82W\x18;+\a%$\x0f\xa6\xf2\xb1\xd4;\x87\x8b[\x17\xb0\xb5\xb9\x86n\xb7\x9d\x19\xbe\x9f\x1d\xce\xcc\xe8\xf3\x9bGP\xbe\xcag\xd4W\x9a\x1e\x12\x8b%\x84\xef\xac\x15\xd0\xc8ة\a\xa3~]\xbc\x9d\xe5\x16\x1f·_\xa6^\xd6`\xe4\x13\xbc$#\xc42G\xf0\x12\xaeN\xb7\xb0{x\x8c'\a;\x18̎\x10s\xe2\xe0\x1c@D\b\xc8Ú\n\xb1\xe6\xf7\xf0j\a\xf8efh\xce9\x17\xd6HYW\xe9V\xf1\uecc2\xca}\xbcO\x1e<\x10\x82\x1c9)\x0395\x18\v\x01\b\xbd\x00\x1b\xdd5\\=w\x0ek+]\xb4\xdb~\x19\xed\xbd\x9c\xd9/\x8c\xbe\xf8\\\x8e\xfc6\x16\x80\x10\xec\x01\x1f\xa6\xf4\xd7\xe6\\LQ\x0f\x8b\xcd\xc5v\x05\xc0\xd0\x05\x90\xa3\f\xf8\xa2\xe6\x01\x18g\x82u\xb6\xa57\xab\xc7\x19$]6IF\x95\xcdi\x9c\x9fff\xe1\f\n\xf8_Dpa\xe8\\\xd6\x03\xb8B\x06\xf9\xa0\x91\xf2T\x94\xbf\x83r\xb2p\xe1Oˋ-\x9ey\xa52.\x0e{\xa6\x01P\x949\x81\xac\x8d\x88\xe01\xc1g\x85\x945\x82@\xa1\xd3\t\xb0\xb1\xb1\x8c\xc9\xfc*\xf6\x0e\x8fqxp\x88\xd1\xe0\x10Q4E\xd9L#\x17oT\xe0S\x81\x10\x12!dUI\x1c$ eX\xc0\x87L@d\xb4J\x887\xd1S\x01:\xed\x15\xac\xadm\xe0\xfc\xd69,\xf7\xbbh\xb5|\xf8A\xb6R\xcb\xf7U9|\xd2\xf3U>\x802K\xb5\xb2\xfe\xfe\xba\xe1\x17\x13\x99Ȃ\xbc\\[gm\x1b\t\x97\x1d\x97\xc5\xe1\xf0\xbc\xacr\xa3\x94\x82R\x1a\xcaS\xd9Nv\x1f\xf0SB\x92h\x04!!l),-\xb5p\xe5\xc2:\x06\xa3)\xb6\x0f\x8e\xb0?:\xc2(\x1a \xe1\xd8\f<&kBD\xf0\b\xf0@h\xc1\x13\x0e\xcb*\xfc\xf1iR,\xb2\xbd9\x10\xaa\x10\xcb\xed%\x9c_^\xc3\xf9\xf5>z\xdd\x10A\xe8\xe5\x06\x9f\xe7\xf6\x96\xe1WN\xd5\x1a\xf9]\x96\xb3\xdd\x03@L)\xefi\u009e\x06M\x80\x8d\x0e\x88^,\x02\xb0I@m#\x00b\xb0R ]$\xe0\n\x9cf\x8d\xe4\xb5\xe8_\x846-\x8d\xda\xe1\f8\x8f\xfe\x05\xbcdSUȥ&0\xd7\x17\x94\xa2\x9ej\x94\x82\xbd\xb5E\xc9F#\xb1\xa2\xa9B\x03\xc8\xc2\x05\x18)g\xa1\"a\x85\x90\x15\xda-\x1f\xcb\xfd\x0e^\xba\xb2\x89\xc9,\xc2p<\xc1\xc1\xc1\x11F\xe3!f\xd3!\xd24B\xb1Г,\xc3.\x9d\xa64v\x16\x83\x92\xac\xe8n\xb8/\"(\xe5!\f{\xe8v\x97\xb1\xb6\xb6\x8a\xf5\xd5et{m\xb4Z\x99|\u05c8\xf2b\xf6\xbc\xf2s#,\xa3RՓn\x1f\x92j\xe4\x16ע`m\xf59\xccYtrYg1\xe1M\x15\xaf-\xafа\xceS\x02\xcd\xf0\x82l\x9fK\x92*\xa4\x89F\xd8R\xe8t\x03l\xac/a\x1e]\xc0x2\xc7\xd1p\x84\xbd\xc11\xc6\xf31\xa6\xc9\x04)\xa7ل$:\xa5\xca\xefh\x1fqA\xfaJ\x9bF\xf0\xc9G'\xe8`\xa5\xdd\xc3\xd6\xca2V\x96\xb2\xd6\xe8 ̯\xa90x\xcf+\x14}$\x1ck\x9e\xeb\x17ݬd)\xf8Ȅ\xec6\xb9ڨ\xf1\xa7*\xea\xd7Ѐ}\u007f:C\xf4~\x11:\x802\xc0\xe9l \b\xabL\x12\nΜ\x00H(\xf8\x8az\xbd]&\xf4\x94\xe5\xd02\xd0\xc6\xc2j\x8c\xfc\xbe\x1c%\x96\x9b}\xee\x18\n\xe7AFB\xcce\xa7P\xd9z\xec\xa0ݳ\xbc\xaeB\x03\x8a24P\xf4\"\x15h \x00#A\x86\bRVh\xc1C\xb7\x13`u\xa5\x8bK\x17\xd6\x11\xeb\x14\xf3(\xc1d6\xc3h2\xc5x:\xc1|>G\x14\xcf\x11%\x114\xa7\xd9\xcc?\xd2\xd52\xc9\xe2e*\xaaR$\xa52\xf2\xcc\x0f\x10\x86-\x84\xad6:\x9d\x16\x96\x96zXZ\xea\xa0\xd5\n\x11\xb6|\xf8\xbe\xca\"\xaaO\xd9\xe7\x1c\xd6W\xa3\xa6U9̃\xbc*2A\x91\xa9̮\xa9\xe8]*4˘\x9cN@\xfe>\x97\x99\x9c\x8c\xdc\xc4\x04V\x19&\xd7Zg\xc2DM\xf04C\xa7\x84T\xab|¯F\xab\xad\xd0\xeb\x85\xd8\xd8\xe8\xe1\xd5d\x13Q\x9c`\x16\xc5\x18Mf\x18N\xa7\x18\xcfg\x98\xc5\x11\xe6\xe9<\x9f\xa9\x98\x96\xd7U;\xa0o\xe6\xe7\xf2\x12\xb0R\bT\x80\x96\x1f\xa2\x13\x86\xe8\xb5[X\xeev\xd0\xeb\xb4\x10\x86\x1e\xc2\xd0˯'\xb9?\x1b\xe3\xbcŖ\x1f*\xae/[\xd3}\xcc\xe8]\xf7]\"\x82SCd\xa7St\x00̵\xe6\a\xb2\xcb~\xfc\x02\x1d@eg\x1a\xd0i\xfe\xa6\xcb\x1cGeON\xa92\xd2p\x9e\"\x94\xe5\xc2\xd2\xe0Ue\xf0\xc5\xf6\xa0V\x0f?\x9cz\nw\xf3\x8eM\xea\xa1!\xea\xd7$\xc1v\xfck\x92\xf3~\x91\x14\xa0\xd6\xc2Vt\x03\xe63\xc8Xe( \xbb \x04h.\r\xbf\xe0\t\xc0\x04\xf6\v\xa2\xafr\x04\xe0\xactX$\x9c$\x8b\xd9$\x81}\x15\xed\xb3\xc1\xa3\x82\xb9\xca1u\xc1\x13\x90@\x02%\xb7PF*9\x86Y\x90\x85\x05AY\x1ah\xf6\xb7u^\x84\xf0\x919\x81\xac\xe8\\l\xf9+\xc7R\x96\xdf7V\x98\x14\x0eF椥\x11\x92p\x04\x950\xaa\x82\xeb\x19:\xa02\xe2\xe4ƯD>\xafȺ\xa14x2f\xdcs\xed\xb0ԆH:\xe15[g\xc1\"A\x8d\xa1N\\\x1bniCn\xce'>3\x00\x95;z\x9d\x1b\xaf֜\xfd_g\x0e7\xfb?Ck\x95\xaf\xf0V\xe5:\xef\xecV\x98\x86\r\xa8\xeb\xe3\xbek\xe2T\x91\x12)\xe3\xeb\x82'\x11\xc3;\x94\x98OY4D\x12\x99\xfd\xfc\x8b\f_\xa0\x01n*\xf7\x11?w\xf9\xaf\xa9\xd4\x1f\xc7\xfa\xe73\x15\xd8PV\xa4i\xd6\v\xc0Y-+\xeb\xcc\xc9\xde(R*7$\r&\xaf\xac\xbb\x91R\x15\x83/\x99..\x8c2w\x12E\x92$\xa3\u007f^\x1d`\xb2\xb3}Y%\xe0Jxd\x1d\xda\xd2\xfa\x88\x8c\x01\x9d$\xbe\xe6\x00\x1a\xecy\xf9\x8c2\x95\xcd\rTU\xf4\xa7b\xd5\x0f\xcb\xcfU\xf47ˀ$J}\x95Ɨ\x05\xcdl\x94\x06\xf3\x94\xa1D\ne\xc5\xc0\x0egr\x8fOA>\xda\xc3Le\x19\x0e\xa6\xe8E\b\x1ee\x1d?\x1bQn\x1avM\xe0h\x18\xbd\xdb\x01T\xb3n\x1cĝ\xaa\x0e*\xdb[a\xed\xe7\a\vuXo\x1e9J~&d\x87c(%\xea\xec4\xdb\x02\"nN!\xc8QM0\xaa\x91l\xf6\t8i/I;RM\nm>o\xf9\xbeZ\x06[Ω\xa84\x10 4FyԐ\x92k\xf6\xbe\xc3\xc8iA\xa4?\xa5\xeb\xef\xac\x1f\xd2yΧ)\x9e\x1eO\xec\xbb\xec`\\n2\xfa\\\b\x80\xec\xb3a\a\x972v'I\xbe\nKeJ\xc0\x82\x18T\f.\xdb\xf42c/\x8c\x9e\xa1\xf2\xcf9\"(Ø\x12\x8b\x0e\xc8\\CƹҰD\v\xd5֡\xaaT\xc80\xa7\xab\x93\x15\x10Y\xbc\xa5T.,e)\x8a\x11\a\x8ejQ$/s*\x98\xe5=\x11\xe5ݎ@\xfe\x9fk\xf7\xab\x8c\x1dfg\x0eY\xf0\xb9\xa1\xfe-E3\xf6\xf2\x11\xb3\xe3\xcc\x11\xc1%J`\U000fe56fe\xa7QK\xc6\xdfT\xb3ق\";\xfa\xb1\xbb\x82`;a\xf1\xfc\xb91\x15!\xf3\xe7\x8b\xe62\xd9\x13yȺF\xce\xca\a\x9b\x8e\x89\xdcU\x14\xd7|\u007fv\xee쫳\xfeM%\xd8EU\xbd\xe2\xe7\x87\a3lO#\xf9\v)\"|\x0f\x1f\xbc\x00)\xf0i\x82\xaa\x12\xca\xe9ld8L\x82>\xac\xf05\x97\x11\\\xce\xcc\x03Ȋ\x16f.M\"ݨ\x13{\xd6\x0ew\"\xb1\xec\x93E$璐\xe2\x066\x9e\xa9\xbeF\xcc\r\xd5\x1d\xc2\"\xe39s\xad\xb4Ghx\x9c&C\x82\xbb$X\xd6\xfa\x1c\xea\xc1z۫tfl\xa4bl\x13\x8d\xb2\x86N6\x81\xe9Ε\xc9\xc9\a\xa0y\x90\xd8\x02hߜJq3\xe4wDz\xb2B\x8f\xbb\xa1\xe7\xec\xc6^\x9b\x1fnj\xbbw\a\x18ick\xf0\x18\x1e~\xfaB\xab\x00N\xa3\x979P\x91\xb3\xa5I.\x02R\x80\xf6rV\x9f\x01\xad2\xe5 sn\xec\\\x1ay\xad\x1a\x80\xac\xa4H\x9e)\x19.J@$\x19:\x90\x18\x14R\xb5\b\xb3\xac\x12T\x05\xc5\xea\u007fD\xb5\xc1\xa9\f\xd9R\xc0e\xdb1l\x99\xae\xf0!ܔ\"5I{mD`\xa1W&\x9b@\xa3\x1a\xacw\x1e\x96\x85\x87h\xc1\xc1\x96'K5\xaf\x97j\x8e\xc4.c\xaf\x97\xca\xea?c'O\xe0B\v\x125\x98\x80\xcc\xedx\xea,\xbd\x03\x82\x93{\x96\x1e\xe34\xc7\xe0\xde\xd6S\xdf`\xc8\x0e\x87ȧd\xf8\xa7\xab\xf9\xec\xf7x:Iq\xfd\xc1\xb1I\x00k<\xc4\x1c\x8f^\x88\x03p\xe9Bl' \x82\xa8`ݳM\xc2`\x0f\xcc\x19\x12 V9\xf4WY\xfdGeN\x80\x05\" !\x9eg\xd9,$\xfaU\xcd2 `\xf4\x1e\x94\xedsl,\"A\x8d\x16\x94\xe2a\xaa\x97ZXF\x14\x12\xb0Z`\xeeҸ\xc9 \x9f\x98\xea\xd1OF-2\x92\x11\x91e\x939͙\xc5\xc6\x17\x03\xd6\xcb%`\x8d,4բ}\xad\xd7_B\xfe\x1aW`\xa5\x16\xb5}\x86u\x82\xd0pd6YV\x93\x16;\xc42\xc4\v5\t\xb2\xdaP\xbd\x16\xae\r/\xb1\r\x97\x9d\xe8\xc0e\xe0\xd4\xc0\xd47A}\a\xdaXt\xbfZ\xe9\x0fg\x82\xfe\xe4\x1c\xf0\x9f=\xceγ)n\x1e\x8d\xcc\x1f\xa5\xf8C\x8c1\xfa\xc2J@7\xf4\xa0\x1a\xe3[?\xecB\u007f\xcfiV5\xf0r\xdd@\xee\x04\xf2}߹\xa3P\xa8\x86}\xabr\xb0\x87\xd1\x14T~\xadʼ\xbd\x8a\xfe2Y\xad\x889\x92-\xc3 \xb3\x1ePt3\x1a=\x04dUY-cg\xaa4\t.%r\x19ըܞT\xc97\xabR_\xe3h(\x96\a\xc7*\xbc+w\x18\xa81\xeaΒ\x93\b\xba\x84\xc6zr#y\xe7<||z\xd3\r\xb3\x9bY\x97=\b\xe4(\x19\x1a\x15\rGǜ\xe1\xd8\xd8\xed\x00\xa9\xaeap\x1a7\x91\xb3\x9a\xe12bnPF\xdaeN\xf7l\u007fv^#\xaa\xbd\vu.\xa4\xc9\x0eg\xb3\x14\u007f\xf1\xfe6\x86\xda h\a\xd0\xf8}\xfc\xc9\xe9\x10\xe3\xf9u\x00\xe2\t\xb3\x95\xe7\x19\xa9\x80\xe8>+\xa3\x18'y\x84\xf7\xaa\x01\x06\x9c\xed\xf7\xcb`\xbdΣ~A\x16V\xc5x\xb2\xf0H\xa1\b,\xf9\x01\x81\x9fIP\xe1\\\xea{\xa9\x1c\xefR\x89\x8bH\xf4\x19\xb0\x95\xfb\xb3\xb9\xc2LD\x9bҸ\x8bǓ\x06\xcb֡a;U\x10\x04$SUUp:\xd2*e)\xe5\xd1DN\x18.ݗ\xf3\xf1\xe8\x8c\xe9\x80\xc5\xf4\xbb\xf3@^\xfcx\xb0P\x87cŅM\xfe\xd5\f\x85\x9b#\xbcm\xe4\xce\xc6\x18j\x80\xefN\xfd\x03\xbba\xbe\xc3\xd8e\x1cf:=\xe27:\xd7\x06l\xbfp\xa0\x8f吙\x81\xeb\x9f\x1c\xe1\a\x8f\x0e\xed\xb7\xe7}\xc4\xf8\xe4,\xc1\xfdLR\xe0\xe2C\xd5RGk\x05\xb6\xf4XJ\xbc`%E\x18\f\xe6\xb4L\r\xa8\xd8jZ\xa2\x02\x16P\x9fE\xee\xaf*\xa3\xcd\x195\xa6\xbc\x8aP,\x0fɵ\a\x92\xaf5\xaa\x02$چI8\x03\xb2\xfb\b\xcd\xff\vW\xd0\xc0\xac\x93\xb3\xfce\x80\xc9|\x9aq\xd5܄R\xc0\x9d\xcd\U00063188\xcb\x16\xacv0\xf9l>\x8fZz\xe0`\xb9k\x8e\x81씠\xa1\xee\xef\x84\xfc\r\x19-\x998\x8a\x1b\xcbg\xcd_\x97i\x03/v:$\xf3\xefS\xb8\x80F\x0e\x01\x8e\xd4b\x011h:\x83\x05\xd3}\x88ܼ͂\xf2\xdaY\b\xc1\xbd\xdd)\xbe\xf3W\x8f\x11\x99N{\x86\x04\xff\x1d\xeec\xf2\x85\x1d\x00\xe0\u07b9\xe4B\x04\xc6\xd7b\x1a\x1b)\x93ܢb\xde\x1fe\vxY\xb0\xfd\x94;\x05\xe8B\x16\\\x9c\xf2\xac\xc1\x88K\xf1P\x05\xad\tbM9\xb1\x85\x14\x84 HHO\x19d\xb0x\xd5\xd2R\x16\x15\x05r\xe6\xfe\xa5Ȉ\xac\x18]\xf4\x13XG\xc36\xb4\x12\xae\xb3\xdd\xff\xcf\x02M\x88z\xfe\xa2Z\xb73\xf7\x17m\xa7\\\xa9\xe0\x98QW\xfb\x11\xdc\xfa\xfe\x9a!qs\xe9\xd02\b^\x18I\x9a\x10)\x1b#\xc7\xd8\x11\xb5\xa5\xb1\xd6R\x03\a\xd47\xb9\x06\xeb\xb9ӂ\xd2\x1d\x9d\xa5\"\xc0N\x94P\x9b\xe6C\xd4hT\xf6\xdb\xc8g\xac\xf7\x17\x1f\xe3Q\x82\xff\xe7ۏ\xf0\xe9pj\xfe@㻘\xe1\a\xf8\xf1٪{ϯ\x04\xa4z\xee\xc2v\x8dTD\xfc2\xb5\x97B\x16\x98\x88\xa0\x18\xf1V\xa6\x02R\x04\x94\x93\x83U\x89PUs\x00XUNŨ\x06\x88\xbd\x85\xc6`\x12.u\xa8\xd5\xf0\x90\xdc\xf4J\xa1\x91L\x05D\r!\xcf\xfd˸^\xe4\xf3\"\u05f5I>6\xf8\x00+MP\xb6\xc4\x1a%:\x91Sy\\\xf9\xbaٚKf\xef\x13\x04a\xa8\xeah\xa11E\x00\x16\xe4\xd1\xec\x98\x15\b\xa7$\xb8\xb9tXg\xf9+\xe4µ\\\xd7]ʳ\x1b\x8e܂#\x17\x9f\xb0\xb8\"P\x87\xfbM\xbcJSE\xc0`\x8c\xe8\x94E]g(\xe1.\xe2\xe1f\xd3\x14\u007f\xf6\xe7O\xf0\xdd'\a\xe6}5\xf6\x90\xe0\xbf\xc1\x9d\xb3E\xffS\x1d\x80jB\x00\xb2\xe4gA]ِR\x88bH\n`\x94\xc1\xd5Y\xa2\x89\x8c,d\x8fr݀\xce\t?.\xc9?.\xc5DTv\xfe\x95Ρ\xc8\xfb\xc5$\xa2R\xdf\x0fk\xb0H\xc9\x1d\xb0\xa04\xc9Hm\x8c\x8c\x9dH\x969\x04\x11J\x0emvѐ\x92G^e\x86ߺQ\vu\xa0\xfds\xa3\x9a@\x8e\xfa=\x1bZ\x046u1\xb5)CΒ>\xd5\t\xc8&\xe2o\xa1\xe3\x10L\xbb\xbb\xfe/%\xc1\x96\xc6\xc1y\x15\xd9%?u\x10\x8aV>\xde\xc0\x05\x98\u007f\xbb\x01\xae\x1b\x8e\x86P[\xe1\xd5\xd4J\x8dzttL4Z\x18e\xed\xb7\xc1u}\xe7\xd3\x14\u007f\xfegO\xf1\x87\x9f>\xcbD\xfe\xd5c\xc6\xd0\xf8m\f\xf1\x13\xfc\fx!\x0e\x00p\xac\a\xb7N@\xcd$\x84(\x86\xacQWv)ʐ\x92\n!MfRI\x0e\x1f\x8a~;\x95\xcf\x06,\xfa\ad\xb9\xcf\x14\x05\x016i(\x9d\x02\xcaށB\a\xc0\xc6\xdc\x00\x94\xa5Gb.\xd1F\xa9b$\x98(@\xcc\x11\x80\xe5R\xc0\x10\rHl\x14\u007f\x1a\xc9>\xfb\xe7lC\xcf\x05\xa7\xe8\x94\x1f\xdbFꂣ\xdc\x00S\x9d*@n\x12$qm\x03|\x95\xf7H\xe4wZz\xc0\x8ee\xd1|\nLf\xb7Ӳ\xd4|ur\xae\x89շ\xcaw\xec\xba\x1e\xd4\x1c\xb9\x1b[\xb1\x17 %QI\x93\xbf7\x1a\xc6\xf8\xd3?}\x82\xff\xfb\xb3g\x983\x9bO4\xc1\x9f`\x86\xdf\xc6\x1f,n\xfe\xf9\\)\x80\xf9\\\xc9-\x04*P\x80\xe8hc\xb1\xcb\xd50ve9\x01E\ruj\x9d\xf3\x02y\xf4gU\x91ze߀\x18.R\x13\x06)\x93'p4\n\x95\xa8\x81\\\xd1_\xbe\xe6\x8a\xf9\x97\x1b\x8e\r\x82\xd0E\x16\x12٢c\xbb\xaa\xed>\xd8eُ\x9c\a\xbc\x98\xb6S\x87\xbd\x96.\xff\xb4<\x1f\rd\x9f\v\x19\xb8X\xef\xda\xd0\bv\x1b\xab\xab\\\x064.Ŕ\xe54\xf7\xfd\xc8\rÝ\xa9\xc1Y\x04=\xae2l\xb3^\xa0\x12\x83\x91;\x1dZ\x04\xe5iA\xa4w\xf0\x06Z3vw\xa6\xf8\xa3o?\xc4\xf7\x9e\x1eBۏ\xad\xf1WH\xf1\x9f\xe3w1\xc0s~\x9c\xb9\n\xe0\x92S\x97\xb6(=\x16\x19\xa5\xfb\xca\xd8%\xfc\x97H\x01TC\x02R\xa3]E\xcf4\xefȯ\x1e\x88\nlRH\x89\x8d\xe8/҅\x1a\xbc\x17\u0380\xe5\xccB\x88\xa6#6L\xcft\x1e\\\x11\x89\xa2DWk\x98\x97\x18\xd0\xce\xdb\x17\xa1\x02.\v\x1a\x82]&\xeb\xe7\f\xbb\xfa(\xb9\x05v\x8d\xf6\xb6\x14]\v\xd7\xc8\xd1\xd9\"\xec\"\xa9/\x1aS\x01\xae\xe9'\xaa\xc1\"p\xe6\xed\xf5r\xe6\x02\xb2\xae\u058b\xb0\x00m\x90\xd8;-S\x04p\xe34$\xe9\xd8k\xa9\x15\x9d^\xc6sEz'\xfea`6M\xf0\xb3\x9f\x1d\xe0;?~\x8c[\xe3\xb9\xcba}\x84\x18\xbf\x85;x\x80\xcf\xf1\xf1\xdc3\x01]u\xde2\x150\x06\\X0\xdfj\x86!1\x15G6\xb7\xd8\xd3p\v\x9d\xbc\xac)\x83S\x14j\xc3\"ٕ\xb3\xb4\xb3\xf2\xa0\x16m\xc4\n\xf6\xe4a\x99&\x98\xa9@\x95L\xb3\xf0H\x86N@\xb0\x98D\xb6\xab\x10\a_@ÚL\xd6VS\xb0\xf5\xfa\x99,\xa6\xbe\xc2\x10\xec*\xc94}\xcd\r_/\x10{4\xa3\x06W\x8f\x00\x9fR\xdebw\x8aa\x19\xf7\xe2\xa2\x177\x13\x90\xb4X\x9b`Ⱥ\xf9,%B\xae#)r\xe1\xfa\xc5\x06NMDi\xc3\xe3\xc8ז\xa6\x8c\xc98ƃ\xfb#\xfc\xe5\a;\xf8\xe1\xf6\x11\xd2\xfa{\xc7\xd0\xf8!b\xfc\xa7\xf8\x17\xb8\x89\xcf\xf9\xe1?\xef/Ђ\xb3Uc\xff]\xcd+\x12\x12\x93s\xa7G=\x1d\xb0\xf9\x84\xf2`\xa5%]ɂ#ȮMU\xf2㢊 &\x0fW\xf3\a\t\xd0J\x14\x1d\xb2\xef\xb3\x05CXx\xb4rX\x85\xae*\x01l%\xabE\x19\x8e\xad\x13\xcb\xce\n\xba\xfc}\x8buf\xf1\xba\xe5Z4\x87b\x84\x1b)\xbb\xc5\xdfg\x1b\xe6sC\xbeʧ+\u061d\xf7 QM\xb4$\xc7&R\x82!\xc3.\x1b\xab\\NL\xae\x84\xa8\x91Q\\Cge\v7s=בЪ\xa1L®\x91\xceM\xb5p\xeb\xfd\xe1E9\x00\x18iʈ#\x8d\xe94\xc1ӧ\x13ܹw\x82\x1bO\x8eqs4C\xec\x1a\xdb\x06D\x88\xf1GH\xf0_\xe0\xd6\xe9z\xff\x17\x82\x00\\o\xbc\xf4rT8\x00\xe5\x88\xf8\x90\x04\x9f\x15\xe1\x1d\xf0\x9f-\xa7\xe1\xd2ԛ\b<\xeb9(\x8cw0e|\xba7\xc1\xf1,-\x056\x9c\x0f'e\xe3k\xf1\xb3rx\x879\xf0\x03\xe5\xcfP\xfb\xbf\\e^\x9f\xfaC\xb5\xa5G\x10\u007f\xc3u_\xc0u\u007f+\xdaY\u007f\vv\x05\xa0i\xd7\x00\x1c\x8fې\xc7;\u007f&\x86\x9a\xba\xfe6\xec(\xdf0\xae\x1b\xc4\xee\xc7p\xe6\xeb\xd6\xe35\x96\xd3\x16\x8d\rw\xf4\x02\x10\xb9\xab\n\r\u007f\x87O)\xe15\nz\xa8\x19\x1e0\x03I\xaa1\x9e$\x18N\"\x1c\x8f#<\x1eMp\x94jD̋<\xec\x13D\xf8\x1f1\xc3\xff\x8c\u007fu\xba\xd6\xff\x85\xe9\x00`\x95\xad$\xd5T\x13\xffذ^\xc2}\xfb\xb3Ŕ\x9a\u0381\x8c\x03@\xce\xfbT\x8e`\x1a\xa7\xf8\xd9\xf6\x18\u007fuw\x88\xed\xed\x18\x9a\xeb+d]+e\xed\x9f\xd9;\xbd\xf5\x82\xfb\xbb\xb9bT\v@\x8a)h^U[-\xf8\x90b7*<\xd4\xe6\aH\x02\x95\x95Y\x97eT3U\xe4\x180\xb6\xd2,\xfb\xff\xe5\xfd`>~\xf9\xbbr\x1b\x91\xaaol3\xee\x0f\xf3o\x17\xdfק9 \xf9\xdc\xec\x03\xa6\x1c\xc6&g*\xca\xfa\xb4\xcb\xe18\x1c\a\x9d\xb6$\x84\xc4F\xbd\x86^\v\xa6\xcf\xe1\x00\x9egA\xc7\xd9\xf6\xf8\x8d\x90\xe2\x8f\x11\xe1\x9fc\x1f\x9f\xe2\x8f\x16\xcf\xfa{a$ 5\xd6}My\x8b\x13\xfe\x13-\x8e\xf0p\xf7\xa4\x93c:\x8f]N\x94o\xbe\x06\xf0t\x10\xe1On\x1e\xe1\xf6\x83\x19\xd2\x14\x8d<;-\x80ĢAٸ\xbaM\x8fAp\xa3\xc12\xb0(\a\xa4E=\xd5q3\xed\x8e?\xc2\xd5A=m\t\xec\"\xc1\x0f9\x88*\xa3fMƚ\x05\xa7j\xb0q\xa0H\x93q۵{nF'\v+\x16gnV\xb2\x85E\xcd|I\xe3s\x86\xfb\xb5/4j\xc2\xe9\x93yϨ\vȣ\xec>4\xbe\x87\x18\xff\x03\xc6\xf81\xfe\x0f\xcc\xf1\x02?\x9e\x8b\x03\xa0\x86\x94`!\xc1\xe7\xe8\xa3o\xe4\x06\\\x86N\x8b\x95k\xe3X\xe3GO\x86\xf8\xe1\x8d\x01\x86C\x8d&\xdd\x05/(\xba\xd9:\x87E\x8eb\x91$z\x11\x01\xe4tt\x82\xed\xb5\x89S\x99\x9b\x93\vzs\xbddG\xae\xd7Eh \"O?\xa4\xb5t\xed\ful\x9b\xa8#8\x9e\xfb\xa2\xf2$;\x9c\xa2\xc3)7V)\x1a\xa2\xa9\xe1\x8c\x1d\x06\x0e4#\t\xe7s\xfe\x82\x87\x9f\"\xc1}\xa4\xd8\xc5c\xcc\xf1=\xfc\\?Nu\x00\xca\xe1\x04LTZ\x8d\xb4Z(\xfe\x81\xdb\t@\b)\\\x86O\x0e\xe2\xead\x96\xe2\xfb\x0fO\xf0\x93\xdb#Lg\xec\x8a\xe4\x91\x06\xbe\x97\x00\xff\xd5S\xe0ô\xc1P\xb5\xf5\u007f\xd7}\\ƿ\xe8\xf7\xec;\xb1\xd3͟\x8d\x9d_X\x18\xb3\"(\x8bwR+Ө\x85A:#\x91\xcey\b\xa9Xfϊv\xcaz.V\xee\xef\x12%A\x89\xd7j\x19\x1d\xd3)FI\r\a/`\xbe0\x00\x00\x05>IDAT\xd1\xe5l\\\xbf\u007f\xd6|]\x9d\xf2<\xe0\xe6*΄\xa2p\x86\xd7\xc1\x00\"hD\xd0gm\xe0\xf9\xff\xcc\x01(4\xe7X\x86\x13PVu\xc41\f\x93Ȇ\x93T3t&w-\xb5\xf8\x1ck\xc6\xcd\xc3\x19\xfe\xed\xcdCl\xef&NX\xcf\xc0\xfd9\xf0\xdf&\xc0\xff\xf6]`\x88\xff\xbf~\xd4\xd6\xc2\xe0ˏ/?^<\x02X\xe4h\xed9wu#w \x00\xa9\x9d'w\xceh\xb3\xb8)\x80\x83i\x82?\xbb\u007f\x8c\x8f\xeeN\x90$\xceiD\xd3\x14\xf8\xd7\x11\xf0\xcfw\x80\x9b\x9f<\xcf|\xe5/?\xbe\xfc\xf8\xd2\x01\x9cFH6\xa4G6\xa1'\xe7\xe7\xcbyy\xc5\xe4\x1d\x03\xfe\xdb\x030\xebL\xf3$\xd1\xf8po\x82\xef\xdf9\xc6\xe1Q\xeaJ\xb58\x05\xaeG\xc0\u007f=\x02\xfe\xcd\x0f\x80ٗo\xeb\x97\x1f_~\xbc\x00\ap\xfaD \x87\xd6\x1fuƻ\x88\xfc\xe6\xff\x1d,\xac@\x05\x1a\xc0\xb3Q\x8c\u007f{\xef\b\xb7\x1eM\x91h\xb8\xa2\xfeI\f\xfc\x8b\x18\xf8\xef\x0f\x80\x87?\xfe\xf2\xfd\xfc\xf2\xe3ˏ\x17\x8f\x00\f\x1e\xc0b4kZ\u007fUM\xfe\xb1\xb5\xfeM\xf5|[\xf17\x8a5\xfezw\x84\xbf\xbcs\x82\xd1X\xd7\xf8\x00\x00:\x05~\x12\x01\xff\xe5\b\xf8\xe1\x9f\u007f\x99\x01\u007f\xf9\xf1\xe5\xc7Ϗ\x03\xb0\xbf6\xe0;\xd95Vr\xb3\xfdX\\\xe6#\"Ĭ\xf1p\x18\xe1;w\x8f\xf0p{^c\xcbs'\xb0\x17\x01\xbf\x1d\x01\xff\xd3M`\xef\xee\x97\xef\xe1\x97\x1f_~\xfc\xfc9\x00\xb3)\xb5\x8a\xfe%\x17 \xe7\x004m\xb1Y\xa0(;\x8e\x12|\xff\xc9\t>|8\xc2t^\xef\xfe\" N\x80\xff\xb7\xbd{k\x8d\xab\x8a\x028\xfe\x9f諈\xdf\xc0o\xe1'\xabUB\x051>\b}\x11\x04\x11|\x91\"\x98B\xc1\x96\n\x15\xadm\f\x86`j/!5ը1\x9d4m\x9ad&\x93\xcc\xe5\\\xf7\xf1!\x89=\x99s\xa2>T\x93\x89\xff\x1f\fü\x9e\xcdY{\xf6e\xad5\x95\xc0\xd9U\xb8{\x9b\xe7s\x15R2\x00\xfc\x85\xb1\xda \xb0\xffb\x8eQ\xbd\xeb\xcf\xd0\xdd\xfe\x9a\xdf\xe5\u007f\x01I(\xf8\xa9\x1d1\xb5\xd2f}+\xad\xcdr\r\xd0L\xe1\xdd\x1e|\xf6+t\x96\x1c7\xe9\xdf\x0f\x00\xe5\x1c\x94\xc3%\xc1\x1a\xcf\xfaڽP\x9f\xe0C\xe9E/*\x8d!\xf6J{lD\x19S\xab\xdb,>\xea\x93\xe6\xb5\xf5\xe6\xa2\x1c\xaeF0\xfe\x04\x96f=ړ\xfe\xfb%@\xdd^@\xf9H\xaf\xb6\xd9d\xe9(px\xc90\xc8\x03\xf3\xed\x1e3\x0f;\xb4w\xb3ڣ\xbd\x02\x96R\x18o\xc1\x17_\xc1\xc0\xa1\x92\x8e!\x004\x0e\x970x\xf6=6\xb4\xbb_\xce߯\xc9\xe3>\xb8\xd0\xf3\xb8\x9f\xf2\xcdj\x8b\xe5\xa7\x11Y\xa8\x06\x98\x00;\x19LF0q\x1f\x1e>p\x8c\xa4\xe3\t\x00G\xa5\xbdR~\xf1\xa9V\xfd\xad\xe4\x024\xa0\x9b\x05nmu\x99[\xedЋ\u009f\xb5{\xcaK\xfd\x1c\xee%pv\x17\xa6\xaeB\xe2\xf0H\xc7\xff\x0f\xa0\xf2{\xf8\x18\xb0\x92\xf8S\xba\u0557\x17\xd0\xec\xc5\xdcXk\xd3ܪ?\xda\v\xb0\x19\xc3G1\xbc\xbf\b\x1b\v\x8e\x8btr\x02@%\xef}\xa8\x12\xcdQ7\xffvҌ\xef6w\x98\u007f\xdc%ʪ\x17z\nHs\x98\x8d\xe1\xcc\n\xccM{\xb4'\x9d\xfc%@c8\xb5\x93\xc3I\xb8\rO\xee\xf9\xac\xa5\xd1\n\x00u\x85O\xbb!\xe7z\xbb\xcdB\xb7K\x14B\xdd^A\x9a\xc1L\f\xaf/íkn\xf2I\xa3\xbd\aP\xde\xc5\xff\xa1\xd3!)\x8aڂ\x9c\x01\xd6\"x\xaf\v\x17\xe6\xa1m\x85\x1e\xe9\x14\xed\x01\x8c\x01iQ\xed\xed^@\x9c×\x03x\xb3\t\x0f\xae8\xebK\xa3\x1f\x00\xca5\x00\x8f\xe8*S\x04X\x8e\xe1\xdc&|~\x01\xfa>R\xe9\x14.\x01\x86[\xd7\x05\xe8fp\xa9\x0fo\xcf\xc2\xf2\x9c\xcfR:\x95\x01 \x19\xaa\x06Td\xb0\x10\xc1\x1b\x1d\xb8\xfe1ϷY\xa1\xa4\x93\x13\x00\x06/\xc2e\xe0\xd5\x06\xbc\x12\xa05\x80O\ap\xfe\x0e\xacO\xfb\xfc\xa4\x91\xf6\xb7]\xc9'\xe0\xe5\x00\xaf\x05x)\x82\x1f\x17\xe1\xe7\xcb{W\x01$\xfd\x1f\xbc\x03\x8d\xf1\u007f\x10,$I\x92$I\x92$I\x92$I\x92$I\x92$I\x92$I\x92$I\x92$I\x92$I\x92$I\x92$I\x92$I\x92$I\x92$I\x92$I\x92$I\x92\xa4\xd1\xf7\a\xf9\x00\xfc\xe1(q\xe3\xd5\x00\x00\x00\x00IEND\xaeB`\x82") diff --git a/icons/cchat_variant2_256.go b/icons/cchat_variant2_256.go deleted file mode 100644 index 71fdf0a..0000000 --- a/icons/cchat_variant2_256.go +++ /dev/null @@ -1,6 +0,0 @@ -// Code generated by file2byteslice. DO NOT EDIT. -// (gofmt is fine after generating) - -package icons - -var __cchat_variant2_256 = []byte("\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x01\x00\x00\x00\x01\x00\x10\x06\x00\x00\x00\f\xe2t%\x00\x00\x00\x06bKGD\x00\x83\x00\xe5\x008\x88.\xdb\xe8\x00\x00\x00\tpHYs\x00\x00\r\xd7\x00\x00\r\xd7\x01B(\x9bx\x00\x00 \x00IDATx\xda\xec\xbdד\x1b\u05f6\x1e\xde茜\xc3$`2g\xc8a\x1a\x91\x14)J\xa2¡\xa4\x13t\xee\t\xe5\xb2\xfd\xe0*\xdf\x17\x97\xab\\\xfek\\~\xf1\x83}\xfd\xe0s\xef\xad\xfa\xdd{\xeeI\xbaʢtD\x91\x14È\x1c\xcep\xf2\f&\x0frl\xa4F\xe3\xf7\xb0\xbd\xdd\xc0\x066\xba\x1b\xc0\f)\xa9W\x15\xd5B\x0fB\x87\xd5\xeb\xfbV\xd8k\x19\x9cN\xa7\xd3\xe9$t\xd1E\x17]t\xd1E\x97\x1f\x91\x90\xfa%\xd0E\x17]t\xd1E\x17\x9d\x00袋.\xba袋.:\x01\xd0E\x17]t\xd1E\x17]t\x02\xa0\x8b.\xba袋.\xba\xe8\x04@\x17]t\xd1E\x17]t\xd1\t\x80.\xba袋.\xba\xe8\xa2\x13\x00]t\xd1E\x17]t\xd1E'\x00\xba袋.\xba袋N\x00t\xd1E\x17]t\xd1E\x17\x9d\x00袋.\xba袋.:\x01\xd0E\x17]t\xd1E\x17]t\x02\xa0\x8b.\xba袋.\xba\xe8\x04@\x17]t\xd1E\x17]t\xd1\t\x80.\xba袋.\xba\xe8\xa2\x13\x00]t\xd1E\x17]t\xd1E'\x00\xba袋.\xba袋N\x00t\xd1E\x17]t\xd1E\x17\x9d\x00袋.\xba袋N\x00t\xd1E\x17]t\xd1E\x97\x1f\x87\xd0?\xb6\x13fY\x96eY\x82\xa8T*\x95J\x85 j\xb5Z\xadV\xeb\xfc\xfb\f\x06\x83\xc1`\xd0\x15I\x17]t\xd1\xe5y\x89V;\x8e\xdam\x86a\x18\x86!\x88r\xb9\\.\x97u\x02\xf0\x83\x11x\xa3\xa1\x82\x80\x1b\xdc;\xc8\xee\x96@袋.\xba\xe8\xf2|\tC#\xf0\xd7j(n\xfcP\xe5\a\x97\x02@\x99\x1d\xb8\x81p\x8f\xee\xab뢋.\xba\xe8\xd2\x1eE\x1aq\xe3\x87\x1b\xe9\xfd\xc1E\x00\xd0\x1b\xa7\x8b.\xba袋.\xdd\x13\x02\x19et\x02\xf0\x9c\x85$I\x92$\tB\x92$I\x92\xe4\x1b\xf5CU@\xfd!\xd4E\x17]\xbe\xafn\xd9\x0f\xd3\x1e\xd7j\xadqH'\x00\xc7.\xe0\x82?o`ԁY\x17]t\xd1\xe5Ű\x93'M4\f\x86F\xe0\xff\xfe\x11\x1dZW\xa8\x93\xf8~\xadߧ\x13\v]t\xd1E\x8f\x04h\xfb\x9cZ\xbby\\@-G\x06t\x02Х\x1co\x88\xbf\xd3\xef\xc1}N\ax]t\xd1E\x97\xe3\x01h\xdc甀\x16\xf7w\xa5\xe3\xe8\x16\xc0\xbf?)\x02\xfa\xc5S\x11Pm\xd9\xdb\x10\xbf\xda\xef\xd1\n\xf0:\xf0뢋.\xba<\x1fO\x1a\xb5\xa78\xe2\x80\xfb\x1e\xb5\x04\xa1SB \xa7\b\x00\xae\xd5j/ڲB\xfaŹ\xe5\xf5\xeb.\xbb\x05J\xa5ϣ\u007f?.\xe0\xd7\t\x82.\xba\xe8\xa2Kg\x80\xaa\x15\x88q\x80\xafv\xff\xf1\x11\x02\x88k/\x1a\x11\xa0_\x1c\x95\xe8\x06\xf8\xbb\x05|\xb5@\xdf)!8\xae\xf3\xd2E\x17]t\xf9\xbe\x01\xbfV\xbb\x86\xfb\\\xaf!\x14G\x14\x94R\x12ꏣ\x11\xe7\x9e?\x05xA\b\xc0q\xe7\xe4\x95\x1a\x01=/\x82p\\\x91\x04]t\xd1E\x97\uf2e7\xaf\xf4~\xb5\xfb\x95\x88\x82\xd6Ԃ\xda\xdf\xed\x14П?\x11x\xce\x04\xa0\xd7!r\x14\xe8\xb5\x02{\xa7\xaf\xbb\xfd\x1e\x1d\xf8u\xd1E\x97\x1f;\x11\xd0\n\xf4\xe8k%B\xa0\xf6\xf5IG\x06\x9e\x1f\x11xN\x04\xa0W\xc0\xdf+\xc0W\xda\xdfkb\xa1\x95\xd0袋.\xba\xe8\x04@\x1d\x01P\xfb\xf7n\x81W\xa9\x86@\xeb\xf7\x9f<\x118a\x02p\xd2\xc0\xdf)\xb0k\xfd\xfe\xe3&\x04:\x11\xd0E\x17]~h\x04\xa0[\xc0\xef\x96\x00\xc0\x85yj\x8b\x01;=\xdf\x17\x97\b\x9c\x10\x01\xe8\x16\xf8;\x05\\\xad[\x92\xec-a\xd0S\x01\xba袋N\x00z\xeb\xf9\xf7j\x8b\x03~%B\xa15\"\xd0i\xc4\xe1\xf8\x89\xc01\x13\x80^\xad\xbf\xef\xb5G\x0f\x81\xfe\xb8ޯ\xd7\x06袋.:\xe0\x1f\x8f\xe7\xafu\v=\xfd\xe3z?z|J\x8d\x8bz\xb5\xbc\xf1\x85%\x00\xc7\x05\xfcZ\t\x00\n\xdc8 ǽ\xafWD\x01w\xbcj\xaf\x97\x0e\xf8\xba\xe8\xa2\xcb\x0f\x8d\x10(\xedW\x02\xdaN\x81\x1d\xfd\x1c\xfa\x1a\xda[\xdc\xfbz}=z\xb5:\xe1\xb9\x13\x80^5\xf0\xd1J\x00\x94\x80^\t\xe0\xd5\x12\x00\xb5\x84\xa2W\x04@\x8f\b袋.\xdfWO\xbf[\xcf_k._\xe95\xb4\u05f8\xbf\xa3[\x94\b\xf4\x9a\x18\xf4\xaa\xf8\xf09\x10\x80\xee:\xf7\xf5\xba8O+`S\x946b\xa0\x14\x11\xd0\x1a)P\"\x04:\xc0뢋.?\x16\xa2\xa0\x15\xf0Ն\xecq\xc0\x8enQbP\xadj#\x02J\xe7\xa1\xf6\xfah\xaf\x11足\xa0f\x02\xf0b\x03\xbfZ\xc0G\xb7J\u007f\xd7\x1a)xы\x02uB\xa1\x8b.:\x00?\xef\xdf\xeb6\xe7\xaf\xd6\xf3W\xdaB\xc0G\xed4\xfaw\xa5\xf3\xeb6E\xa0\x9d\bt\xdbbX5\x01\xa0i\x9a\xa6i\x82\x10EQ\x14\xc5\xe7\x05\xfcZ\x01\x19\x05v\xdck\xb5\x04\x00\xbe\xaf\xd3\x1a\x03\xb5\x9e\xff\xf7mܱ.\xba\xe8\xa2\x13\x81N\x8f\xa3W\x9e\xbfZ\xc0\xc7E\x00P\xcf\x1f%\x06\xe8\xdfqv\x15\xfd\xfe\x93#\x02\x00\xa7k5\x80\xd3=$\x00j\xbf\xf0d\x81_\xadG\x8f\x02=\x0e\xf8\xb5\x12\x02\xb5\xa9\x87^\xb7&\xd6E\x17]t\xf9\xbe\x11\x8fnk\x00\xba\r\xf5\xa3\xc0\x0e\xb7\xa8\x1d\xc7\x01?\xee5.%\xd0md@;\x11Њ\xd3\x1aS\x00\xc7]\xdd\xdf)\xf0+\x01:M\xb7\u007f\x1f\xfaw\xb5\x11\x84\xe3J\x05\xe8\x1e\xbb.\xba\xe8\xf2c\x898t\x1b\x01\xd0\n\xfc\xa8=\x87\x90\xa9d\xcfqD@\xadh%\x02ǿZ@%\x01\xe8uu\xbfZb\xa0\x15\xf8\xd1-\x0e\xf8q\xfb\xd5F\b\xb4\x16\t\x1eW\xf5\xbf.\xba\xe8\xa2\xcb\x0f\x85\x18t[\xf5\x8f\x03|\x9c\xe7\x8f\x12\x02\xf8\x1a%\x04\xe8V+\xf0k=o\xf4\xf7\x8eo\xb5@\x13\x01 I\x92$I\x82\x90$I\x92\xa4^\xe7\xfa\xd5\xee\xef\x15\xf0\xa3@\xaf\xb4\xbf[\"\xa05\x05\xa0\x03\xbe.\xba\xe8\xa2\x13\x82\xce\"\x008\x02\xa0\x16\xf8Q\xc0Wr\xe0\xba=?\xdc2D\xa5酸\xfd\xeaW\v\x00\\\xaf\xd5\x00\xae\xb7!\x00\xe8\x1b\xba\x8b\x10\x1cW5\u007f\xa7\x80\x8f\xdb\xe2\x88\x00|}\\\x11\x00]t\xd1E\x17]\xba\x8b\x04\xa8\xcd\xf5+\x01\xbf\x92\xe7\xaf\xe4\xc0j\xf5\xfce\xd4\xed\xec{\xd4\x13\x01\x1c\xae\xd3\xda\x00]+!\xe8\xb4\bP\xab\xe7\xaf\x16\xe8\xe1\x96a\xb4E\b\xd4D\x00\f\x06\x93\x89a\b\x82a\x1c\x0e\x9e'\b\x8a\xb2\xd9l6\x82\xe08\xab\xd5d\x02,\f~\xaf\xd6\x10O\xe3uT\xbe;\xed\xbeO\xfb\xbd\xed\x15\xffU\xf7}\xf2_\xb5>^\xdd\x1d\xa7\xf2\xa7\xc1;ԇ\xe3\xd4\x1d\xcf\xf3'\x85\xea\x1a\x93j\xd3\xd1N\xb4\xa4\xdbQ,\xcd\xe7\xd1ڰ6\u007f\xbf\x96_l\xa5m\xea\xce]\xfe\x95\xce\xceP\xfeT\xfb\xdf\xeb\xf6w\xf0߫\xe6<\r\x86\xc6_վ>\x1d|\x83$\x81r\xb6R)\x9b\xcd\xe7\t\xa2Z\xcd\xe5r9\x82(\x97\xd3\xe9b\x91 j\xb5b\xb1RiM\bp\x11\x00\b\xf0h\xe8_m\x04\x00\x87kj;\x1a\xe2tHm\xeb\xe0ާ\x04\xe8\x93\r\xf9\xe3\xde\u05eb\xe2>%\xc0G\x81_md\xa0\xfe\xf7I\xd2j\xe58\x82\xe0\xf9\xa1\xa1@\x80 \x8c\xc6@\xe0\xfcy\x82`Y\xb3yz\x9a h\x9a\xe3\xfc~pvf3H\xaa\xf0\x9eU\xe2꿵\xbb\xdfW\xb3V\xfa\xc5 :J\xe6_\xdb\xe7\xb5k\x81\xd6\xdf\xef\x15!Pw\x1e\xb8\x88\x01Jxj5\xf8O&\x06\x1b\x1b\x04\x91\xcf\xc7\xe3\x9f\u007fN\x10\x99\xcc\xc6\xc6\xe2\"AT*ɤ \xb4\x8e\x00\xc0\xd7p\v#\n\xe8kt\x8b{?n?\xfa{\xb8H\x05nV\x81R\x11d\xe7\x9a\xf4\u007f\t\xc0I5\xf6\xd1\n\xfc( \xab\x05~\xb5[\xf4\xf3\xe0w\x18\x86e\t\xc2j={\xf6\xd4)\x820\x9b\a\x06~\xf3\x1b\x82\xa0(\x96\x1d\x1d\x05@\x05\xde\xdf=@\xf7\xd6\xe4j=\x9e\x17\x95`h\x05ؓ!\x0e'珿\xa8\x95\"\xc7\xdbF\xa6\xd7\x00\xaeֳLJ\xf2\xd1P\xb6\xfc\u007f\xb8\xbf\xa8\xbb{jC\xf9jϤ=`\xd6G\x12Z\xff\x1e\x1eF:K\x06u~~\xbdѣZ\xadR!\x88j\xb5\\^_'\x88L\xe6\xe0\xe0\x9f\xff\x99 R\xa9g\xcfVV\b\xa2V\xabT\xca\xe5F\x00V\v\xfcJ[\x1c\x11\xc0\x11\x8en\x89\x80R\x04B\x85\xad\xe9-\x01\xd0\xea\xf9+\x85\xf6\x95r\xf7(\xa0\xb3l\xe7D\x80\xa6\x03\x01\xbb\x9d l\xb63g~\xf1\v\x82\xe08\x9b\xed\xc6\r\xe0\xe1\x83\x1c\xbe\xb2g/I@\x01AȪZM\xa5\bB\x92\xaa\xd5X\x8c j\xb5j5\x91\x00\xafs9p{\xa1\"\xd4j2\x90Af\x8b^\xbd\xfa_;\x1eS\xfc|Cཇ=u\xe7\xd3\xfbT\n\xfa\xbb\xdaj ~(ҹ\xe7\xdf)\xd0\xcbח\xa6\x95\xef\x16\ns\xf80j\xfb\x10{\xefV\xf4\xa8\xad\x818ވ\x03h\xf4\xde\f\xe4\xb8\xeb\xd2.EQ_5S\xff\xf7V\xd7\f:V$\t\"\xaa\x06\x03E\xb9\\\x04A\x92`k0\x90\xa4\xdd\x0e\xde\rR\xaa\xeaj\x12`\x84\xa0X\xccf\xbf\xfc\x92 \xe2\xf1\xe5\xe5\xbf\xfc\x85 J\xa5H$\x9d\xee\x8c\x00@\x02\xa1\x95\x10\xa0[\\\xad\xc2\xc9E\x024\x12\x80^y\xfeZs\xfa(\xf0+\x01=\xfaw\xdc\xfbi\x9a 8nbb`\x80 l\xb6\xf1\xf1\xbf\xfd[\x82\xa0i\x9e?uJ\xc9;\x00@/\b\x04Q\xab\x89\xe2\xee.AT*\xb9ܷ\xdf\x12D\xa9\x14\x8bml\x10D\xb9\x1c\x8f'\x93\x04Q\xadf\xb3\xa5\x12AHR\xa1 \x8a\x80\b(\xddX%\x93\xd0\xeb \xde\x0f\xd5g\xfd\xb1ˋ\xd2\xfaUק\x1f\xc6}\xc0\xe9\x93֚\xafv\u007f7\x18\x18\x86$\t\x82\xa28\x8e\xa6\t\x82a,\x16\x9e'\b\x9e\a\xc9j\xa3\xd1\xe9\x1c\x1f\a5W\xb3\xb3\x04AQ4\x1d\f\x82O\x1b\x8d\xca\x11\x94J\xa5TZZ\"\x88Dbs\xf3\xef\xfe\x8e r\xb9\xcdͽ\xbd\xf6\x04\x00\x05|%\x02\x00\xff\xae6%\xd0-\x11\xe8<\x12pL\x04@k\x8f~\xa5\x90\xbf\x12\x01\xc0\xbd\xc6\xed\xa7i\x820\x1aO\x9d\n\x85\b\xc2j\x1d\x1b\xfbO\xff\x89 H\x92aB\xa1泫\x0f\xa5\x95\xcb\x04!I\xe5\xf2ӧ\x04!\b\xfb\xfb\x1f\u007fL\x10\xc5\xe2\xce\xce\xc1\x01A\x88b\"\x81\x16\x9f\xa8\x9dV\xd5\xe9\r\xed\x94\xf9i\xaf\xcbՁ\xe1\x87\b\xc0\xcf\xeb\xf8^\xb4\xfb\xa8\xebUo\xaeC\xa7}`\xb4NY%I\x82`Y\x87\x83\xe3\b\xc2b\xe9\xef\xef\xef'\b\xab\xd5\xef\u007f\xe7\x1d\x82\xa0i\x96=s\xa6\xd1\u07b7\x92j\xb5R\t\x87\t\"\x91\b\x87\xff\xc7\xff \x88Lf}=\x1cV\a\xecJ\x84\x00G\x00\xbaM\t\xa8ō\x13#\x00\xdd\x16\xfb\xa9]ƧֳG\x81\xbf\x15\x11`ٱ1\xe0\xf1ON\xfe\x97\xffB\x10\x14\xc50\x80A\xe2D\x92b1\x82(\x16c\xb1\xdf\xff\x9e r\xb9\xa5\xa5\xa7OA\x80\x1f\x02>n]\xaa\xd2zU\xb5\x84\x00\x17\x11\xe8u\xfd\xef\xf7\xcd@\xfe8\xb3\xe5?\x9c\xe3\xd3\xf5\xea\xfbuߴ\xb6,\xc7\x11\x80Nq\xa3]\xab^\x86\xb1\xd98\x8e \\\xae\xb1\xb1\x99\x19\x820\x9b]\xae_\xff\x1a\xa4\x0e<\x1e\xfcU\xacVEq{\x9b b\xb1\x8d\x8d\xff\xfe\xdf\t\"\x97\xdbކ\x11\x01\x1c\xf0k%\x02ZS\x02\xdd\x16\a\x1e;\x01P\x1b\U00087bd5\x86\xeeh-\xeaS\x02\xfaV[\x8a\xf2\xf9\x1c\x0e\x82\xb0\xdb/\\\xf8\xaf\xff\x15T\xf1OM\xe1\xd5Z\x92*\x95\xb55\x82\x10\x84\xad\xad\u007f\xfcG\x82\x10\x84\xa5%\xa0\x18\xf2\xfab\xa5\x06\x14\xf0\x06\xa07T\x890t\x1b\xea镡89C\xd88Ʋۚ\x94\uf2c1\xae?c\xa5b\xc6\x1f\x02\xb0\x9c\xfc\x19j\x1b[\xfe}\x89\x04\xa80\xec\xffw<\xec\xc9ܿNS\x00J\xc0\xde\xd9\xd6` I\x82p8FG\xfb\xfb\t\xc2\xe1\x18\x1c\xfcw\xff\x8e (\x8a\xa2\xc6\xc6\xf0\xe7!\x8a 5px\xb8\xb4\xf4\xdf\xfe\x1bA\x94J\xf1x*\xa5\x8e\x00(\x11\x03\xb55\x028\x02\x80\xe2I\xa7)\x81f\xe9\xf1,\x00\xad5\x02\x9d\x0e\xfb\xd16\x03\x80a\x18\x86 \xcc\xe6\xc9\xc9_\xfd\nx\xfc \xc7\xdf|\x99@\x03\x8aJeq\x91 \xb2ٕ\x95\xdf\xfd\x8e J\xa5\xcd\xcdDB\x1d૭\xeaT\xda\xf6*ף~]\xe8\x8be\x88\xbb=\xae\x932\xe4\xbd[i\xddz\x8e7\x9c\xf4\xfd}#\x06/\x1aq\xfc\xb1\x11\x00\xe5\xb9\xf0\xda\b\x82Z\xcf_-\x11\xe8\x16\xf8q\x0e%,7\xac\xd5\b\"\x95Z_\xdf\xdb#\bQ,\x14\xfe\xd7\xff\"\b\x8fgd\xe4\xdf\xff{`\xffa\x8a\xa0\xfe\xf8h\x1a\xe0\x82\xdb=2\xf2\xab_\x11\xc4\xc1A:\xfd\u007f\xfe\x0f\xa8\xf1B\xfb\b\xa8\xdd\xe2\x86\x10\xe1\xb6\xf0\xfd8\xbcԺ\uefc3Y\x00\x9d=\xe8\xc7\x05\xfc\xdd\x0e\xff\xa1i\x83\x81\xe7'&N\x9d\x02\xc5$\xaf\xbe\n\xd4\xc3`h~@j5Q\\[#\x88lvy\xf9w\xbf#\x88r9\x1c\xc6\x01?\n\xf0\xb8\x1c\x8e\xd6⎓[\xfeq\\\x9e\\{\xc3\xd3\xe9\xd4C\xb5\xbfw\xf2\x06\\\x9b!\xd5N\xd4p\xa6\\\x1b1\xf8\xbe\x14\x03\xf6Z\xaf:\x9f\xb2\xd9\x19a\xed\xb5^i\xbd\u007fꋁ\x1b\xaf'\x1a\x89\xea\x96x\x1f״W\xf8\x1a\xed\xad\xdf\xee\xfcs\xb9\xfd}`\xc7k\xb5\xdf\xfd\x0e\x10\x81\xbf\xfd[P<81\xd1|\xfc<\xcf\xf3\xaf\xbeJ\x10N\xe7\xf0\xf0\x83\a\x04\x91H\xac\xad-,\xb4\xc7\x01\x1c\x1e\xa9\x05\xfen\x89@\xe7\xcf9\xdd\xdb\a\xb5\xd3U\x02j\x8b\x05\xb5D\x04\f\x06Ђ\x97\xe7\x03\x81\xdf\xfe\x16\xec7\x1a!?\xac/퓤H\x04\x84\xfa\xff\xe1\x1f\xd4\x01\xbfRoi\xa5a\x14\xc7\x15\t\xc0)\x82R\xab\xc9^\x1bf\xad\x06\xb9y\xbf:\x03\xfc\xbc\xc6(\xe3\f\xa9z\xa0Wg\xe0\xf1\xfbq\x80\xd8\xde|\xbf\xa8D\x00w\xff;\x8d86\xbfnO\x14{\xbdD\xb4\xfb\x1e\xf1Z\xf5\xaa\xb3\xfb\xde\xec@\xa8\xd3+\xad\x11\x81n\x8bġ=D_\xa3\xcb=\xe1\xe7ZI.wp\x90L\x82\b\xc0\xdf\xff=A\xb8\\\x83\x83\xff\xf9?\x83e\x87>\x9f|5\f\x06\x80\x13V\xab\xcb\xf5\xdb\xdf\x12D&c6on\x12\x84(\xe6\xf3j#\x01\xb8\xf3A\t\x81V|T\xf2쵷\n\xa6\x8fG\xb1\xb5F\x06:e\x82\xf8\xfd$\xc9q\xa1\xd0\xf4\xb4\xc1@\x104=:Z\xabIR=l\x82\u007f\xa5\x92\xc1P.\xc7b\xff\xf2/\xb5Z\xb1\xb8\xbazp\xd0\x1e\xf8q\xb9\x1a\xdc~\xa5\xad\x12\xf0\xf7.ף\xf6\xbe\xa93\xbc\x9d\x1b\xe2ֿ\xa3l\x80\xdb\x13\x82\x17\xb7\x06\xa0u\x84\x00ghQ\x82\xa0\xbd\xd6C9\xf8\xdb\vOS\xcb\x15\xe9Ɠ\xee\xb5^\xa9%\x9a\xbd\xae\x86\xef\xf6\xfa*\x13\xc7\xf6\xf7\x1d%\b\x9d\xeaUk\xed\xc1\x13\x03\xb5\xc0\xaf4\xf4\r\xdaA\xb4\xb5n'\xf60\x9d\x06\xab\xb68\xceh\xfc\xfd\xef\t\xc2ju:\xff\xe3\u007f\x04G\xc1q\xf5d\x82$GG\t\xc2\xe1\xe8뛞&\x88Xlm\xed\xc1\x83N\xf1\xa8\xfdV\xeb\xf0\xa1\xeeC\xff*\t@\xa7\xb9\x9f^\x85\x86\xb4v\x10\x04\xafY\x96e\r\x06\x86q\xb9\xdey\a\xa8\x0fM\x1b\f\xe8c.I\xa5\xd2ӧ\x92T(\xac\xae>}\n.W\xa7\x1e\xbf\xd2\xfaN%\x02\xa0T$x|\xa1\u007fm\x1e\xbc\xf2\xfdUg\x80\xb5\x1a\xeaN#\x04\x9d\xeau\xe7\xd7\x13\x05n\\\xa8\x15\xf7\x1a~\xbe=A\xd0j\xd0\xdb\xdf}e\x8fO}\xa4\xa83ϽWz\xa5\x04\xe8Z\t\xc4IE\x96\xe4\x90nkO\xbes}R\x17\x01\xd0J<\xd5\x12(\xf4|\x94\x00\x1f\xf5\xf0\xd5FF\xb5\xdd'p\xbc\x89\xc4\xf6\xf6\xc2\x02A\x18\x8df\xf3\xfc<\xa8\x01\xb8t\t\x81G\x9a L&\xab\xf5\xddw\xc12\xf1\xf9yP#\x86z\xf2J\x80\xaf\xb6Q\x9e\xd6\xe9\xb1Z\xfb44\xff\xfd\x98R\x00\xdd\xe6~:\xaf\x15 I\x9a\xee\xeb\xeb\xeb3\x18\b\x82\xa2\x86\x87\t\xa2\x95\xe7\x9f\xcf\xd7j\xc5\xe2\xe1\xe1\xc7\x1f\x13\x84$e\xb3\xb0jS\xedXI\xa5\xe5\x1cZ#\x02\x9d.\x13\xec\x1c\xc0:\xf5\xa8\xd5yLАj5\xbc\xbd\xf6\xf0\x8e\xcf\x13S\xf2\xc0\xdb\x1br\x9c\xc1E\x01Y\x89 \xe0\x8fG]m\x82\xda\x10t\xaf\x8bŔ~\x0f\xaf7\xbd\xd5+\xa5\x14\xc1IG\x9c$\xa9\xbb\xc8P\xaf\xf4JkDK\x89\xe8\x1b\f\x8dT\x00\xb5\xefhh]\x89\btJ\x00\xea\u007f_\x14\v\x85r\x99 2\x99H\xe4\xe3\x8f\t\xc2\xe9\f\x04\xa6\xa7\xc1\xdf\xe0l\x17\x18\t\b\x85\b\xc2bq\xbb\xfb\xfa\b\"\x939<\xdc\xdc\xec\f\x9f\xb4\xe2\x9f\xd2\xf6{\x9b\x02P\x9b\x12\xd0^5j0P\x94\xdd~\xfa4x\xa7ٌ>P\x06C\xadV\xa9\xec\xec\xd4j\x95\xca\xde\xde\xfe~k\x80U\xeb\xf1k%\x02\xb8\x1a\x81n\x19\xafZ`\xd2n\xa0;3\xcc$\xd9Y$\x00\xbd\xcf2\x9cvKHz塵\xf6ؚ#4\xa8!m\xedQ\xcb@\x8e\xfb\x1e\xb5\x1e^k\x83\x8f3\xf4\xdaS\x19\xbd\x8e\xb4(\x013N/\xdaG\xac\x9a\x81\xa7=\xe0\xe3ǭ\xaa\xd5\xfb\xde\xe8\x95R\xe4\x05\xa7W\xcd@\xafN\xaf\xd4F\f\xd0Ϸ\xba2\xad\xf4\tw\xbd\xe5\xfb\b\x04\xb5\xdf(\x11\xc0\xd9\xc1N\xf5\xaf\x95>d\xb3\xd1\xe8\xc1\x01A\xd8\xed.\xd7\xf66(\x0e\x84D\x00\xbe\xc7l&\b\xa3\xd1b\x99\x9a\"\x88L\x86 `àN\x81_m\xc8_k\xa4\xbd\xe7)\x00\xed!\xe0ޤ\x00\xd4\x12\x81\xc6\xfd\x14EQ`6\xdf\xf9\xf3\xf5\xc5~rw\xfdZ\xadV\x13\xc5l\xf6\xde=\x10\a\x80\xeb1\xd5z\xfe\xdd\x12\x02\xb5\xa9\x00\xad\r\x1e\xf0\xe3$Ն4\x95r\xf28\x83\x8a>\xd8\xed\rh\xb3!h\xfc\x9ev#O\xdb\x01\x82\xd6\xe2\x99\xe6ԇR\xe8U\t\x98\xc1\xe7\xd1\xea]\xf9\xbe\xe1\fu\xa3\xe7%\x1b:m\x84\x00o\xf0\xb5y\x82\xdd\xd6\x04௯\xb6\x88\x0e\xaaW8}V\x02|\x94\x88*\x13\x10u\xfa\xa4\xacWڊ\xf2\x94<\xf8f\xbdj\x1d\tR\"\x82\xf2\xe7\xd4\x12\x00\xa5\xe3k\xfd\x1cᮗ\x1c:o\x8c\f\xb4^Χ\xbd\xc6I\t?P;\v\"\x01\xa5R\xa5B\x10\xc5b>\u007f\xef\x1eA\x98\xcdV+\xe8\x0f\xd3x\x9f9\x8e\xe3Ο\a]\x06>\xfd\x14$\x8c\xb564\xea\x14\a\x95γs\xc2\xde#\x02\xd0+\xc0\xef\x9c\b\x18\f\x06\x83\xc5b6\x93$A\x18\f^o}\xd1\x1f|g\xad&\b\x92$\x8a\xc9\xe4\xd6\xd6\xf1\x02\xbf\xda\xdeϝv|\xc2\x1b\x12\xb5\x9e~{\x80\xd6\xea\xe1\xcb\x06\n\x17\xa2E\xbf\x17}_\xeb\xcfQT#\x10\xc8[\xf4x\x94\x1e4u\x91\x02|\b\xb5\xf5\xfb\x9a\xefWk\xc3\r\ro\xf3}F\x8b\xa8p\xa1X\xd4\xe0\xab\xf5\xfc\x94ޏ\x02U\xfb\xe5aJ\xa1{\xb5\x04\xb2{\xbd\xc2\xfdn{\xbdB\xf5G\xab^\xa1\xcbΔ\xf4Km\xc8\x1e\xdf٭\xf5}\xc3\xebU\xe3\xeb\xe6\xc8O#AQ&\x90\xda\"Tx{\xd3\b\xf4\xe8}%\xc9\xd6\xcfG\xb7\x04@i[O\xac\x8a\xc5l6\x1c&\b\x93\xc9l.\x14\xc0>\x93\xa9qɡ\xdfO\x10,k2\x99\xcd\x04Q*\xe5r\xb0\x13l\xb79\xfe^\xd5\x04\x1c\x1b\x01\xe8U.\xec\xf8\x88\x81\xc1`0\x98L&\x13\x18'a\xb5\x1a\f\xb5Z=\xcf\x03-~\xd2\xe9ZM\x92\xd2\xe9d\xb2}\xe8\xbfSB\xa0\xd4\xf2Q{\r@k\x83\xac\xfe\xc1hox\x95<7\x9c\x87\x8f\a\xf0\xc6\xf7+\x19f\x9cA\x86\xc0\x8f\xf6u@\xff\xae\xb4\xfcFmȭ\xf5U\xab\xf7\xacZ\x1b&\x1c\xa0㗁6\xfe\x1d\xbeF\r6\xd4h\xf8\xbef\xcf\x1c%\x1aJ\x86\x1bF\x18\xda\x13\x1b\xf5)\xa5\xf6)\"\x9c\x9e\xc9\x11\x9cF}iN\xad\xa0z\x87ꕺ\x88\x14\xfc\x1dYOZ\xeb\x8dV}R\xafW\xed\x9f_\xa5Z\x1f\x9c^\xc9\xfa\xd5z?\xaaWh1\x1e\xfc\\\xb3\a\t\xf5C\x9d>ɯQ\xe2\x8a\x12\xdbF\xfdC\xedw\xa7DCmm\x99R\x8a\x95$\t\xa2P\xc8\xe5\x12\t\xd0\x0f&\x99\xac\x9f\x02\v~\x9d$k5\x8b\x05\x94\x98\x03\x02@\x10\x10G\xd4F\x02\x8e\v\xe8;\xaf\t8\xe6\"@\xb5D\xa1{B\x00\x80\x1f06\xf9An<}QL&k5I\xcaf\xc1\xb8^\xe5\aP\xeb\xb2>\xb5\xab\x04\xf0\x04\xa05\xf0(m\x95\xd7Q\xb7\xf7\xa0\x94<,\x94\x88\xc0\xe3l\x0eŷ\az\x9anmh\xe1\xfe\xe6鏸\xfd\xad?\xaf\x95\b(\x85h\x95\x80\x1f5\xb4\xd5*8\x0e\\\xe4G\x14\xc1\xfb\x9b#F\x8d\x86\x1c\xbeO\u038d\xb6&\x04\xa8\x81ǥ\x16P\x0f\x10\xff\xf7\xce\b\x00\x0e\xc0Q\r¥\x88\x9a\xf5\xb0\xbd~\xe2\x80\x1d\xa7\x17\xb2\xfe4\xbeF\xf5\xaa\xb9\xa1X\xe3\xfb\xbb'\x96\x9d\x11I\xa8Wj\xf5\t\xb7\x1fz\xda\xf0us$\x00G4qD\x12\xd5\x1f\x1c\x11h\x8cm\xc1W\xe8\xfa~\xf9\xbe\xaa\xab-\xe8\xb4h\xbc\xd5\xf5/\x97\v\x85b\x11\x10\x00\xd0\a\x86\xa2\x06\x06\x1a\xef\x1eM\x833\x81E\x82\x9d\xa6\x8a\xb4\x86\xfa\x95>\xdfyc \xba\xb7\xc0\xdf\xe9\tt\xfa\xf7ƿ\x90$\xcf\x1b\f\x92$I\xe0A\xae\x9f\xe6W\xab\xd5j\x95J4\nn7\xae\xb7\xb2\xda\x16\xbfJ}\x00\x94\x00\x1f\xed\x1c\b\x01Ui\x19 \x0e\x90\x95C\xfch\xd1S\xeb\x90<.T\x8f\xa6\x16p\x06\x19\xe7\xa1CC,\xcfth|-\x0fk\x02\xfb\xdb\rsjܢ\xbf\x03\u007f\xdf`0\x18h\x1a$\x84\x18\x86\xa2\xc02\x1e`THR\xd6\f\xb9>D&7\xc5\"\xb8\x1f\xe52\xbc\"\xe0>\xb4Z&\n\r3\n\xe0\x8d\x11!y\v\xde_.\x83\xf7\xcbCC\xc0~H\x04\xe0k\x94 \xa0\x06\x1eM\x1e\xe0\x8b\x13\xd1Pt{ϭU\x93\xecv\xfa\xd6\\$ٚ\x106\x17\xdf5\xea\x1d\xfa\x9cˀКH6\xcf\x0e\xe9\x8d^\xa1\xdf_OXI\x92\xa6I\xd2` I\x8a\x02\xaf)\n\xea\x13\xb45\xad\x9eFQ,\x16\xc1\x99J\x92$5\x9e\xb1\x92\xbd\xc1\xa7\x18\xa1>A=\x82z\x05\xf5\t\xb7\xbf\xf15\xd4'T\x9f\xe1\xfd\x81\xafq\xfa\x03\xcfFNi\xb5_-\x80.\x13\xc4\xeb[\xeb>\x03Z\x1b\xc9)\x15\x17\x92\xa4\xfc\x9cW\xab\x95J$\x02l\b\xea\x0e\x801\xc5\x06\x03\xcfw\xe6\x00k\xcd\xedw\x1ai\u007f\xee5\x00\x9dF\f\xba!\x04\xb5\x1a\xb89\xb2\x99\x86\x8a\t\x1fKQ\xccd\xa0r\xa9\r\xbd\xa9\xf3\xf4;\xef\x14\xa8\x0e\xf8\xf1U\xc0\xed=}\xbc\xe7\xaf\x04\xf8\x8d\xaf\xd1\xdc(\xea٣\x9e\x12\n\xf8\xb2\xc1\x05\xfba\xc3\r\xb8\xe5y\xdc~\xf9\xf3\x06\x03E\xb1,E\xb1\xac\xd7\xcbq\x16\x8b\xc739i6\x1b\x8dVk_\x9f\xd9\xcc\xf3V\xab\xcfg\xb5\xb2,\xcf;\x9dV+E\xf1\xbc\xc5b\xb5R\x14M\xf3\xbc\xc9DQ4\xcdqF#0\xdc\xe08)\n\x10\x04\xa8=\xe0\xceT*\xf9|.'\x8a\xa5R.\x97N\x03\xf3W\xa9T\xab\xa2X.\x97J\xa2X.\xe7\xf3\xc5b\xb9\\,\xa6R\x82P.\vB2)\b\xc5b6{t$\b\x85B<\xbe\xbaZ(T\xab\xe5r<^.\x13D\xadV\xa9\xa0CBJ%p\xbe\xa5\x120p0\x97\b\xf7\xc3\b\x154ܐ\x10\xa0\x86\x1e\xeaS\xf3\xfaq\x1c!h_\xbc\x85\xaf\x1ao\xdf\xdf\x00\xbfjC\x9b~\xa2D\x12\x05\xe2f\xbdj\xd4\x1b\xa8gPo8\xae\xf1\xef\xf2~\xf9\xfd$\xc90,KQv\xbb\xcf\xc7\xf3\x1c\xd7\xd77:j6s\x9c\xc3\xe1\xf5\x9a\xcd,k\xb5\xba\\6\x1bM[,6\x9b\xc5BQ,\xcb\xf3V+I\xb2,˚L\xe0\xd3\x1c\ah%\xf0\x10\xd1\x14\x18\x80XA\xc8d\x12\tI*\x97K\xa5B\x01<\xf5\x95\x8a$U*\xa5R\xa9$\x8a\xa5\x92 \x14\x8b\x95J>\x9f\xc9\xe4\xf3\xa2\x98ͦR\x82P*%\x12GG\x82 \x8a\a\a\xdbۅB\xadV.\x17\x8b\x95\n \x12j\xf5\xaaX\x84\xfbQ\xbdj\xfd\x1a\x8d \xa0\x9e<\xbc\xcfr\xee\x1e\x8d\x1c\xc0\xfbN\x92$I\x92\xb8\x88e\xb3]o]\x93\x02\xf5\x17\xd7I\x0f\xd7{\x1f}?\x8e\b\xd4\x1f\x9f$\x89b:]\xff\xaeF\xbc\x01\xad\xe5N&\xb7\u007f\xfc\r\xce\xe8\x93\x01z\xad\xefӾ\xacK6\u2007\xd6\xdf.\xf0\x0f\x18ru\x80\xafv\xdby\xe7\xbfF\xe0W.\xfek\r\xccx\x03\xdb:\x94\xda\f\xfc\xed\rtsQ\x94:\x83\f\r1\n\xf0Fc\xa3!6\x99\xc0V\xdeOQ,\xeb\xf3\x99LNg\u007f\xffK/9\x1c6\x9b\xc731\xe1\xf3\x99\xcd\x0e\xc7\xd0P0\xc8\xf3f\xb3\xd7;8\b\x80\xddn'I\x8ab\x18\xa3\x11\xe4\xec\x18\xa6V\x03\x10\x8f/[\xab\xaf\x1bi\x1d,\x83\xc3Cq\x8b\xc3`\x81i\xadV\xadJ\x92$I\x92(\x02s.\b\x80(d\xb3\xe5\xb2 \xc4\xe3\xfb\xfb\x82\x90N\xef\xee\xee\xee\xe6r\xf1\xf8\xfaz$\x92J\xed\xed=z\x94L\x8ab.\xb7\xb9)\b\x8d\x80_(\xb4\xdeB\xc3-\xbfn4\xf4\x90 \xc8!^\xd4p\xe2<|\xb48\xac}\xcd\x01\xbe\x06\xa0}N^\xa9(O\x99@6\xea\x15\xd4\x1f\xa8W\xf05\xd4#\xa8W\xf2~\x8ar:\x87\x86L&\x8beddf\xc6\xe52\x9b\x03\x81\x91\x11\xbf\x9f\xe7=\x9e\xbe\xbeP\x88\xa6\xcdf\xbb\xbd\xaf\x0f\x00\xba\xcdf0P\x14M\x1b\x8d\xe0\x18i\xda` I\xb4\x16\x06\xb6\x8e\x95\xfb\x8bȯ\xd1\xf8\b\xc79\x1cNg\xbd\xae\xd5\u007f\x0e\xeaS\xbd]\x90\xa4j\xb5\\\x96\xa4j\xb5R\x11\x04@\x1c\xd2\xe9r9\x93\x89\xc5vw\x8b\xc5X\xec\xf0poO\x10\x0e\x0evv\xa2\xd1Bam\xedٳT\xaaV\xcbfS)@0d\xbdB\xf5K\x10\x1a\xf7\xcb\x04\x01\x12\x87\xc6\b\x02\x8c\x18\xa0D\x13F\x06d\x8a\x89\x12I\xf0|\xe0\b\xa6\xac\a\xadka\xe4\xd5\x03\xed\x89\x00\x0e\xd8\xd1\xfdJ)\x18\xf0}\xd5* B͕9\x8d\xef\xd6^\xf3vR\xf8\xd95\x01\xe86\x04\xd1mND\xeb\xdf\xd1p\x1b4Y\xcd0\xaa.\u05eb\x94\xa3S*\x16\xec\x96X4\x03\u007f\xa3\xe0\x00\xbf\x99\x18\xe0r\xa9\xea\"\x05\xf8\x90kk\x8f\x1dz\\\xa8!F\xb7f\xb3\xc1@Q\x16\x8b\xc9\xe4\xf1\x04\x837n\xb8\xdd.W 03\x13\n\xd9ln\xf7\xd8ؙ3\f\xc3q6[ `0\x90$\xcbZ,\x00\xe0\x01\xb0\xb7\xd39\xb9\xe0\x13\x17\xb2\xaeV[\x95\xc6@\xa2\b\xa2\x1d8\x9d\x87:\x05s\x94\x14\x05\x80\x82ek5\x8a\xa2i\x93\t\xd0\x11\x8f\x87e\x8dF\xbb}d\xc4bq\xb9FF\xaaU\x8f'\x14\xbav\xadX\xacVϞ\xfd\xedo\xe3qAH\xa5vvVV\xd2飣\xc5\xc5\xf5\xf5x<\x1c\xbe}\xfb\xe8\xa8R\xc9dVWs9h\xa8\xc1\xf5\x84\x06\x1b\xddB\x83\x0e\r9J\f\x9a\xefs\xfbH\x81\xec\xc9)M'T\v\xf8\x8d\xfb\xe5\x1a\x8dֹx\xb5\x04\x12\xa7W&\x13IZ,>\x9f\xc5b\xb3MO_\xbd\xea\xf3Y\xad\x83\x83\xa7N\x8d\x8c\x98L>_0x\xfa4Eq\x9c\xd1\xe8\xf1\x90$MS\x14(\xf2\"\b\x92\x04Ayp\xac\xe0)ĕ\xa2\xc1\xfd\xea\x17\xd35_\v\xf4\xfd0)\x05\"R\x10\xb4@ċaH\xd2b\xa1(\xa3\x91e}>\x86\xb1\xdb-\x96\x89\t\x93ip0\x18\x14E\xa7sffvV\x10*\x95\xd7^{\xe7\x9dH\xa4P8<\xdc\xd9YX\xc8緷76\xb6\xb7\xf3\xf9\x85\x85ヒ\xc5\x001\xc8\xe7\xc1w\xe7\xf3\x8dz%\x13\x03\xb0\xbfP\x00\xf7Y֫\xc6TU=\xd4\xd7\x13K9u\x80\x02>\x88\x04(\xd5D\xc8E\x81\xadk\x04d\x82\xd4z\xd5\x00\x0e\xf0\x95\x1c\xbe\xc6\xf7A\xcdW\xdfWQk\xe7\xc9^\xd7\n(\xe10~\x8a\xe0\t\xa5\x00\xba\x8d\x00\xa8\xfb;\xda\xf0\a\x9d\xf6\xa7\xbeȫ\xd3\b\x81\xf2\xe7\xda{\xfer\x11 Z\f\x88\vݣ9\xfa\xf6!~\xa5\"=\xa5ܽl\x98\x1b\r2j\x98-\x96ƭ\xd9\xccq\x16\xcbؘ\xd5\xda\xd772\xf2\xc6\x1bCCnw\u007f\xff\x85\v\x17/r\x9c\xc9\xe4r\x8d\x8c\x80\x10\xbd\xdd\x0e\x80\xbe\xf9\xfe\x02\x9f\b\x1a\x87vw\xbfV\xabV\xa1?%\x8a`/\xf0\xd0E\xb1Z\x95\xb7\xf5\xb9\xfdZ\x8d$i\x9a\xe3@H\x98\xa6\xd1\b\x02\xb8\x1e \xdb\v\x8f\x8f$\x81\xdf\"\x9b\x1d\x14*e]\xa5(\x9016\x9bI\x92\xa2,\x16\xb3\xd9n\x0f\x04\xa6\xa7\x83A\xab\xd5띘\xb8~\xdd\uf7dc|\xfb\xed\xa3\xa3L\xe6\xe8\xe8ٳG\x8f\xe2\xf1\x9d\x9d\xfb\xf7762\x99p\xf8\x8b/\xe2qp\x16\xb2\x01o4\xe4\xf0\xb5\x1c9\x80\x1e \x1a\xeam\xcc\x01\xcb9\xdeFB\x80\xf3qԦ\xf2\xd0\xc8\x11\x0e\xf8Q\x0f\x1f\xf5\xe4qz\x05\x1b|Y,\x1c\x17\f\x9e;g\xb7\xbb\\SSW\xaf\x0e\x0f\xdbl\xa1\xd0\xf4\xf4K/Ѵ\xc9d\xb5\x0e\r\x91$M\xd34\x04\xfaFϽ\xbe\x12\x88$\x010\xcbD\x00\xb5\x18\xb5\x9a(\xc2\xdc=ЧjU\x14k\xb5jU\x14%\t\xbc\xae/\xd6\x03`N\x92\f\xc30,\v\xb4\x06\x1e\x03x\xde\xc0s\x06\x9a\x97\x81-|O\xab\xda\x14Ծ\x81P\xb4\xc1\xc0\xb24m\xb31\f\xcbZ,6\x1b\xc3X\xadSScc\x16\xcb\xe8\xe8\xf8x>/\x8a\x97/\xbf\xfc\xf2\xceN>\x1f\x0eol\xccͥӋ\x8b\x8f\x1f\x87Õ\xca\xda\xda\xca\n\x9cw\x0f\xf5\a\x12O\x1cA\x80[h'`\xea\x00\xda\x0fXS\x80F\x06\xd0e\xb205\x80\xb3\xc7h\x84\n7\f\xa8S{ܾ\xa8\x1aG\xe0\xd4\x03\xffqG\xd0_\x98\x14@\xaf\xd6'v\xcbx\xa0O\x02A\x14-4i|\xf4լ\xbfU\xa78\xea\x87\xf9\xa8\xad\xeeW\a\xfc\x04\x01Bk\xcd9W\xb0_\xc9\x13k\x06\xfe֞>\x0e\xf0eO\xbeqk\xb5B\xc3l4\xda\xedSS\x0e\xc7\xc0\xc0\xd8\xd8[o\x8d\x8cx\xbd\xfd\xfd\xe7\xcf_\xbdʲ\x1cg\xb7\x0f\r\x19\f\x00r\x9b\xa332=ju\x87\xabUI\x12\xc5b\xb1Z\xadT\x8a\xc5\\N\x14\x05!\x1eO&\x8bEAH$\xf6\xf7A\xe8\x1d\xbc\x8e\xc7A\xb6>\x97\xcbf\xab\xd5b1\x9b\x15E\xb0\xadV\xc1\xe7a \xbfV\xe38\x97+\x18\xa4i\x83\x81ax\x1e\x18c\x9a\xa6i\x86\xa1(\x965\x1aY\x96e\xadV\x93\x89\xa6M&\x97\x8b\xe3X\x96\xe3l6\x8f\x87\xe3L&\xa7\xd3\xeb\xa5(\xa3\xd1\xe1\xb0\xdbAj\xc2b\x01S\xc7x\x1e\xd0\x06h\xf0['$H\xd2h\xe48\x86\xb1ن\x87\xdd\xee\xc1\xc1+W\x82A\x87\xa3\xbf\xff\xec\xd9D\"\x9f?u\xea\xed\xb7\xe7\xe7c\xb1\xad\xad;w\xe6\xe7\x13\x89\xd5Տ>:<\xac\xd5$\xa9P\xc8倁\x84\x86[6\xe0\x8d\x86\\6\xdcp=\xb4\xeb\x00\x00 \x00IDAT\xd0`7\x86x\xa1\x1e\xc85\x05\xad\xf5X\xed\xf3\xdb\\\xa5ߨ_\xa8\x87\x8f\xd3+\x8b\x05\xea\x13|\xcd\xf3##\xb3\xb3.\x97\xc7s\xfa\xf4\xf5\xeb\x13\x13Vk085u\xf5*E\xf1\xbc\xc9\x04\"F \xa2 \xc3\x06\x95\xdaݭT\xd2\xe9d2\x9b-\x97s\xb9T*\x97\x13\xc5B!\x97\xcb\xe7\xab\xd5BA\x10D\xb1Z-\x14\n\x05I\x029}I\x82\xa5\xa6\x1c\xe7\xf1\xf8\xfd4M\x92\fCQ\x00\xec)\x8aeI\x92ey\xdeh\xa4i\x93\xc9l6\x1a\x19\xc6j\xb5Xx\x9e\xa2\x8cF\x8b%\x10`Y\xbb\xddnw\xb9H\xd2h\x04\xa9.\x8ecY@ )\x8a\xe3\xea\t\r\xb4r0\xf2\t\xd2`$i0X,,\xebp8\x1c\xd3\xd3,k\xb7\x9f??1a\xb3MNNLD\"\xf9\xfc\xeen8|\xff~2\xf9\xf4\xe9\x93'++\xa5\xd2\xfc\xfc\x93'\xf18Џl\xb6Q\x9fr\xb9\xc6\xfb\x06\x89\x1b\x1a\x81\x82\xc7\xd3x\xc5e\xbb$I\xb0&\xa0\xb3\x8e\x862\x11h\xbdl\xb07\xe3\xd5aL\xa3Q뛭\xb7\xf6\x14v\xaf\xd7\xf5w\xdf\x10\xe8\x05)\x02\xec\x9eh\xd4g\x15\xebի\x15\xecv\xde\x01K\xed\xd4>\x1c\xf0\xe3\x15\x14\x9a\xa1֡\u007f\xf8\x0e\xa5\x90\u007fs\x88_\xc9\xe3o\xed\xe9\xa3ES\xd0@\xa3\x06\xd9f\x83\xc0\xcfqf\xf3Ȉ\xc3\x11\fNN\xbe\xf3\xce\xe8\xa8\xc7\xd3\xdf\u007f\xf1\xe2+\xaf\xb0,\xcf\xdb\xed\xc1 \b\x98C\x03\"\x03}\xbd\xc7\x03@\x1exR\x92T\xa9\x14\x8b\xd9l\xa9\x94\xcdF\"\a\a\xd9l*\xb5\xbd\xbd\xb6\x96\xc9$\x12\x1b\x1b\x87\x87\xe9t4\xba\xb2\x92N\x17\n\x85\xc2\xd6\x16\xf0xE\x11׀\t7lIփ\\N\x10\xd6֔\xaa\x8b\x1b\x01\xcd`\xa0i\x83\xc1``\x18\x9a\xe68\x9e\x1f\x180\x1a\xadV\x9foj\xcaj5\x9b\x9d\xce\xe1a\xaf\xd7lv:\x83\xc1\xe1a\x8e\xb3\xdb\xfb\xfb\a\ai\x9ae\xcdf\x87\x03\xa6\x0eP\xad\x86\xa1`\x90\x81\xf6xl6\xaf\xf7ԩ7\xde0\x9b]\xae\xe1\xe1\x8b\x17\xbdޑ\x91W^y\xf2$\x1a\xddܼ}{n.\x91X]\xfd\xf0C@\bJ%\b\xa0\xa0ص\xbe\xf8\x12\x18J\x18\xe2\x85\xe7!\x87v\x1bSA\xe8\xf5R\xfb|\xa2U\xd8͞~cH\xbf\x19\xf0\x1b\xf5\xcaf㸡\xa1s\xe7\\.\xafwf\xe6\xb5\xd7&'m\xb6`pj\xea\xda5\x00\x9c}}0\xc2R\u007f\x97\x1bs\xf2\xf0\xff\xabUQ\xacT\xaa\xd5r\xb9PH\xa7K\xa5x<\x12\xd9\xd9\x11\x84htwwc#\x9f?<\xdcގD\x04aww}=\x9b\xadV\xb3\xd9H\xa4P\x00\xb9x\xa5\xe5\xbc\xf8V\xb5\xa2xx\xb8\xbe\xae\xb6Z\x1dF\x9eh\x1a\x10H\x9a\xa6i\xbf\u007fp\xd0l6\x1a\a\x06\x06\a\xadV\xa3\xd1\xef\xef\xeb\xf3\xfby\xde\xe7\v\x04FGY\xd6\xe5r8\xfa\xfb)\x8a\xe3\x18\xc6j5\x18(\x8a$i\xba9\x82@\x92\xb5\x1aMS\x94\xd9\xcc\xf3\xfd\xfdV\xeb\xe4\xe4\xe4\xe4\xfb\xef\x9bL\xc1`0\x18\x89\b¹sg\xcf\u07bf\x9fL>y\xf2\xe4ɳg\xa5\xd2\xfc\xfc\xfc|,\x06\x89Y#1\x80[tY%$\x04\xcd}CP\" '?@$\x00\xe7 \xb5ohU\xef\x02\xb5#\x02j\xed|c\xec\xb8Q\xfb\x9bS?Ǘ\xd3?\xb9\xe2\xc0\x13.\x02<\xde\x10G}\x00\xa7ucW\xad\xeb\xeb\xb5n;\xf5\xf8\x1b\xcdo\xb3\xa7\x8f\x12\x00\x19\xf0\x1b=\xfe\xe6ڀ\xd6\xc5V\xe8\xb29\\q\x95\xec\xd97n\xedv\x83\xc1``Y\xbb=\x18߹s\x04A\xd3$\t>\xdfh\xee\xe5\xb0'X\x87!\b\xf9|<\x9e\xcb\xed\xedml<~\x9cH,/?z\xb4\xbc\x9cϯ\xad\xcd\xcd%\x12\xb5Z\xb5Z*5\x17Mj\x03~\xdc\xcc\x0e\xad\x91\x12\xb5z\x85\xeaS=\xb1\xaaV+\x15\x96\xadT67WVR\xa9Dbsse%\x12I$h\x9aeWVx~zzz\xda\xe5\xb2ۧ\xa7\xa7\xa7'&\xcc\xe6Phh\xe8\xdc9\x8a2\x99x\xde\xe3\x01\x91\x02\x90\x12\x92\x8f\x9e$)\xcal渾>\x9b\xed\xf4\xe9\xc9\xc9_\xfd\xcad\n\x06\xfb\xfb77S\xa9\xf9\xf9\xc5\xc5[\xb7\xd2\xe9/\xbe\xf8\xeb_77k\xb5R\xa9\\\x86\xa9Ax\xbfAD\xcc`\x80\xf6Fy\xfac\xebFU\xb8\xa1C\xb8N\x83J},\xd46\xb6j\xf4\xfcq\x13Xz7>\xfd\xf9\xe3%}\xbc\x00~\xb2'\x8a\xaa\x1c\xeau*\xb7\xd4\xed\xdc\xe3o\xa7P\xea[\xae6\x87\xf8q\x11\x80\xc6\\\x18\xbe\xe7y\xa3AA\x1b\xa2@Ìz\xfa\xd00;\x1c\xe0\xae8\x9d\xc3Ó\x93\xff\xe6\xdf\f\x0f\x0f\x0e\x8e\x8c\xbc\xfe\xfa͛\xa0\xca}x\x18\xfa\xa7\xf2\x83\xdb\x18o\xa9VE\xb1P\xc8d\xb2\xd9x|c\xe3ɓ\xfd\xfd\xad\xad\xaf\xbf~\xf2$\x1298\xf8\xfa\xebX\f\x9c#ZĦ\xd5@+\x01\xbe\xd20%\xb5!9\xa5\xcec8Bк\x88R\x14y>\x97\x8b\xc5\x1e>\xccf\xc16\x1egY\xb3yddu\xd5\xe7\x1b\x1b{\xfd\xf5`\xd0\xed\x0e\x06gg/_\xe68\x9b\xcd\xeb\x1d\x1a\x02\xb1\x00\x86i\\\x83O\x92\f\xc3\xf3\x16\xcb\xc0\x80\xd7;:z\xed\xdao~c\xb5z\xbdcc\x8b\x8b\xfb\xfbϞ}\xf2\xc9W_%\x12\xcb\xcb\u007f\xf9\xcb\xde^\xe3q\xe0Z-Ú\x05\xa0_\xf2u\xc65vA\xcf\x13\x02?Z\xbc'\xeb\x15I\x9aL.\x97\xd3\x19\b\\\xbb\xf6\xfe\xfb\x93\x93.\xd7\xf8\xf8\xec\xec͛\xa0[\x83\xdf_O\xdfaa^}\xe0W\x14\v\x05A\x88\xc7s\xb9pxu\xf5ѣh\xf4\xe9\xd3;w\x9e=+\x14\xc2\xe1\xf9y\xd0\xc9M\xae}@\x97\xbd\xa1\x91$\xad\x11$\xa5\x10\xb3\xd6T\xa6Z\xbd\xc2u0\xac'\\\xa2X.\xf3|\xb18?\xff\xf8q&\x03\xb6GG4\x1d\n\r\x0f\xcf\xcf;\x1c\x17.\x9c;71a\xb5NL\x8c\x8e^\xbaD\xd3V\xab\xd1\xe8\xf3\x81Ȋ\xbc\xf2\x1d\xfc?M\xc3U\an\xf7\xcb/_\xbc\xd8\xd7g2\r\x0e\xf6\xf5ݻ\x17\x8bݾ}\xf7\xee\xbd{\xe5\xf2\xb3gkk\xf0\xf7\xe5\x86M\xe8\x82\xc1\xf6\xb5M\xe82U\xdc\xcc\x02%\xbb\xda\v\x87\r\x1f\xeaמ\x028i\x0f\xff\xd8\xc7\x01\xbf\xb8\x82[Ӎۯ%\xa9\xa0\xfe\x1bԇ\xfc\xbbے$\f\xfd\xab\x03 \xb4a\n\n\xfc\xb2'\x06\xb6N'ðl \xe0v\x9f:u\xf6\xec\xbf\xfd\xb7\xe7\xcf{<~\xff\xcc\xcc\xdbo\x83j}\x87\x03\xa5S\xf2x\x8dj\xb5T*\x95\xf2\xf9Tjggi\xe9\xe0`k\xeb\xf6\xedo\xbf\xdd\xdb\xdb\xd9\xf9\xf4Ӄ\x83F\xc0\xc7\x01?\xdcv\n\xf8\xbd\n\xd6im`\x85K\x19(\x19n\xb9֢\\\xce\xe777\xf3\xf9\xdd\xdd'O673\x99Hdm\xed֭\xed\xed@`j\xea'?\x19\x1d\x05!\xffk\xd7\xc0\xba\xf5@\x00T\x9a\xcb\xf5\xd4\xc0\x90s\x9c\xd1h\xb7\xfb\xfd\x17.\x84B\xb3\xb3\xbf\xfeu\u007f\xbf\xc5\xe2v\x0f\x0e~\xf2\xc9\xee\xeeÇ\xff\xdf\xff\xb7\xb4$I\xa5R<\x8e\v٢[\x14\x18\xd1\xf3\xc5\x01?J(\x9dN\x8e\x1b\x18\x98\x9e\xf6x\x06\a\xaf]{\xff\xfd\xabW-\x16\xbf?\x14\xbav\xcd`\x80\xcb\xf2\xc0\x92<ԏ\xabV+\x95R)\x9f\xcf\xe7\x0f\x0e\xc2\xe1Ǐ\xa3\xd1Ǐ\xbf\xf9fn.\x97[]\xbd\u007f\x1ft\xf8\x94WC(\x11J\x9c^u:\x94\xeb\xa4\xf5\n}\xce\xd1N\x86h\r\x0fϋb8\xbc\xb5\x95\xcf\xc7b\xe1\xf0\xd6V:\x9dJ\x85B\xa1\xd0ښ\xd3y\xe5\xca\xec\xec\xe9\xd3V\xeb\xc4D(t\xe9\x12E\x19\x8d\x1c\xe7r\xa1\xc7I\x92,K\x92\x16\x8b\xd9<<\xdc\xd7\xf7\xc6\x1b,\xebv\xbf\xf3N(\x94H\f\f\xf8|\x1f}\x94\xc9|\xf6\xd97\xdfll\xc05\x15h\xa8\x1f]\xb6WS\x90\xf6\xcbX\xb5y\xf4Z\xefW\xeb\x1a\x80np\xa4׳tz'\x94\xd1h4\x1a\x8dZ\xe7\x11k\x9dڧ\xa4\xc08\x86\xdb\xdc\xe2\x15\xb7\xa5i\x820\x9b}>\x8a\"\b\xb3\xf9\x95W\xea\xff\x0e\x83\x98\xa2\xb8\xb0 \x8a\x04\x11\x8f\xaf\xac\xb4\x0e\xe9u\xbaU^\x96\xd2z\xca\x19\xbe\xb1O\xebb>\xb4S\x1a\xba\xcc\n\xb7\xae\x1a\x05\xfef\xc3\f\xb6n\xb7\xcd\xe6p\xcc\xcc\x04\x0233\x17.\xfc\x87\xff\xf0\xc6\x1bn\xb7\xd7{\xea\xd4[o\xd14E\x81\xf5\xf8\xadc\x16\x95J\xa1\x90NG\"\x00\xf0?\xfexiin\xee\xef\xfe\xee\u07bdT*\x9d^\\<<\x04\xef\x84ˎ@\xa7-\xb9X\r\xad^G\r7\xea\xa9\xe1\x88\x00\xee\x81\xeft\x16\x85Vb\x88[\x97\xac4-\x12\xadi\x90ϷZ\xadT\xd2\xe9r9\x9d>8\x98\x9bK&s\xb9Xlwws\x93a\x18\xc6d*\x95@\xe5\x80\xdb\r\xd6,\x80\xfb\\\x1f\x1d I\x9af\x18\x8b\x05\xa4\b\xc6\xc7-\x16\x9fol\x8c$s\xb9t:\x16K$\xaaUA\x88F\x95\x00\x10\xf5T\xd1\x1c?\x1a\xe2o\xa5W\xd3\xd3ׯ\x0f\x0e\x06\x83\xaf\xbe\xfa\xeb_\xff\xecgf\xb3\xc730p\xf92(\xa4\xe48Y\x87\xe5\x069ժ$\x95˩T<\x1e\x0eG\xa3\xdf}\xf7\xd5W\x1f~\xb8\xbf\xff\xd9g\xff\xf0\x0fss\xe5r<\xbe\xb3\x03k\x1d\xa0^\xc1-\xd4+X\xac\x06\xf5\n%\x98\xbd֫N\x87\xc0\xa8u$p\xf6\n\xa7_\xf8\xad$\xa5\xd3\xe9t\xb1(\b\x8b\x8bKK\x91H\xa1\x90\xcd\xe6\xf3[[\fc\xb5\x9aL \x15`4\xba\\\xa0\xd7\x05M7zȠ\xbe\x87\xa6].\xa3qp\xd0\xef\x1f\x1f\xa7\xe9\xbe>\x8fG\x10\n\x85\x9d\x9d\xfd\xfdt\xbaV+\x16\xcbe\\\x8bl\x94\x10\xa0\xfd\x02\xd0V\xc1rD\xa1\xf1us\rE\xeb\xfd\xb8m+|r8x~|\x9c X\x96\xa2Νk\\A%I\x04Q,\x96\xcbw\xef\x12\x84 T*\xc0\xaeu\x8f\x1fjqDk\xcaY\x99\xb2\x1c\x13\x01P\xda\xe2\x80_\xed\xfe\xd6\x04\xc0d\xf2\xf9\x00\x11h$\x00\xf0\x12T*O\x9fV*\x04\x91H@\x02\xa0\xd4\xca\x175\x8c\xb8\\ \n\xf48\x03\xd2\\$\xa8\xad\x8a\x1f\xb7\xbe\xba\xd9\x13h\xbd\xae\x1a\x05~\xc8\xf4\xddn\x9f\xcf\xef\xbfvm`\xe0\xf4陙\xdf\xfe\xf6\xa7?\xb5Zm\xb6\xc1\xc1˗\xc1\xe3\xc40\xf2\xe2\x189\xf3*\x8a\x95J6\x9bHln\xceϯ\xad-,\xfc\xfe\xf7\x1f}\xb4\xbd\xbd\xbd\xfd\xc1\a\x1b\x1b\x92T\xab\x95JpZ\x96\x92a\xc6\x01>j\x90q\x06Xk\x0e\x15\x1d*\x84\xbeVK@\xd5\x0e\x19R\xea$\xa9~\xbct\xb9,\bGG\xa5R2\xb9\xb3\xf3\xed\xb7\x91H\xb5Z\xa9\x88\xe2\xde\x1eϛ͠e-\xf0\xfe\x9b\x8b\xbeH\x92$\x19\x86\xe3,\x16\xa73\x14\xb2\xd9|\xbe\x91\x11\xa31\x99\xdc\xdf_]\xddݕ\xa4R)\x9d\xc6\x19$T\xdf\xe0\xf5\x82\xfa\x05#I0\xb7/\x03\xbf\xcbu\xf1\xe2\xbb\xef\x0e\x0f\x0f\x0e^\xb9\xf2\xde{\xbf\xfc%\xcb\xdal\x0e\xc7\xe4$\xec\xab\xdf\xe8-\x12\x04XFW(d\xb3\xe1\xf0\xea\xea\xbd{\xdb۟\u007f\xfe\xcf\xff\xfc\xd9g\x99\xcc\xf2\xf2\xbd{;;@\xf3pz%7Pj\xd4+\xd4\xf3G\x9fc\xb5z\x85\xd3'\xad[\xb5\x80\xa4D\x10\xd4v(\xc5\x11\x03Y\xcfD\xf1\xf00\x12)\x16s\xb9\xf9\xf9\xa5\xa5\xdd]Ib\x18\x9a\x8eFY\xd6\xe3\xb1\xdb=\x1e\x8a\xe28\x8a2\x9b\t\x82\xa2@+-P\x93B\x924M\x10F#\xc3x\xbdv\xfb\xf88\x88\x1b\nB>\xff\xe4\xc9\xeaj$\x02\xe8\x1cn\xa6\x85L\x10\xd0Ví\xc7d7\x13\x01\xf4:\xc2\x1a\x84\xd6\xd7U\r\x9e8\x9d\x1c7>\x0ejOΝk\x84YI\"\x88B\xa1R\x01\x04@\x14u\x02\xd0#\x02\xd0\xfd\x16F\x00 \x01\x90;\xb6A\xc3\x02\"\x00\x8d\x04\xa0w\xad}Ն\xa6\x95Z\xf3\xc2뉮\xe7o]\xe4\xd7\flZ\x81\xbf\xbf\xbf\xbf\xffƍ\xa1\xa1\xa9\xa9\xe9\xe9\xf7\xdf\xff\x9b\xbf1\x9bM&\xb7\xfb\xf4i\xf0p\x81ߩ\xf7\x03\xe1\xfa\xfbHdg\xe7\xdbo?\xff|q\xf1\xf1\xe3\xff\xfd\xbf\xef\xdc\xc9dr\xb9\xb5\xb5\xa3\xa3FÌz\xfa\x10\xf0\xa1\x81F\r3n\xf9\x99r\xa4\xa39\x17\xdaj\x8b\x16\xc3\xc9!\xd2\xc6\xfd\xe8\xf7\xe0\x87ƴ7,j==\xb5\x9e]#!\x92$Q\xcc\xe7\xe3\xf1\x95\x15AH\xa7\x8f\x8e\xb6\xb6vw\x01\xfcK\x12˚\xcdN\xa7\xd7\vB\xeb\xb0G= \x02\xc0l\xf3\xbc\xd9\xec\xf7\x83F5\x87\x87\xe9\xf4\xf6\xf6\xdc\x1c\xbco(@\xfe?sA\xb5\x0e\xf5\xa3\xc0\xefry\xbdW\xae\xfc\xfc磣\x03\x03/\xbd\xf4\xd6[\u007f\xf37\fc2\x81*~ؘ[\xee\xb8\b\x9eMA\xc8\xe5\xe2\xf1ht~\xfeΝ\u007f\xfd\u05fd\xbdO?\xfd\xdd\xef\x1e=\x12\xc5\\.\x16\x83\xcb\xd1P\xbd\xc2\x11I\x1c\x81D\t\x8dҲE4\xa4\xdeܡ\xb0\xbd\x9e\xe1\xf4\n\xfd\x1e\x9c^\xa1S\n\x95\b\xa7\xdaΥ\xed\bg\xb5Z\xadV\xab\xc5\xe2\xda\xda\xd6V&S(\xa4R\xd9\xec\xce\x0eø\\6\x1b\xcfӴ\xd5ʲn\xb7l\x1f`\xc1(I\x82\x05\xb16\x9b\xd9\xdc\xd7'\x8a\x92$\x8akk\xe5\xf2\xe6\xe6\xc1A6\v\x1bR\xc1!D\x8dð\xe4aC\x8d[%\xc1㋶H@\xfd\xf5u8\x00\x01`\x18@\x00\xea\xeb\x18@\x04\x00\x10\x80|^'\x00/\x10\x01`\x18\x99\x00\x98L\xadS\x00\x95\n \x00\xc9d\xafR\x00j[\x00\xe3\x8bUZ\x03\xbd\xbc\x85\xed3\xda{\xb8\x00\xf8\xf1U\xd7\xcd\xc0?0\xd0\xdf\u007f\xe3F08555\xf5\xf3\x9f\xff\xeaW\x8c\xc5\f\x06\x8a\xe2\xf9T\xcaht8|>\xbf\x9f$Y\x164&\x92\x89\x80$Q\x14˚LV\xabŒH\xecﯭ\xad\xacHR\xa1\x90L\xe2r\xfe\xf0|\xe0\xf9Cb\t\x8aE\t\xc2\xe5\xf2\xf9^~\xf9\xfd\xf7GG\xfb\xfa.\\\xb8q㗿\xa4i\x9e\xe7\xf9\xbe>\xf9\xec@\x8e\x1f\x00\u007f\xadV.g2\xf1\xf8\xee\xee\xfe\xfeݻ\x9f|\xf2\xe7?\xc7b\xf7\xef\u007f\xf8\xe1\xfaz\xa3\xa7\x8f\xd3+\x9c\x87\x8f\x8b\x18\xe1\"f8\xe0Ʒ\xb2\xeeN\xaf\xd0Y\x05J\x84\x01\xa7W\xc7\x1d1\x90\xa4j5\x12\x89\xc7+\x95\\ne%\x1c>8 I\xab\xd5l.\x958\xce\xed\x06\xad\xbaA\xf3,\xd9bд\xc1\xc0\xf3\x14e2q\\\xa9\x94\xcb=~\xbc\xba\xba\xb9\t\x12:͵\x180\"\x80\x0e\x15B\x89\x00\x0eOڧ\x02Ԧ\x00\xea_;\x9d\f\xd3>\x02 \x8a\xbd&\x00Zq\xa4w\x04\xe0\aS\x04(\x87:q\x95\xff\xadk\xee\xb5\xffBw\xc5\x18\xad=\xfe\xe61\xbd\xad;\xf9\xb5n\xe0\x03\r\x85\xec\xf9\xa3\x9e\x99l\xa0\xfd~\xbf\xff\xeaՁ\x81\xc9\xc9\xc9\xc9w\xdf}\xff}\x9e\xe78\xabut\x14\xae\xa1h\x9c\x0f@\x10\xa5\x92 $\x93{{\xeb뫫\x9f~\xfa\xe1\x87\xe1\xf0\xde\xdeg\x9fmo\xab\x03|\\\xe8\x15\a\xf88\x03\x8d\x1aB\xf5c]\xe1V\x1e\x0fL\x104\r<\x04y\x8c+\x8c\x125\xde\x0f8\xa2\x05\x8e֩V\xc1\x03\xdaj.{\xe3y\xe2\xfa\x14\xe0r\xceJ9x\xf89e\x0f\x01̈#ɽ\xbd\xb9\xb9\xbf\xff\xfb\xf5\xf5J\xa5XL\xa5\xaaա\xa1\x97^\xfa\xe9Oo\xde$I\x8e3\x1a\xc1l\x85Z\x8d \x18\xc6h4\x99\x06\a\xbdޱ\xb1\xd9ف\x81\xfd\xfdx|c\x03z\xd6\xf0w\xd1\x16\xac\xf0zC\x82\xe9px\xbf\xb9\xf9\xe4\t4\xa8j\x01\x1f\x97\"\xc2\x01F\xf38iu\xfa\x84\xae\x9a\x80s\xe1A\xbf\x06\xb0\x9c\x0et\x8f\x84\xe0Ӻ\x13I}\x9a\xb0~}O\xb5\n\x17ɪ\xcb\xe9+\xf5\xc1\xc0\xe9\x95|\a\xd4E\f\xea#\x97\xe9t&C\x10\xb1\xd8?\xfe\xe3G\x1f=~,I\x95\xca\x1boT*.\xd7\xe5˧N\xbd\xf5\x16x\xba\x18\x06\\i\x83\x81\xe3|>\xbb\xfd\xfcy\x8e;\u007f~t\xf4\xeb\xafK\xa5o\xbf]Y\x81\x8e\x82\x1c\xd9h=\xee\x19\x8dԜ\x04r(U`\xe0g9|\x9f\xe5\aG\x00\xea\x89@\xbdqG\x89\xc1\xc9\x1dS\xbb\x8e|ʝ\xfc\xd4\x00\xa4\x9a\"?\x97\xcbn?s\xc6\uf7de\x9e\x9c\xfc\xe9O\u007f\xfaS\xd0`\x14x\xfc\xf2\xc0d\xf8\xdfZ\xadX\xcc\xe5b\xb1\x9d\x9d\x95\x95g\xcf\xfe\xf2\x97\x0f>\xd8ۋ\xc5\xee݃\xcb\xc8p\xb9W\x9c\x81\xc6\x15\x93\xe1\x96˩\r\xa9\xf2<0\xc3\x1cg\xb3\x99Lcc\x16\x8b\xd5\xeav\x8f\x8e\xda\xedf\xb3\xd9\xec\xf7\xbb\\`=\xbd\xc3\xc1\xb2\fc2\xf9\xfd\x14\xc50f\xb3\xc9D\x92\x1cg2\x81)o\fS\xdfJ\x19\xde\x0fQ,\x16\xc1,6\xd0P\xb8R\x11\x84d\x12\xccd\x8bD\n\x85\\\xee\xe8(\x95\xca\xe5R\xa9\xbd\xbdd2\x9d\x8eǟ>\xcdd\xaaUI\x12\x04t\xf9\"nY\xa3\xd2r4\x9c\xe1\x86\u007f\xc7\xe9\x87\f\\\x91ȳg\x1f~xxh\xb7\xf7\xf5\x8d\x8e\xae\xac8\x9d\xa3\xa3g\xcf\xce\xce\xcaT\x87\xa2\f\x06\x8e\xe3y\x87\xc3\xeb\xf5\xf9\xc0\xdep\xb85\x01\x80\x9f\x92#\x00N\xe7\x993\xaf\xbe:008x\xf1\xe2\xeb\xaf\xff\xecg\x14\xc5\xf3<\x1f\b\xc0\xb4[}\xff\x02\x10-:<\xdc\xdd]X\xd8ܼu\xeb\x0f\u007f\xf8\xec\xb3R\xe9\xf0pc\x03-\xe6C\xf5\n\xbd~Jz\x85K\x11\xa9M\tq\x1cXn\xc9q\xba{ws\xd3b\x19\x1b\xeb\xeb;<\xe48\x9f\xcff\x1b\x1a\x92c-4m0\xd8l<\xef\xf7;\x1cN'\x987\b\x1b\a\xe1#c\xad\x89@o\x01\xbe\xbdȱ\xcf\xce[\x01\xeb\x04\xe0\x85 \x02\xa8*w\xbf\f\xb0\xfb\xd6Ÿq\xbc\xad\xab\xfbq\xbd\xd5\xd1\xf5\xfc\xd0p\xa1\x8dV\x1c\x0e\xa3\x91\xe3\x06\x06<\x9eӧO\x9d\xfa\xe5/\xdfx\xc3l\xe68\xb7\xfb\xf4i\x00&\xc0\xe3\xafW\xecbQ\x10b\xb1\xed\xed\xa5\xa5\x85\x85?\xfc\xe1/\u007f98H&\xe7\xe6\xf6\xf7[\xe7`Q\xe0Gs\xaf(\x93G\x1f|\\N\x15\r\xe9\x1b\x8d\xa0\xff\x9b\xc9\xe4\xf5z<\x97/\xbb\xddN\xa7\xcf7558h\xb39\x1c\xa1\xd0\xf44˚Ln\xb7\xdf\x0f&\f\x98͠\xfe\x1d\x18\x1c\xb0LN^S\x8eޫ\xd6cn\r\x06\xab\x15l\xbd^\xf9\x88\xeaI\x02\x18\x03#\x8a\xe52\xe8!\x9f\xcf\xc7\xe3\xa0e\xf1\xcaJ&\x13\x8b\xad\xad\x85\xc3\xd1\xe8\xf6\xf6\xbd{\x91H\xa5\"\x8a\x89D\xf3О\xc6-Z\x04\t\xb7\xb8\xa2R\x94\x10\xb4\x06\x04\x10h\x8fD\xd6\xd6\xf6\xf7\x9d\xce\xe1ᩩs\xe7\xc0\x80\"\x9a\x96\xef\f\xc30\fl\xe4\x04\x1b\xef\xc0\uf144\x02\xea\xa7\xc9d6\x0f\x0f\x9f=\xeb\xf1\f\r]\xbe\xfc\xd6[?\xf9\t\x88$\xf4\xf7ã\x84i+\xd8\xcbB\x10\xf6\xf7\xc3ᅅ\xcd\xcd\xcf?\xff\x97\u007f\xf9\xf4\xd3r9\x16\xdb\xdeF\x81\x1f\xea\x15.\xa7\x8fz\xa68\"\xd9\xdc\xd9\x12\xa7W`ɤ\xd9l\xb7\x9f={\xf6\xac\xd7k\xb5\x86BCC\xc1\xa0\xc9\xd4\xdf\xef\xf7\x9f:E\xd3f\xb3\xc9\xe4\xf5\x92$˂\xa1B\x14e00L\xe3\xb0\xf1FO\x11\x9d&YoE(\xcaj\x051;\xa0_r\xa1\xa6l\t\xc0\x18\xe0R\xa9\\\x16\x84J%\x9b\x15\x84HD\x10\xf6\xf7\x0f\x0f\x97\x962\x99\xf5\xf5\x9d\x9d\x9d\x1dAx\xfcxy9\x1e\xaf\xd5*\x15QD\xfb\x1c4\x8f\xfbm\x9f*A#\x00\xe8\xea\x14T\xaf\x8a\xc5Z-\x9f/\x16\x8bEA\xd8\xdd=<\\_\xe78\xbf\xdfb\x19\x1a\xaa\xf7\x90%\x89$)\x8a\xe7\xc1uS\x93\x12\xc3\xdbK\xb4(\xf08#\x04\xed\x87\x01\xe9\x11\x80\x17R\xea=}\x18ʭ\xdf\xd7]\xe8_\xf9\xf3\xad\xc7\xeb\xe2#\x00\xf5\xef\xaa\a\xfe\xd6U\xffJ=\xfb\x9b\xd7]\x83\x0e\xe9N\xe7\xcc\xcc\xe4\xe4/~1;k\xb7[,\x81\xc0\xe5\xcb\xe0\x17\xea\as\x82s\x01\xc3tvw\x97\x97\x97\x96\xfe\xfc\xe7\x0f>\x00\xc0\x8fz\xfcj\x81\x1f5\xd08\x0f\x1f\x9f\xbb\xe7y\x86\xf1\xfbm\xb6\x81\x81`\xf0\xfa\xf5\xa1!\x8f\xc7盞~\xe9%\x8e\xb3X\xfc\xfe`\x10\x00\xbd\xc5\x02\xe0\x1d\x16\x94\xb5\x06\xf4\xc6\x16\xd1h\x94\b2\xfbF\xc3\r{\xdcA\x1d\x02\x03V\xea\x1bM\x83\x16\xa8\x14Ų\f\xc30\xa0/\x9f\xcdƲV\xab\xd392\xe2r\xf5\xf7OO\x17\n\xfd\xfd\xa7Nݸ\x11\x89\xa4RGG++ss\xd1\xe8\xf6\xf6\xfd\xfb\x1b\x1b\xe9t,\x06\x1b\xd64\x8f\xf9E\r8\x8eX\xa1\x03V\xf1\xb9\xder\xb9P\xc8d\n\x058\r\xd1`\xa0i\x9a\x06\xa1l\x99ؠ\xd5\xfdhH\x9aah\xdan\xf7\xfb\xad\xd6`\xf0\xe5\x97o\u07bcv\x8d\xe3\xacV\xbb}t\x14\xe4\xf4e@\x04\xcfa\xad&\b\x91\xc8\xfe\xfe\xd2\xd2\xd6\x16\xf0\xf8\x1b\x81\x1f\xcd\xf1\xa3\xc0\x8f\xcb\xe9\xe3\x96#\xe2\x80^\xce\xcds\xdc\xe0\xe0А\xc3\xe1v\x9f;w\xf6\xecȈ\xcd66622;\v\x8a\xd7\xfa\xfbI\x92ah\xdahD\xc1\x1d\a\x00(\x81\xc6\x03\t\x9c\xf2\x00\xa7\x0e\xd6_wX\x9c\t\xf7q\x1cE\x81e\x9d\x14e6\xdblN'\xc7\xf9\xfdV\xeb\xe4\xa4\xdd>33<\x9cϗ\xcb7n\\\xbc\xb8\xb7\x97ɬ\xac\x84\xc3\x0f\x1f\xa6R\x0f\x1f.-\xed\xec\x88\xe2\xfe~4\n\xafg\xa7z\x85\x1b\x06\xd5\\+P\xad\nB\xa1\x00\x86N\x89bc\xf1^}\xc7\xff\xd6\x11\xab^\x0f\xc7\xe9%\x01\xc0\x0f\x03\xfa!\xc9\x0f4\x05\xd0\xd8'\xad\xfeA;yZ\xa2&%\xd0ܻ\xbf\xf5454'\x89k\xb1\xeapLO\x8f\x8d\xfd\xeaW\x13\x13>\x9f\xcb51\xf1\xd6[`m-\xe8 W\xdfۺR)\x95\xb2٣\xa3\xb5\xb5\xb5\xb5\x8f>\xfa\xe0\x83\xfd\xfdD\xe2\xc1\x03\x1c\xf0\xc3\xdc0\xce3\x93\xfd\x9c\xf6Nj\x16KY,\fCQN\xa7\xcd6<<2\xf2\xf6ۣ\xa3>__߅\v\xaf\xbc²&\x93\xc310`0P\x14ðlk\xea\x85R*Y\x1f\x80\xb1\x05Y|\xb0\x05\xad\x8a\xc0`\xe0R\t\xbc\xa7\\\x06\xef\x030\x0f\n\x9b\xc0Zg0\x96\x87\xe7\xe12:yX\vz\u007feO\x05li\x9a\xa6\x8dF\xb0Z:\x14\xf2\xf9FF\xae\\\x19\x1ar\xb9\x06\x06ΜI$\xd2飣\xe5\xe5G\x8f\x0e\x0f77\xef\xde]XH\xa7\xa3\xd1'O`\xafut\xb5\x04.\xb5\x82\xbb\xde\xcdEb`uu\xfd\x94\xbc\xe6^\xe7\xd5*|?$h\x8dI5\x92両\xa1\xabW\xdf}\xf7\xd4)\xb3\xd9\xe3\t\x04@\x95t#\xa1\x04d\xacXL&\xa3ѭ\xad\xad\xad/\xbf\xfcӟ>\xfb\xacT\x8aD\xc2aа\xa79ԏ\xf3\xf8q\xab\x10pD\x12\x9d1`\xb1\xb0l \xd0\xdf\xeft\xfa|\x97/\xbf\xf4\xd2\xe4\xa4\xdd>116v\xed\x1aM[,F\xa3\xcf\a\xfahe\xa5R)\x97c1\x14 Q\xcf\r\x8d\x04\xa0\x80(\xe7\xb4M&\xbb\xdd\xe7s:An\x1aܟ\xe6\x1c=\xfa=2!\xf5\xfbgg\xdf|\xd3\xebu\xb9\x86\x87''\xc1\xec\x87V\xdfS\xa9\xe4r\x99\xcc\xd1\xd1\xee\xee7\xdf|\xfa駟\x16\n{{kk8\xe0\xc7E\x92\xd0\xd5\ah\xca\b\xa7W6\x1b\x98\x9d`\xb3\xf9|\xaf\xbd\xf6ꫣ\xa3n\xf7ٳg\xceܸ\x01Z\xda\x0e\x0e\x82b58\xbb@\xbe\x8a\xa8'\x0f \xbeR\x91\xa4rY\x14\xb3YQ\x14\x04A8:*\x16\xe3\xf1dr{\xbbTJ$\x92\xc9h\xb4TJ&\x93\xc9t\xbaTJ\xa7s\xb9b\xb1R\xc9d\xb2\xd9J\xa5ZM\xa73\x19\x99\xa8Q\x94\xddn\xb1\xd04M\xdb\xed\x16\vÀ\xc1NF#ǹ\xddv\xbb\xdd\xceq^\xaf\xdd\xee\xf5\xf2\xbc\xc7\xe3p\x84B4m2q\x9c\xcf\a\xa2LV\xabLL\xd1X\x16M\x83\x04\x8e\xd3i4\x0e\x0e\xba\xddW\xaeLN\xfe\xfa\xd76\xdb\xe4\xe4\xc0\xc0\xceN\"17\xb7\xba\xfa\u05ff&\x93\x9f\u007f>7\xb7\xb5U\xab\x95J\xa2\b\xaf\x1f.⢤W\xf2\xaa\x17\x8e\xf3x\xac\xd6@\xc0`\xa0\xa8\xfa\xa8\x86\xec\x86\x01\xca\xdd\xd8\x10\xe8\xb8:,v\x93$\xc6Ez\x9a\v\xbfu\x02\xf0=H\x05\xa8\xdd\u007fR\x11\x00\xa51\xbe\x8d\x9e?\xae\x98\t\xe7\xf1\xd8l4MQV\xab\xc319\x19\n\xbd\xf6ګ\xafr\x1cM\x1b\x8d\x03\x03\xb2G\f\x03ޠ\xa9\xea\xe1\xe1\xc1\xc1\xa3G\xb7n\xad\xae\xee\xee~\xfc\xf1\xc6F#\xf0\xa3\xa1~\x14xp\xc0\xaf4c\xc0f3\x99\x18\xa6\xaf\xcf\xe5\x1a\x1f\x1f\x1f\u007f\xe7\x9d\xf3\xe7\xddn\xbf\u007ff\xe6\xfau\x9af\x18\x93\t\x16-\x82ㄆ\xb9\u07bb\xafV%I\x14s\xb9b\xb1\\N\xa7\xb7\xb7\x93\xc9Dbccq1\x91\x88\xc7\xd7\xd6\xf6\xf7\x93\xc9X\xecٳtZ\x14+\x95d\x12x6\x92\x84\x16C\xe1\xa7\x04V\xab\xb9\\\"a0\x14\x8b\xb9\x1cAP\x14\xb8\x12͍\x96\f\x06\x924\x1a\xef߷X\\\xae\x89\t\xab\xd5\xe5\n\x04\xa6\xa7}>\xbb\xdd\xeb\x1d\x19\x99\x980\x99l6\x9fob\x02\x94\x929\x9dpfBc5\xb1\xc1\x00z\xf8\xfb|~\xff\xd8\xd8\xcb/\xff\xf2\x97v\xbb\xc7\x13\n\xad\xae\xee\xec,/ߺ\xf5\u05ff\xc6b\xdb\xdb\xdf|\x03\xfb+\xe0<6\xf8\x9d\xf0\xfa˞0M\xf3\xbc\xdbm\xb1\xb8\\CC\x93\x93\x13\x13`\xd2 IJ\x12\x8c\x04\x00\r\x01͛\xc1\xf7\xd7\x0fw\xe18\xbf\u007fx\x98\xe3\x02\x81\x99\x99˗/_\xa6i0vVn\xef\x02\x80_\x14\xcb\xe5R)\x9b=8\xf8\xee\xbb;w>\xfb,\x95ZYy\xf4\xe8\xe0\xa05\xa1D\t\r\n<\xcdEg8\xbd\x87[\xa3qxxd\xc4\xe7\xeb\xef\xbf~\xfdڵk\xd7,\x96Ph`\xe0\xe2E\x83\x81e)\n\x86\xf4q\t\x12ж\xaaRI\xa7\x8b\xc5T*\x9d^_\xcf嶷\xf7\xf6VV\xd2\xe9\xcd\xcdp\xf8\xf0\xb0PX[\v\x87\xb3\xd9Z\xadXl\x9eJ\xa9TuO\x10\x92\x94J\xe5rp\xe5;E\x81+\x8dI\xa4\xd9c\x00\x00 \x00IDAT\xae*`Y\x83\xc1b\xe18\x8e3\x1a''\a\am6\xabullp0\x10\xb0X\x86\x87\xfd\xfe\xe9i\x96u:-\x96\xe1a\x92d\x18\x8a\xb2\xd9\xe4\xbe\n\x90pR\x14AP\x14˺\xdd&\xd3\xf0\xb0\xcfw\xe3ƙ3~\xbf\xd9\x1c\fz\xbd\xdf}wt\xf4\xc5\x17\xdf}w\xff~\xb9\xbc\xb2\xb2\xbf\x8f\xa6\xa0P\xbd\x82v\b\xd5+\xb3\x99eϞ\x1d\x1ct:\x8dơ!\x87cd\x04\x92qy\x143\xa0Ԡ\x86\x01\xdew\xedc\xba\x1bs\xff\xed\xb3\xf4\xbdN\x014'\r\xf5\x14\xc0\xf7\x02\xf8[\xcd\x02\xe8\x8c\x00(\x17\xa74\xb3\xc7v\x00\x8f~/\xba\xfc\x0fW\xed\x8f\x16ˡ9\u007f\x9bmz:\x18\xbcysl\xccf3\x99\xbc\xde\v\x17\xc07ʏ\x0f\bMJR*\x95H\xac\xaf?z\xf4\xf4\xe9\xc6\xc6\x1f\xff\xb8\xb0\xd0\xda@+yf\xffO}hu)\t\xbb=\x10p:gg\xfb\xfa\xc6\xc7\xc7\xc6n\xde|\xeb-\xa3\xd1f\xeb뛚\x02\x13\xc8\xc0\xf7ԇ\xdc\xe0\x15\x12EQ\xacT\xd2\xe9L&\x93\xd9\xdd}\xfc\xf8\xe8\xe8\xf0\xf0ɓ\xc5ţ\xa3\xc3ù\xb9hT\x14E1\x1eDž4q\xbdߕ\f\x0f~\xd9%$\x00\xb5\x9a$\x15\n,\x9b\xcd\xc6bO\x9e\xf0<\xd8\x1e\x1d\x19\f$ɲkkv{ p\xfe\xfcݻ>\xdf\xd0Ѕ\v\xa3\xa3\x0e\x87\xcf76\xf6\xd2K\f\xc3qfs__\xfd:e9DL\xd3F#\xa0\x12\xa3\xa3\xb3\xb3\xef\xbf\xef\xf3\x99\xcd\x0e\x87\xcf\xf7\xe5\x97\xdb\xdb\xf3\xf3\u007f\xfa\xd3\xd6\x160\xac\xa8\xa1\x86\"\xdf\ap\x1cV\xeb\xf0\xf0\xcb/\xbf\xf7\xde\xe4\xa4\xd1\xe8ry<\x81\x00\xa5HR\xbb\xa1B\x06\x83\xc1\xe0p\xf4\xf5\xbd\xfd\xf6\x9boNO{\xbd\x17/\xce̼\xf3\x0eM\x1b\x8d<\xefv\xcb\xe7\aW\xa4\xc3\xf4\x86(\x8ab>/\b\x87\x87\x91\xc8w\xdfE\"\x0f\x1e\x1e\n\x05\x83ׯ\xff\xfc\xe74\xcdqV\xab\xc7S\x9f\x1b\x84!>`6\xaa\xd5b1\x918<\x8cF\x17\x17o\xddZ[[_\xff\xf4ӥ\xa5b\xb1T\xda݅\xb9cX\x8b\xa0\xd4\xf3\x1d\x17\x9aU;\xe4\x05\xbd/\xb8\xcea\xb8V\xc4h5\xbaٜ\xcdF\xa3O\x9f\xe6\xf3Ϟ\xc5b\x8b\x8b\xe9t_\xdf\xc4\xc4\xdbo\x87\xc3\xfd\xfd\xe3\xe3W\xaf\xbe\xf1\x06\xcf[,N\xe7\xf8\xb8\\\f\x06{\xad\x83\xba\x01\x87ch\xe8ԩK\x97\xac\xd6@ \x18\x9c\x9e.\x97\v\x85t:\x95\x02k\xcb\x05\x81\xa6)\x8a\xa2\xacV\x86\xb1Xl6\xbb\x9d$A \xb9\xbe]k=\x8d\x03S\x05\xb2\xd9Hdy\xf9ѣp\x18\xdc\x01\x90\x94\xe08\x9a\xee\xef?sfvvl\f\x86\xfc\xe5\xab\a\xbe\xabR)\x16\xf3\xf9Dbo\xefѣ;w\xeeݫV\v\x85L\x06\xbdO\xa8Ǐ\xf30q)\xa4z\xbd\"I\x92t\xb9\x86\x86\xde{\xef\xe6\xcd\xf3\xe7]\xae\xb3g\xa7\xa7oޤ(\x8ec\x18\x8b\xa5\xbe\xc3`\xbd\xaf\x0fr\xf7\xfb\xfb\xd1\xe8\x93'KK\x9f\u007f\x1e\x89|\xf5\xd5ݻ\x9b\x9b\x92\x94\xcf\x17\n\xb8\x96\xc2JフBٸrc\xadc\xa4Q\xbd\xaa_\xdd I\xb5\x9aٜ\xcf߽\xbb\xba\x9a\xcf\v\xc2\xe2b8\x9cHx<7o\x9e?\xbf\xb1\xe1t\xce\xce\x0e\x0f\xbf\xf5\x16M\x9b\xcd\x1c\a\"7\xd0*\xd4j\x04AQf3E\xd9\xed.ץK\xc1\xe0\x1bo\xd8l\xa7O\xfb\xfd\xb3\xb3\x95J6[,&\x93 s_.\x93$DZ\xac\xdd\xce06\x1b\xc79\x1c\x06\x03˒$\xcf\xcb}\x1e\x1a\xa5Z\x15\x84bqk+\x91\xb8{w}}q\x11\xe8\xb3\xfc\xbc\x82ץ\x12\xda\n\x18\x8d\x00\xa0S\xff\x1a;\x04\xe2R\x03Zr\xfd\xda?\xa5\xaf\x028\xc6\x1cy\xaf<\xffV\x11\x80\xfa\x82\xb1\xeeIF;\xa0W\xaa\xfaW\x9a\xfa\u05fa\xc5os\x87?\x8b%\x10\xb0\xd9Μq\xbb\xfd~\x87#\x14\xbav\x8d$\tB\x92\x00q\xa8?\xf3d2\x91\xd8ܜ\x9b[Y98\x90C\xb3(\x90\xa2\x9e\x0en\xb9\x99\x12\xf0;\x1cSS\x83\x83\xef\xbd71\x11\f\x86Bׯ\xff\xe2\x174\rZ\xf1\xa0\x01Q\xe8\xf5\x17\x8b\x85B&\xb3\xb9\xb9\xb9\xb9\xbb{\xe7\xceg\x9fmm\xed\xec|\xf2\t\xe84(I\xb8bD\xad\xc0\xaf\xb6E\xb3R$G\xb9%s#a\x83\xdb\xfaeX\xb5\x9a$\t\xc2\xc1\xc1\xca\xca'\x9f\x14\n\xe9t<\xbe\xb5\x95L\x8e\x8c\x9c={\xf3\xe6\xa5Kv\xbb\xcf\x17\f\xbe\xf2\n\x00~\x10\xe9\xa9\x0f\xebR\x14\xc7q\x9c\xc5b4\x1a\x8d^/\xe8\xe8\xd7\xe8\xb9\xc8\x15\xf9\x10\xb0\xe12F\xe8\t\x97˂\x10\x89\xac\xae>~<7\x97H,/?|\b\xaf/Iz<\xa7O\xcf\xceZ,f\xb3\xdb\xed\xf3\r\x0e\x92\xa4\x1cF\a\xdf#Iժ(&\x12\xab\xab\x8b\x8b\xf7\xee\xa5R++\x8f\x1f\xc3\x1a\x05\x1cA\xc3U\x99\xab\xd1+\x92$I\xa73\x14\xfa\xe9Oo\u07bcx\xd1\xed>{vj\xea\xe6M\x83\x01\xac\xcb\a\xed\xb2\xeb5\x1e\xac\xf6(\x16\xe3\xf1Dbqqo\xef\xeb\xaf\xef߿u+\x93\x99\x9b{\xf6L\xa9\xd3 \xaaW\xb8\x06M\xeas\xd8\xedSKj\xc7y\xc3\xeb\x03\x8f\x0f\x8dT\xe4\xf3\xb5Z&S.\x17\n\xd1\xe8?\xfd\xd3\xfd\xfb\x85\x82 \xec\xed\xc5bѨ\xdf\xff\xd6[\xd3\xd37np\x9c\xd7k\xb5\x9e;\a\x97\xaf\xca\xd1Q8\x1b\xc2ba\x18\x87\x83\xa2\xc0\xb6Q\xefZ\xe5\xc6\x1b\xafy\xb5Z(T*\a\a\x89Ľ{\x1b\x1b\u007f\xfcc\xa5\xb2\xb8\x18\x8dF\xa3\xe0\xf7\xd0\xe7\x16\xdf\nX\x1d\x04\x1f'\x14\xb7[\xfdqr.\xa5\x1e\x01\xe8Q\n\xe0y\x11\x13\x14\xf8\xd5y\x98胏6ȑ\x8b\xbbFF\x02\x81\v\x17\xa6\xa6\x18\x86$9\xce\xef\aS\x03\xe4o.\x95*\x95|>\x16[_\xdfٹsgn\x0e\x18q\x9c\x81F\x81\x1f-\x02B\x8f\xa794;1\x11\b\xbc\xf9\xe6\xe8h(48x\xf5\xea/~AQ \x9f\x8d\xae\x9f\x05\x06\xbaZ\xcd\xe5\x04!\x1a\x9d\x9f_ZZ_\xff\xe4\x93/\xbe\x88F\x13\x89G\x8f \x90\xc0\xf5\xe1Jc]\xb5zf\xed\xb3{\xf8V\xcfZ\x89\x00<.h\xb8\xe1\xf1\xa2D\xabP\x10\x84x|u\xb5Px\xf6\xec\xeb\xaf\x0f\x0er\xb9P\xe8\u0085w\xdf\xdd\xdd\xf5zC\xa1\xe9\xe9\xd7_g\x18\xa3\xd1l\x1e\x1a\x02\xcb\x10\xc1\xaa\byy#\xde0\xcbE\x9f\xa0UQ\xb1\x98\xcfg\xb3\a\a\x91\xc8\xea\xea\x93'\xf3\xf3\xfb\xfb\x0f\x1f~\xfe9\xb8ε\x1aX\xa2Ʋ,\xeb\xf7\x9f:u\xe6\xcc\xf00E1\f(\x9e\x83\xeb\xd4\xc1\xf7\x17\n\xc9d<\xbe\xb3\xb3\xbf\xff\xf0\xe1ݻp\xa6\x06\xaaW\xf0>\xa1!s\\\x91\x1fԫ\xfa\xe2>\x10\xea\x1f\x1az\xf7\xdd7\xdf\xf9\xfa\xeb\xbbw\xcb坝\xc3Ct\x98\x10\x8eP\xe2\x1a1)\xe5\xf8\x95f~4\xdb\x15t\x98\r$i\xb2>\x01?\xbdQ\xbf\xd0\xc6>8\xbd\x12\x84|\xfe\xee\xdd\xcdMA\xd8\xde>8H$\xd2i\x9f\xef'?9sfc\xc3j\x1d\x1f\xf7\xf9\xae_\a5\x03~?\xd0ayh\x1a\xf4\xab[Am\xa3k!\x8a\x92\x94˕J\x89D>\xbf\xb0\x90L~\xfb\xed\xd6\xd6\x17_d2\x1f}\x04z\xff\xb7z\x8e\xe5\xe7\xb7\xf5T@\xb4\x06@\xee)\xa0\x96\x18\xa8\x8b\f\x1cG\xdc@'\x00/L\n\xa0\xde\xcc\xd4\xff;\tbк\xe1Os\xe4\xa0}\xab_\xfc:\xe7\xbe>\x9b\xed\xf4i\x97\xcb\xe7\xb3ۇ\x86^~\x19\x9c\x97ܢ\x06\xfah\x91H4\xba\xbc|\xef\xde\xfe~>\xbf\xb4\x04\r .ĉ\x1b\xfe\x82\x86f\x9b\x81?\x18t\xb9.]\x1a\x1c\x1c\x19\t\x85\xae_\xff\xf9\xcf\x19\x86eM&\x19\xf8\xeb#\x1d\x92$\x8a\xe9t.wp\xf0\xf0\xe1ӧ++\u007f\xfe\xf3\x97_f2\xf9\xfc\xda\x1a\xae1\f4\x1c8ϬS\x03\xaddH\x94j;\x94<8x=!\xc0\xe1Z\xb8ʆ\x1b\xacm(\x1467\x1f<\xf8\xa7\u007f\xcaf#\x91\xed\xed\xf1\U0006db7e\xbe\x89\x89\x8b\x17GG\x1d\x8e@ \x14\xbax\x91\xa6y\x1e\xac_\a\xa0-ws\x84\xc4\x00\xac\xf3\xa8TJ\xa5|>\x1aM$vw\xd7ח\x96\x0e\x0e\x9e=\x9b\x9b\x8bF\xcb\xe5Db\u007f\x1f^\x0f\x19\x80\xbd\xde3g.^t8\xccf\xb7\xdb\xed\x1e\x18\xa8/\xea\x02W\x06́\x8cŖ\x97\x17\x16\xbe\xfd\xb6\\N\xa7c1\xa5\x90?\xba\\\x11\a\xfc\xcdz\xd5\xdf\u007f\xe3Ƶk\x13\x13^\xefٳ\xa7N\x81\x19\x06\xf5\xc0/ߑjU\x14\v\x85dr}}{\xfb֭\xed\xed\x0f>\xf8\xf2ˇ\x0f\xab\xd5d2\x9b\x85}\x15P\xbd\xc2\x01?\xaeS\x9eZ\x8f_\xedzw\xd91\x90\xc7\xdcBo\xbc\xder\xc1\xfe\x04\xf0\xf9Fg\x01\xe0Z\x01\xcb51\xa2\x18\x0e\xa7ӂ\xb0\xbf\xff?\xff\xe77ߤ\xd3F\xe3K/\r\f,-\xb9\\\x97.\x85BSS&\xd3\xe0\xa0\xd3y\xf6,\xe8\xd8\ajQ\xe4߭\xef\x19\x02\xfa\x1cT*\x99L\xa1\x10\x0eg2\v\v\x87\x87\x0f\x1f\xa6R_}\xb5\xb6\xb6\xbd-I\xf1x\xb9\f\xf5\xa1\xf9z\x83\xf3,\x14\xe0T\xc0\xc6\b@\xf3\xf0\xa6F \x87\xc4@-\xb4+Y\xfa\x1f\x13\xc4\xffH\b\x00n\x15@\xaf\"\x03\x8d\x00\xae\xbc\xae_i\x95\x80\xcc\xfcA\x11 \xd8\xc2N\u007f\xb8\xf5\xcef\xf3\xf0\xb0\xd7;331\x01z\xd0\xf9|\xf5\xcbo\f\x06\x82(\x95J\xa5l6\x12Y[\xdbۻwoy\xb9u\xc8P\xa9\x83\x1f\xea\xd16\xf7\x1dp\xb98.\x18\xf4x&'C\xa1\xd7_\u007f\xe7\x1d\x96e\x18\x8b\xc5\xef\x97\xfb\r\xd4\xd7\xf2V\xab\xe9t6\xbb\xb7w\xff\xfe\x93'KK\u007f\xf8×_\xe6rŢ\xdc\x11\x0e.G\xc2\x01\n.$\x8b\xf3\xf8Q*\xa8\xd5P\xab/\xeel$\x00h\xe7<\x94\x10\xe0\x86\xba\xa0\x86;\x9f\xcf\xe7#\x91\xb5\xb5lvm-\x12Y[\x8b\xc5h\xdadr:\x9f>\xe5y\x87\xc3\xe3\x01U\xfe4\xdd8.\x16,\xed\xabVE\xb1V+\x16\x93\xc9H\x04\x18\xedl\x16^\a\xf4\xbe\x82\xef\xa1(\x9a\xf6\xf9&&\xa6\xa7\x87\x87I\x92\xa6\xa1\xe7_\xdf\x11\xadPH$\xa2ѭ\xad\xa3\xa3'O\x1e>\x84\xfd\"P\x8f\x1fG(Q\xbdB\xfbDȫF\\\xae\xf3\xe7Ϝ\x19\x1c\xf4\xf9fgϜy\xef=\x8a\xe2y\x8a\x02E\xa5\x8d\x84\x04\x04\xfa\x93\xc9\xd5\xd5p\xf8\xf3\xcf\xc3\xe1?\xfd\xe9\xf3\xcf\x1f>\x94\xa4\\\xaeX\x84\xc0\x8f\x9bR\x89\xf3\xf8\xd5V\xf5w:\x95\xadY\xbf\xa0#\xd0\x18\x11\x80\u007f\xafVeb\x00*z\xe0u\x04\x9f\xc3\r\xa1B#\x04 \xf5D\x10\xb9\\\xa1\xf0\xe0\xc1\xde^:\xbd\xb7\xf7\xe0\xc1\xde\xde\xc1\x01E\r\rY,w\xefҴ\xd3i2\x81\x86Whc$P\xd8W*\x89b\xa5\"\x8a\x9b\x9b\xa9\x94 \xd4jŢ$\xc9\xfa\x8aF\x82\xc0\xf9\xe0\x1d\x0e\b\xfc\xa8\xe7\xdf8\xeeW\x8e\x01\xf4\x06\xc0\xd5|\x0e}\xa6\xd5:\a:\x01x!\b@\xbbF@ʷ\xbfW7W\xed*\x01\xfc\x10\x17\x94\x008\x9d\x9f\xfc\xfc\xca\x11\x0eI*\x97S\xa9\x8d\x8d\xed\xed/\xbf\xdc\xda\xfa\xcb_\xbe\xf8\xe2\xd1#\x00\xfc0҅\x12J\xa5H\x92R\xb1\xa8Z\x02\xa0\x048x{\x00\xbb\v\xb6\x1e\u007f۬W\x8d\x9es\xa5\x02>\x8f\x12\xccfb\xd9hW8\xaeZ\xdd\xd9\xc9\xe5\x18\x06n[\xdb/\xb4\x150\xee\xfba\x91\x9fL@Т\xbf\xc6\xe3V\xf2\xfc\x9bC\xff\x8d\u007fG\xf7\xeb\x9e\xfd\x8f:\x05\x00U\x067L\xf28ԣ\xf5\x94\xbf\xe6\xe5\u007f\xe8\xfb\xdb7\xfc\x81\xcb\xfed\x02\x10\n\xb9\xdd\xd3\xd3\x03\x03\x1cGQ\x1c\xd7\xd7G\x92p\x98(x *\x95J%\x9f\x8f\xc7\xc3ᣣ'O`c\x1f\xd4\xe0\xe1\xd6_\xcb\x11\x89\xd6\x1e\x9a\xec\xf9OM\x05\x027n\x8c\x8d\xb9\\Ng(t\xf9r}\xa3R\xd8X\xc6` \x88B\xa1XL&WV\x16\x17\xd7\xd6>\xfc\xf0֭l\xb6P\b\x87Q\x8f\x1f\x97#\xc4\x01\x8aZ\x03\xad\x16\xf8\xd5j\x84R\xa7G\xdczo\x9c\x01E\xcfC)\"\x80\x1bS\x8b\x12\x00\xa5Z\x12H(\xe0\xe7%\xc9\xed\x1e\x1e\x1e\x1b\x03S\x12A5\xbd\xdc\xd9\x0f\x1cQ2\x99N\xef\xedE\"\x8b\x8b\v\vp(\x14N\xaf\x94V\x8f\xb4\x1a^e0\x18\fV\xeb\xd0Ы\xaf\xbe\xf4\xd2\xf9\xf3<\xef\xf1\xd8l\x13\x13\x10&\x1a;\xf4U\xab\xb9\xdc\xfe~$\xf2\xe0\xc1\xd6\xd6G\x1f}\xfd\xf5\x83\a\x92\x94\xc9\x14\n(\xf0\xe3sϭ=\xfe^\x11\xcan\x89esj\xa0\xbd^\xc1\xe3\x04\xe3\xade`\x85\x03\xacq\xfa\x84\x1b\x8b\f\xf5\x06g9\xe1\xf9+\x8d'Ƨ\xe8Z{\xfch\xee\x1e\x9e\xa7\x1c\x11\xd0F\xb4\xba\t\xf9+9\x81z\x04\xe0\x85\x95vc\u007fO\xb6\x13\xa0R\r@s\x11Y\xebe\u007f\xbf\xb3sx87\xf7\xc9';;\xb1\xd8\xfd\xfb\xd0cT2\xd0J\xcb\xf9p\xc0\xaf6\xd7߫\x06\"j\t\x00.\x84*{6\xad\r9\x1a!\x90\rx{\xa0ǥ\x90\xe0\xef\xc0\xfd\xf2\xef\xbaݣ\xa3ccv;M\xf3<˺\xdd\xe8U\x14\xc5R\xa9PH\xa5b\xb1\xb5\xb5\x95\x15\xb0,\xb3Y\xafp\xa9\x19\xa5\x88\x92\xc9D\x92,˲V\xab\xdf\u007f\xe1©SׯS\x14\xcf3\fh\xf4S?\xacH\x14K\xa5r9\x16\xdb߿w\xefɓ\xcf?\x17\x84\xb5\xb5\xbd=\\\xd1h\xa7\xc0\xdfi\xae\x1f\x8d\xa0\xf5^\xafZ\xd7\b\xe0\b%.BP_d\b\x8a\xfcPGD^\x85Ъu\x9a\xbc\x0f|\x0f\x8ex\xe0:\xfb\xe1\x00\x1f\xb7\xae_\x19\xe8Յ\xfc;\xb9\x1f/\xd6dB\x9d\x00h\xb8m\xf2z\u007fy\xc5f\xbd:\xe3\xfb\x00t{\xb3\x95\x00\xa0y\n`\xeb\x14@s\r@\u007f\xbf\xcd\x16\n\xf5\xf5\x81>n\x0e\x87L\x00\xc0\x03Q.\x17\x8b\xd9\xec\xd1Q8\x9cN/,@È\x03~\xad\x9e\xbf\xc940`2MNz\xbd^\xaf\xc31<|\xe5\nl0\n\xb2\xc3r\x95p\"\x91\xc9\xec\xec\xacV[\xb5\x18V\n\x1dk\xed\xb0\x86#\x00\xbd\x06~\xf4\xfd\xb8ܨھ\x018B\xa0\xd6\xd3T\">\xe82\xbbf@&I\x9e\xe7y\x86\xb1X<\x1e\x97kl\f\x10fٻ\x043#*\x95Lf\u007f\xff\xe0`c\x03\x98s\xa5\x96\xb8\xe8\xf1\xe0C\xff`Z\xa2\xc9\xe4\xf1LM\x85BW\xae\x80\x11\xcb@\xdf\xea\xfb\xf6\x83\xa1<\xab\xab\xbb\xbb\xb7o\u007f\xf7\x1d\\\xcd\x02\xf5I\xebr>%\xe0Wң^\x03\xbfR\xea\t\xdf\x02\x17z\xea\xcd5\x02\xad\xac\x1cJ\b\x94\x1c\x14\xadNj\ue5ef\x13\xeaѷ\xf6\xf8\xd1j\u007f\\\a@\xad!\xffn\b\x82^\x03\xf0\xbd'\x00\xf5\xfeU\xe3\x80\xca^\x87\x83Ԏ\x01\x96\x19n\xfb\xa1?\xb0\xf3\x1f\xc3\xd8\xed4\xedr\x19\x8d\x16\v\x18\xe9\x02[\xfc\xc2yr\xa2(I\x95J\xa9\x14\x8be\xb3{{pY\x96\xd2zf\\\xd1_s\xe3!\x8f\x87a\xfa\xfb\xedv\xb7\xdbf\x1b\x1c\xbcx\x11N\xb9\xaf7Ե\x9a(\x1e\x1c$\x12\xab\xab\xdf|st\x94\xcd.-\xc1\x9c,\xae\x81\x0f\xce\xe3\xd7\n\xf8\xbd^\x96u\\D@iȐ\xd2\xfb\xd5\x1e7\xea\x01\xe2z\xd0Ӵ\xc3\x11\n\x85B\x16\vh\xf1\xeb\xf1\xa0\x9d\xcf$\xa9T*\x16\xb3\xd9T*\x1c\x96Wk\xa8]'\xafF\xaf.^\x9c\x9c\f\x04\xc0\x8c\u0091\x11\xf4\xf7k5Q\x14\xc5\\.\x12\x99\x9f_[\xbb{\xb7R98H\xa5pc\x84q\xcb\xf9\x94\x00_)\xe4\u007f\xd2z\x85ӣV\xaf\x1bC\xf4\xf5\x10Z\xbft\xad\xb1\xb1\x10\xea\x06i\x05\xfe\xc6w\xcbE\x8a\xf5\xe4C\xfe\xe6V\x00\xde\x1a\xf0\xf1!\xfd\xd6!~\xad\xab.\xf4\b\xc0\x8f*\x05\x80\xaac}8\xab\xbeU\xce\xf1\x87\x8bp\x0fps\r@\xebP.\xcbz\xbd&\x93\xdfo\xb3\xb1,h\x85*/\xb3\x03\xe7\x02ڲ\xa4\xd3\xd1h.\xb7\xb3\x03\r\xa4R\xebR\x1c\x10\xa1\x9e\x1a\xcf\x0f\r9\x9d\xa7N\r\r\xb1,Eq\x9c\xdb\r\x8b\r\xe1wT*\xa2(\bGG\x9b\x9b\x87\x87\xdf}\aC\xfe\xd00+\x19h\xad\x9e\x99Z\xcf\xffy\x18\n-D\x01\xe7\x99i\xf5>p\xa1_\x9cG)\xeb\x99\xd5\xea\xf3\xb9\xddN'I\xd24I\x9aL\x04AQ\xf5\xdaQ*\xa5\xd3\xe9\xf4\xd1Q.wttt\x04\t\x1cZ\x9b\x81\xcb\xf9\xe3B\xff2\x01p\xbbGG\xfb\xfb'&(\x8a\xe3\xc0\xef\xc3\xd0?\xfc\xa5T*\x93Y_\x8fF\x1f\r\xa2(4]\xab\xd5\x17\x1f\xd6j\xf1x&\xb3\xb7\xf7\xf8q2Y*\xed\xec\xa09\xd8^\rS\xe96\xe4߫\"\xa1n\x17\x94\xe2\x88 \x9a\xfbG\x8b\xbcZir\xabϫ\x1dgLQf\xb3\xd3i\xb7{<\xc0<\xd3tc\xb7\xb7ZM\x10\x92\xc9drk\v\xb6\xd6m\xbco\xe82?\\这\x00\xb0\xac\xcbe\xb5Z,\x16\xcb\xc0\x80\xdb==\r;\x18\xcaD\x1d\xac\xefO&76\xf6\xf6\xe6\xe7\xab\xd5L\xa6XD\x1b\r\x1dW\xa8_\xeb:\xff\xe3\"\x96\xda疢\xd3E\x01\xf0\xe2j\b\xb4\x0e-\xd3J\bp\xc5{\x90\x10\x18\f\xb8H@\xfb\x86?σȟ\xc4\"r\x9d\x00\x1ck\n\x00\x97q=>\xb6\xd7\x1cZk]\x03 \x17\x01\xe2\x86\x00\xfd\xff\xec\xbdד\x1b\xf7\xb5'~:7Ј\x83Ɂ\x138\x8c\")*[\x14%+\xcbI\xb6\xeaZ\xebڇ\xfb\xb4\xfb\xb4\xffϾl\x95k\xb7j\xc3\xcb]\xfbھ\x0e\xb2\xa4+ɒlEJ\xa2\x18\xc5\xe10L\x8eȹ\xe3>\x9c\xdf\xf7\xd7\xc0\x17\xf8\xa2\xbb\x01\f\x93f\xaa\xa4f\x03\x8d\x8e\xa7\xcf\xf9\x9c\xcfI\x98\xf5?8\x88\xc0\x05\xbf'\x19\xb8\xb6\xed8\x85B\xad\x96ˑ\xe1>\xb4\xc7\xcf\x1aOJS\xb4\xad\x00`pP\x92FG\xa3QMS\x94x|j\x8a\xa4T\x92\xd7\xdb4\x1d\xc74K\xa5\xad\xad|\xfe\xf6mr\xfc\xc6a7A(\xe3^\xb3\xaf\xfd\x1a\xfe~Q\xff\xdd*n\xd6\xf7,\xc3\xcf\x02l\xac\xedY\xc7s\x81&\x9a\x06QT\xd5hT\xd3\xc6\xc6H\x1f6\xf7L\xb0\xd9o\xb9\x9cNg2dZ\xa4ߖ\xcb\xder50p\xf8\xf0\xc4\xc4\xe0\xa0(\x86â\x98J\xb9\r\x87p/\xa6Y\xab\xd5j\xe9\xf4\xce\xceի\xb7o{\xf5\x1b\xf0\x92+/\xc0\xd8/\xc3\xdfo\xa3\x10T~Z\u007fo۶\xdd<\x9e\xd7\x0fS\xd9/\xc3Ϟ\xda\xc7J\x02\xa4ϟ\x05$\xee\x0e\x97\xdc\t\xbc\xef\x03\x80{>\x04\xc0\x02\x06\xfd\x13\x8en\xeb\xc5\xd9\xe3@\x05\x81\xe3\x04A\x145M\x14C\xa1\xa1!\x9ew\x1c\xdb&e:$I˲\x8a\xc5j5\x9d&\xd4?\v\x00\xf8\xa7\x86\x89\xa2\x1e\x1e\x8eDPQ\xf3\xbc D\xa3n\x83\x1fb\np\x96\xdc\xdaZ>\u007f\xed\x1a\x89\xf9\xb3\x14\xb4\x97\xc7\xef7\xe6\xda픰;\xa5@\xbcr\x00\xfc\xfe\x9eu\xfe4\xa4\xf52T\xad\f\x00χB\x8a\"\x8a\xb2\x1c\x0e+J*E\x8a\xb9\xdc=\x1a\x86\xae\xd7\xeb\xd5j:\x9dɐ$;\xbf-\x97\xe9\xe3\xb6V\xb5D\xa3\xe3\xe3\xc9\xe4\xd8\x18\xcfK\x92\xe3`H\x00\xf7N\x86\fe2\xb9\xdc\xe2b\xad\xb6\xb4\x94N\x13\xca\xdf+\xa9\xd5o\xcb\xde^\xcbD\x83\x1a\xa4n\xab\x01\xfc\xee/8S\xd0^N\xbb\u007f?:\xc7\xf2\xbd\f?;$\xe0u\xbc;\x0f\f\x1e\xec\x90\xc0\x03;\r\xb0\x1d~\xbbwH\x1cV.\x80 (\nǩ\xaa(\xaa*\xcf\xcbr2I\f0!LI\x0f\xf4BA\xd7\v\x05\xa2\xa8\xfdνg\xc5\xfe]E\x9dL\xaaj*5>\x8e\xdd\xc0\xf1s\xecȆ[\xe4\xf3\x95\xca\xd6\xd6\xf5\xeb\xf5\xbam\x97J{e\xf8\xf7\xba\x11K\xbf\xa8ڠ\x8aڋ\xe2\xf4R\xd0~\r?\xed\x91\xf3|8\x9cJ%\x93\x8a\xc2\xf3\xa2\xc8q\x9a\xd6Xo\x8fwڶ\r\xa3T*\x16\xb7\xb6vw\x89\xe7\xed\x97Qb\x85\x1c\\\xf9Ҵ\xc1\xc1htn\x0e\x8fۘ*\x86-lK\xa5\xf5\xf5Lfi\xc9q,\xcbq\xe8^\xf6\xbd\x86\x90\x82\x02ʠ\x86\xbf\xf1\xfbn\fF\xfb\xe2;\xffr\xd6+0\xe8\x95\x01\xf0\x02\x00\xec\xa5\xd7=\xbb\xfb\x86\u007f\x9f\x01\xb8\xef\f\u007f\x90W\xc9\xfb\xd5\xec%fƎű\x98\x00E\xe18\xf4\xd48N\x10\xa2Q\x8e#]\r\xf0\xba,\xcb0\xea\xf5z\xbd\\\xd6\xf5\\\x8e5\xc6\xd7K\xc1\xb5\x96!J\x12\xfe_\xd3d9\x12\x99\x9cl\xbc\xabH\xd5ڶ\xe3\xe8z.W\xa9\xec\xecll4+fV\x92X\xafCU\xfae\xf8\xdb\u007f\xde\xfdl1\xbf\x9d\x03\xbd\f\xba\x97G\xef\x05\x04\xfc\x03LU\x8dF\xc3aY\xe6yA\x00P\x14l\xde\xe4\xeeɲ*\x95j\xb5\\6\x8cj\xb5V#\xcf\xd3\xefxe\xf6xdYN&\xc3\xe1PH\x92\xe2qd\x1e\x9a\x998\xdb6MèT\n\x85\xb5\xb5\xdd]\xd2җ\x95{Я\xce}^\x80j\xaf\r\xbe_i\xec\x170\xe8?@p\xf5\"\xa9\x05h\a\x04Z#\xfb~;\xf7\xdd=\xc3\u007f\xf7A\xd5>\x00\xe8\xf1\xaf]\x04\xb5\xb5X\xe5n\xd2D쐀\xaa\xf2\xbc\xa2H\x12~\xa2(\xa4\xfc\xcf\x1d\xb2\xe38\xa6Y.\x17\x8b\xb6](\xb0\x92\xb2X\x8a\x90.?kd\x1ex>\x1c\x96$U\x95\xa4p8\x91 \xc7u}&\xdb6\x8cJ%\x9f\xafTvvH\a6\xaf\xaa\x83~\x19\xfcn)\xd7\xe6ϻ}\xea\xdeľ\x17 \xf0[>\x184\xe6\xec\xe5\t\xbaK|\xb2\x92\x84\x8d\u007fdٝ\"\x89L\x80aT*\xe5r\xa1@$̟\xe1\xf7\x06\x96\x91\xc8\xf8x2\x19\n\t\x82(\xf2<\xf6\xfeo,\xfb\xc3\xd1\xc5\xf9|\xb1\xb8\xb4\xb4\xb3C\xa8\xff\xa0\xfd!z5\xf4Ab\xfew\xda\x03\xec4\xde,\xa8\x1e\xea\u007f\xb6|+\xa5O\xfekL\xfec\x19\xfe\xd6k\xbbwr\x00\xfa\xa5\xeb\xf7\x01\xc0\x1d\xfb\xa3\x19\x80^\x8bK\xf6\x9e>j\x05\x02\xa1\x10\x01\x00\x98\x1c\xd8h\x88Qic\xaaV\xa5\x82\x03\x80\xfc\x19Z\xd6\xf9\xb9\x1e[4\xca\xf3\xa1P($IH\x18\x93\xaa\x03\xf2\xdab_\xb6b1\x97\xab\xd7wv\b\xf5\xcf2\xfcA{\xf4w\xab\xc0\xfd)\xba\xbd\x82{\xbdW\x95\xf8\x9d\x1d\xd0mL\xd9]\n\x82,\xf3\xbc,c\xc7v\x9ew\xdbÒ'h\x9a\xba\x9eN\xa3g\xe7\xf79\xb2\xe5\x89,e9\x1eW\x94P\b\x8f-I\x8d\x1d\xe2\xf1\xb8\xa5R\xa5\xb2\xbdmY\x85\x82\xaew\xdb\x11r\xaf\x80\xe5\xbd\xcau\xb2d=\xe8\f\x82\xde\xce\x02;\x0f`=\t\xed\xb9\xb7\xafF`y\xfa\xad\xb9\x01\xbd\x01\xff\xbb\xe1\xd4\xed\x03\x80{ⵠ\xfb\x00\xb4g\x00\xf6\x12\x84\xb4\xeb\x04譠]O\x8d\xe3DQ\x10\xd0\x00\xe3\x94/\x92\x03\x80*Q\xd7+\x15\xa2(\xbdb\xe6^\x86\xdf]j\x1a\xcfk\x9a\xa2\xe0t\x02E\xc1\xe4C\xb7\xad\xb2a\x98f\xbd\x9e\xcf\x17\x8b\x96\x95\xcb\xf9\xa5\x88\xf7:˺\xf7'\xea\xedݳ\xb7`\x9b\xe7\xa0\r\x83\x82^\x8f_\x0f\xd0}ނ I\x82 In\f\xbe\xf9\xbd\xb0m\xc30\f\x12\xfb\x0f:\xf6\x96\xcdh)\x8a\xaa\xcar4\x8a\xe0U\x92\\Ё\x12\xad\xeb\xa5R\xa5\xb2\xb3\xe38X_\x12\xcc\xe3g\x01\xc4n\xe5\xe9^\xf2\xfc\xfb'\xc1{a09\x8e\x00\xc8\xee\xc6\xf1\xf8M\xfe\xdb\xff\xdb\a\x00\x81\x01@\xbb6+\xf7V\x12 \x1b\b\x88\"\xa2g\x8c\xfd\xbb\x9d\xf7\\\x8f\xc94k5\x02\x00\xba\x9dS\xdez\\E\x11EU\x15ET݂@\x00\x80\xdb\xf2\xd70\xaaURu\xe0\xb7\xce\xfaN\xd5O{{\xfe~\x95\f\xad\x8e\u0600`oGK\xf5W\xae\x10\x02\xb8\xed~\x1b{\xb8\x91\xee\xed\xba\xae\xeb~\xfb,\xf8?\xbe$\x85B\xa2\xa8(\x00<\xdfx\\R\xf9o\x9a\x95J\xbdN\xea\x18~\x91C\x00\x00 \x00IDAT\xfc{\xed\xd8\x17\xd4\xf0?\b\x8c@/\x80\xe0n\x9ees\xe3\xa2{\xe7\xccX]:\xf7\x93\x00\xefy\xb1o\f\x01\xd0\xd9\xff\xfd)\x03\xf4\xfb\xf2u?\x15̍\xac\xe1l-B\xaf9\x0e\xe9f\x88e\x80\xfd6\x14\x82\x80\xf9\xe1(\xfe<\xef\xe6\x1e\x90\xd6æY\xad\x12E\xed7\xcb\xfa\xfeW\xc8\xdd\xf8\xff\xf7\"0 \xc4l+\x10&i\xa6\xa6iYA\x93\xe8\xbc\x19-\x9e\xc7\xc4C2\xa5\xd3m\xf9\x8b\x00\xc00\xaa\xd5z\x9d$\xb3\xf6ڈ\xe7N\x01\xac}@Э\xc7Or\x02\xf6\xef\xdb>\x00\xb8#@\xa0\xb9\xd6\xf9\xfe\xb8\x063\xd3oд\x0f\x00\xee\nQ\xc3\xf6\x05\xfd\uedd7NU\xad\n\xb9\xb9\x01F\xab'^\xafcͽaX\x96a\x94J\xe89\x91\xec\u007fl\xa6\xca\xf3\x8a\x12\x8dr\\$\x82cU\xbd=\xb6V\x02\xce\xf5\xc1pY\xafc_\xf6J\xc54+\x95\xd5U\x12zhd\x1e\x00\x14%\x95R\xd5htx\xb8YQ\xfbUؽ*\xeen\x93\xc3\xf6\xea\xe5\xedv,t\xbf\xbc\x0f\xaf\x19\x02\x8drU*U\xab\xba\x8e\x00\x00\xeb\xee\x1b\r\xb1(j\x9a h\x9a$\x85B\x82@\xcb\x15\xfd\xfd\x06:ޔ|\xa9\xb4\xb3S\xa9\x10\x00P\xa9\xb8\xb1x\xc2\xf4\b\x02@$\x12\x8b\x8d\x8c\x84\xc3$)\x8f\x15bb\xf1i.\xa3\xe4.\x1d\a\xc00\xca坝R\xe9\xf6m\"u\x04\b\xf0<\x0e'\x8aǧ\xa6\xc2\xe1\xc9I\xfc\x86\x96'\x16\xc0\xecV\x9e\x82&\xcd\xfa\x91'\xbf\xfcQ'\xbe\xa9_\xf2\xd9/O\x9f\xbd$\u007f\xae\xc1\xc6\xf3'\xeb\xedC\x02A\x99\x81;\xe1\xe9\xdfIVa\x1f\x00\xdcq¦\xbf\x00\xa0_S\xc7Zc\xa5Da\"\xf9o\x18ժaT\xab;;\xd8\x10\b14R\xa6\xb6mۢ\x98L\nB8\x9cH\x04\xa3JY\f\x00Qغ\xbe\xbd\xad\xeb\xe9\xf4\xf6\xb6e\xe1\xd0!7\x04\x81@ \x14\x12\x04I\x1a\x1f\x9f\x9e\x96\xe5\xe1ar\xfc^\x81\x00+`\xd3oøWt_\xd0\xf3\tj\x90\xfc^?K\xce,˲*\x15\x9c\xbcW\xad\xd6j\xe9tc\x12 \x1abY\x06PUM\x1b\x1a\n\x87\t\xb0d\x85vX\xc0\x92\x96+\x17X\x16\x8b\x9b\x9b\xa5\xd2\xda\x1a\x02\x10leM\x1a]Y\x16\xc7E\"\xa3\xa3\xaaz\xf8\xb0\xa2LL\xb8\xe5\xa6$ׄ\xc8UP\xa6\xa9_\x8cSP\x86\x86\x06\x06\x8d\xcb~\x02\xd1^\xe5\x8a5\xc6\xd9;\x04\x84\x06\x1aG\x965{\xf8\xcds\x13\x9a\xbf\xf7˜\xddK@\xe0\xc1\x0e\x05|oB\x00\xbd\x86\x02\xfc\x01\x83\xc6㶛gM\x87\x02X\x86\xd84\v\x05\xd3,\x97ww\x11\x00X\x16\xa6\xdb\x10C\xccq\xc9$ϫ\xea\xf4tgEMS\xb6,\x00@\x14\xb5\xae\xaf\xaeZV6\x9b\xcfW*\x86Q*ml\x10\x0f\x91\x00\x01Y\xe68\x8e\x8bǧ\xa64mppj\n\u007fG\x16\x1b\x1b\v\xe6\x19\xd1\x1e\"\xad\xa8\xeb\xf5۷-+\x9f\xcff\xd3\xe9Z-\x9bE&\x80$\x8d9\x0e\xee\xd1qTu~>\x1a\x1d\x1e>sf`\x80\xe7U\x95\x00\x11b8\b \xf0b\x04X\xd4\xed^\xe5\f\xec\xb5\xe7ޭb\xf5{\x1f\xbc\x148\xcb \x9bf:}\xfbv\xa1P,\"\x15\x9fN\xbbT<\xc7a\x92\xa9\xaa\x02\xc4b\xa9\xd4\xc1\x83\xd1\xe8\xe0`{\x00\xc7\x02\x984\xb0l\x05\x00\xeb\xeb_~\x99˭\xaf\x1bF\xa1P\xaf\xaf\xad5\xb6\xee\xb6,\x00QT\x14\x8eK$&&\x9ez*\x99|\xe4\x11\x9e\x8fF9\x8e\x94\x9d\x06\x95\xab\xa0\x8d\x85\x82R\xe4A\x01C\xb7rʖ/\x8eòMb\xe8i\x0f\xbcy\x12\x8a[Ձz\x86\xbeO^\xcbƪ\x10ܯ{\xbcf@\xc0\xca\x11\bf\xf8{\xf5\xda\xfb\xc9\x00\xec\x87\x00\xee\xeb\x10@\xff\xa3u\xedc\xfc\xcd\x1e?퉱˥h\xca\x14\xf3\xa7\xeb\xf5\x9d\x1d\xcb*\x14n\xde\xc4^nnV>2\x01\x1c7>.\b\x91\xc8C\x0f\xc92\x00DZ\x92\U0007c4b7h\x85]\xad\xe27\x95\xca͛\xe5\xf2\xe6\xe6\x85\v\xa6iۺ^,\xd2做&\x8a\x9243s\xfat<>=}\xec\x18\xfe\x9e(l\x92LF\x14\xb7_\n\x97>_/\xc5\xed7\t\xacW\xa0\xd0/\xc3\xcf2\xe8\xf4\xd2K!{5\xcai\x05\x02\xa6Y(ض\xae\x97\xcb\xe9t\xb9|\xe3\x86 \x90l|\xb2\x14EǑ偁\x03\a4mn\x0e\xa5\xdc\v\x00\xd0\xd429\x1e\xcd,U\xab\x86\x91\xcfcM\u0095+\xb9\xdc\xe7\x9f;\x0e\xa6\x9b\xba@\x00C\x11\xd1\xe8\xf8\xb8\xa2<\xfc\xf0\x81\x03/\xbd\x14\x8f\x93\\\x17Z\xaeh \xc0:\xbfn\x81@\xbfB\bAc\xec\xdeIz\xae\x01o4\xf0\xac\xed\xd9r\x84\xfba5`\xa2\xdfKIb\x03\at\v\xda\x03\x81V`B\xc7\xfei p\xf7\x18\x01\xbfa\xb7}\x00pO3\x00~Efo\xffܡ:t(\xa0}\x12 Q\x94\xaeǴ\xbclY\xd9\xec\xfa:\xa6p\xe5\xf3<\xefz\xe2\xb6\r\x10\x89\xf0\xbc,\x8f\x8c\x1c=\xcaq\xb1\x98_\x8f\x8d\x05\x00\xdc\x10\x00.+\x95\xabWMswwssw\xb7Z\xcdf/^$\x00\x800\x11\xf8*\x8b\xe2\xf4t$\x92L>\xfb\xecɓ\xa1\xd0\xc8\xc8\xc4Dg @S\xb9^@\xc0o\x92W\xb7!\x84^\u007f\xcf:?\xaf\xf3f)h\x96\"&\xf7\x89~\xae~\x19\x1f\x17\xe8\xe5r\xab\xab\x85\xc2ʊ\xe3X\x96i\xd6j.ÄR\x89Y\xf9\x87\x0eE\xa3\xe3\xe3\xa2H\x9e\x1fM\xbdӍ\xa8\xfc\xcb\xd5\xea꧟f\xb3\xb7n\xd5\xeb\xb9\\\xbd\xbe\xbc\x8c\x12\xd5X\x1e(I\x8e\xa3iccO<\x11\x8f?\xff|2\xf9\xc8#\xb2LB\x02\x84i\"\xf2\xe5\xc5\b\xb0\x92\x18\xfb\x05\b\x822R~C?\xad\xf2Ҟ\xc2g\x01\xc7V\x03\xde^\x8e\x14\xa5\xb9\xfc\x92\xd6\x1f\xf4:\xab\xdee\x9a\xad!\x8afm\xcdJ\x16\xbc\xf3ɁߏfDB(\x14\n\x85B\xfd\xcar\xed6\xd6\xd9\xfb\x12U\xc2\xf00\xfa*g\xce\xe0\x19a\x03[W\x05]\xbe\xbc\xb5\x05\x00\xb0\xb0Ь\xa0Xu\xf9\xf4\x92\xbd=1\xec\xcd\bա\xfeZ\xcb_\xda\xdf\x17\xf7\x05\xc6P\x80\xa2\f\x0f\x03H\x12\xcf\x0f\x0f\xf3|(\xf4\xd0C\xe4\xfaPas\x1c&\x05j\xdaښee\xb3\u05ee\x15\x8b\x98\xcd\xdf\f(\x88\"\xa6\xaf\x875\xf3۽\xbf\xe9\xb4\xe3\xd4\xeb\x8e30\x80g50\xa0(\xa1\xd0\xfc<\xf2\x1bx\xfe\x8e\x83Ê\x04!\x99L$$)\x14\x02XY\xa9T\xb2٭-\xc3p\xb3\bZ\x8f\xeb\xd5W\xc1o\x16\xbe\x97\xbcv\xcb\x04\xf4\x8b\xf2\xf7k\xf8\xe9\xf27\x1a\x00\xd0\xeb\xb4\xe7\xc6\xf2\xd8\\C`\x18Ţm+J29=\xad(\xaa\x1a\x89\f\x0e\xca\xf2\xcc\f\x99\x0e\x88\rzx^\x92d\x99\xe7\x05ac\xe3\xf2\xe5B\xe1\xe6M\x84\x9dD\x9eh\xb9\"\x00\x92\xf5<[\xe5\xbdPX^\xae\xd7u}``~^\x96c1U\x1d\x18\x10ʼn\t\x92\x14H\xceG\x96\xa3Q\x9e\x1f\x1eV\x94d\x92\xe7K\xa5t\xfa\xf2\xe5Z-\x97CYf\xc9\x15K\xce\xfc\xea\xb9^\xf5\x9f_\xb9a\xcb\x13\xde\x01\xbf\xa1#W\xbeP\xc7\xc82^3\vP\xfa]\xd2\xf2\xd3\xce\xc0\x93$\xc3\xc6Aӭ\x8d\x83\xe8\xf5f\x86\x94\xfc\xb9\xd7\xdd\xfc\xbb\xd6\xfb\xd1\xfe\xfe\xb0:Xz\xad\v\x02\xc0\xe4$\xc0\xfc<^\xeb\xa9S\xad\x80\xb6X\x04\xf8\xec3\x80\xdd]\x80\xcd\xcd\xce\xf6\xc2\uf4b6;,;\xe3\xb7i\xb9\xd7\xfa\x03\b\x00\xb0\x89h+\x00 W\x80\xaa\xe9\xf2e|d\xfd\x03\x00\xed\x93\xfa\x1c\xa7\xd5\xf4\xb7\xfb\x86M\xfd5\xc7\xe6\x14Ų\x00\f\x83\xe3\xe6\xe7y>\x1e?|\x18=\u007f\xbcZ$ݐ\xc2s\x1cDZ\xed\xad\xad\x1b7\x1c\xa7\\N\xa7\x9b\x154\xad\xa8\xe9\xf3\xf6\xe2UD1\x9b5\xcdR\xa9Z\x9d\x9c\x94\xa4Hdh(\x14\x12EQ\x1c\x1ajl\xf1\xea8\x1c\x17\x0eK\x92,\x8f\x8e&\x12\x82\xa0\xaa\xb5\xda\xd2R\xad\x96\xcbe2$|\xe1O\x90\x83R}\xbd\xd6\xd3\xf7\v8xQ\xfb,\x83O\f:\xf1\xb8\xe8\xa47:\xf6M{hth\x85婹\x06A\x10\xc2a\xdb\x06\x18\x1c\x9c\x9eִ\xf9y\x92\x03\xc0q\x98\u0605Iy\x9a\xa6\xebժ\xae\xaf\xac\xe4\U000ebac6Q,\x06\x93+6\xc0$\x19-\xf5z\xad\xa6\xeb\x85\xc2\xc0\xc0ܜ\xa2LO\vB8L\xae\x1f\xe5J\x10\x00D1\x14J\xa5Dq|\\\x92\x12\t\x80L&\x93\xb9|Y\xd7K\xa5\xce㛼\f\u007fPy\xfa\xff\t\xd4.\xeb\xe7\xbd\xe5ȟa#KYn6\xf84\x10\xa4僖+\xb2N\u007f\xeeU\xcd\xd3Zn\xdc|ޮa\xf7Z\xa7\x01\x00\xeb~\xb0\x00Qg\x86d\x1f\x00|o\x00\x00\x92\x81\xad\x00\x00}\x15/\x00\xc0z A\x1f\x14\x8b\th\x174hGm\xd1\x02*\xcb\xf9<\x80iJ\xd2\xd4\x14\x80\xaaJR2\xc9q\x8ar\xf8\xb0\x8b\xb99\xceqx^\xd38N\x14#\x91\xa5%\xdb\xce\xe5\xae_\xafT\xb0\x92\xbfYA\x93%\xeb:\xd8\x06\xb0VC\xc6\xc14\r\xa3V\xcbf\xc7\xc6T5\x12\x99\x9e\x16E\x9eǺm\xd2Y\x0e\xb3\x92#\x11E\x91\xe5\xc9\xc9DB\x10d\xb9\\^^\xaeV\v\x85|\x9e\x059\x82\xd1r\xbd&]\xf5\xab\x1e\xdao,\x9f\xf6\xc4h\x83O\f<\xa1\xb4ɒ\xa6\xba\xc9:\x9d[A\xc7\xc2Y\x8aۥlK\xa5\xdd]\xd3\xe4\xf9\x91\x91c\xc7\xc2\xe1dRQ\xa2QA\x18\x1ar\x9f\xa3(:\x8e$I\x92\xaar\x1c\xc0\xfa\xfaŋ\xe5\xf2\xca\n\xb29,\x06\xc0/\xc3\xe4\xde\xc7juk˶m[\x104Ͷ\v\x85XlrR\x92\x0e\x1e\xc41\xc5$F\x8d烣\x8bFG%irR\x14c1\xdbN\xa7\xb3\xd9+WHY#;4\u05ed<\xf5\x9a\xd4\xe7\u007f\xd9l\xc8X\x06\x8bx\xf8\x92\xd4\xde\xc3'ϝ\xc8\x05K\xae\xe8\xd0\x1c+g\x87\x95cA\x03\x01\xdac\xa7\r}\xeb\xfd\xa7\x19\x80\xc6b\xc6F\x06\x80ܗ\xf6\x00!(\x13\xd0\v\x00(\x95\x1e$\x00 >\xa8\xb1\x8d~7\x04\"\x82J\x1bv\xaf\x1c\x00\xb6\xe9od\x10,\v\xb7b'M\xe1\x1e\xca\xe5ᄈ\xedt\xfaڵ\xa9)\x8e\v\x85\x9e~ZQ\x1cG\x10\xb0s\x1a\xc7\x01h\x1aϋ\xe2\xf8\xf8\xa3\x8f\xf2\xfc\xc0\xc0\xfc\xfc\xdbo\xdb\xf6\xeen\xa9\x84\xfb!\n\x92\xec\x97\x0e\t\xb0\xab\x02h@\xf2\xddw\xa6Y*\xad\xaf'\x12\xf9\xfc\xe6\xe6\xdbo\x9f<\x99L\x8e\x8e\xbe\xf1\x86$q\x9c \xc4b\x04Ԡj\b\x85ff\"\x91X\xec\x95W^x\x81\xe3&&8\xeeo\u007fK\xa7\xd7\xd6Ο7\x8c\xc6X\xa0\x97\xa7CΛ\xe4(\xd0\xe7O/\xfdR\xc1~\r\x04\xcb\xf3\xa3\x15\x92\x97\xe7O{\xe8t\xcc5\x12A#\xa0i\x13\x13\x87\x0f\x87B\xa9\xd4\xc0\xc0\xd8X8<2\xa2(\xe1\xb0(&\x93\xf8\xbd$\xe11I\xb6\x89\xe3\xd4뵚i\x96˙\xcc\xfaz\xa5\xb2\xbb\xbb\xbe~\xe5J\xb5Z*\xd966\x99n>OY\xb6m\x1c\x11\xbc\xb1q\xf5j6{\xfdz$28\x98J\xcd͡\xe1UUr\x8d\xd1\xe8\xe8\xa8,\x1f:t\xe0\xc0\x93O\x86B\x17/\u07be\xfd\x8f\u007fT\xab岿\xe7\xc2*;\xa5\xe5J\x92\x96\x96\xdez\xabR\xb9q#\x14J&\x05\xe1o\u007f\x1b\x1e~\xfc\xf1p\xf8\xd5Wy^\x96\x1b\x81\x80(*\n@291\xf1\xf4ӑ\xc8O\u007f\x8a\x8c\x05\xc7ݸ\xf1/\xffR\xab-,\xe0\xb1Yυe\x00\xc8{Gֽ\x80r\xb7L\x96\x17E\xdej\xe0\xdcz~R\x84\x1b\x04X\xba\x1e=\xcf\x0f\x0e\x02h\xda\xc0\xc0s\xcfq\\*\x15\x89\xcc\xcd\x01\x8c\x8e\x8ab4\n\x10\x8b\xb9!=<\x17\xbc\x12\xec\x05\x02\x90\xc9\xe4\xf3\x17/:\xce\xfaz>\xff\xef\xff\x0e\x90\xc9\xe0\xbd!\x8c\x10\xc9-(\x14\xe8\xc6C\xb4\x16l\xce}\xa2\x1d\xa5V\x9e\xa0y\x8bV&\xa1\xfd\xef\xf6c\xff^\u007f\x0f\f\x00\xf0K\xd6\xddٿֆ@\xcdK\xf2b\x10 \xe0&\x03\xe2\xe7D\xa1\x12EY._\xba\x04P\xa9\xec\xee\x9e8\xe18\xe5\xf2\xb9s33\x8e\xa3i?\xfa\x11\xa2h\xf4\x8f8N\x14\xe7\xe7\x05!\x16\xfb\xc1\x0f\xae]\xb3\xed\\ni\xe9\xf6m\x1c\xfa\xebOQ\xb3\x1a\x04U*\xb4\x81\xfb\xfc\xf3Z-\x9d^\\\f\x85\n\x05Ax\xe7\x9dÇ\xe3\xf1T\xea'?\x11\x04\x8e\x13\x04L\x1aBU\xc5\xf3\x1c\x17\x0e\xcf\xceF\"\xf1\xf8+\xafສ\xfe\xfdﻻ\xeb\xeb\xe7\xce\x15\n\xb6mY~\x93\x9a\xc8\xf7~=PV\xa8Ë\x87\b\xea\xe1\xb1\f?+\x99\xaf\x91\xda\xe78\x80htf桇\xc2\xe1\xd1ѩ\xa9#G\x12\x89ӧ\xe3\xf1\xc1AU=}\x1a\rr2\x89\xc7\"\xff\xe1\xb1\xf1\x1e\x93Zl\x84\xa9\xe3\xe3G\x8ehZ\xb185u\xf2d\xadv\xf5\xea\xcaʕ+\xf9\xfc\xc2\xc2\xda\xda\xf9\xf3\xf5z\xb1H\x1a<\x13\x03\xb3\xbc\xfc\xd5W\x95J\xa101q\xf2d$\xb2\xb6\x16\x8d\x0e\r\xc9\xf2\xc1\x83D&\x04A\x96\x1d'\x1c\x9e\x988}:\x12y\xfc\xf1\xb5\xb5o\xbf\xadն\xb7\r\xa3Tr\x1c\x02\x00Ȓ<\x17\x96\x87C'\x9b\xbaϝt\xb9XX\xf8\xdd\xef\x8a\xc5o\xbe\x91\xe5X\x8c\xe3\xa2\xd1d\xf2\xe8QE9{\x96\xe3$\t\xcb\xd0\x10\xf4\x88b(\xe48\x03\x03\x13\x13O?\xadi\xaf\xbf\x8e\x93\f\xdfygq\U00077fedծ\\\xb1\xedb\xd1?CC\x9f\u007f\xbf\x00&돦\xb4\x1b\xeb\xe9\x1b\xeb\xf6[s\x83\xda\xcb\x15m\xf0\xa3Q\f\x13\xc6b##?\xff9\xc7ML\f\x0e>\xfd4\xc7=\xfex(4:\xcaq\x0f=\xc4q\x92\xe48\xd1(\xf1\xc3\t\x18oμ'\xdd?,+\x95z\xfai\x8e\xdb\xdd-\x95\x9e\u007f\xdeq>\xfblk\xebo\u007f\x03\xb8p\xa1Px\xfbm\x80\x8d\r\xf79v2Ȭ\xdc(z\x9d\xc5 \xdc\xc9\x06@~\xc3G\xf7\xe7\xdf\x03\x13\x02H\xa5\x9aC\x00.5\xd4\xf8*_\xbe\xbc\xbe\xee'\x04\xe0\x97\xb2a\xe5\x04\x10Af\xe7\x04\xb4\x17t\xbf\x1e\xa5,s\x9c\xe3\x18\x86a\xcc\xccp\x9c\xa6\x1d>\x8c\x15\xbd\x9a\x86\x19\xb4\xc4\xe0j\x1a\xfap\xd5\xeaw\xdf9N\xa5\x82)\x90\xecP\x80\x17u\xcb\xfe[]5\x8cr\xb9T\x8a\xc7\x1d\x87\xe7k\xb5DBQ\x14\xe5\xc0\x01\x9e\xc7\x1e\xf3do\x18\xb2\x90\xa4X\f\xbf\x1f\x1d\r\x87\xc3\xe1P\xa8R\xa9ժ\xd5\\.\x9fǙ\a\x9d\x9f\xb7_9\xf2\xdb`\x87\xe5\x19z\x19\f\xe2\xd1\xd31W/j\x9fP\xaf\xa9\x94\xa2h\x1a\xc7\r\r=\xf2ȳϦR\x0f?|\xf0\xe0ɓ\x03\x03\xff\xf4O\x9a\x96HH҉\x13\b\xe94\r3M\xd0\xf0\xa3b\xc5%Yw\x93\xe6x\xdeqx\x1e\u007f\xa7\xaa\xa1P<.\x8a\x93\x93\x83\x83\a\x0e \xfc\x1a\x1e\xe68\xd3\xdc\xd9Y^\xd6\xf5J\xc5q\f\x03k\xefu\x1dg\xf3\x85B\x96U\xab\r\f\x1c8\xa0\xaaSS8%\x10\r.^y8\xccq\xb1\x98 H\x92e\xed\xee\xee\xee^\xbfn\x18\xf9\xbc?\xb9b\x19L\x1a0\xa3t\x03\x00d\xb3\xb7n\xe9z&\x13\x8bMM\xf1\xbc$a\x12\xe0\xd8\x18\xb9N74 I\x8e\xa3\xaa\x91\xc8ؘ \xcc\xceF\"33\x00\xb6](lo[V\xa9d\x9a٬\u007fy趜\xd3o\xcc٫\xee\xde+G\x84\x8eݓ\x90\x10\x19\xa7<0\xa0\xaa'O\x02\f\x0f\xcf\xcf\xff\x97\xff\xc2q\xcf<34t\xf6,ǽ\xfe\xba\xa2\f\f\x00\x1c:\x84 JU\xb1\x89\x10\x01\x94\x04\x8c\xa0<5\xfe\x87\xe6W\x10phT4\xaa\xaa\xa3\xa3\x00\x87\x0f\xc7\xe3'O\x02\x1c:$\x8a\x93\x93\x00\xf9|\xa1\xf0\xf9\xe7H\x93;Nk\xab\xf3֤i\x17\n\xa1\xa6`e\bt\xce\x05\xa0C\x01A(\u007fz95\x85!\x00U\xc5\x10@\xa3n\xb6m\x80B\x01C\x00;;\xfb9\x00\xf7\x10\x00\xc0\nx\xef\x1c\x80^\x01@\xfb\xa4?\x96\xe1\xa4C\x00\xac\xd4@6\x10h\x16tW\x81lo\x03\x98&\xcf\xcf\xcc\x00\x88\xa2 )|\xe8\x10\xfe\xd2\xddO$\xc2\xf3\x8208h۶\xad뫫kk\x00\xa6I\xa8[\xda#\xf3ʦf\v\x18\xd9beE\xd7\xcb\xe5\\\x0e}\xdar9\x91\x90eY\x9e\x9a\xc2+Aņ\x14\x1e\xcfc\xc4W\x96Eq||l,\x1aմ\xf1qIr\x1c\xdb.\x14\xb6\xb6j\xb5z\xdd4\x89\xffٞ\x01`\x19h\xafu\xaf\xcf\xe9\xfa\xfa\xd6\xe49\u007f\x8a\x99\x8e\xd9\x13\xc3?00663#I\xe3\xe3\xa7O\x9f=;8\xf8\xdcs\xc3\xc3\x13\x13\xe1\xf0\x8b/\x8a\xa2$\xe1\xefР\xbbwۥ\xf91\xc3\x04\xa7D\xe0\xbf\bݍ\xb2\xe2\xc2P\xf4\xe4l\x9b\xe3x^\x92\x00T5\x12\x19\x18\x90\xa4\xf1qE\x89D\x1c\xa7X\xdc\xde^X\xd0u\"\x0f\x00\xa5R:mY\xa692r\xf8\xb0,G\"\x8a\x12\x89\xf0\xfc\xc0\x00\xd9\x1f*WA\b\x85\x06\x06\x04a`\xa0X\xdcݭח\x97+\x95\xdd]\x97\t`\xc9\x15\r\x04\xbc\x15\x1a\x8e.\xb6\xedl\xf6\xd6-\xc3\xd8ىF\xc7DZ_\xe1\xc0\x80\v\x040\v\xddM\x16\x94\xa4pxpP\x10ff\x92ɣGy>\x91\xc0Z\x81|\xbe\\\xbe}\xdb}\xf3\xfc\xcaQ\xd0\xed\x82\xd4߷3\xf4^I\xa14\x90$\xccP*54\xf4\xc6\x1b\x00SSss\xff\xfc\xcf\x1c\xf7\xa3\x1fE\"\xb3\xb3\x00O=\x85\x800\x1cn5\x9aD\xc6P\x92\x10xY\x96[]A\x00\x81\v\xb6\xdc\xdf\xf3<\xe9\x1c\x89\xa3\x9c\xe7\xe68.\x91\x00X_/\x16\xbf\xfc\x12\xa0Xlf6I\xa7\xd3\xc6\x01㍌h\xbb\xfa\x80f \xd09\x19\x90N\xa2\xee\x05\x00\xb0r\x00\xf6\x01\xc0}\xc1\x00\xec\x15\x00`=(V5@\xb3\xe1o\x17$\xf0S\xef\xcab\x04$\xc90\x00t\xbd^\x9f\x9b\x03\b\x85\xe6\xe6\xb0\x1a \x16#\x839E\x91\xe7\x01\x14%\x16\x03\x10\xc5Xlk˶+\x95\xa5\xa5B\x01\x80xY\xde\f\aK\xd0Z\x81\x01\xc9\xf2_Z\xd2\xf5J%\x97\xd34\xc7q\x9c\\\x0e\x81\xc0\xc4\x04\x9e\x8f\xaa6S\xd7\x1c'ˢ\xc8q\xc9\xe4\xf0p$\x12\x0e\x1f<8:\x1a\x0e\xcb2\xcfW\xab\xba\xae\xeb\xd8\x12\x19=\xe0v\x06\xba\xdb%˰\xfbUȴ\xc1'\x9e>m\xf0\x93IU\r\x879np\xf0ĉ\xc7\x1f\x8fF\x8f\x1e=v\xec\x91G\x92ɟ\xfe4\x1a\x8d\xc7%\xe9\xf8q\xf4\xc4$\xc9m\x88\x83\xd2DrC*\x95BA\xd7\xd7\xd666n\xdc(\x16\xbf\xfaj}}a\xa1T\xbati{\xfb֭r\xf9\xfa\xf5r9\x9f\xd7\xf5\x8d\rI\x92e\x8e\x13EQTU\x8e\xd34\xf4\xabPa\xa2D\t\x82\xe3\x88b(\x94H\x88b\"\x91\xcfg2\xb5\xda\xeaj\xa5\x92N;\x8ea \x13`ێ#\x8a\xa6Y.\xa7R\xd3Ӳ<>\x8e\x1e6v{@rZU\x01\xc2\xe1p8\x16\xe38\x9e\xdfظxQ\xd7760\x8f\x85f\x02\xbc\x14\x9c\x1f P.\x03XV:\xbd\xb0`\x18\xdbۚ64\xe48\xba\xae\xaa\xa9\x14\xcfOLp\x9c(:\x8e\x1b\x1a\xc0u\x9e\x97\xe5X\x8c燇\x13\x89Ç\x05av6\x14\x9a\x9ar\x1c\x04\xa9\x8ec\x18\xa6\x99\xc942k\x9d\r\xb6\x97\x1cџ\xb3\xca3Y9 ,\xb9b\x01\xc9dRQ\x8e\x1f\a\x18\x1a\x9a\x99\xf9O\xff\x89\xe3N\x9d\x1a\x1b{\xe5\x15\x8e\xfb\xc9O\x14%\x99\x04\x98\x9dE#\xe8>\u007fr\u007f\xf0\xdd\xd7\xf5juu\x15\xe0֭t\xfa\xb3\xcf\x00\xbe\xfc2\x9d\xfe\xf4S\x80K\x97\xf2\xf9K\x97\x00\x16\x16t=\x9b\x05\xd8ڒ\xa4X\f\x87\x81\x87\xc3\xf8\x1e42\x05$93\x1cV\xd5\xe1a\x80X,\x9b\xbdv\r\xe0\xda5\xdb\xde\xde\xe687\xa4\x82z\x92,]\xf9pӘ\x1b\x99\x00\x96᧫\x05\xee$\x00 U\x00\xfb\x00\xe0\xbe`\x00ș\x11\x00\xb0\xb6\xd6O\x00\xe0\x1d\x12`1\x02\xed\x19\x00\xf7~7\xaf\xb3\x10\xaf(\xa6\xd3\x00\xb6\x8d\xa9=\x1cW\xaf\x0f\x0fs\x9c$\x1d9\x82\x06\x04\xe1\x00\x16\x06\xf1<\xc7\xc5\xe3\x9a\x06\xc0q\x86\xb1\xb0\xe08\xf5\xfa\xf66\x9e\xa1\u007fFß@\xe2\xc4B\x00ǹ}[\xd7k\xb5|^\x14MS\u05f7\xb6\x12\tE\x11\xc5\xe1aI\x12E\x8e\x8bF\x89\xc7\xea*\x12Ap\x1cU\x8dFUU\x14gf\xa6\xa6\x12\tM\x9b\x99I$\x14\x85\xe7-K\xd7u\xdd0l\xbbT\xb2,4\x98\xed\f7K\xf1\xfa\xad\x83\xf62\xf4,\xc5\xec*hU\xd54\x8eK\xa5\x0e\x1f>q\"\x14\x9a\x9d=u\xea\xf1\xc7\x13\x89\xe7\x9f\x1f\x19\x99\x9c\f\x87\x9f}\x16\r5\xf1\xac\t\x95\xef\xdeE\xd34\f\xcb*\x97\xd7\xd7\x17\x17\x8bſ\xff\xfd\xeb\xaf\xdf{/\x9b\xfd\xec\xb3\xe5\xe5k\xd7\xea\xf5\xd5\xd5Lfs\xd34\xd3\xe9lvk˲r\xb9\xed\xed[\xb7t=\x9b\xdd\xd8X\\\xacV\xd7\xd6$I\x96m\xbbR\x89DR)Q\x1c\x1e\xc6l~Q$\xe5}$ɏ\xe7EѶ\v\x85\x8d\x8d+W\f\x83\x94\x8dZV\xb1\xb8\xb1a\xdb\xf5z\"1=\xcd\xf3\x986&\bcc\b \\\u007fMQ\xe2q\x9eO\xa5$)\x1c\xb6\xaclvg\xe7\xbb\xef,\x8b\x84\x04\xbc\x14\x9d\x97<\xb5~n۵\x1a\x80e\xed\xee^\xbchY\xbb\xbb\xb2\x1c\x8d\xdav6\xabi\xc3\xc3\xce\xf3\x8a\x82ϱqT-\xc7\t\x82,\x03hZ$2>\xce\xf3\x87\x0e\xa5R\xa7N\xf1\xfcؘ,\x8f\x8c\x00\x18F\xb5Z*!\xd4\xcaf\xbd\r8\x8b\tb1C^\x86\xde\xcb\xe0\xbbr\xa5(G\x8f\x02\f\x0eNN\xfe\x87\xff\x00p\xe8\xd0\xcc̯~\xc5q\xaf\xbd\x16\x8b\x1d>\f\xf0\xc4\x13\x01\xd8\xdd\xcd\xe5\x16\x17\x01\x96\x97e9\x91\x00\xb0m\f\x01\f\x0f\x13\x80A\xee7\xde\xffh\x14\xd7WV\xf2\xf9\u007f\xfc\x03`w\x17%\x86\xe4|\xb8UI\x04\b\x10\a\x8aHV{ \xe0\xb7L\xb2\x17\x00p\xe0@\xfb\x10\xc0>\x03pO\x03\x00\xec97<\x8c\xaf\x8a\x9b\x03@3\x00\xc1\x00\x00˃\xf1\n\x05\xb0\xaa\x00Z\x1f\x18+\xe9\xa5\xf3\xfdo\x05\x02\xdb\xdb\xc8\x04\x1c:\xc4q\xb2<0\xa0i\x00\x8206\xd6\xd8P\x05\x80\xe7c1\x8e\x13\xc5\xe1aUu\x1c\xd3\xccdn\xdet\x1c\xd3,\x14\xfc\x01\x19/E\xcd^\xae\xad\x99\xa6a\x94J\xa5R\xb5Z\xa9,/\xc7b\x92$\b\x8a\x12\nI\x12ϧR\x84\xcau\xa9f\xf4\aDQ\x108.\x16\x1b\x18\xd04E9|xzz` \x1c\x9e\x9f\x1f\x1f\x8f\xc7%)\x1c\xd6q'$\xc4\x00\x00 \x00IDAT4I\xc2:rðmQ\xac\xd5,\xcbq\xe8X<\xbd\xa4\xeb\x9bY\n\x99x\xf4\xf4\xd2UЂ \b\x00\x89ā\x03\xd3Ӓ4>~\xf4\xe8\xf1\xe3\x9av\xec\xd8ɓ\x8f>\x1a\x8f\xbf\xf8\xe2\xe8\xe8\xc4D8|挪j\x9a LM\xa1Zsc\xea\x8d\xedz1\xed\xb3\\6\x8c\xf5\xf5\x1b7\xbe\xfd\xb6P\xf8\xeb_/\\\xf8\xf4\xd3J\xe5\xeaU]\xaf\xd7\x01r9ܖd]\xd3Y\xf8\x86a\x9a\xba\x0e`Y\xdb۷n\x19F\xa9\x14\x89$\x12\xb6mY\xb1\xd8\xf0\xb0$\x8d\x8f\x93\xd89Q\xb7\xb2\xaci\x82\x10\n\xed쬮\xd6j7o\xd6\xeb\xf9<\xee\x0faH\xadV\xa9\x98f\xb1844?/\x8aCC\xc8,\xa0\x81A\xca]\x14\x1dG\x104mpP\x10FF,˲Lss3\x9f_^v\x1c\x92t\xeaW\xd1yM\xcdl,\xb3E\x9a:\x9d\xbetɶs9˲,\xcbZ]\xd54\xec\x14\x88\x9ej<\xee\x1a(\"W<\x0f \b\xa2\x18\x0es\\*\x15\x8f\xcf\xcc\xf0\xfc\x91###\x8f?\xce\xf3\xb3\xb3d\x141\xb6\x16\x13\x84j5\x97ä\xb6j\x95\r\x14Y\xf2\xe5%Wt\xf9\x9d+W\xd8\f)\x99\x1c\x1c|\xf9e\x80\x89\x89\x89\x897\xdf\x048q\xe2\xc0\x817\xde\x00x\xf9\xe5D\xe2\xf8q\x80\xa7\x9e\x12\xc5H\x04`h\x88\\\x17\xadkI\xf2^\xad\xb6\xb6\x06p\xe3\xc6\xca\xcao\u007f\v\xf0\xf6\xdb\x1b\x1b\xff\xfb\u007f\x03ܼ\xe98\x95\n\x00\x01lD\xaeH\xb2\xaf+W\x96\xb5\xb5\x85-\xa4\xbf\xfd\x16 \x9b\x8dD\x8e\x1d\x03\b\x87\x15ed\x04\x00\xcbF\xdd\x1c\x02QD\xc6@\x10vwϝ\x03\xb8z\xd5q\xf2y\x8es\xf7K\x86\x9e\x91\x90@3\x00h\r\t\xb4\xcf\t`\x97\xff\xb5\xcf\x05\xd8\x0f\x01\xd0\u007f\x0f|\x15\x00]\xd9~g\xfe\xd8-\x81\xdb\x0f\vr\x05\xbe\xd9\xf3\xa7˦ܡ*\xcd\x06\xa0P\xc8\xe5\xb0\xc5\xe7\x17_\xd8v>\xff\xe1\x87/\xbc \b\x89\xc4Ą\xaa:\x0eϏ\x8e\x92\xbc^I\xe28\x80p\xf8\xe4IQ\x8cF_z\xa9X4\f\xcb*\x16?\xff\xdcq\f\xc3\xcb\xf3o\x86S\xad\xd3\f[\xaf\x9f\x06T\x8b\x8b\xa6i\x9a\x86\xb1\xb1\xb1\xb5\xb5\xbb\xfb\xa7?=\xfex<\x1e\x0e/,\xcc\xcd\r\fD\xa3\xcf=\xa7(\x8a\"\b\xa3\xa3\x84\xb0n~n\xa2\x18\nI\x12Ǎ\x8dMN\xaaj(4::6\x96L*J\xb5z\xf2\xe4Ԕ\xe3\xa4\xd3\xf9|\xbd\xae\xebKK\xd9l\xb5\xaa뫫\xd9l\xa5b\x18\x99L\xa1P\xa9\x98f\xb9\x9c͖˶]\xaf\x97J\x86\xe1\x86@Z_\x10I\x12\x04\x00AH$b1\x9eW\x94X,\x1a\x15\x84P(\x1a\x8d\xc7E1\x91\x88\xc5\xe2qY\x1e\x1eN$\x12\tY\x9e\x9f\x97\xa4P\x88燇\x05\x01\xe7\xd8c\xcd2&X!\xc0k\x8e\xe5\x93\xeb2\xcdz\xddqJ\xa5\x9d\x9d\x8d\x8dZ\xed\xeb\xaf\x17\x16.\\(\x95\xbe\xfez{{cö\xb1Eo;\x85\xdc|\xdeD\xb1\x11\xe0cY$\xcb\xff\xfa\xf5/\xbe\xa8\xd5n\xde\x1c\x1a\x9a\x9bS\x94C\x87T5\x91@\xbe\x88\\\xa7\xa28N$2009)\b\x8aR(,/\x9b&\x01\x1a\xa6\x99\xcd^\xbfnۆ\xb1\xbc\xfc\xf5\xd7\xe5\xf2g\x9f\x1d<\xf8\xec\xb3\xe1𫯒\xeb$g!I\x9a\x06\x90H\xcc\xcd=\xf7\x9c\xa2\xbc\xf4R\xb5\x9a\xcdV\xab\x95\xca\xf6\xf6\xa5Kny++)\x90,\xc9u\xd1r\xcf\x02\x9c\x96E\x80\xca\xea\xea\xbb\xefڶ\xaeg\xb3\x8b\x8b\xf5z6;3\xf3\xdak\x82p\xf2\xe4\xc0\xc0\xc3\x0f\v\u00993h\xf0\x93\xc9f @r\x06\x14EQ\x12\t\x80\xe9\xe9\xe1\xe1G\x1f\xe5\xf9\xa9\xa9T\xea\xe4I\x8e+\x97gg\u007f\xf63\xf4\x8877m\xfb\xe6\xcdryc\xc3q66J\xa5\xf5u\xc7\xc9\xe5*\x95\x8d\r\x80r\xb9RY[\x03\xd0u4\x94tGDWK\t\xc2\xc8\b\xca\xf1\xd4\x14\x80\xa2\x84\xc3\xe3\xe3\x18J\x99\x9a\x02H&5mb\x02`l\f?\x9f\x9d\x15EM\x03\x18\x1aB\xcf\x1a\x93|\x1b\xa9w:\x96Ot\x8ba\x94J\xd8(\xe9\xdc9\x80\u007f\xfcce\xe5_\xff\x15\xe0\xeaU]_\\D#\xd6(WD\x9f\xb0\xe4\x8a\x00\x1e\xdbF\x99\xe4\xf9\xcd\xcdw\xde\x01\xb8pA\xd3\xe6\xe7\x01\xa6\xa7\x05!\x12q\x01\x0e\x80(\xc6\xe3\x00\x13\x13\xe1\xf0\xe1\xc3\x00\x91H\xa9\xb4\xbc\xec\xdd\"\xd8ﰟ\xbb1\x06\x98\xe5\x1c\xdf\xdf\u007f\x0f\x1c\x00\xa0ǟxML\xef\xfd\xb8\x8d\x9e\xbe\x17 h5\xf8͆ߥ\xc0\x9a\xfb\x024\a2\xdc\x17\x87\x00\x007\x16\xf9\xd5W\x00\x86\xb1\xbe>6f\xdb\xc5\xe2;\xef\x9c:\xc5\xf3\x9a\xf6\xe6\x9b\xe8\xf7\x11\x0f\x05 \x14\xc2\xde\xfdO>)I\x91ȏ~\x84s\xda\xfe\xf0\x87\v\x170\xbd\xac=\x10\xa0\xffX@\x80\r\x00\xc8\xef\xcae\xc7q\x1c]\xff\xf0\xc3\\\xae\\\xaeVo\xdf.\x95\xaa\xd5\xd5\xd5c\xc7\x06\a5\xed\xa1\x87\xc6\xc7\xe3\xf1P\xe8\x89'dY\x92\x04a`\xa0Y\xbd\x91\xe7I\xd0\u007f8,\b\x82\xc0qᰪ\xaa\xaa\xa2LM\r\r%\x12\xb2lY\x18^\xd0uLi\xaaTL\xd3q\x1c\ag\x1c8N\xb5j\x18\x8ecە\x8ae\xe1t\x03A\x90$\x9eWUI\x92$\x8c\xa1\x8b\"DžBH\x99\x87\xc3h0T\x15\xd9\n\xec\xc7\xd8\xecq\xf1<\xc6\xee\x9b!\f9s\xd34\fۮT\n\x85lV\xd7\x17\x17o\xdf^\\\xacV?\xff|q\xf1\xeaU\xc3X[C)\"ϕ,\xe9\x96\xce\xe4>\x92c\x13\x85J>'\xf2\x81\x8d~\x1c\xa7\\\xce\xe566\xaa\xd5۷GG\x13\x89P\b\x01\x00\xa9\xca\xc0X\xb9[\xf3\xdf:\x94\x8a\xe3n\xdcx\xff}\xd3\\Y\x89\xc5\xc6\xc7k\xb5/\xbf\x1c\x199zTQ\x9e}\x16e\xd5e4B\xa1d\x92\xe7\xc7Ǐ\x1e\xfd\xf1\x8f\x15\xe5\xc5\x17k\xb5R\xa9^\u007f\xeb\xadB\xe1\xf6mW\x9e\xbd\xaaK\xe8\xdc\x14Z\xaeXe\x85\xba^.ߺ\x05P\xaf_\xbe\xfc\xdf\xfe\x9be\x95J##\xcf>k۷nML<\xf3\f\xcf?\xf1D$2;\xcbqǏ\vB(D\f\x16\t\xc1\xb8w\x94籜0\x1a\x15\x04Uu\x9ch\x14\xb3\xe7gg\x93\xc9c\xc7\x00L\x13\xdf\xd5z\x1d\xfb+T*X\xbbR\xad\x9a&Y\xd7u\xf2\xdcp,\x0e\xe6L`(\"\x1cƤ\xccP\b\xdf\xddp\x18\xbdUE!\x1e\xb4WAs3[\x88Y\"\x00\xc5b\xb1x\xed\x1a\xc0ŋ\x9b\x9b\xef\xbf\x0f\xf0\xcd7\x99\xcc{\xef\x01lo\xe3\xbd\xf3+W.r\x9cju{\xfb\x93O,k{{t\xf4\x87?\x04\xf8\uaad1\x91\xc7\x1e\xe3\xb8\x13'\"\x91\xb99\x8e;~\\\x145\xcdq\x12\t\xd2r\x98\x15\x06%\x06\x9al\x871wM\xc3\xe4V\xf7M\xf46$\xee\xfc\x8c\xe6;\xe0\xf5;L\xb2Ğ\x1e\xd9l\xa1p\xed\x1a\xc0\xa5K\xbb\xbb\x9f}\x06p\xe5J:\xfd\xce;\x00\xdb\xdb\xf8\xbc\x88<\x91\xe7H3I\xb4\\э\xa2\xc8:\xd13\xae\xb1\x9f\x04\xbd}\xf3\xbfP>l\x9b\x00.4\xf4\xc5b\xad\xb6\xbd\x8dIu\v\v\x00\u05ee\xed\xee~\xfe9\xc0\xeaj\xa9\xf4\xcd7\x18\xc3\xefE\xaeh\xb3M\xcb\x13\xbbS&\xe6Z\x10\x00\xca\xce\x1e\xeb\x1c\x9bf\xed\xbf߆\xbf\x1b\x9d\xef5\x90l\x1f\x00ܓ\x00\x80\xc5\x00\xf4&R~\u007fM\x1b\xf6V@\xd0~If\bЁ\f\xb7uf3e\xa6\xeb\xb8N^\xf0\xd6F6\xe8o\x89\xe2\xdf\xfefەʿ\xff\xfbk\xafq\\(\x14\x89\xc4b<\xcf\xf3G\x8e\x10\x84Nf\n\f\f\b\x82 \xccͽ\xf8\"\x80\xa2\xfc\xf4\xa7\xa2h\x18\xf5\xfa[o]\xbe\xec\xa7<\x91f(h\xc3\xc5ZoU\u0604j$\xb1\xed\xdd]\xcbr\x9cBawwgG\xd7\xd3i\x8e\xdb\xd9\xd1\xf5\xebדIA(\x97\xc3\u1249DB\x10\x12\x89d2\x12\xe1\xf9\xa1\xa1hT\xd3Dqp0\x14R\x14A\x18\x1bS\x94Pȥ\xf4\x15\x05\r\xb7,\x93$1\xd2T\x86\x8c*\xc5Ёa\xe0\xb2^7\f]\xb7\xedj\xb5Z\xd5u\xcb\xcad\xca\xe5ZͶ77s\xb9bѶ\xb7\xb7wvvw-+\x9b\xdd\xde\xced\x1c\xa7XDϞ\xf6\xb4\xe8\x8ey\xe4s\xdacguht\xcdy{ \xd0\n\x04\x05A\x92\xb0\xf1\xd2\xd0\x106a\xc6T\xab\xc6\xf7\x86\x00\x19\xb7\xf3\xa4ۂ\xba\xf9\xf9\xb8m\xb5\xb6\xb6Οw\x1c\xdbV\xd5XL\xd7\xdfy\xe7ȑ\x97_\x96\xa4\xd7_Ǥ4L>\xc5_\x88\"\x00\x8e\xaa\xe6\xf9ӧO\x9f\xfeկ\x1c\x87\xe7/\\\xf8\xfd\xefm\xfb\xfd\xf7K\xa5\xa5\xa5V\xf8E\x1bW\xbaC\x1fm\xb8X!\x03\x1aА\xebA&\x04@U\xb1ܭP\xc0\xe5\xf66\xc7ɲ\xe3\\\xbe\x1c\x89\x1c<\b\x10\x89$\x12G\x8f\xba\xb1\xf9\xe1aU\x1d\x1a\x02\x18\x1e\x96\xe5X\f`x\x18c\xdd8\x8bӥ\xf0e\x99\xae\x9b\xc7{N\xb4\x01\x06\x9e\x00j5\xccʯVu\xbdP\x00\xd8٩\xd5vv\x00\xb6\xb6J\xa5\xd5U\x80\xed\xed\\\x0e\xb3\xf1\xab\xd5\xeb\xd7\x01\xcae\xf4\xbc\xe9\xe7Ē/zj#ݠ\x89\x96+V\x83\xa3\xd6\xf2GE9q\x02 \x14Rձ1l@\xd4N\x03\x13 \xe3f\xf9w\x0e-\xdeM\x83\xff\xfd\x04\x02\x0f|\b\xa0_\xb3\x00\xba?\x9f֎ծ\to\r\t4gú\xad\x82\x9b\xaf\x82\x8e\x01{WY|\xf7\x1d\xf6\x12\x0f\x87m\xbbV\xfb\xf3\x9f\u007f\xf8C\x8eS\x14Y\xc6\x10\xc0\xec,B\x0f7b\x9dL\n\x82 \xccξ\xf0\x02\xc7\xc9\xf2믫\xaa\xae\xeb\xfa_\xff\xfa\xd5W\x9dz\xf7{\x01\x01\xaf\xecW\x1a\x10\xb0\x1a\xf3\xe0\xf43\x00E\xc9dАg2\xe9\xb4emo\x03\xa4Ӗu\xeb\x16\x9aoQ\xc4BHQĤ>Q\f\x8506\xa9\xaa\x92\xc4q\x92$\x8a\x8deL\x1c\x87\xf9\x0f\xb6]\xafc\x96y\xb9\x8ct\xa7a\x98&z\xfa\xb6\r`YX\xe8H\xb7 \xa6\x935YK\xd6\x14=V\x12&\xeb~\xd3\xe5jt6z(4?\xff\xf8\xe3\x1c7<\x1c\x89\f\x0er\x1c\x1a\xe6ƽ\xe3x\xdfJ\xa5R\xc9\xe5\x1c\x87$\xff\xd1\x00\x80\xac\x93?\x97\xd1YZ\xfa\xe8#\xc7q\x1cI\n\x87\r\xe3/\u007f\x99\x9b{\xee9Ax\xfduQ\f\x87\x01pF\x05\x86\x18\xf0>\xc7\xe3ss\x1cw\xea\xd4\xe9\xd3\xff\xf1?r\x9c$]\xbd\xfa\xa7?9\xce\xfb\xef\xa7ӗ/\xfb\xef\xe0H\xdfG\xafa^4\x10 \xd7\xd3N\xaet\x1d@\x96\x8būW\x01\xb2Y\\\x92l\xef\xc5E\x97\xfa\x8fD0\x14\x10\x0e#\xbf\x12\x8d\x02Ȳ,G\xa3$4ИydY8\x8b\x01\x9b.\x99&\x1a|]\xb7\xedJ\x05)\xf5b\x11\x97h0\xf7V\xaehmɚ-\xc0*\x8b\r\x85\xc6\xc7\u007f\xf63\x80\xe9i\x9cʈɕ\xcdA\x1b]\a\xc8\xe7+\x95\xe5e\xec\f؞ɡ\xb3\xff\xdb\x03\x82\xbd\n\x05\xec\x87\a\x1e\xf8\x10\xc0\xbd1ځ\xf6\xe4\xbds\x04\xfc\xc6\xc8\xdc2\x184\xcc͝\xf3Z=\xf4\xaf\xbfF\xefV\x14-\xab^\xff\xb7\u007f;{\x16@\x92~\xf1\vM\xe3y\x8e\x9b\x99i>K\x8e\x8b\xc7\x05\x81\xe7\x0f\x1cx\xf6YU\x95\xa47\xdeдz\xdd0\xde~\xfb\xa3\x8fl\xdbqn\xdel\uf072\x86\xf8\xb0(mZA\xb1<8\xff\x1d\xd8\xc8}0\fl[\x83\x06\x9c\xe7Ѥ\xf1<\x80\xae\xbb@\x86\xbe\xbf^e\x8e\xacrѠK\xafq̬\x16\xb2\xf4\x98\xd7\xd6>\x0533\xa7Nq\xdc\xe8\xe8\xc1\x83\x8f=&\x8aO?-I\xb2\xec8dX\x8b+\x13\x95J\xa1`\xdb7nll\\\xbd\xea8t\xd5\x01\x9d%N\xee\ay\x9e\xeeu,.\xfe\xf5\xaf(\x81\x92dY\u007f\xfe\xf3\xcc̙3\x1c\xf7\xb3\x9f\xc9r8\f04\xe4BXd[b\xb1\xc9I\x80\xe3\xc7O\x9e|\xf3M\x8eӴ\xc5Ł\x01\xc7y\xf7\xdd\xd5Տ?\xf6n\xa5ˢ\xb4Yr\xc4b\x06\xc8u\xf8\xed\xe8'\x8ad|1\xf6:\x10\x04\xa4\xdfy\xde476\x00x\x1e\xa3\xee\xac\xf76\xa8\\\xb1Λ%O^U\x16\xeci\xa3\xed\x81dc\x83+\xcc\x18\x1a\x1f\xff\xcf\xff\x19`zzp\xf0\xecY\xec0\x88\xd52\x8dAN\x00\xcb*\x95n\xdc\x00\xf8\xe6\x9bz\xfd\xe2E\x80r\x19\x8f̚\xb1\xe0=K\x81v\xa4\xda\x03\x86~\x18uV:\xf9\x83\t\x10\x1ex\x00\xc02\xa5\xfd\t\x05\x04\xdd\v]\x0eH\x87\x04Z\x05\x9e\xce\th\u007fՆ\xd1\x18}l\xa5\xea[\x97_|\x81@\xc0\xb6-K\xd7\u007f\xff\xfb\xb3g9N\x14_\u007f\x1dǂ\x1c\x03p_\x00\x00\xba\xdc\xef\xeeFn\xd8\x02\xdc\x1c\nhM\"\xa4\x99\x00\xe2\xe97\x03\x01wlN\xf3v$7\xc0\xab\xc1\x93\xe3\x9c;\x87[\x1a\x86i\x9a\xe6\xef~\xf7쳂\xc0\U000eff56L\n\x02N\v\xc3\"&\x92\xe3\xad(\xd8j\xf8\xf8qE\xe1\xf9\xd7^\x1b\x18\x10\x04\xc7\x19\x1f\xff\xfcs]w\x9cO>\xf9\xee;\xc7\xc1&\x19\x8d\n\x9b(\x1aڰ\xb4f\xab\xfb3\xa0\xcd#\x9e\xd8\xe3y\xfd6\xb0\xa2\xef\x8fW\xb2\x92ߎ\x88,C\xcfn\xe8\xd4\xfe\xbe\xb1g\x0e\f\rMN\x02\f\x0e\x1e;\xf6\xf4\xd3\x1c\xf7\xd8c\xa9ԁ\x03\x1c\xf7\xc8#Xn\x86\xbfò\xc4\xc6DH\xdb.\x14vv\x1c\xe7\xfc\xf9\xc5\xc5O?u\x9c\xe5\xe5f\xc0Fg\x8f\xd3=\xfe\xc9y\xb3<9۾~\xfdO\u007f\x02\xb0,\xcb\xd2u\xc7\xf9\xdd\xef\x0e\x1e|\xfey\x80\x9f\xfc\x04c\xe7\a\x0e4WZ\x00 u>443\xf3\xfc\xf3\x00?\xffy4:1\x01\xf0\xe5\x97\v\vo\xbd\x05\xf0\xd5W\x85\u008d\x1b\xecV\xbc\xac\xecvZ\xae\xbc\xa6C\xd2e\xb7^\x01E/ \xc9rG\xbc\xe4\x8a%g\xac\xdf\xd1\xc7gu\xc0\xf3/W\x03\x03?\xf9\t\xc0\xe8\xe8\xe4\xe4\x1bo\x00\x9c9\x13\x0e\xcf\xcd\x01\x1c=\xcaq\x98SB_#2#\xba\x9e\xcf_\xbc\b\xf0\xd1G\xb9\xdc_\xfe\x02\xb0\xb5\x85\xdf\xd2\xe3\xc8\xe9N\x80$\x14Ю&\xa2\xd9\xf3\xf7\xa7Ճj\xfbf\xd7\xeb·\x1d\xee^\xee\xc3\x03\xcf\x00\xdc\x19\x1c\xe7\xf5\x00\xd9\xc9.\xac\\\x00\xfa{\xbaU\xb0\xd7U\xb6/#dS\x92\xdf~\x8b\xc0\xa2T\xb2,\xcb\xfa\xe3\x1f_|\x11\x80\xe3\xf2\xf9\x91\x11A\x00x\xf2I|9\x89\xe2\xc0\x86B\x1c'\xcb\x13\x13\x92\xc4q\x8f>\xfaꫢ\b0>>9Y\xaf;\xceG\x1f}\xf2\x89i\x02ܸ\x81\xaa\x99\xf64h \xe05Oދ*\xa4==\xbf\x9d-\xf7\xfaE\xf5\x9b\xa3\xc1\xea!ߪ\xa0EQ\x14\x01\xa2ѣG\x9f|\x12`ffz\xfa\xc4\t\x8e{\xee\xb9P(\x1e\a\xc0A9\xeeHWZ\x91YV\xb9\x9c\xcb\x01\\\xbe|\xf5\xea\xc7\x1f;\xce\a\x1f\x98f\xa5\x02\x90\xcd\xe26\xa4A\f\v\xa8\xd1\x06\xd2k\\\xaeeݼ\xf9\xce;\x00\x96U\xafW*\x00\xff\xfa\xaf\x87\x0f\xbf\xf2\n\xc0\xab\xaf\x86B\xa9\x14\xc0ѣ\xb8/\x92Y\xef\xce\x18\x18\x1az\xe8!\x80\xb3g#\x91\x91\x11\x80\xe9\xe9\xe5\xe5\xcf>\x03\xf8\xf0\xc3[\xb7\xdez\v`y\x19A0\xb9O\xc4\xc0\xd0!\v:D\xe0\x05\bX\x06ׯw\x18\x14\x00\xf4\xcb\xdda\x01I:\xa6\xcf\x1e\x1f,I\xb3\xb3\x00\xf1\xf8\xd4ԛo\x02\x1c>\x9cJ\x9d=\v\xf0\xcc3\x92\x14\x8f#\x83\xe4N\x9cl\xbe\"\xcb\x02\xa8\u05cb\xc5\x1b7\x00>\xfe\xf8\xf6\xed\xff\xf1?\x00\xbe\xfa\xca\xed\x9a\xc7q\xee\xf3\xf1\n\x05\xd2\xf7?h\x00\u05eb\x9b@7z\xa1_\xbac\x9f\x01\xb8+\f\x00]ٺ\xb7X\xabS\xf1O{\x0f\xbfs.\x00\xbd\x17\xd6\xd5x1\x024\x10`{\x1a7n`g\xb5t\xda4\x1d\xe7\xddw_y\xc5q\x00\xb6\xb7\xe7\xe7E\x11ॗ\xb0\xde9\x91 \x8a\x80\xb4O\x89F\x05\x01`l\xec\xd1G#\x11\x8e\xfb\xc5/&'M\xd3q\xae^\xbdx\xb1V\x03\xf8\xf2˯\xbf6M\x80\x8d\r<\x12Q@\xb4¦\x81\x00Kqw?T&\x98'\x11T\x91\x04U̬\xa4+\xd7\xf0\xe3ӋDff\x8e\x1c\x01\x18\x199x\xf0\xd4)\x80\xc7\x1f\x8f\xc7\xc7\xc6\x00\x8e\x1f\xc7d\xb3P\xa8\xb1IR㹘\xa6e\x01\x94˙\xcc\xfa:\xc0'\x9f\\\xba\xf4\xf1\xc7\x00\x9f~\x9aNߺ\xe5&\xb7\xb1Z\f\xd3ex\xb4ad=\x17:vmYkk\u007f\xff;ΡL\xa7\x01~\xff\xfb\xa3G\u007f\xfaS\x803g\x92\xc9\xe9i\x80\x1f\xfc\x00\xabPB!\xf7\x89`\x1f\x87pxt\x14`ff~\xfe\xc7?\x06\x18\x1c\x1c\x1c\xbbCc\xb3bV\x14,O\f\x87gg\x0f\x1f\x06\x18\x1aB\xc3\u007f\xecX29>\x0ep\xe2\x84(\xaa*N\x83k\xae+\xa7}!,\xe7+\x95\xb2\xd9t\x1a\xe0\xfc\xf9\x85\x85\xaf\xbe\x02\xf8쳕\x95\x8b\x17\x01\xb6\xb6\x9a=}\xb2$\n\x9a\xa6\xd0\xdd\xfbݾ~۽?\xcd-\xab\xbd\xb2\xd2]\x00g\x9a\xd9,\x80\xae_\xbc\xf8?\xff'@\xad\x96ͮ\xac\x00lo\xcf\xcd=\xf7\x1c\xc0ٳ\xe8\xf9\x9f:\x85cf\x1b\xdb\x14\xe3[\x819\x03\x83\x83\xa3\xa3O<\x01\xf0ꫩ\xd4C\x0f\x01<\xf6X&\xb3\xb0\x00\xf0\xed\xb7\x9b\x9b\xe7\xce\x01,, C\x90NcY\x9a\x17#\xe0\xc58\xdd)\xb9\xf2\v$\xd9c\xadEqr\x12@\xd3FG_~\x19`l,\x95z\xea)\x80S\xa7\xc2\xe1\x99\x19\x80C\x87\xdcV\xc8\xcd\xe7@\x13\xfc\xe8\xe9\xe7r\x18\xdb\xff\xfbߗ\x97\xff\xef\xff\x05\xf8\xf6\xdbJ\xe5\xb3\xcf\\O\x9f\x00\xc9V\xb9by\xfe\xed\xef_k\xf2s0\x8f\xdeo\xaeϝ\xa6\xf7\xfb\xd5\xe8\xa8\xffn\xeb\x03\x1f\x02\xe8\xad\x0f\xc0\x9d\x03\n\x9d\r=\xab\x8c\x103\xf5It\xae{ \xe0\xddc\x9d(̅\x05\xc7\x01\xa8\xd7\x17\x17\r\x03\xa0X\xfc\xe1\x0fm\x1b\xe0\xe6\xcd\x13'\x14\x05\xe0\xd9g\xa3Q\x9e\a8t\x88\xce\x19 \x8d\x86T\x95\xe3\x00\x12\x89\xe9\xe9H\x04\xe0̙\xf1\xf1H\x04\xe0\xf4\xe9G\x1e\xb1,\xf4X\xabU\x80\x8b\x17o\xdd*\x95\x00\xd6\xd6n\xde4\f\x80|\x1eϨ[ \xe0\xbfܨ;\n\x96\xce\xdao\xa5\xf8\xf1))\xca\xf8\xf8\xe8(@,699=\r0>>221\x01p\xf2\xa4\xa6\r\f\x00LM\x89\xa2$\x01\x84ä1\x91e\xb5\x97A\xecW\xa0\xeb\xd5j\xb9\fp\xf3\xe6\xd2\xd2\xc2\x02\xc0\xc7\x1f_\xb9\xf2\xe9\xa7\x00KKDq7+d\xb2dQ\xfd\xaeG쥨\x9b=4\xb7:\xa0\x19\x10\xb0\xea\xf1\xe9\xba\xf6z}u\xf5\x83\x0f\x00j\xb5\xedml|3?\xff\xdak\x00W\xae\x8c\x8d=\xf2\b\xc0s\xcf\xe1\x18\xda\x03\a\xdcV\xd6n/K\x00\x9e\xc7\xe4¡\xa1\xd1\xd1\xc7\x1e\x03x\xe9%d\n\x9e|rv\xf6\xb5\xd7\x00\x96\x96vw\xbf\xfb\x0e\xe0ҥ\xed\xed\v\x17\x0067\xb1\xc1N\xb1\x88\xe7\x18\x14\bx\xe5\x10\xf8e\x00XU\x04t\xf9#-O.\xa0\xe4\xf9h\x14@U\a\x06Μ\x01\x18\x18\x18\x18x\xfcq\x80\xa9\xa9D\xe2\xc4\t\x80\x13'dy`\x00`t\x94\xe3\x14\x05gXt6\xa6\xa4/D\xb5\xba\xb1\x01p\xf5\xea\xfa\xfa_\xff\n\xf0\xc9'[[\xff\xe7\xff\x00\xac\xae\xe2\xb5\x12ƈ\xc8\x13M\xf5\x97\xcb\xc4\xf0\x13\xc0\x85\xeb,Ͽu\xfa_\xf3_+\x93\xc9b\nz\a\n\xf4\xb0\xa5~\x1aݽ权\xef\xff\x81\xef\x04H\x93\x95w\x96\xda\xf7\x1a\x12\xd4Jͷ\u007f!Z\xfd\xbeVO\xbe\xb1\fп\x80\xb4\xdf\u007f;&\x00k\x05\x88\xc2\xc6-\xaa\xd5\x0f>\xb0,\x80J\xe5\u0085j\x15`c㩧L\x13\xe0\xe0\xc1C\x87\xc2a\xcc\x1e\xe6y\x80\xe9i\x04\x04\xb2\xdc|\x968x\x15@\xd3R)Y\x068|8\x91\xd04\x80\x83\a\x8f\x1cI\xa5\x00\x8a\xc5BA\xd7\x0166\x90\x1b\xb8~}s\xb3Z\x05\xd8\xda\xda\xd8(\x97\x01\n\x85\xad-\x8cq\x13\xa6\xa2;\xcf\xcd/\xacdy\xfc\xae\xa2N\xa5\"\x11\xa4Z\xc7\xc6\x00b\xb1Tjp\x10`d\x04\x97\x87\x0e\x85É\x04\xc0ؘ$\xc92@,\x86YՂ\xe0v\xe7k\x1e\"D\x8e\x88\xfd\xfb\r\xa3V+\x97\x01\x96\x97WWo\xdd\x02\xf8䓅\x85\xf3\xe7\x01n\xde,\x14\xb6\xb7[\r>1\xf4ny_\xb3bfUcxՓ\xb3\xf9\xb6fƀ%O\x96EZ[7\x1f\xbfV\xd3\xf5\xedm\x80j\xf5ʕ\xff\xf5\xbf\x00\xca嵵\xaf\xbe\x02X]\x9d\x99y\xe1\x05\x80Ç\x87\x86\x8e\x1d\x03x\xfai,o\x1c\x1f\xc7\xc6<\xee\xd8o\xa2\xbc1d\x10\x8b\xc5\xe3\a\x0f\x02\x9c<\x19\x8d\xce\xce\x02\x1c;65\xf5\xc2\vؠfc\x03`u5\x97[Y\x01\xb8q#\x9f\xbfu\v;\xef-,\x00\x14\x8b\x95\xcaҒˈ\x04\x05\x96\xac$B\x96\x96b\x01JQD\xf9\x90\xe5h\xf4\xe1\x87\x014-\x16;|\x18 \x1e\x8fF\xe7\xe7\x01\xc6ưc\xe1\xe1ò<8\b0<\xcc\xf3H\xe5c\x0eE\xa3\xd6\xebd\xf0\xab\xd5z=\x9d\x06\xb8qc{\x1bsD\xd6\xd6~\xfb[\x80\xa5%\xcbZ[c\x03\xc8b\x11\x9f\xb7\xdb7\xa2Y\xbe\x88\xc7O\x1b~\xcb\xe2y\x9e\xc7BP2\xa8\x9c\xe7I#t\xb6\x81\xf7[\xd5\x13\xb4\xfa\xe7N\xb3\x04w\xdf\xf3\xff\xde\x00\x80\xbd\xf1\xe5\xfd\xef\xcd\xef\xb4@\x16#\x80/\x06z|\xd8}\xae\x1d\xe6\xf5*\x1b\xa2\xff\\\xc5\xee/'\x80\xbc\xb8\x86A\xa6\xd67S\xa9\xd5j:\xed8\x00\x95\xca_\xfe\xa2\xeb\x00\xa5\xd2Ȉa\x00ܾ\xfd裪\x8aI\\\x9a\x06\xf0\xf4\xd3\xe1\xb0$\x01\x1c8\x80*\x8eP\xe1\xee1\xc9\x10\x9fPH\x10\x00\x12\tE\x89D\x00\x12\x89\xc1\xc1h\x14\xe0\xe8\xd1#G\xf0\xb8x\x06\xa5\x12\xce\xf5\xcbdr9\xc3\x00\xd8\xda*\x97\r\x03`g\xa7T\xaa\xd7\x01*\x95rٶ\x01J\xa5z\xdd0\x00t\xbd^7M\xec\xcbf\x9a\x00\xb6\x8d\x86\xb5\xf1\xbe\xa2獞8\xc7\xc92\xf6\u007fW\x14U\x05\x90\xe5PHQ\x00\"\x11M\x8bFq\x8ck(\x0408\x18\x8d\xc6b\x00cc\x8a\xa2i\x00\xc9$\x99&\x87S\xdfT\x15[\xe2\xbaY\xd4n\x13\xa2fh\xe1B\x14\xf4Lk\xb5Z\r`eeeei\t\xe0\xd3O\x17\x16.^\x04\xb8u+\x97\xdb\xdaj\x9d\xe3N\f}P\x83ߚ\x1d\xdfސ{y\xb6t\x99*;7\xa0\x99a e\xab\xad\xb3!\xf2\xf9+W\x00*\x95o\xbf\xbdr\x05 \x97K&O\x9f\x06\xb8~\xfd\xc0\x81\xb3g\x01\x0e\x1d\x1a\x1c<~\x1c\xe0\a?\x90elA\x8c\x80\x00\x9f]\xe3}F\xb9\x12E\xdc.\x95\x92\xe5#G\x00R\xa9X\xec\xd0!\x80\x93'q\x14v\xad\x86\xfd\x10\x8aE]\xcf\xe5\x002\x99juw\x17`c\xa3V\xc3\xf5Z-\x9d\x06\xa8Tj\xb5R\t\xa0T2\xcdr\x19\xc00p\xd0\x12\x96=\xe2\xd33\f2o\x11\xa5\n\xcf\t\xab\x1cx\x1e\xc7\xe7\xf2\xf6\x98\xa2$\x12\x00SSh(I\xac\xbbu\x88\x0f>W\x9e\x97$\f\xbd`l<\x1cF\xea|d$\x12\x04\xbaТ\x00\x00 \x00IDAT\xc1\x9c\f\x12`Cp\xe3\xe6\xc6\xe0\xbam\xa3'\x8d׃\xef\v\xf6\xc2o>.\xb6\xa5F\xb9B懴\x16v\xa7\f\x12\x19#\x86ݟKC\x1bA\x04\x90\x96\x85\x80&\x9b-\x97WV\x00\xae^M\xa7\xbf\xf8\x02\xe0ҥ\x8d\x8d?\xfd\t`cò66\x1a\r=\xee\x87%O$\x96\xdfZf\xd9\xec黽\xff\xdb/[c\xfd\xedC\x00\xb4\xa3ӫ\xe1\xefԿa/\xba\n\xfa\x9f\x1d\xd3~}\xef\x87$=p\x00\x80~L\xf7\xd6\b\a\xd7ද\xcfw\x99\x80f\xcf\x1f@\x10\xd0\xe4Y\x161b͂\xd0\xcc\x1c\xb0\x18\b\xba\xc3Vk\xddms\f\xb7\xd9;gS\xb9\xad\xbd\xd6i\x03\x85\xf9\xc1\xc5\xe2{\xefU*\x8e\x93\xcb}\xf8a\xb5\x8a\xb9\x03\xb2\f\x90J\xcd\xceb\x83\x98\x91\x11M\x038~<\x1c\xe68\x80\x89\t\xbc\v\xa4A\x89\x1b\xfb\xa5\x89B\xd7̺C}\xb0';.\xd1\xd0c\xff\x82fCݼ\xa4=tz\xe9\x8eq\xa5\xe7\xb27'Q\xb5&\xe9\xa1\xc1\xc5\x0e|\xe52r\x18\x9b\x9b;;\xe94\xc0\xe5\xcbkk++\x00KK\xb7n]\xbf\x8e\xf3\fL\x93\xe3\\E\x8c\xd7\xcbj\xd1\xeb.\x89'FDz;w^k\xa5\xb2\x9b\xe5\x84\xcd(5\a\xa3Z\x8dU\xfb\xd6\xd7\u07bd\xfbY\x8c\x00\x891\xe3z8\\,^\xb9\x02P*]\xbe|\xf9\xb2\xe3d2\x9244\x04\xb0\xb001q\xe6\f\xc0\xd0P*u\xec\x18\xc0\xec,V\r<\xf4\x10\x86\x0e\x86\x86\x10\x18\x902KA\xa0\vk\xe9w\x930C.À3%\x1a\xa1O\xb3<\xb5\x0f#\xb9wҟ\x97\xea\x86\xccX\x1e\xbdm#\x03\xa1\xeb\x00\x85B\xbd\x9e\xcd\x02\xac\xada\xb5\xc5\xe5˻\xbb_|\x01\xb0\xb2\x92˽\xff>\xc7e\xb3\b\xfe\x9a){v\xf9$\xb9߭I\x93͎\x00\xed\xe9{y\xfcD\xbf\xb5f\xf9\xb7\x8f\xfe\xfb5謎\x8cA\x1a\x83\xf5\xa3t\xd0\xcbpw\xdbI\xb6\xff@\xe0\x81O\x02\xbc\xb7\xf8\b\xff۷/\x03\xe48\x02\x04h\x00A\x140\xbdl篹\xbflM\x02\xf4W.\xe8*\xec\xe6)\x85\xad\xe3d\xf1s\xa2XB!\xe2i\xa0\xaa\x0f\x85\xbe\xfd\x16\x87\x86|\xfb\xed\xee.\xc0\xfaz8\x9cN\x03\\\xb8p\xf0`(\x04\x10\x8f\x8f\x8dE\"\x8e3<<8\x18\x0e\x03LME\xa3\xaa\n05%˲\x8c\x94(ϻ\xf5͒D\b_ܿ\x9b9\xdf\b\xb1\x9a\x99\x05V\xb6H3\xd0h\xef\x89!3\xe2.\r\x03\r|\xa5\xa2\xeb\x96\x05\x90\xcf\x17\x8b\x18\xb3\xcfd\n\x05\x80\xd5խ\xad\xad-\x8e\xdb\xdaZ]]Y\x01\xc8\xe7\xeb\xf5Z\x8d]\x06\xe9\x8eGn\x06V,\x85\xdc:\x14\xa6\xd9\xc0\xbb\x8a\xb9\xb3\xa7\xef5\x9cŋ\the\xa0\xbc\x86b\xd1\x1d.\xdb\xcb\x15\xb9>Z\xae\b#\x12\x0e\x9b\xe6\xee.@(\xb4\xb4\xf4o\xff\x06\x90\xcb\xe1reE\x96''\x01Ν\x1b\x1e~\xf8a\x80d2\x91\x98\x9fw\x9c\xd1\xd1Hdb\x02`j*\x14\x1a\x1cD\xc0\xa9\xaaXf)IX\x9eI?\xbf\x8c@\xb7\xf2\xd1=\x80\xd8/\x03\xbc\xa3\xb0\xc4+;\x95\xdd\xfa\xb7s\xb9\x15\xbb>\x96\xb5=K\xc1\xf9\x03\x02\xad\xc9:^\fBg\xe6\x80\xeec\xd0:\xff\xbc\xf9\xf3\xd6\xfb\xd7\xf9\xbe\x04\a`\xdd\"{\u007f\x86\x9b\x95mߚL\xd5^\x91\xb6\xcaK\xe7\xfd\xbḃ?\x03\u07fb\aҙ\x89b庰\xe5ׯ\\\xd3\xccA3\x10`}N\xef\x870R~\r\u007f\xb7\f\xa0_yj\x95\x8f\xce\xcf\xdd/#\xc4\x0e\x01u\x06\b^\xd3K\xfd\x1a~:\xfb\x9f\xd5\n\x995\x13\xc1\xeb\xf3 L\xc0\xd0\x10\xce\xdc\x10\x04\x04\x00\xb4\x8e\xb0m\xac\xc6)\x97\xbd\x01\x80\u05cc\x88\xa0\xd3K\x832J\xfe\xdf\xe3\a\x1e\x00\xecMY\xa0ߎR~\xb7\xf7\x1fJ\xf0\v\x04\xbc\f}\xb3\xc2l\xf5\x84ڿ\xb8^\xd7\xeb\x97q`\x85\x12X\xad\x89Y\x80\xa159\x8dU\x8f\xbe7\u007fl\x85HS\xbc^Y\xf5,\x83\xd9\xd93\xa7[\xf0\xd2\xdf\x13O\xd6{Lu\xbf\x01\x00}\xff阿\xbf\xe9n,\xb9b\xbf\a\xddɕ7\x15\xdb\x1f\xb9b\xfd\xaeӰ\xaf\xce\x00\xb4\xf3\xd8ܠ\xbd\xf3\x83\x1a~/\xe0\xc7~\x9e\xac\xa4\xbf\xceKV\x0eP\xb7\x86\xbfQ\xaeR)\x80\xc9I\xfc\x8c\x94\x157\x9e\xb3e\x01lo\xe3\xe8i\x1a\x00\xf4\xcb\xe0\xf7\v\x10\xec\x87\x00|\xbez\xbd\xf6\u007f\x0ej\xe8\xfdn\xef\xf75c\x19p/꒕}\xdb\xfa}g\x05\xebm\xe8;\x87\x18\xbc\r`\xfb\xdc\x03o\xea5\xe8\xb8\xe4\xee<\\\xbf\x8aݯ\xe1c\x01\x03/\x0f\x8f\x95\xf9\xc22(A=\x89~\xdd/\xef$B/Cՙ\x99\xf2\x92\xabV@\xd2\x19x\xb1\x01Lo\x9e\xbe_\xb9\xf2\xcfgz\x19t\u007f\xc0\xcf\u007f\xff\x87`\xe3y\xbd\xcb\xfc\xda\x1bl\x16\xd5\xdf-\x10\xa0\xf7\xcfq\xd8dL\x14\x11\x00<\xf5TcIp\xf3\xb5\x97\xcb\x00\x97.a\xfc\x9f5$\xcbk=(\x95\xef\x97)\xda\a\x00]\xfb\xdaA\xb6ꮧt;\x8a\x9f\bF\xbbD\x93N/:\xdb\xc3g\xc5\xca;wԢ\xa9s\xb6\a\xefO1\xfaU\xa8A\xab#X\n؛)\xe9Nj\x82ƼYCr\x82zv^\x06\xdc[a\xf83\xf8~\rQp\x05\xe3\xcfPz\x190\xf6\xf3\x0e\x06\x04\xbdr\x12\xfc\xcbUo\xf2\x14\xf4\xfe\xfb\x95+:\x97\xa3W\xb9\xf2\x02\x92\xc1\xb5n\xf3\xef\xbc\xea\xf1\xbd\x98\x00֔Ġ\x86\xbfq97\a0<\x8c%\xa2\xb3\xb3\xed\xaf\xafV\x03\xc0\x8e\x9dn)g;}\xce\x1a6\xe6w|t\xbf\x98\x80\xefa\x0e\x00K\x05\U00106442+2\u007f@\x80M5\xfa\xdb\x1f\xcbP\xfb}\xc1\xd8T\u007f\xd0ا\xbf1\x9c~=y\xb6\x01\xe8\xecq\xf7K1\xf7ϓ\xf3g\xa8\xbd\xb7k\x1f\x02蕲\xf7;\x15\xb2wf\xa43\x13\xe3\x05\xe0\xbc\r\r+\x19\xb53`\xf5f\x9e\xee\x8c\x1c\xf5*g~={\xb6\xbe\xe9O\b\x88\x1d\x82\xe9l\xf8\xbd\x98\x00/\x00\xd0K.\x00\xf1\xfcgf\x00\x9e\u007f\x1e\xbfkW\xfeg\x188\x06\xf9\xd6-\x80\xb5\xb5\xce\x06\xdf\v\b\xf4\x1b\x10\xf4\xce\xe0=\xa09\x00\xfe\xb1zw\xf0\xc2oOj:i\x8d\x05\x00\xfa}ܠ\x1d\xb1\xd89\x03\xc1\x92\xeb؊\x97e\xc0\xfdyzA\x81\xd7\xdd\xfa\xeb\xd6\xf3\xf6\xeb\xc1\xf7/V߭\x87\xdf\x1b \b\xca\x14x?\u007f\x96\xa4\x04\x93\xab~\x1b\xfcn\xab\x01z\x957z\xd6H\xff\x99\xa1\xce\xcf\xc1\xaf\x03\xc4Z\xf7[\xde\x17\xb4*\xa0\x9d\x1e\xebd\xf0\xc9rz\x1a\r\xff\xa3\x8f\x02\xfc\xf2\x978\xe1\xf1\xd4)\xf6\xb5T*\x00_}\x05\xf0\xed\xb7\xad\x9e\u007f\xb7\x06?(c\xb0w\x8d\u007f\x1e\x10\x06\xa0{2\xaa7\x8f\xdf/u\xc5\xdao\xaf\xc9~~_\x84~\x01\x81^\x1b\xa0\xf8W=~\x15U\u007fʱ\xee\x86\\ޙ\x98\xfb\x9d\x052{eP\xf6\x9e9x0\xe4\xe9N?\xbf^;\x9f\xf6\n\x04\x82,\x8f\x1f\xc7Ҿ\xe3\xc7\xd1\xf0\xab*\xc0\xc3\x0f\xb3\xcfW\xd7\x01\x96\x960\xd3\xff_\xfe\x05\xbd~\x12\xf3g\xcd\xf2h\x9d\xfd\xe1\xcf\xd0\xf7j\xe0\xef\xfbY\x00\xfd~\xe1\xfcVVwk\xe0\x83\x1a~/8\xe2\xe5\xf9w\xeb\xe9\a]\xef\xd6\xf0w\xdf\xc8h\xaf\x15\xfa\xfe߽d\xe8\xef]`\xb0/O\xfdx>AC\x98\xfd\x06\x04\x8dۑ\xac\xfe\x87\x1f\x068x\x10c\xfc\xbf\xfc%\x96\n\x1e8\xc0\xbe&\xd3\x04\xd8\xda\x02\xb8y\x13\xe0\xbf\xffw\x80\x85\x05L\xfc\xebd\xe8\xbb\r\x05\x04\xad\x16\bj\xf8\x83\x03\x05\xf1\xce\n\xce^\x1a\x86 \xbei\xaf\x1e?1\xa4^\x0f\x8cN\x0e\f\xea\xf9\xf7\x1a\x13\v\xca\x04x\x01\x81\xa0\x94߃f\xc8\xeeUSq\xaf\x1b\xf6\xef\xcbs\xf8\xbe\x00\xc8ns\x01\xbcf\xb5\x06\xa9\x1a\xd044\xf8ss\xe8\xe9\x1f<\b\xf0\xc3\x1f\xe2\xe7?\xf8\x01n\xabi\x9d\r\xff\xf66\x96\xf7\xfd\xfa\xd7H\xfb\u07fc\xe9\xcf\xe3\xf7b\x02\x82\x86\x04\xfcV\x05\xb0\x98\x81\a&\x04Я\x86<^[\xf6;\xb9\x8eE\xfd\x93\a\xc3\xca\xfa\x0f\n8\x82f\xc9\xfa\xfd}\xd0\xe4?\xbf\x8ax_Q\xef\x1b\xfc} \xf0\xe0\xc9W\xbf;\xa3\xb6[\xaa\xaak\xc4%\t`d\x04 \x1a\xc5\xe5\xe4$\x1a\xfd\xc7\x1e\xc3\x01>G\x8e\xa0NK$\xdc߳Αd\xf7߸\x81\x1e\xff\x97_\xe2\xbf\x1d\xc7\x1d\xabL/\xfd\x1a\xfc\xbdb\x00\xf6\xae%\xb0xo\xbf\xc8\xc1c͝\xa3\xee\xbdz\xfc\xe4A\xd1\f\x00\xfd{/\x04\xc7B\xc2A=\xff\xee\x81\x00\x9e\x01Ϗ\x8e\x02\x00$\x12CC\x00\x00\x87\x0f\xe3\xe7\xaa\xda|\xe6\xecq$^\x98\xd4/\xa6\xed\xb5\x00\xa6S\xcb\x1d\\o\xbe\xe7\xac\xee\x87\xe4sz\xc9\xf2ZZ\xb7\xf3\x17.q\x9b-\xb5_w\xf7\xdf\xee\xf3N}\xe9;]o\xa3bl^\xb6\x1b\xcc\xd3x\x9c\xf6\xdf{\xfd\xbe\xfd\xd8\x19?\xc7e\u007f\xdf\xfe8\xfe\xbbD\xfaۯ\xbf\xe3v\xfa\x1d\xeb\xcf\xcb\x19h\xbf\xde\xd8\xfb\xaf\xfdq:\x83\xf5\xf6۷\x1f4\xde\x19X5\x0f\xfd\xf5\xa7\xcbY\x9f\xd1\xfb\x92$\xf4\xea5\r;\xf3\r\r\xe1g\xa3\xa3\xcdcz\xa3Q\xdc^\xf4a\xbf\x88a'\xc9}W\xae\x00\xfc\xe67\xb8\xdc\xdcl6\xe8,\x83\xef\x05\b\xe8\x1c\x80\xa0\x80\xa0[\x83\xdf{\x8e\xc0}V\x05\x10\xdc\x03\xe8\xcd\xf3gQ\xfd\xf4\x1fy\xb0\xac2?\xbf1\xff\xa0\x9d\xb1\x82\x1b~\x1ct\x19\x0e\xcf\xcd\x01\x00<\xf5\x14\x92d\xaf\xbd\x86G\x1e\x1d\xc53u\x95T\xb7ݮ\x83bڠ\xfb\xf5\x12u\xf6+\x81\xd7F\f+\xdd\xf5\x90\x06\x06\xb6\xdd\xfeY\xb5n\xd7:\xb0\xa6\xdd\xfe[\r;\xae\xbb\xbf\xf7G\x8fz\x01\x8fV\x80C\xee\x1f{\xc0N\xfb\xf3\xa5\u007f\xc72\xe0,\x00\xe3u=~\xf7\xdf\xd9\x10{\x01\"/\xa0E\xdf\xf7Ʃ\v\xfd\x01\x00\xac\xeb\xf2w}\xec\x8e'\xfeΫq\xac\xd4\u07b2z\xfd\xc8\v\xe2\xf9\xde\xc2ƶ\x8d\xc6z}\x1d\x8d\xfc\x1f\xff\x88Y\xfd_\u007f\x8d-}+\x95Ά\xde\v\x10\x04e\x04z\xa5\xfe\xf7\x8e\t\x10\x83=\xcc{\x85r\xf3\xd3y\xae\xbd\x8f\x1e\xcc\xe0\xb3<~\xd6\xf9x\xf9\xb9A\x81H\xef\xd4?bdA\x98\x9f\a\x00\x98\x9eF\x8f\xff\x97\xbf\xc4-\x8f\x1f\xff\xff\xc4@d\x19V\xd6}\f\x1a\r\xf42\xd0A\xb9\x1e\xd6\xf9\xb0\xb7\xf3硱\xf7OC\xc9f\xc3Ӯ\xfb\u007f\xb0\xf3\xc3\u007f\xb5\x1a(\u007f\xf7\xb7\xdd\xe0\xd7 \x9f{=1V6K\xeb\xfeX\xf7\xa9\xf3\x95\xd0\xf7\x93u\x9f\xbc\r\x9c\xd7q\xbc\f{g\xb9\xf2[_\xe4-g\xed=\xfc\xa0uLlyae?\x05}\xfe{e\xf0{\xb5-\x8dw\xda0\\\x83\x9f\xc9\x00|\xf4\x116\xf0!\xf4~&\x83\xdbцٯ\xe1\xef6$\xe0\xb7\x1a\xc0\xaf\xdd\xe8\x9f\xe7O\xb6\xbf\xcf\xca\x00;\r\x9dh\xf7Zu\xcb\x00Д\xbf\x97\x01\xf7Bv\xac߳\x92\xf0\x82\x1a\xfe\xd6\xed\xc6\xc6\x00\x00b1\xf4\xf4\x9f}\x16{]\xbd\xfa*~\x9fHx\x1b\xa4\xcej\xd7+\xbd\xd1+_\xd8\xff\xfc\xbc`\x86/(\x17\xe4\x1f\x10t\x1e\x98\xe2\xd7\xd0uo\x10\xfc\x01\x16\xaf-\xbd\xb7\xef\xfc\x04\xfc\x8f?\xea\xed\xcd\xf6\x06R\xc1ίu;\x02\xb8:C\xda^\xaf+\xe8\xf3\xf7\x0ee\xb4g\x06\x82\x86,hW\xa9\u007f\x80\xc0\x8fw\x1f\xccH\xa1\x81u\x1c\xf4\xdc-\v\xbd\xf8j\x15\x8d\xfc\xf66\xc0\xb9sX·\xbc\x8c\x8d{J\xa5\xf6\x06\x9f\x05\x00\x822\x01\xf4\xfa\xfd\x97\x03@\xaa_\xc4~\xed\xae\xbf\x94~Ж\xbd\xfe_\xb3f!$7\x94\xe5\xe1\xfb5\x0f^\x0f\xd0oc\x8c\xee\xcb\xfcT\x15\x00@\x92\x8e\x1e\x05\x00\x98\x9f\x1f\x1e\x06\x00x\xf3M\xdcrn\x8eP\xfb\x9dc\xec\x85B\xb1\b\x00\xf0\x8f\u007f Iv\xfbv\xf3\xf7tS\x15w\x9d\xb5]\xfb\xdfym\xdfko\xac\xd6\xfb\xee8\x8dP\xc5qH\x9c\x99|\xceR\xbc\xad\xb1\xf4\xf6\x149\x9b\x9a\xf7\xa2\xac\xfdR\xda^Զ\xdf\\\x04\xd6\xf6~=\xd0\xceԳ\u007fʾ\xf3\xf1\xbc\xa8j\xbf\x94\xbf\x97\xe1\xf1op;\x1d\xb7\x13L\xf0ʉ\xf0\xba?^:\x92l\xdd\xf8;\xaf8}??\xf7\xab\xeb\xfd\x9cS\xe3\xdb\xed8\x00\xf5:\xd6\xe2W*؋\x9f\xfcW*a\xa9^\xad\xd6<\x9d\x8f\xd5p'(\x00\xf0\v\f\xbc\x98\x00\xafN\x80~\xb3\xfd\xfb\xef\xf9\x93\x06Y{\xcc\x00\xecՐ\x8dvC>\x9a\x97\xedo\r\v\x00\xd0@\xc0/\x80\b\xea\xf9{1\x00\xfe\x99\x00\xdcB\x10\xa6\xa7\x01\x00\x92I\xf4\xf4_{\r\x81\xc03\xcf\xe0v\x9a\xd69FnY\xff\xaf\xbds\xfb\x8d\xaa\x8a\xc2\xf8\u05f92\xa6\xa64@\x9a\bDMD\xb1\xd1hmL\x88\xd1\b\xc1'\x13M\xfc\x13\xfd\aH\xc5p\xd1xy0\x80\r\x91\xbb\x976\x82U\x81\x1a\xd1*\xa1\xd0\xcbt:>,\xb6\xc3\xec\x99\xdd}9\xfb\\f\xe6\xfb\xbd\fsf8\xe7Lϙ\xf9\xbe\xbd\xf6\xdakmn\x02\xc0\u0082\xf4\xb9\x9a\x9b\xfb\xe5\x17\x00\xf8\xed7\xf9D\xea\xc6\r-\\\x11\xab\xa9M\x12\xe7\x9b^\x06-!$ft\xc07\xb5\xd8֎\xd7\xd5\x00\x84\x1a\x82\xd89\x00\xe9\x17\xfe\xd1\x19\x90U\x00\xee\xcd&\xdc\"\x006\xa1\xb7\t\xb6\xcdѹ\x1a\x18\xffe\x88O?\r\x00\xb5\xda\xcb/\x03\xc0\xf4\xb4d\xef\xab9\xfd\xfd\xfb\xe5\f\xcc5\xe7\xe4\xcc\xff\xfe\xfb\xaf\xbf\x00\xe0\xf4\xe9\x9b7\x01\xe0\xe2E\xa9v\xbd\xb6\xb6\xf3\r\x1a\xba>\xd57\x87?\xa6\x01 \x84\f\x06\xa1k\x8b\\K\xee\xba\x1a\x00\x93!\xb0m7\t\u007fZm\x80}&@\xa5\x12\xa9^\x1a\xbb\xe2\xfaߋ\xe5$]\xfa\xd4\xf7\xfb\x13\xe9\x82\xea\xba_\xbd\x8b\x9f\x1e\x01p\xcd\xfa7\x1d\xc7\\\x90G\xb6\x94\xcb/\xbd\x04\x00SS2\xe2\xff\xe0\x83z\x1d\x00ff\xe4H\xf2\xacߑ\xe4\xf5\xcdM\x91\xf6kז\x96\x00\xe0\xe4\xc9_\u007f\x05\x80\xe5ey\xdd\xf5FMz\xe3\xa6\xdf\xe6v\xb4~ \xf3\x1a\xa9\x91\xe1\xbe?B\xef\x9fX͌\x92\xae\x1dr5\x00\xb6)\x01\xd7ȁ\xef\x9c\u007fv\xb5\xfe\xd5\xff7\xf5\xc4(X\x04 VII\xd3\x02\xbb\x9d\x97@\x99\x9f\xeb\x17\xd0f\x00\xf4\v\xe8\xdf\x1cC\xe6\xf0w풑\xfe\x1boLN\x8a\xf0\xcb;\xf6\xed\xb3\x1dIf\xab\xeeޕ\x95\xaess\x8b\x8b\x00p\xfd\xba\xcc\xedK\xe0߿MeRC\xe0*\xf8\xb1\xbb\xe9\x11B\x06g\xc4o3\x02\xb6ߧ\xa4F \xad\x92\xbf\xbe\x03\xa2\xa4]\xff2/\x05\x9c\xd6\xc8½\x86\xb4\xdf\x14\x80.\x9b\xeaB\x99\x84?\xd4\xc9ٍM\xad&\xe7\xf5\xca+\x00p\xe0\xc0\xc1\x83\x00\xf0\xe1\x87\xd5*\x00LO\xcb\x1e+\x15\xd3WD\xcehmmu\x15\x00\xe6\xe7\u007f\xfe\x19\x00N\x9f\xbe}\x1b\x90\xacY\x97ϣ\u007fAl_0_#\x10\xfb\x06\xa7! dt\x84?t*\xc0$\xfc\xb6\xed\xb6\xe6>ie\xf9\xa7/\xfc9E\x00\\\r\x82\u007fD\xa07\xfb\xb5\xdf\x1el\x06\xc0\xb6\xbc\xcf&|\xb6\v\xd0\xfb\xb9$\xa4?>.+\xf2\xdf~{|\x1c\x00\x8e\x1d\x93wLL薤\xfb\b\xed\xb6\x8c\xf4\x97\x96$\x89\xefĉ\x9f~\x02\x80\xc5ō\x8dN\x1c\xc0\xff\x06vM^\xf15\x026\x03\x10\xdb\x10\x10B\xf2\x13\xf6\xac#\x00\xaeI\x81\xa1\x06\xc1w\x80\x94\xd7\\\xbf\xad\r\xb6\xd1\x00\x14m\xae\xdf}\x04\xad\xd7\x01\xd89\a\xc0d\x00L\xd9\xfd\xa1B\xa7_\xc0\xb11\xa9\xbcW.KG\xea\xe7\x9e;p@F\xfaR\xb0\xa7w\xb9^\xff3z\xf0\xe0\x9f\u007f\x00\xe0\xeb\xaf\x17\x16\xe4qy\x19\x90\x16\x96>\x0e\xd77\x84e\xba\xf1\xd36\x004\x02\x84\f\x8f\x11\xf0\r}'\x9d\n\xd0_\xf7\xfd\xbdK:U\x9a_\x92_\xc1\"\x00I\r\x82=\a\xc0\xaf\x0e\x80\xbe\xdd$\xbb\xae\x82\xd7{\xe1\xd4\xea\xdc\x17_\x94\x11\xbd\xac\xd3?zT\x8c\xc0\x91#\xf2z\xefr\xbd\xee[\xa2Ւ\x11\xfd\xe2\xa2$\xf1\x9d8\xf1\xe3\x8f2\xf2\x97 \x95m\xfd\xa9\xebܕoH+\xd6T@\xec\x91\x04!d\xf0\x8c@\xac\x0e#\xae\x02\x1d\xfa\x18[\xf0\xd3K\xf2\xcb\xd8\x00$\xad\x03\xe6[\xffٞ\x04\xd8\xff\xfdz\x04\xc0$\xf8\xfav\xd3\xf3\xde\v)5\xf7\xcb\xe5\xd7^\x03\x80C\x87\xa42\xdf\xfb\xefˑ\x9fyFo\xb2\xa3#GXY\x91\xceԟ}v\xe3\x06\x00\\\xb8 \xcb\xf7d\xa6\xdf]\xd0\xf5\xecUߐWR\x03\x10:\xf2\xa7\x11 d\xf4\"\x00\xae\x06\xc05' i\xc4 -\xc1\xcfn\xae\u007f@#\x00\xae\x06\xc1<\x05\xe0\x16\x010U\x967mׅ\xbf\xd3\xcaE\x92\xf8&'e\xa4\u007f\xfcx\xa3\x01\x00\x12\xf0\a\xeauS\xa5\x00\xd9S\xb3\xf9\xf0!\x00\\\xbd*I|\x9f~*s\xfaw\xeet\x17\xe6\xf1]\x96\xe2\x1b\x01\b\r}\xa5\x15ꢰ\x132xB\x1fj\x00b\x1b\x81\xd0籧:\x8b#\xfc\x9e\x06\xc0V\xa1=օ\x0f5\x06\xae\xd6\xc1f\x00\xba\xc7\xdfvc\xb0\xbd-\xcdu\xea\xf5\xd7_\a\x80Ç\xa7\xa6\x00\xe0\xbd\xf7d\xa4\xbfw\xafmO\"\xdd\u007f\xfcq\xf7.\x00\x9c:u\xed\x1a\x00\\\xbe|\xff>\xd0)\xccc\x13z\xdf\xed\xb6)\x02\xdf&\x16Y\x87\xfei\b\b\xc9^\xb8\xd3:n\xd2\x12\xb8\xbeS\x04\xb1^O\xab2jv\u05ed\xe2'\xf4;7DI~C$\x9fB0%\x01v\x1b\x00\xd7\xf5\xff\xbd7\x82,\xcb\x03D𧦤@\xcf\xf1\xe3R\x82\xf7\xd0!}\xb9\x9e\xbeg\xd9\xd3\xfa\xba\xa4\xeb]\xbc(s\xf9g\xceȈ\xff\xde=5\xe7\xdf_\xc0}\x9f\xdb\"\x06I\x97\xb7Ě\xfbg\xf6?!\xa3c |\xbf\xef\xb1#\x03I\x05?\xf4\xbc\x8a7\xe0\xa9\x14\xf3F\t\xff\xc0&\x03п'\x80{\x84A\x96\xeb\xd5\xeb33\x00\xf0\xea\xab{\xf7\x02\xc0[oI,abb\xe7K\xdcnK\x12\xdf\xef\xbfK\x05\xbe\xb9\xb9˗\x01`aA\xc6\xf8\xf2jx\t\xcaP#\xe0\xba\xdc%\xf6\xf2?\x8e\xf8\t\x19]#\x904\x12\x90\x951Hz\x9c\xa4\u007f\xb7\xf4\u007f\xf7*\xf9\xdc(\xbe#@\xfb\xa3{\x8d@7# s\xf7cco\xbe\t\x00\xfb\xf7\xbf\xf0\x02\x00\x1c;&Ew\x0f\x1e\x14\xc93\xb7\xb6\x14\xe9|\xf8P\x92\xf6Ν\x93\xd0\xfeW_\x89\x01\xf8\xf7\xdf\xfe\x82\xee\xdbt\"\xd4\b\x84\xce\xf9\xc7.i9h#\u007f\x1a\x11B\xd2\xff\x1e\x85&\t\xfa\xeaF\xe8~\xd3\x1a\xe9g\xff;Sq;\x11[w\xf7X\x170\xb6C\xf3\xcfZ\x90\xe4\xbd\xf1q\x19\xe9\xcf\xce\xee\xde\r\x0033\xb2\x9f\xa7\x9eR\xef\xeb\xbfn`{[F\xf4\xb7nI\xe9\xddO>\xb9t\t\xe8,\xd7S%x\x93v\x9d\nmN\x914\xeb?V\xc8,\xab\x1b\x9e\x82M\xc8\xe0\x19\xe8\xd8\x06 i\x84!\xab\x81L\xf6\xbfW)/\x03L>\xb2\xdf\xf9\xb1#@\xb6n\xe4\xddc\xf5\xce\xfb&&\x00\xa0\\>r\x04\x00\x9e}\xf6\xf9\xe7\x01\xe0\xe8Q)\xcc#)}O.\xd7\xd3?\x91H\xe7\xfd\xfbR\x89\xef\xcb/%\xb4??/5\xf8\xd5r=S?i\xd7\xfe\xd2Y\t\xbfo\xa1\x9f\xd0~\xd6\xc3.\xd84\x1e\x84\xc4\u05cb\xa4F!\xb6\xc1\x88\xf5\xfd\xcf\xef\xf7\xa2\x12\xe7\x02\xba\xfeAbuy\xea}T\x06`\xe7\xd2A\x9d\xe3\xcc\xce\x02\xc0\xeeݲN\xff\x9dw\xa4\x04\xef\xe1\xc3\xf2\xbeZ\xcd\xd4\xe0W\xb6om\x89\xb4/,\xc8\xfa\xfcS\xa7\xae\\\x01\x80;w\xd4r\xbe0\xe1\xb7\x19\x02W\xe1\xb7\x15\x06r\x9d㏕\xe5\x9fW$\x80BL\xc8\xe0\x1b\xe4XS\x06\xbe\x03Ӵ\a.\xf9\xff>E^\x06\x18;\vӽɃ\x9c\x99i\x95\xbd\x8a\x00\x94J\x1f}\x04\x00\xd3\xd3R\x82\xf7\xddwe\xb9ޞ=\xb66>\x12\xbc\xbfwO\xe6\xf0Ϟ\x9d\x9f\a\x80\xeb\xd7e6_-׳\t\xbazn\x13z\xf5\xbaI\xf0m\xc2\xefZ\xe8'V-뤡7\n;!4\x04i\x1b\x82\xa4\x03\x94\xe1\xfb\xfd\xca8\t0\xa9\xf0\xdbCڦU\x00{\xf6\x00\xc0\xec\xec\xbe}@\xa7\xf4\xae\xad\xbb\xde\xc6\xc6\xca\n\x00\\\xb9r\xf5*\x00|\xf1\xc5\xf7ߋ\x11\b\x1bѻ\x1a\x00\xdf俤m*\xd3*i\xc9\x02?4,\x84\x14\xc5 \xe4\xb7\n)\xb4V\u007fN\x06\xc0u\xbd\xbfi\xb1]h\xa9F\xdfZ\xf6\x1d\x81\x943Q\xdb{\xcf\\\xe6\xf4]\x97\xebݾ-\xeb\xf2Ϟ\xbdp\x01\x00\x16\x16\xa4B\x9fZ\xae\xa7\v\xb0o\xc8\xdf\xd7\x00\xf8\n\u007fV\xc9}\xb1Bo\x14RBH\xe8\xf7\xbd\xa8m\xc5\xdbm\xdf\xee|\x05\x8d\x00\xf8\xae\x06Hj\b\\\x85_\xd5\xf4o6%į\"\x00\xee\u007fj\xd9\xd3\xea\xea\x9f\u007f\x02\xc0\xb9s\xdf}\a\x00\xdf|#Y\xfcR\x8fϾ\xcc\xce7\x02\x90t\x99\x9fk\xbf\xeaX]\xfc(\xfc\x84\x90\xa2\x8e\xec\x8b\xf6{\xd2\xd9\u007fQ\x85\xdf\xd3\x00\xb8~\xe0\xd8s\xfc&\xc1W\x8f*\xb7\xbfT\x12\xe1W\x91\x80\xde\x18E\xf7\x99\xb6Z2k\u007f\xf3\xe6\x0f?\x00\xc0ɓ\xe7\xcf\x03\xc0Ғ\x8c\xf1M\xc2jK\xc6\xf3\x1d\xd9\xdb\xe6\xfaCC\xfc\xb6\x12\xbe\xb6\xeba\xba\xae\xa1\xa14\x16\xfc\xa1\x91!dؿg\x83\xf7\xfd\xae\x84}@\xdb\xfa\xff\xd0\x11\xbf\x12t%\x80\xea\xb9.\x90j{\xa7\xb6\xbf\xbccuU\x8e\xb0\xbe.\xef\xa8V\xbbk\uebec,/\x03\xc0\xe7\x9f\u007f\xfb-\x00\x9c?\u007f\xeb\x16\x00s\x06\x00.]\x92\xe4>={_O\xd2K\xeb\xd1\x161Hڵ/t9\x9f\xef\xc8\xdff\xfc\xf8\xc3A\b\x19>\x03S\xa9T*\x95\n\xb0\xbd\xbd\xbdm^{6\x00\x06frrrrr\xd2U\xd8\x156\xa1\xee\x84\xe6\x1f\xfb\x8cr\xff\xe7\x95\xcaΏ\xaa\xf5\x8e\xfb\xa3t\xe7۵K\n\xfc\xd4뒯\xdfn\x8b\xe0\xabKe\xcbYp\x9d\x92\xf0\x8d\fd\x95̗\x96ೖ?!d\xf4\x04\xbf\xe8\xc9|\xa1TB\xff ;\x1b\x05\x93\xa0\x9a\xba\xec)\x81\xf3\xab\xe4\xdf{>\xdb\xdbR\x81\xafՒ\xc7\xf5\xf5\xfe\x86$\xa9\x010\x19\x02\x9b\xb0\xdbr\v|\x05?v2\x9fo\xe8\x9fBO\b\x19>\xc1\xef\xdd2\\¯\x19\x00\xdf6\xc0\xae\xcb\x04m9\x00\xba\xc0ی\x80Y\xf8\xfb\v\xa8\x1ey0\xed/\xe9\xea\x04[\xae\x80\xeb\xea\x06\x9b\xe1H\x9a\xc5\xef:\xe2\x1f\xd6\xf5\xfbٟ\xb7\x1a9\x10Bb~\x93\xe3\b\xb2\xfa~\x96\xcb\xe5r\xb9\flmmm\xa9_\xedQ\xa0R*\x95J\xa5R\xe8\\\x86\xcd\x18\u0604_?\xa2n\x04L\xc73\xed\xd7$\xfc6\x03\xe0\x1a\tp-\xad\xebZ\xcf\xc0W\xf0Ck\xf1\x87v\xb1\xca[\xf0\xfb5w\xea/\xa8Eu\xe8\xc3:r d\x98\x8cĨ\t\xff\xff\x06\xa0[\xf8C#\x01\xa6\xed\xa6\x91\xbai\xff&\xe1\xb7\t\xb4\xbe<\xd06\xf2w\x8d\\\xb8\x97\"v3\x02\xbe\xcb\xf5\x92\x86\xf8]#3y\t\xfe\x93͛\xdc\xe6\xd8(\xa8\x84\x10\x12\xc9\x00\xa8\u007fĉ\x04\xb8\xben:B\xe8\xf2B\xdfпo\xe1\xa2P#\x10Z\x827\xadZ\xfcy\t~g\xff*\xd4\xd6j\xb5ZO\xda=\n;!\x84\xe4d\x00\xe2D\x02LB\xeek\x00\\G\xb0j?\xfa\xea\x02\xbd\xae\x80o2aR#`*m\x1c{\x84_\xd4оy\xbf\xba\xf0\x13B\b\xc9\xd9\x00ĉ\x04\xf8\n\x8b\xe9\bJ\xb8M¦\xcf\xed\xabG}\x8a\xc1\x94\xf5\xef;\x05\x10Z\xd1\xd0U\xe8\x87o\xa4O\b!d\xc0\f@\xdcH\x80+6\xaba\x1b\x91ے\xfd\\\xf3\xb0}W1\xf8\x86\xecc\xaf\xcf\xcf_\xf0\x87u},!\x84\x8c\x9c\x01P\xd4j\xb5Z\xad\x06lnnnnn&\x1d\t\xba\x1a\x04\x930*a7%\x1d\xeaF -\x03\xe0:RO\xbb\xadn\xfe\xc2_\xadV\xab\xd5*\xd0l6\x9b\xaa\x9e!!\x84\x90!0\x00\xdd\xc2\xef\x1b\tз\xeb\x02\xed;E`2\x02\xba\xc0\x9b\xea\v\xe8F\xc4U\xf8m#\xeeX\x8f\xbe\xc7\xcdZ\xf0;\xc7QI|\x14~B\b\x19R\x03\xe0'\xf4\xae\xaf\xfb\x1a\x01[\x9d\x01[\x92_h\t\x16\xd7\x11\xb7\xef:\xfcX\x82\x9f\xddH_\x0f\xf13\x89\x8f\x10BF\xcc\x00\xf8%\a\xdar\x03l\xf5\x00|\xbb\x0e\xba\x1a\x00\xd7\b\x80\xaf\x80Ǯ\xad\x9f\xffH\x9f!~B\b\xa1\x01x,\xd9\"\xfc\xdd\xed\x0f]\x97\xd5ٲ\xeeC#\x10\xa6\xfd\x9b\xce+\xd4\x00\xa4\xfd<\xff\x91\xben\xf0(\xfc\x84\x10B\x03\xa0Iœ\xd9\u07b6\x91z,#\xe0Zh\xc9'\xef\x00\x00\x02CIDATr\xd8V\x97 td\xed\xdb\x16\xb7\xf8\x82\xaf\x87\xf6\a\xbd\xad%!\x84\x90\x94\r\x80\x9f\xc0\xfb\x1a\x01\xd7\xfdd\x1dqH\x1a1(J\xad\xfdv\xbb^\xaf\xd7\xebu`ccccc\x83_\x00B\b\xa1\x01\xc8\xc5\b\xe8#\xf4X\x82\x18j$B\xdb\u07baF\b\xb2\x17|}.\x9f\xc2O\b!$\x05\x03\x10*\xc0\xbe\xed\x85m9\x00I\xcf;T\xf8\xf3\x17|=\xb4Ϲ|B\b!\x19\x1a\x80\xa4F\xc0\x14\x19p5\x06\xb1#\tY\xfd\xbf\xe4\xe7Ɋ|\x84\x10B\n`\x00\xf4U\x036aw\x15R\xdfl\xfe\xf4\x857\xeb\xe3\xc6\xe9\xd9@\b!dT)\xa5/U\"\xfc\x8dF\xa3\xd1h\xc4\x1e\x99\xbb&\xd9\xc5\xda\u007fZdz\x9f\x8f2Rj\v\x85\x9f\x10BH\xa1#\x00\x8a\xb5\xb5\xb5\xb5\xb55Sd \xab9\xfcA\x83\xa1}B\b!\x03\x1a\x01p\x8b\f\xe45\xb2.\x9e\xe0Kh\x9fRO\b!dH\r\x80)2\xd0-\x80\xc3.\x84\xbd\x82\xcf\xd0>!\x84\x90\x910\x00:\xba\x00v\xcf}\x0f\x8b!\xa0\xe0\x13B\b\xa1\x01\xb0He\xbf\xb9\xefA3\x02\xbdI|\x84\x10B\b\r@\x00\x83\"\xa8j\xb9\x1e\x93\xf8\b!\x84\xd0\x00D\x8c\f\x14\xdb\b\xb4\xdb\f\xf1\x13B\b\xa1\x01H\xd1\b\xa8g\xbc\xa4\x84\x10B\xc8\b\x18\x00\x85\xearW\x14[\xc2[\x8b\x10B\b\r@\x06tw\xb9˯D/o)B\b!4\x00#D\xb9\\.\x97\xcb\xfc;\x10B\b\xa1\x01\xc8\x05\xd5\x0e7\xdb\xe3\xb5ۭV\xab\xd5j\xf1\x86\"\x84\x10B\x03\x90\vY%\x05\xf6\xefrH\b!\x84\xd0\x00\xe4\xfb\xc1\x1e\xaf\xbf\x8fm/\x9e\xb4\x19\x14~B\b!4\x00\x05C\xad\xbfO\xd6[\x80\x15\xfc\b!\x84\xd0\x00\f\xb4\x11PT\xab\xd5j\xb5\xaa\v{\xbb-I|\xbd\xcdy8\xd2'\x84\x102\x8cTF\xed\x037\x9b\xcdf\xb3ٻ\x9dI|\x84\x10B\x18\x01 \x84\x10B\b\r\x00!\x84\x10Bh\x00\b!\x84\x10B\x03@\b!\x84\x10\x1a\x00B\b!\x84\xd0\x00\x10B\b!\x84\x06\x80\x10B\b!4\x00\x84\x10B\b\xa1\x01 \x84\x10B\b\r\x00!\x84\x10Bh\x00\b!\x84\x10\x12\x89\xff\x00\xf2\xbc6\xd1>Q\xabL\x00\x00\x00\x00IEND\xaeB`\x82") diff --git a/icons/icons.go b/icons/icons.go index 31a6810..78c4cfd 100644 --- a/icons/icons.go +++ b/icons/icons.go @@ -3,6 +3,8 @@ package icons import ( "log" + _ "embed" + "github.com/gotk3/gotk3/cairo" "github.com/gotk3/gotk3/gdk" ) @@ -10,6 +12,12 @@ import ( // static assets // var assets = map[string]*gdk.Pixbuf{} +//go:embed cchat_256.png +var __cchat_256 []byte + +//go:embed cchat-variant2_256.png +var __cchat_variant2_256 []byte + func Logo256Variant2(sz, scale int) *cairo.Surface { return mustSurface(loadPixbuf(__cchat_variant2_256, sz, scale), scale) } diff --git a/internal/gts/httputil/image.go b/internal/gts/httputil/image.go index a90f2e3..0d8484a 100644 --- a/internal/gts/httputil/image.go +++ b/internal/gts/httputil/image.go @@ -1,7 +1,6 @@ package httputil import ( - "bufio" "context" "io" "mime" @@ -9,7 +8,6 @@ import ( "net/url" "path" "strings" - "sync" "github.com/diamondburned/cchat-gtk/internal/gts" "github.com/diamondburned/cchat-gtk/internal/log" @@ -21,32 +19,6 @@ import ( "github.com/pkg/errors" ) -// bufferPool provides a sync.Pool of *bufio.Writers. This is used to reduce the -// amount of cgo calls, by writing bytes in larger chunks. -// -// Technically, httpcache already wraps its cached reader around a bufio.Reader, -// but we have no control over the buffer size. -var bufferPool = sync.Pool{ - New: func() interface{} { - // Allocate a 512KB buffer by default. - const defaultBufSz = 512 * 1024 - - return bufio.NewWriterSize(nil, defaultBufSz) - }, -} - -func bufferedWriter(w io.Writer) *bufio.Writer { - buf := bufferPool.Get().(*bufio.Writer) - buf.Reset(w) - return buf -} - -func returnBufferedWriter(buf *bufio.Writer) { - // Unreference the internal reader. - buf.Reset(nil) - bufferPool.Put(buf) -} - type ImageContainer interface { primitives.Connector @@ -93,9 +65,19 @@ func AsyncImage(ctx context.Context, scale = surfaceContainer.GetScaleFactor() } - ctx = primitives.HandleDestroyCtx(ctx, img) + ctx, cancel := context.WithCancel(ctx) + cancelHandle := img.Connect("destroy", func() { + log.Println("image destroyed, canceling") + cancel() + }) go func() { + // Ensure the contexts are cleaned up in the main thread. + defer gts.ExecAsync(func() { + img.HandlerDisconnect(cancelHandle) + cancel() + }) + // Try and guess the MIME type from the URL. mimeType := mime.TypeByExtension(urlExt(imageURL)) @@ -143,20 +125,11 @@ func AsyncImage(ctx context.Context, l.Connect("area-prepared", load) l.Connect("area-updated", load) - // Borrow a buffered writer and return it at the end. - bufWriter := bufferedWriter(l) - defer returnBufferedWriter(bufWriter) - - if err := downloadImage(r.Body, bufWriter, procs, isGIF); err != nil { + if err := downloadImage(r.Body, l, procs, isGIF); err != nil { log.Error(errors.Wrapf(err, "failed to download %q", imageURL)) // Force close after downloading. } - if err := bufWriter.Flush(); err != nil { - log.Error(errors.Wrapf(err, "failed to flush writer for %q", imageURL)) - // Force close after downloading. - } - if err := l.Close(); err != nil { log.Error(errors.Wrapf(err, "failed to close pixbuf loader for %q", imageURL)) } @@ -206,11 +179,13 @@ func loadFn(ctx context.Context, img ImageContainer, isGIF bool) func(l *gdk.Pix } func execIfCtx(ctx context.Context, fn func()) { - gts.ExecLater(func() { - if ctx.Err() == nil { - fn() - } - }) + if ctx.Err() == nil { + gts.ExecAsync(func() { + if ctx.Err() == nil { + fn() + } + }) + } } func downloadImage(src io.Reader, dst io.Writer, p []imgutil.Processor, isGIF bool) error { diff --git a/internal/keyring/keyring.go b/internal/keyring/keyring.go index b9b3acc..3cfa333 100644 --- a/internal/keyring/keyring.go +++ b/internal/keyring/keyring.go @@ -17,16 +17,16 @@ var store = driver.NewStore( ) type Session struct { - ID string + ID cchat.ID + + // Metadata. Name string Data map[string]string } // ConvertSession attempts to get the session data from the given cchat session. // It returns nil if it can't do it. -func ConvertSession(ses cchat.Session) *Session { - var name = ses.Name().Content - +func ConvertSession(ses cchat.Session, name string) *Session { saver := ses.AsSessionSaver() if saver == nil { return nil @@ -45,28 +45,60 @@ func ConvertSession(ses cchat.Session) *Session { } } -func SaveSessions(service cchat.Service, sessions []Session) { - if err := store.Set(service.Name().Content, sessions); err != nil { - log.Warn(errors.Wrap(err, "Error saving session")) - } -} - -// RestoreSessions restores all sessions of the service asynchronously, then -// calls the auth callback inside the Gtk main thread. -func RestoreSessions(service cchat.Service) (sessions []Session) { - // Ignore the error, it's not important. - if err := store.Get(service.Name().Content, &sessions); err != nil { - log.Warn(err) - } - return -} - -func RestoreSession(service cchat.Service, id string) *Session { - var sessions = RestoreSessions(service) - for _, session := range sessions { - if session.ID == id { +// RestoreSession restores a single session. +func RestoreSession(svc cchat.Service, sessionID cchat.ID) *Session { + service := Restore(svc) + for _, session := range service.Sessions { + if session.ID == sessionID { return &session } } return nil } + +// Sessions is a list of sessions within a keyring. It provides an abstract way +// to save sessions with order. +type Service struct { + ID cchat.ID + Sessions []Session +} + +// NewService creates a new service. +func NewService(svc cchat.Service, cap int) Service { + return Service{ + ID: svc.ID(), + Sessions: make([]Session, 0, cap), + } +} + +// Restore restores all sessions of the service asynchronously, then calls the +// auth callback inside the GTK main thread. +func Restore(svc cchat.Service) Service { + var sessions []Session + // Ignore the error, it's not important. + if err := store.Get(svc.ID(), &sessions); err != nil { + log.Warn(err) + } + + return Service{ + ID: svc.ID(), + Sessions: sessions, + } +} + +// Add adds a session into the sessions list. +func (svc *Service) Add(ses cchat.Session, name string) { + s := ConvertSession(ses, name) + if s == nil { + return + } + + svc.Sessions = append(svc.Sessions, *s) +} + +// Save saves the sessions into the keyring. +func (svc Service) Save() { + if err := store.Set(svc.ID, svc.Sessions); err != nil { + log.Warn(errors.Wrap(err, "Error saving session")) + } +} diff --git a/internal/ui/config/file.go b/internal/ui/config/file.go index c0977ad..2f713bd 100644 --- a/internal/ui/config/file.go +++ b/internal/ui/config/file.go @@ -56,12 +56,12 @@ func SaveToFile(file string, v []byte) error { f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_SYNC|os.O_TRUNC, 0644) if err != nil { - return errors.Wrap(err, "Failed to open file") + return errors.Wrap(err, "failed to open file") } defer f.Close() if _, err := f.Write(v); err != nil { - return errors.Wrap(err, "Failed to write") + return errors.Wrap(err, "failed to write") } return nil @@ -72,14 +72,19 @@ func SaveToFile(file string, v []byte) error { func MarshalToFile(file string, from interface{}) error { file = filepath.Join(DirPath(), file) + dir := filepath.Dir(file) + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return errors.Wrap(err, "failed to create config dir") + } + f, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_SYNC|os.O_TRUNC, 0644) if err != nil { - return errors.Wrap(err, "Failed to open file") + return errors.Wrap(err, "failed to open file") } defer f.Close() if err := PrettyMarshal(f, from); err != nil { - return errors.Wrap(err, "Failed to marshal given struct") + return errors.Wrap(err, "failed to marshal given struct") } return nil diff --git a/internal/ui/messages/container/compact/compact.go b/internal/ui/messages/container/compact/compact.go index 91354bd..e8e985b 100644 --- a/internal/ui/messages/container/compact/compact.go +++ b/internal/ui/messages/container/compact/compact.go @@ -4,7 +4,7 @@ import ( "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/gts" "github.com/diamondburned/cchat-gtk/internal/ui/messages/container" - "github.com/diamondburned/cchat-gtk/internal/ui/messages/input" + "github.com/diamondburned/cchat-gtk/internal/ui/messages/message" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" ) @@ -12,40 +12,31 @@ type Container struct { *container.ListContainer } +var _ container.Container = (*Container)(nil) + func NewContainer(ctrl container.Controller) *Container { - c := container.NewListContainer(ctrl, constructors) + c := container.NewListContainer(ctrl) primitives.AddClass(c, "compact-container") return &Container{c} } +func (c *Container) NewPresendMessage(state *message.PresendState) container.PresendMessageRow { + msg := WrapPresendMessage(state) + c.AddMessage(msg) + return msg +} + func (c *Container) CreateMessage(msg cchat.MessageCreate) { gts.ExecAsync(func() { - c.ListContainer.CreateMessageUnsafe(msg) - c.ListContainer.CleanMessages() + msg := WrapMessage(message.NewState(msg)) + c.ListContainer.AddMessage(msg) }) } func (c *Container) UpdateMessage(msg cchat.MessageUpdate) { - gts.ExecAsync(func() { c.ListContainer.UpdateMessageUnsafe(msg) }) + gts.ExecAsync(func() { container.UpdateMessage(c, msg) }) } func (c *Container) DeleteMessage(msg cchat.MessageDelete) { - gts.ExecAsync(func() { c.ListContainer.DeleteMessageUnsafe(msg) }) -} - -var constructors = container.Constructor{ - NewMessage: newMessage, - NewPresendMessage: newPresendMessage, -} - -func newMessage( - msg cchat.MessageCreate, _ container.MessageRow) container.MessageRow { - - return NewMessage(msg) -} - -func newPresendMessage( - msg input.PresendMessage, _ container.MessageRow) container.PresendMessageRow { - - return NewPresendMessage(msg) + gts.ExecAsync(func() { c.PopMessage(msg.ID()) }) } diff --git a/internal/ui/messages/container/compact/message.go b/internal/ui/messages/container/compact/message.go index e070650..8054cf4 100644 --- a/internal/ui/messages/container/compact/message.go +++ b/internal/ui/messages/container/compact/message.go @@ -3,14 +3,13 @@ package compact import ( "time" - "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/humanize" "github.com/diamondburned/cchat-gtk/internal/ui/messages/container" - "github.com/diamondburned/cchat-gtk/internal/ui/messages/input" "github.com/diamondburned/cchat-gtk/internal/ui/messages/message" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" "github.com/diamondburned/cchat-gtk/internal/ui/rich/labeluri" "github.com/diamondburned/cchat-gtk/internal/ui/rich/parser/markup" + "github.com/diamondburned/cchat/text" "github.com/gotk3/gotk3/gtk" "github.com/gotk3/gotk3/pango" ) @@ -29,41 +28,32 @@ var messageAuthorCSS = primitives.PrepareClassCSS("", ` `) type PresendMessage struct { - message.PresendContainer + message.Presender Message } -func NewPresendMessage(msg input.PresendMessage) PresendMessage { - msgc := message.NewPresendContainer(msg) - +func WrapPresendMessage(pstate *message.PresendState) PresendMessage { return PresendMessage{ - PresendContainer: msgc, - Message: wrapMessage(msgc.GenericContainer), + Presender: pstate, + Message: WrapMessage(pstate.State), } } type Message struct { - *message.GenericContainer + *message.State Timestamp *gtk.Label Username *labeluri.Label + + unwrap func() } var _ container.MessageRow = (*Message)(nil) -func NewMessage(msg cchat.MessageCreate) Message { - msgc := wrapMessage(message.NewContainer(msg)) - message.FillContainer(msgc, msg) - return msgc -} - -func NewEmptyMessage() Message { - ct := message.NewEmptyContainer() - return wrapMessage(ct) -} - -func wrapMessage(ct *message.GenericContainer) Message { +func WrapMessage(ct *message.State) Message { ts := message.NewTimestamp() ts.SetVAlign(gtk.ALIGN_START) + ts.SetText(humanize.TimeAgo(ct.Time)) + ts.SetTooltipText(ct.Time.Format(time.Stamp)) ts.Show() messageTimeCSS(ts) @@ -80,31 +70,37 @@ func wrapMessage(ct *message.GenericContainer) Message { ct.PackStart(ct.Content, true, true, 0) ct.SetClass("compact") + rcfg := markup.RenderConfig{} + rcfg.NoReferencing = true + rcfg.SetForegroundAnchor(ct.ContentBodyStyle) + + user.SetRenderer(func(rich text.Rich) markup.RenderOutput { + return markup.RenderCmplxWithConfig(rich, rcfg) + }) + return Message{ - GenericContainer: ct, - Timestamp: ts, - Username: user, + State: ct, + Timestamp: ts, + Username: user, + unwrap: ct.Author.Name.OnUpdate(func() { + user.SetLabel(ct.Author.Name.Label()) + }), } } // SetReferenceHighlighter sets the reference highlighter into the message. func (m Message) SetReferenceHighlighter(r labeluri.ReferenceHighlighter) { - m.GenericContainer.SetReferenceHighlighter(r) + m.State.SetReferenceHighlighter(r) m.Username.SetReferenceHighlighter(r) } -func (m Message) UpdateTimestamp(t time.Time) { - m.GenericContainer.UpdateTimestamp(t) - m.Timestamp.SetText(humanize.TimeAgo(t)) - m.Timestamp.SetTooltipText(t.Format(time.Stamp)) -} - -func (m Message) UpdateAuthor(author cchat.Author) { - m.GenericContainer.UpdateAuthor(author) - - cfg := markup.RenderConfig{} - cfg.NoReferencing = true - cfg.SetForegroundAnchor(m.ContentBodyStyle) - - m.Username.SetOutput(markup.RenderCmplxWithConfig(author.Name(), cfg)) +func (m Message) Unwrap(revert bool) *message.State { + if revert { + m.unwrap() + + primitives.RemoveChildren(m) + m.SetClass("") + } + + return m.State } diff --git a/internal/ui/messages/container/container.go b/internal/ui/messages/container/container.go index f8aa239..a0722c8 100644 --- a/internal/ui/messages/container/container.go +++ b/internal/ui/messages/container/container.go @@ -2,11 +2,8 @@ package container import ( "github.com/diamondburned/cchat" - "github.com/diamondburned/cchat-gtk/internal/ui/messages/input" "github.com/diamondburned/cchat-gtk/internal/ui/messages/message" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" - "github.com/diamondburned/cchat-gtk/internal/ui/primitives/menu" - "github.com/diamondburned/cchat-gtk/internal/ui/rich/labeluri" "github.com/diamondburned/handy" "github.com/gotk3/gotk3/gtk" ) @@ -17,45 +14,43 @@ const BacklogLimit = 50 type MessageRow interface { message.Container - // Attach should only be called once. - Row() *gtk.ListBoxRow - // AttachMenu should override the stored constructor. - AttachMenu(items []menu.Item) // save memory - // MenuItems returns the list of attached menu items. - MenuItems() []menu.Item - // SetReferenceHighlighter sets the reference highlighter into the message. - SetReferenceHighlighter(refer labeluri.ReferenceHighlighter) + GrabFocus() } type PresendMessageRow interface { MessageRow - message.PresendContainer + message.Presender } // Container is a generic messages container for children messages for children // packages. type Container interface { gtk.IWidget + cchat.MessagesContainer // Reset resets the message container to its original state. Reset() - // CreateMessageUnsafe creates a new message and returns the index that is - // the location the message is added to. - CreateMessageUnsafe(cchat.MessageCreate) MessageRow - UpdateMessageUnsafe(cchat.MessageUpdate) - DeleteMessageUnsafe(cchat.MessageDelete) + // SetSelf sets the author for the current user. + SetSelf(self *message.Author) + + // NewPresendMessage creates and adds a presend message state into the list. + NewPresendMessage(state *message.PresendState) PresendMessageRow + + // AddMessage adds a new message into the list. + AddMessage(row MessageRow) // FirstMessage returns the first message in the buffer. Nil is returned if // there's nothing. FirstMessage() MessageRow - // AddPresendMessage adds and displays an unsent message. - AddPresendMessage(msg input.PresendMessage) PresendMessageRow - // LatestMessageFrom returns the last message ID with that author. - LatestMessageFrom(authorID string) (msgID string, ok bool) - // Message finds and returns the message, if any. + // LastMessage returns the last message in the buffer or nil if there's + // nothing. + LastMessage() MessageRow + // Message finds and returns the message, if any. It performs maximum 2 + // constant-time lookups. Message(id cchat.ID, nonce string) MessageRow - // FindMessage finds a message that satisfies the given callback. + // FindMessage finds a message that satisfies the given callback. It + // iterates the message buffer from latest to earliest. FindMessage(isMessage func(MessageRow) bool) MessageRow // Highlight temporarily highlights the given message for a short while. @@ -67,6 +62,21 @@ type Container interface { SetFocusVAdjustment(*gtk.Adjustment) } +// UpdateMessage is a convenient function to update a message in the container. +// It does nothing if the message is not found. +func UpdateMessage(ct Container, update cchat.MessageUpdate) { + if msg := ct.Message(update.ID(), ""); msg != nil { + msg.UpdateContent(update.Content(), true) + } +} + +// LatestMessageFrom returns the latest message from the given author ID. +func LatestMessageFrom(ct Container, authorID cchat.ID) MessageRow { + return ct.FindMessage(func(msg MessageRow) bool { + return msg.Unwrap(false).Author.ID == authorID + }) +} + // Controller is for menu actions. type Controller interface { // Connector is used for button press events to unselect messages. @@ -77,20 +87,13 @@ type Controller interface { Bottomed() bool // AuthorEvent is called on message create/update. This is used to update // the typer state. - AuthorEvent(a cchat.Author) + AuthorEvent(authorID cchat.ID) // SelectMessage is called when a message is selected. SelectMessage(list *ListStore, msg MessageRow) // UnselectMessage is called when the message selection is cleared. UnselectMessage() } -// Constructor is an interface for making custom message implementations which -// allows ListContainer to generically work with. -type Constructor struct { - NewMessage func(msg cchat.MessageCreate, before MessageRow) MessageRow - NewPresendMessage func(msg input.PresendMessage, before MessageRow) PresendMessageRow -} - const ColumnSpacing = 8 // ListContainer is an implementation of Container, which allows flexible @@ -106,7 +109,7 @@ type ListContainer struct { // messageRow w/ required internals type messageRow struct { MessageRow - presend message.PresendContainer // this shouldn't be here but i'm lazy + presend message.Presender // this shouldn't be here but i'm lazy } // unwrapRow is a helper that unwraps a messageRow if it's not nil. If it's nil, @@ -118,10 +121,8 @@ func unwrapRow(msg *messageRow) MessageRow { return msg.MessageRow } -var _ Container = (*ListContainer)(nil) - -func NewListContainer(ctrl Controller, constr Constructor) *ListContainer { - listStore := NewListStore(ctrl, constr) +func NewListContainer(ctrl Controller) *ListContainer { + listStore := NewListStore(ctrl) listStore.ListBox.Show() clamp := handy.ClampNew() @@ -139,12 +140,10 @@ func NewListContainer(ctrl Controller, constr Constructor) *ListContainer { } } -// TODO: remove useless abstraction (this file). - -// // CreateMessageUnsafe inserts a message. It does not clean up old messages. -// func (c *ListContainer) CreateMessageUnsafe(msg cchat.MessageCreate) MessageRow { -// return c.ListStore.CreateMessageUnsafe(msg) -// } +func (c *ListContainer) AddMessage(row MessageRow) { + c.ListStore.AddMessage(row) + c.CleanMessages() +} // CleanMessages cleans up the oldest messages if the user is scrolled to the // bottom. True is returned if there were changes. diff --git a/internal/ui/messages/container/cozy/avatar.go b/internal/ui/messages/container/cozy/avatar.go new file mode 100644 index 0000000..cf89a68 --- /dev/null +++ b/internal/ui/messages/container/cozy/avatar.go @@ -0,0 +1,47 @@ +package cozy + +import ( + "github.com/diamondburned/cchat-gtk/internal/ui/primitives" + "github.com/diamondburned/cchat-gtk/internal/ui/primitives/roundimage" + "github.com/diamondburned/cchat-gtk/internal/ui/rich" + "github.com/gotk3/gotk3/gtk" +) + +type Avatar struct { + roundimage.Button + Image *roundimage.StillImage + url string +} + +func NewAvatar(parent primitives.Connector) *Avatar { + img := roundimage.NewStillImage(nil, 0) + img.SetSizeRequest(AvatarSize, AvatarSize) + img.Show() + + avatar, _ := roundimage.NewCustomButton(img) + avatar.SetVAlign(gtk.ALIGN_START) + + // Default icon. + primitives.SetImageIcon(img, "user-available-symbolic", AvatarSize) + + return &Avatar{*avatar, img, ""} +} + +// SetImage sets the avatar from the given label image. +func (a *Avatar) SetImage(img rich.LabelImage) { + a.SetURL(img.URL) +} + +// SetURL updates the Avatar to be that URL. It does nothing if URL is empty or +// matches the existing one. +func (a *Avatar) SetURL(url string) { + // Check if the URL is the same. This will save us quite a few requests, as + // some methods rely on the side-effects of other methods, and they may call + // UpdateAuthor multiple times. + if a.url == url || url == "" { + return + } + + a.url = url + a.Image.SetImageURL(url) +} diff --git a/internal/ui/messages/container/cozy/cozy.go b/internal/ui/messages/container/cozy/cozy.go index 906b3cc..bb542e5 100644 --- a/internal/ui/messages/container/cozy/cozy.go +++ b/internal/ui/messages/container/cozy/cozy.go @@ -6,24 +6,10 @@ import ( "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/gts" "github.com/diamondburned/cchat-gtk/internal/ui/messages/container" - "github.com/diamondburned/cchat-gtk/internal/ui/messages/input" "github.com/diamondburned/cchat-gtk/internal/ui/messages/message" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" ) -// Unwrapper provides an interface for messages to be unwrapped. This is used to -// convert between collapsed and full messages. -type Unwrapper interface { - Unwrap() *message.GenericContainer -} - -var ( - _ Unwrapper = (*CollapsedMessage)(nil) - _ Unwrapper = (*CollapsedSendingMessage)(nil) - _ Unwrapper = (*FullMessage)(nil) - _ Unwrapper = (*FullSendingMessage)(nil) -) - // Collapsible is an interface for cozy messages to return whether or not // they're full or collapsed. type Collapsible interface { @@ -43,29 +29,26 @@ const ( AvatarMargin = 10 ) -var messageConstructors = container.Constructor{ - NewMessage: NewMessage, - NewPresendMessage: NewPresendMessage, -} - +// NewMessage creates a new message. func NewMessage( - msg cchat.MessageCreate, before container.MessageRow) container.MessageRow { + s *message.State, before container.MessageRow) container.MessageRow { - if isCollapsible(before, msg) { - return NewCollapsedMessage(msg) + if isCollapsible(before, s) { + return WrapCollapsedMessage(s) } - return NewFullMessage(msg) + return WrapFullMessage(s) } +// NewPresendMessage creates a new presend message. func NewPresendMessage( - msg input.PresendMessage, before container.MessageRow) container.PresendMessageRow { + s *message.PresendState, before container.MessageRow) container.PresendMessageRow { - if isCollapsible(before, msg) { - return NewCollapsedSendingMessage(msg) + if isCollapsible(before, s.State) { + return WrapCollapsedSendingMessage(s) } - return NewFullSendingMessage(msg) + return WrapFullSendingMessage(s) } type Container struct { @@ -73,7 +56,7 @@ type Container struct { } func NewContainer(ctrl container.Controller) *Container { - c := container.NewListContainer(ctrl, messageConstructors) + c := container.NewListContainer(ctrl) primitives.AddClass(c, "cozy-container") return &Container{ListContainer: c} } @@ -81,105 +64,72 @@ func NewContainer(ctrl container.Controller) *Container { func (c *Container) findAuthorID(authorID string) container.MessageRow { // Search the old author if we have any. return c.ListStore.FindMessage(func(msgc container.MessageRow) bool { - return msgc.Author().ID() == authorID + return msgc.Unwrap(false).Author.ID == authorID }) } -// reuseAvatar tries to search past messages with the same author ID and URL for -// the image. It will fetch anew if there's none. -func (c *Container) reuseAvatar(authorID, avatarURL string, full *FullMessage) { - // Is this a message that we can work with? We have to assert to - // FullSendingMessage because that's where our messages are. - var lastAuthorMsg = c.findAuthorID(authorID) - - // Borrow the avatar pixbuf, but only if the avatar URL is the same. - p, ok := lastAuthorMsg.(AvatarPixbufCopier) - if ok && lastAuthorMsg.Author().Avatar() == avatarURL { - if p.CopyAvatarPixbuf(full.Avatar.Image) { - full.Avatar.ManuallySetURL(avatarURL) - return - } - } - - // We can't borrow, so we need to fetch it anew. - full.Avatar.SetURL(avatarURL) -} - -// lastMessageIsAuthor removed - assuming index before insertion is harmful. - -type authoredMessage interface { - cchat.MessageHeader - Author() cchat.Author -} - -var ( - _ authoredMessage = (cchat.MessageCreate)(nil) - _ authoredMessage = (input.PresendMessage)(nil) - _ authoredMessage = (container.MessageRow)(nil) - _ authoredMessage = (container.PresendMessageRow)(nil) -) - const splitDuration = 10 * time.Minute // isCollapsible returns true if the given lastMsg has matching conditions with // the given msg. -func isCollapsible(lastMsg container.MessageRow, msg authoredMessage) bool { - if lastMsg == nil || msg == nil { +func isCollapsible(last container.MessageRow, msg *message.State) bool { + if last == nil || msg.ID == "" { return false } - lastAuthor := lastMsg.Author() - thisAuthor := msg.Author() + lastMsg := last.Unwrap(false) return true && - lastAuthor.ID() == thisAuthor.ID() && - lastAuthor.Name().String() == thisAuthor.Name().String() && - lastMsg.Time().Add(splitDuration).After(msg.Time()) + lastMsg.Author.ID == msg.ID && + lastMsg.Time.Add(splitDuration).After(msg.Time) +} + +func (c *Container) NewPresendMessage(state *message.PresendState) container.PresendMessageRow { + msgr := NewPresendMessage(state, c.LastMessage()) + c.AddMessage(msgr) + return msgr } func (c *Container) CreateMessage(msg cchat.MessageCreate) { gts.ExecAsync(func() { - // Create the message in the parent's handler. This handler will also - // wipe old messages. - row := c.ListContainer.CreateMessageUnsafe(msg) + state := message.NewState(msg) + msgr := NewMessage(state, c.LastMessage()) - // Is this a full message? If so, then we should fetch the avatar when - // we can. - if full, ok := row.(*FullMessage); ok { - author := msg.Author() - avatarURL := author.Avatar() - - // Try and reuse an existing avatar if the author has one. - if avatarURL != "" { - // Try reusing the avatar, but fetch it from the internet if we can't - // reuse. The reuse function does this for us. - c.reuseAvatar(author.ID(), avatarURL, full) - } - } - - // Did the handler wipe old messages? It will only do so if the user is - // scrolled to the bottom. - if c.ListContainer.CleanMessages() { - // We need to uncollapse the first (top) message. No length check is - // needed here, as we just inserted a message. - c.uncompact(c.FirstMessage()) - } - - // If we've prepended the message, then see if we need to collapse the - // second message. - if first := c.ListContainer.FirstMessage(); first != nil && first.ID() == msg.ID() { - // If the author is the same, then collapse. - if sec := c.NthMessage(1); sec != nil && isCollapsible(sec, msg) { - c.compact(sec) - } - } + c.AddMessage(msgr) }) } +// AddMessage adds the given message. +func (c *Container) AddMessage(msgr container.MessageRow) { + // Create the message in the parent's handler. This handler will also + // wipe old messages. + c.ListContainer.AddMessage(msgr) + + // Did the handler wipe old messages? It will only do so if the user is + // scrolled to the bottom. + if c.ListContainer.CleanMessages() { + // We need to uncollapse the first (top) message. No length check is + // needed here, as we just inserted a message. + c.uncompact(c.FirstMessage()) + } + + // If we've prepended the message, then see if we need to collapse the + // second message. + if first := c.ListContainer.FirstMessage(); first != nil { + firstState := first.Unwrap(false) + msgState := msgr.Unwrap(false) + + if firstState.ID == msgState.ID { + // If the author is the same, then collapse. + if sec := c.NthMessage(1); isCollapsible(sec, firstState) { + c.compact(sec) + } + } + } +} + func (c *Container) UpdateMessage(msg cchat.MessageUpdate) { - gts.ExecAsync(func() { - c.UpdateMessageUnsafe(msg) - }) + gts.ExecAsync(func() { container.UpdateMessage(c, msg) }) } func (c *Container) DeleteMessage(msg cchat.MessageDelete) { @@ -202,10 +152,13 @@ func (c *Container) DeleteMessage(msg cchat.MessageDelete) { return } - msgAuthorID := msg.Author().ID() + msgHeader := msg.Unwrap(false) + + prevHeader := prev.Unwrap(false) + nextHeader := next.Unwrap(false) // Check if the last message is the author's (relative to i): - if prev.Author().ID() == msgAuthorID { + if prevHeader.Author.ID == msgHeader.Author.ID { // If the author is the same, then we don't need to uncollapse the // message. return @@ -213,7 +166,7 @@ func (c *Container) DeleteMessage(msg cchat.MessageDelete) { // If the next message (relative to i) is not the deleted message's // author, then we don't need to uncollapse it. - if next.Author().ID() != msgAuthorID { + if nextHeader.Author.ID != msgHeader.Author.ID { return } @@ -223,33 +176,11 @@ func (c *Container) DeleteMessage(msg cchat.MessageDelete) { } func (c *Container) uncompact(msg container.MessageRow) { - // We should only uncompact the message if it's compacted in the first - // place. - compact, ok := msg.(*CollapsedMessage) - if !ok { - return - } - - // Start the "lengthy" uncollapse process. - full := WrapFullMessage(compact.Unwrap()) - // Update the container to reformat everything including the timestamps. - message.RefreshContainer(full, full.GenericContainer) - // Update the avatar if needed be, since we're now showing it. - author := msg.Author() - c.reuseAvatar(author.ID(), author.Avatar(), full) - - // Swap the old next message out for a new one. + full := WrapFullMessage(msg.Unwrap(true)) c.ListStore.SwapMessage(full) } func (c *Container) compact(msg container.MessageRow) { - full, ok := msg.(*FullMessage) - if !ok { - return - } - - compact := WrapCollapsedMessage(full.Unwrap()) - message.RefreshContainer(compact, compact.GenericContainer) - + compact := WrapCollapsedMessage(msg.Unwrap(true)) c.ListStore.SwapMessage(compact) } diff --git a/internal/ui/messages/container/cozy/message_collapsed.go b/internal/ui/messages/container/cozy/message_collapsed.go index 7d97f66..3562903 100644 --- a/internal/ui/messages/container/cozy/message_collapsed.go +++ b/internal/ui/messages/container/cozy/message_collapsed.go @@ -1,12 +1,7 @@ package cozy import ( - "time" - - "github.com/diamondburned/cchat" - "github.com/diamondburned/cchat-gtk/internal/humanize" "github.com/diamondburned/cchat-gtk/internal/ui/messages/container" - "github.com/diamondburned/cchat-gtk/internal/ui/messages/input" "github.com/diamondburned/cchat-gtk/internal/ui/messages/message" "github.com/gotk3/gotk3/gtk" ) @@ -15,17 +10,12 @@ import ( // the header, and the avatar is invisible. type CollapsedMessage struct { // Author is still updated normally. - *message.GenericContainer + *message.State Timestamp *gtk.Label } -func NewCollapsedMessage(msg cchat.MessageCreate) *CollapsedMessage { - msgc := WrapCollapsedMessage(message.NewContainer(msg)) - message.FillContainer(msgc, msg) - return msgc -} - -func WrapCollapsedMessage(gc *message.GenericContainer) *CollapsedMessage { +// WrapCollapsedMessage wraps the given message state to be a collapsed message. +func WrapCollapsedMessage(gc *message.State) *CollapsedMessage { // Set Timestamp's padding accordingly to Avatar's. ts := message.NewTimestamp() ts.SetSizeRequest(AvatarSize, -1) @@ -42,37 +32,31 @@ func WrapCollapsedMessage(gc *message.GenericContainer) *CollapsedMessage { gc.SetClass("cozy-collapsed") return &CollapsedMessage{ - GenericContainer: gc, - Timestamp: ts, + State: gc, + Timestamp: ts, } } func (c *CollapsedMessage) Collapsed() bool { return true } -func (c *CollapsedMessage) UpdateTimestamp(t time.Time) { - c.GenericContainer.UpdateTimestamp(t) - c.Timestamp.SetText(humanize.TimeAgoShort(t)) -} +func (c *CollapsedMessage) Unwrap(revert bool) *message.State { + if revert { + // Remove State's widgets from the containers. + c.Remove(c.Timestamp) + c.Remove(c.Content) + } -func (c *CollapsedMessage) Unwrap() *message.GenericContainer { - // Remove GenericContainer's widgets from the containers. - c.Remove(c.Timestamp) - c.Remove(c.Content) - - // Return after removing. - return c.GenericContainer + return c.State } type CollapsedSendingMessage struct { *CollapsedMessage - message.PresendContainer + message.Presender } -func NewCollapsedSendingMessage(msg input.PresendMessage) *CollapsedSendingMessage { - var msgc = message.NewPresendContainer(msg) - +func WrapCollapsedSendingMessage(pstate *message.PresendState) *CollapsedSendingMessage { return &CollapsedSendingMessage{ - CollapsedMessage: WrapCollapsedMessage(msgc.GenericContainer), - PresendContainer: msgc, + CollapsedMessage: WrapCollapsedMessage(pstate.State), + Presender: pstate, } } diff --git a/internal/ui/messages/container/cozy/message_full.go b/internal/ui/messages/container/cozy/message_full.go index 94de10f..9506755 100644 --- a/internal/ui/messages/container/cozy/message_full.go +++ b/internal/ui/messages/container/cozy/message_full.go @@ -4,18 +4,13 @@ import ( "time" "github.com/diamondburned/cchat" - "github.com/diamondburned/cchat-gtk/internal/gts/httputil" "github.com/diamondburned/cchat-gtk/internal/humanize" "github.com/diamondburned/cchat-gtk/internal/ui/messages/container" - "github.com/diamondburned/cchat-gtk/internal/ui/messages/input" "github.com/diamondburned/cchat-gtk/internal/ui/messages/message" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" - "github.com/diamondburned/cchat-gtk/internal/ui/primitives/menu" - "github.com/diamondburned/cchat-gtk/internal/ui/primitives/roundimage" "github.com/diamondburned/cchat-gtk/internal/ui/rich/labeluri" "github.com/diamondburned/cchat-gtk/internal/ui/rich/parser/markup" "github.com/diamondburned/cchat/text" - "github.com/gotk3/gotk3/cairo" "github.com/gotk3/gotk3/gtk" ) @@ -23,22 +18,20 @@ import ( const TopFullMargin = 4 type FullMessage struct { - *message.GenericContainer + *message.State // Grid widgets. Avatar *Avatar MainBox *gtk.Box // wraps header and content - Header *labeluri.Label - timestamp string // markup -} + HeaderLabel *labeluri.Label + timestamp string // markup -type AvatarPixbufCopier interface { - CopyAvatarPixbuf(img httputil.SurfaceContainer) bool + // unwrap is used to removing label handlers. + unwrap func() } var ( - _ AvatarPixbufCopier = (*FullMessage)(nil) _ message.Container = (*FullMessage)(nil) _ container.MessageRow = (*FullMessage)(nil) ) @@ -51,22 +44,16 @@ var avatarCSS = primitives.PrepareClassCSS("cozy-avatar", ` `) func NewFullMessage(msg cchat.MessageCreate) *FullMessage { - msgc := WrapFullMessage(message.NewContainer(msg)) - // Don't update the avatar. NewMessage in controller will try and reuse the - // pixbuf if possible. - msgc.UpdateAuthorName(msg.Author().Name()) - msgc.UpdateTimestamp(msg.Time()) - msgc.UpdateContent(msg.Content(), false) - return msgc + return WrapFullMessage(message.NewState(msg)) } -func WrapFullMessage(gc *message.GenericContainer) *FullMessage { +func WrapFullMessage(gc *message.State) *FullMessage { header := labeluri.NewLabel(text.Rich{}) header.SetHAlign(gtk.ALIGN_START) // left-align header.SetMaxWidthChars(100) header.Show() - avatar := NewAvatar() + avatar := NewAvatar(gc.Row) avatar.SetMarginTop(TopFullMargin / 2) avatar.SetMarginStart(container.ColumnSpacing * 2) avatar.Connect("clicked", func(w gtk.IWidget) { @@ -97,87 +84,61 @@ func WrapFullMessage(gc *message.GenericContainer) *FullMessage { gc.PackStart(main, true, true, 0) gc.SetClass("cozy-full") - return &FullMessage{ - GenericContainer: gc, + msg := &FullMessage{ + State: gc, + timestamp: formatLongTime(gc.Time), - Avatar: avatar, - MainBox: main, - Header: header, + Avatar: avatar, + MainBox: main, + HeaderLabel: header, + + unwrap: gc.Author.Name.OnUpdate(func() { + avatar.SetImage(gc.Author.Name.Image()) + header.SetLabel(gc.Author.Name.Label()) + }), } + + header.SetRenderer(func(rich text.Rich) markup.RenderOutput { + cfg := markup.RenderConfig{} + cfg.NoReferencing = true + cfg.SetForegroundAnchor(gc.ContentBodyStyle) + + output := markup.RenderCmplxWithConfig(rich, cfg) + output.Markup = `` + output.Markup + "" + output.Markup += msg.timestamp + + return output + }) + + return msg } func (m *FullMessage) Collapsed() bool { return false } -func (m *FullMessage) Unwrap() *message.GenericContainer { - // Remove GenericContainer's widgets from the containers. - m.Header.Destroy() - m.MainBox.Remove(m.Content) // not ours, so don't destroy. +func (m *FullMessage) Unwrap(revert bool) *message.State { + if revert { + // Remove the handlers. + m.unwrap() - // Remove the message from the grid. - m.Avatar.Destroy() - m.MainBox.Destroy() + // Remove State's widgets from the containers. + m.HeaderLabel.Destroy() + m.MainBox.Remove(m.Content) // not ours, so don't destroy. - // Return after removing. - return m.GenericContainer -} - -func (m *FullMessage) UpdateTimestamp(t time.Time) { - m.GenericContainer.UpdateTimestamp(t) - - m.timestamp = " " + - `` + humanize.TimeAgoLong(t) + `` - - // Update the timestamp. - m.Header.SetMarkup(m.Header.Output().Markup + m.timestamp) -} - -func (m *FullMessage) UpdateAuthor(author cchat.Author) { - // Call the parent's method to update the state. - m.GenericContainer.UpdateAuthor(author) - m.UpdateAuthorName(author.Name()) - m.Avatar.SetURL(author.Avatar()) -} - -func (m *FullMessage) UpdateAuthorName(name text.Rich) { - cfg := markup.RenderConfig{} - cfg.NoReferencing = true - cfg.SetForegroundAnchor(m.ContentBodyStyle) - - output := markup.RenderCmplxWithConfig(name, cfg) - output.Markup = `` + output.Markup + "" - - m.Header.SetMarkup(output.Markup + m.timestamp) - m.Header.SetUnderlyingOutput(output) -} - -// CopyAvatarPixbuf sets the pixbuf into the given container. This shares the -// same pixbuf, but gtk.Image should take its own reference from the pixbuf. -func (m *FullMessage) CopyAvatarPixbuf(dst httputil.SurfaceContainer) bool { - switch img := m.Avatar.Image.GetImage(); img.GetStorageType() { - case gtk.IMAGE_PIXBUF: - dst.SetFromPixbuf(img.GetPixbuf()) - case gtk.IMAGE_ANIMATION: - dst.SetFromAnimation(img.GetAnimation()) - case gtk.IMAGE_SURFACE: - v, _ := img.GetProperty("surface") - dst.SetFromSurface(v.(*cairo.Surface)) - default: - return false + // Remove the message from the grid. + m.Avatar.Destroy() + m.MainBox.Destroy() } - return true + + return m.State } -func (m *FullMessage) AttachMenu(items []menu.Item) { - // Bind to parent's container as well. - m.GenericContainer.AttachMenu(items) - - // Bind to the box. - // TODO lol +func formatLongTime(t time.Time) string { + return `` + humanize.TimeAgoLong(t) + `` } type FullSendingMessage struct { - message.PresendContainer - FullMessage + *FullMessage + message.Presender } var ( @@ -185,51 +146,9 @@ var ( _ container.MessageRow = (*FullSendingMessage)(nil) ) -func NewFullSendingMessage(msg input.PresendMessage) *FullSendingMessage { - var msgc = message.NewPresendContainer(msg) - +func WrapFullSendingMessage(pstate *message.PresendState) *FullSendingMessage { return &FullSendingMessage{ - PresendContainer: msgc, - FullMessage: *WrapFullMessage(msgc.GenericContainer), + FullMessage: WrapFullMessage(pstate.State), + Presender: pstate, } } - -type Avatar struct { - roundimage.Button - Image *roundimage.StaticImage - url string -} - -func NewAvatar() *Avatar { - img, _ := roundimage.NewStaticImage(nil, 0) - img.SetSizeRequest(AvatarSize, AvatarSize) - img.Show() - - avatar, _ := roundimage.NewCustomButton(img) - avatar.SetVAlign(gtk.ALIGN_START) - - // Default icon. - primitives.SetImageIcon(img, "user-available-symbolic", AvatarSize) - - return &Avatar{*avatar, img, ""} -} - -// SetURL updates the Avatar to be that URL. It does nothing if URL is empty or -// matches the existing one. -func (a *Avatar) SetURL(url string) { - // Check if the URL is the same. This will save us quite a few requests, as - // some methods rely on the side-effects of other methods, and they may call - // UpdateAuthor multiple times. - if a.url == url || url == "" { - return - } - - a.url = url - a.Image.SetImageURL(url) -} - -// ManuallySetURL sets the URL without downloading the image. It assumes the -// pixbuf is borrowed elsewhere. -func (a *Avatar) ManuallySetURL(url string) { - a.url = url -} diff --git a/internal/ui/messages/container/list.go b/internal/ui/messages/container/list.go index 0c28aa0..2517a67 100644 --- a/internal/ui/messages/container/list.go +++ b/internal/ui/messages/container/list.go @@ -1,15 +1,15 @@ package container import ( - "log" "strings" "time" "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/gts" - "github.com/diamondburned/cchat-gtk/internal/ui/messages/input" + "github.com/diamondburned/cchat-gtk/internal/ui/messages/message" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" "github.com/diamondburned/cchat-gtk/internal/ui/rich/parser/markup" + "github.com/diamondburned/cchat/text" "github.com/gotk3/gotk3/gtk" ) @@ -63,18 +63,19 @@ var messageListCSS = primitives.PrepareClassCSS("message-list", ` .message-list { background: transparent; } `) -type ListStore struct { - ListBox *gtk.ListBox +var fallbackAuthor = message.NewCustomAuthor("", text.Plain("self")) - Construct Constructor +type ListStore struct { + ListBox *gtk.ListBox Controller Controller - resetMe bool + self *message.Author + resetMe bool messages map[messageKey]*messageRow } -func NewListStore(ctrl Controller, constr Constructor) *ListStore { +func NewListStore(ctrl Controller) *ListStore { listBox, _ := gtk.ListBoxNew() listBox.SetSelectionMode(gtk.SELECTION_SINGLE) listBox.Show() @@ -82,9 +83,9 @@ func NewListStore(ctrl Controller, constr Constructor) *ListStore { listStore := ListStore{ ListBox: listBox, - Construct: constr, Controller: ctrl, messages: make(map[messageKey]*messageRow, BacklogLimit+1), + self: &fallbackAuthor, } var selected bool @@ -113,9 +114,29 @@ func NewListStore(ctrl Controller, constr Constructor) *ListStore { return &listStore } +// Reset resets the list store. func (c *ListStore) Reset() { + for _, msg := range c.messages { + destroyMsg(msg) + } + // Delegate removing children to the constructor. c.messages = make(map[messageKey]*messageRow, BacklogLimit+1) + + if c.self.ID != "" { + c.self.Name.Stop() + } +} + +// SetSelf sets the current author to presend. If ID is empty or Namer is nil, +// then the fallback author is used instead. The given author will be stopped +// on reset. +func (c *ListStore) SetSelf(self *message.Author) { + if self != nil { + c.self = self + } else { + c.self = &fallbackAuthor + } } func (c *ListStore) MessagesLen() int { @@ -133,22 +154,27 @@ func (c *ListStore) SwapMessage(msg MessageRow) bool { msg = m.MessageRow } + msgState := msg.Unwrap(false) + // Get the current message's index. - oldMsg, ix := c.findIndex(msg.ID()) + oldMsg, ix := c.findIndex(msgState.ID) if ix == -1 { return false } + oldState := oldMsg.Unwrap(false) + // Remove the to-be-replaced message box. We should probably reuse the row. - c.ListBox.Remove(oldMsg.Row()) + c.ListBox.Remove(oldState.Row) // Add a row at index. The actual row we want to delete will be shifted // downwards. - c.ListBox.Insert(msg.Row(), ix) + c.ListBox.Insert(msgState.Row, ix) // Set the message into the map. - row := c.messages[idKey(msg.ID())] + row := c.messages[idKey(msgState.ID)] row.MessageRow = msg + c.bindMessage(row) return true } @@ -168,8 +194,6 @@ func (c *ListStore) Around(id cchat.ID) (before, after MessageRow) { } func (c *ListStore) around(aroundID cchat.ID) (before, after *messageRow) { - c.ensureEmpty() - var last *messageRow var next bool @@ -192,25 +216,8 @@ func (c *ListStore) around(aroundID cchat.ID) (before, after *messageRow) { return } -// LatestMessageFrom returns the latest message with the given user ID. This is -// used for the input prompt. -func (c *ListStore) LatestMessageFrom(userID string) (msgID string, ok bool) { - // FindMessage already looks from the latest messages. - var msg = c.FindMessage(func(msg MessageRow) bool { - return msg.Author().ID() == userID - }) - - if msg == nil { - return "", false - } - - return msg.ID(), true -} - // findIndex searches backwards for id. func (c *ListStore) findIndex(findID cchat.ID) (found *messageRow, index int) { - c.ensureEmpty() - // Faster implementation of findMessage: no map lookup is done until an ID // match, so the worst case is a single string hash. index = c.MessagesLen() - 1 @@ -235,8 +242,6 @@ func (c *ListStore) findIndex(findID cchat.ID) (found *messageRow, index int) { } func (c *ListStore) findMessage(presend bool, fn func(*messageRow) bool) (*messageRow, int) { - c.ensureEmpty() - var r *messageRow var i = c.MessagesLen() - 1 @@ -316,6 +321,9 @@ func (c *ListStore) message(msgID cchat.ID, nonce string) *messageRow { if nonce != "" { // Things in this map are guaranteed to have presend != nil. m, ok := c.messages[nonceKey(nonce)] + + // This is honestly pretty dumb, but whatever. + // TODO: make message() getter not set. if ok { // Replace the nonce key with ID. delete(c.messages, nonceKey(nonce)) @@ -334,135 +342,69 @@ func (c *ListStore) message(msgID cchat.ID, nonce string) *messageRow { return nil } -// ensureEmpty ensures that if the message map is empty, then the container -// should also be. -func (c *ListStore) ensureEmpty() { - if len(c.messages) == 0 { - primitives.RemoveChildren(c.ListBox) - } -} - func (c *ListStore) bindMessage(msgc *messageRow) { + state := msgc.Unwrap(false) + // Bind the message ID to the row so we can easily do a lookup. - var key messageKey - if id := msgc.ID(); id != "" { - key.id = id - } else { - key.id = msgc.Nonce() + key := messageKey{ + id: state.ID, + } + + if state.Nonce != "" { + key.id = state.Nonce key.nonce = true } - msgc.Row().SetName(key.name()) - msgc.SetReferenceHighlighter(c) + state.Row.SetName(key.name()) + msgc.MessageRow.SetReferenceHighlighter(c) + c.Controller.BindMenu(msgc.MessageRow) } -// AddPresendMessage inserts an input.PresendMessage into the container and -// returning a wrapped widget interface. -func (c *ListStore) AddPresendMessage(msg input.PresendMessage) PresendMessageRow { - c.ensureEmpty() +func (c *ListStore) AddMessage(msg MessageRow) { + state := msg.Unwrap(false) - before := c.LastMessage() - - if before != nil { - log.Println("Found before:", before.Author().Name()) - } else { - log.Println("Before is nil") - } - - presend := c.Construct.NewPresendMessage(msg, before) - - msgc := &messageRow{ - MessageRow: presend, - presend: presend, - } - - // Set the message into the list. - c.ListBox.Insert(msgc.Row(), c.MessagesLen()) - // Set the NONCE into the message map. - c.messages[nonceKey(msgc.Nonce())] = msgc - - c.bindMessage(msgc) - - return presend -} - -// Many attempts were made to have CreateMessageUnsafe return an index. That is -// unreliable. The index might be off if the message buffer is cleaned up. Don't -// rely on it. - -func (c *ListStore) CreateMessageUnsafe(msg cchat.MessageCreate) MessageRow { - // Call the event handler last. - defer c.Controller.AuthorEvent(msg.Author()) + defer c.Controller.AuthorEvent(state.Author.ID) // Do not attempt to update before insertion (aka upsert). - if msgc := c.message(msg.ID(), msg.Nonce()); msgc != nil { - msgc.UpdateAuthor(msg.Author()) - msgc.UpdateContent(msg.Content(), false) - msgc.UpdateTimestamp(msg.Time()) - - c.bindMessage(msgc) - return msgc.MessageRow + if msgc := c.message(state.ID, state.Nonce); msgc != nil { + // This is kind of expensive, but it shouldn't really matter. + c.SwapMessage(msg) + return } - c.ensureEmpty() - - msgTime := msg.Time() - // Iterate and compare timestamp to find where to insert a message. Note // that "before" is the message that will go before the to-be-inserted // method. before, index := c.findMessage(true, func(before *messageRow) bool { - return msgTime.After(before.Time()) + return before.Unwrap(false).Time.After(state.Time) }) msgc := &messageRow{ - MessageRow: c.Construct.NewMessage(msg, unwrapRow(before)), + MessageRow: msg, } // Add the message. If before is nil, then the to-be-inserted message is the // earliest message, therefore we prepend it. if before == nil { index = 0 - c.ListBox.Prepend(msgc.Row()) + c.ListBox.Prepend(state.Row) } else { index++ // insert right after // Fast path: Insert did appear a lot on profiles, so we can try and use // Add over Insert when we know. if c.MessagesLen() == index { - c.ListBox.Add(msgc.Row()) + c.ListBox.Add(state.Row) } else { - c.ListBox.Insert(msgc.Row(), index) + c.ListBox.Insert(state.Row, index) } } // Set the ID into the message map. - c.messages[idKey(msgc.ID())] = msgc + c.messages[idKey(state.ID)] = msgc c.bindMessage(msgc) - - return msgc.MessageRow -} - -func (c *ListStore) UpdateMessageUnsafe(msg cchat.MessageUpdate) { - // Call the event handler last. - defer c.Controller.AuthorEvent(msg.Author()) - - if msgc := c.Message(msg.ID(), ""); msgc != nil { - if author := msg.Author(); author != nil { - msgc.UpdateAuthor(author) - } - if content := msg.Content(); !content.IsEmpty() { - msgc.UpdateContent(content, true) - } - } - - return -} - -func (c *ListStore) DeleteMessageUnsafe(msg cchat.MessageDelete) { - c.PopMessage(msg.ID()) } // PopMessage deletes a message off of the list and return the deleted message. @@ -475,7 +417,8 @@ func (c *ListStore) PopMessage(id cchat.ID) (msg MessageRow) { msg = gridMsg.MessageRow // Remove off of the Gtk grid. - gridMsg.Row().Destroy() + destroyMsg(gridMsg) + // Delete off the map. delete(c.messages, idKey(id)) @@ -489,22 +432,23 @@ func (c *ListStore) DeleteEarliest(n int) { return } - c.ensureEmpty() - // Since container/list nils out the next element, we can't just call Next // after deleting, so we have to call Next manually before Removing. primitives.ForeachChild(c.ListBox, func(v interface{}) (stop bool) { id := parseKeyFromNamer(v.(primitives.Namer)) gridMsg := c.message(id.expand()) - if id := gridMsg.ID(); id != "" { - delete(c.messages, idKey(id)) - } - if nonce := gridMsg.Nonce(); nonce != "" { - delete(c.messages, nonceKey(nonce)) + state := gridMsg.Unwrap(false) + + if state.ID != "" { + delete(c.messages, idKey(state.ID)) } - gridMsg.Row().Destroy() + if state.Nonce != "" { + delete(c.messages, nonceKey(state.Nonce)) + } + + destroyMsg(gridMsg) n-- return n == 0 @@ -519,10 +463,16 @@ func (c *ListStore) HighlightReference(ref markup.ReferenceSegment) { } func (c *ListStore) Highlight(msg MessageRow) { - gts.ExecLater(func() { - row := msg.Row() - row.GrabFocus() - c.ListBox.DragHighlightRow(row) + gts.ExecAsync(func() { + state := msg.Unwrap(false) + state.Row.GrabFocus() + c.ListBox.DragHighlightRow(state.Row) gts.DoAfter(2*time.Second, c.ListBox.DragUnhighlightRow) }) } + +func destroyMsg(row *messageRow) { + state := row.Unwrap(true) + state.Author.Name.Stop() + state.Row.Destroy() +} diff --git a/internal/ui/messages/input/attachment/attachment.go b/internal/ui/messages/input/attachment/attachment.go index e92f821..b653341 100644 --- a/internal/ui/messages/input/attachment/attachment.go +++ b/internal/ui/messages/input/attachment/attachment.go @@ -272,8 +272,8 @@ var deleteAttBtnCSS = primitives.PrepareCSS(` func (c *Container) addPreview(name string, thumbnail *cairo.Surface) { // Make a fallback image first. - gimg, _ := roundimage.NewImage(4) // border-radius: 4px - primitives.SetImageIcon(gimg.Image, iconFromName(name), IconSize) + gimg := roundimage.NewImage(4) // border-radius: 4px + primitives.SetImageIcon(&gimg.Image, iconFromName(name), IconSize) gimg.SetSizeRequest(ThumbSize, ThumbSize) gimg.SetVAlign(gtk.ALIGN_CENTER) gimg.SetHAlign(gtk.ALIGN_CENTER) diff --git a/internal/ui/messages/input/input.go b/internal/ui/messages/input/input.go index 225e181..ecc86f2 100644 --- a/internal/ui/messages/input/input.go +++ b/internal/ui/messages/input/input.go @@ -6,11 +6,14 @@ import ( "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/gts" "github.com/diamondburned/cchat-gtk/internal/log" + "github.com/diamondburned/cchat-gtk/internal/ui/messages/container" "github.com/diamondburned/cchat-gtk/internal/ui/messages/input/attachment" "github.com/diamondburned/cchat-gtk/internal/ui/messages/input/username" + "github.com/diamondburned/cchat-gtk/internal/ui/messages/message" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" "github.com/diamondburned/cchat-gtk/internal/ui/primitives/completion" "github.com/diamondburned/cchat-gtk/internal/ui/primitives/scrollinput" + "github.com/diamondburned/cchat-gtk/internal/ui/rich" "github.com/diamondburned/cchat-gtk/internal/ui/rich/parser/markup" "github.com/diamondburned/handy" "github.com/gotk3/gotk3/gtk" @@ -19,10 +22,12 @@ import ( // Controller is an interface to control message containers. type Controller interface { - AddPresendMessage(msg PresendMessage) (onErr func(error)) - LatestMessageFrom(userID cchat.ID) (messageID cchat.ID, ok bool) - MessageAuthor(msgID cchat.ID) cchat.Author - Author(authorID cchat.ID) cchat.Author + LatestMessageFrom(userID cchat.ID) container.MessageRow + MessageAuthor(msgID cchat.ID) *message.Author + Author(authorID cchat.ID) (name rich.LabelStateStorer) + + // SendMessage asynchronously sends the given message. + SendMessage(msg message.PresendMessage) } // LabelBorrower is an interface that allows the caller to borrow a label. @@ -333,13 +338,13 @@ func (f *Field) StartReplyingTo(msgID cchat.ID) { f.sendIcon.SetFromIconName(replyButtonIcon, gtk.ICON_SIZE_BUTTON) if author := f.ctrl.MessageAuthor(msgID); author != nil { + label := author.Name.Label() + // Extract the name from the author's rich text and only render the area // with the MessageReference. - name := author.Name() - - for _, seg := range name.Segments { + for _, seg := range label.Segments { if seg.AsMessageReferencer() != nil || seg.AsMentioner() != nil { - mention := markup.Render(markup.SubstringSegment(name, seg)) + mention := markup.Render(markup.SubstringSegment(label, seg)) f.indicator.BorrowLabel("Replying to " + mention) return } diff --git a/internal/ui/messages/input/keydown.go b/internal/ui/messages/input/keydown.go index 5f379ac..f423989 100644 --- a/internal/ui/messages/input/keydown.go +++ b/internal/ui/messages/input/keydown.go @@ -48,12 +48,14 @@ func (f *Field) keyDown(tv *gtk.TextView, ev *gdk.Event) bool { } // Try and find the latest message ID that is ours. - id, ok := f.ctrl.LatestMessageFrom(f.UserID) - if !ok { + msgr := f.ctrl.LatestMessageFrom(f.UserID) + if msgr == nil { // No messages found, so we can passthrough normally. return false } + id := msgr.Unwrap(false).ID + // If we don't support message editing, then passthrough events. if !f.Editable(id) { return false diff --git a/internal/ui/messages/input/sendable.go b/internal/ui/messages/input/sendable.go index 5113cb8..1eccda1 100644 --- a/internal/ui/messages/input/sendable.go +++ b/internal/ui/messages/input/sendable.go @@ -8,10 +8,9 @@ import ( "time" "github.com/diamondburned/cchat" - "github.com/diamondburned/cchat-gtk/internal/gts" "github.com/diamondburned/cchat-gtk/internal/log" "github.com/diamondburned/cchat-gtk/internal/ui/messages/input/attachment" - "github.com/diamondburned/cchat/text" + "github.com/diamondburned/cchat-gtk/internal/ui/messages/message" "github.com/pkg/errors" "github.com/twmb/murmur3" ) @@ -63,17 +62,9 @@ func (f *Field) sendInput() { return } - // Derive the author. Prefer the author of the current user from the message - // buffer over the one in the username feed, unless we can't find any. - var author = f.ctrl.Author(f.UserID) - if author == nil { - author = newAuthor(f) - } - - f.SendMessage(SendMessageData{ + f.ctrl.SendMessage(SendMessageData{ time: time.Now().UTC(), content: text, - author: author, nonce: f.generateNonce(), replyID: f.replyingID, files: attachments, @@ -86,19 +77,23 @@ func (f *Field) sendInput() { f.text.GrabFocus() } -func (f *Field) SendMessage(data PresendMessage) { - // presend message into the container through the controller - var onErr = f.ctrl.AddPresendMessage(data) +// func (f *Field) SendMessage(data message.PresendMessage) { +// f.ctrl.SendMessage(data) - // Copy the sender to prevent race conditions. - var sender = f.Sender - gts.Async(func() (func(), error) { - if err := sender.Send(data); err != nil { - return func() { onErr(err) }, errors.Wrap(err, "Failed to send message") - } - return nil, nil - }) -} +// // message.NewPresendState(f.Username.State, data) + +// // // presend message into the container through the controller +// // var onErr = f.ctrl.AddPresendMessage(data) + +// // // Copy the sender to prevent race conditions. +// // var sender = f.Sender +// // gts.Async(func() (func(), error) { +// // if err := sender.Send(data); err != nil { +// // return func() { onErr(err) }, errors.Wrap(err, "Failed to send message") +// // } +// // return nil, nil +// // }) +// } // Files is a list of attachments. type Files []attachment.File @@ -117,56 +112,23 @@ func (files Files) Attachments() []cchat.MessageAttachment { type SendMessageData struct { time time.Time content string - author cchat.Author nonce string replyID cchat.ID files Files } -var _ cchat.SendableMessage = (*SendMessageData)(nil) - -// PresendMessage is an interface for any message about to be sent. -type PresendMessage interface { - cchat.MessageHeader // returns nonce and time - cchat.SendableMessage - cchat.Noncer - - // These methods are reserved for internal use. - - Author() cchat.Author - Files() []attachment.File -} - -var _ PresendMessage = (*SendMessageData)(nil) +var ( + _ cchat.SendableMessage = (*SendMessageData)(nil) + _ message.PresendMessage = (*SendMessageData)(nil) +) // ID returns a pseudo ID for internal use. func (s SendMessageData) ID() string { return s.nonce } func (s SendMessageData) Time() time.Time { return s.time } func (s SendMessageData) Content() string { return s.content } -func (s SendMessageData) Author() cchat.Author { return s.author } func (s SendMessageData) AsNoncer() cchat.Noncer { return s } func (s SendMessageData) Nonce() string { return s.nonce } func (s SendMessageData) Files() []attachment.File { return s.files } func (s SendMessageData) AsAttacher() cchat.Attacher { return s.files } func (s SendMessageData) AsReplier() cchat.Replier { return s } func (s SendMessageData) ReplyingTo() cchat.ID { return s.replyID } - -type sendableAuthor struct { - id cchat.ID - name text.Rich - avatarURL string -} - -func newAuthor(f *Field) sendableAuthor { - return sendableAuthor{ - f.UserID, - f.Username.GetLabel(), - f.Username.GetIconURL(), - } -} - -var _ cchat.Author = (*sendableAuthor)(nil) - -func (a sendableAuthor) ID() string { return a.id } -func (a sendableAuthor) Name() text.Rich { return a.name } -func (a sendableAuthor) Avatar() string { return a.avatarURL } diff --git a/internal/ui/messages/input/username/username.go b/internal/ui/messages/input/username/username.go index c941821..af3f239 100644 --- a/internal/ui/messages/input/username/username.go +++ b/internal/ui/messages/input/username/username.go @@ -2,12 +2,14 @@ package username import ( "github.com/diamondburned/cchat" - "github.com/diamondburned/cchat-gtk/internal/gts" "github.com/diamondburned/cchat-gtk/internal/ui/config" + "github.com/diamondburned/cchat-gtk/internal/ui/messages/message" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" + "github.com/diamondburned/cchat-gtk/internal/ui/primitives/roundimage" "github.com/diamondburned/cchat-gtk/internal/ui/rich" "github.com/diamondburned/cchat/text" "github.com/gotk3/gotk3/gtk" + "github.com/gotk3/gotk3/pango" ) const AvatarSize = 24 @@ -24,21 +26,20 @@ func init() { } type Container struct { - *gtk.Revealer + gtk.Revealer + State *message.Author + main *gtk.Box - avatar *rich.Icon + avatar *roundimage.Image label *rich.Label } -var ( - _ cchat.LabelContainer = (*Container)(nil) - _ cchat.IconContainer = (*Container)(nil) -) - var usernameCSS = primitives.PrepareCSS(` .username-view { margin: 0 5px } `) +var fallbackAuthor = message.NewCustomAuthor("", text.Plain("self")) + func NewContainer() *Container { box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 5) box.Show() @@ -56,13 +57,32 @@ func NewContainer() *Container { // thread. currentRevealer = rev.SetRevealChild - container := Container{ - Revealer: rev, + author := message.NewCustomAuthor("", text.Plain("self")) + + u := Container{ + Revealer: *rev, + State: &author, main: box, } - container.Reset() + u.Reset() - return &container + u.avatar = roundimage.NewImage(0) + u.avatar.SetSize(AvatarSize) + u.avatar.SetPlaceholderIcon("user-available-symbolic", AvatarSize) + u.avatar.Show() + + rich.BindRoundImage(u.avatar, &u.State.Name, false) + + u.label = rich.NewLabel(&u.State.Name) + u.label.SetEllipsize(pango.ELLIPSIZE_END) + u.label.SetMaxWidthChars(35) + u.label.Show() + + primitives.RemoveChildren(u.main) + u.main.PackStart(u.avatar, false, false, 0) + u.main.PackStart(u.label, false, false, 0) + + return &u } func (u *Container) SetRevealChild(reveal bool) { @@ -72,75 +92,39 @@ func (u *Container) SetRevealChild(reveal bool) { // shouldReveal returns whether or not the container should reveal. func (u *Container) shouldReveal() bool { - return (!u.label.GetLabel().IsEmpty() || u.avatar.URL() != "") && showUser + show := false + + show = !u.State.Name.Label().IsEmpty() + show = show || u.avatar.GetImageURL() != "" + show = show || showUser + + return true } func (u *Container) Reset() { u.SetRevealChild(false) - - u.avatar = rich.NewIcon(AvatarSize) - u.avatar.SetPlaceholderIcon("user-available-symbolic", AvatarSize) - u.avatar.Show() - - u.label = rich.NewLabel(text.Rich{}) - u.label.SetMaxWidthChars(35) - u.label.Show() - - primitives.RemoveChildren(u.main) - u.main.PackStart(u.avatar, false, false, 0) - u.main.PackStart(u.label, false, false, 0) + u.State.Name.Stop() } // Update is not thread-safe. func (u *Container) Update(session cchat.Session, messenger cchat.Messenger) { // Set the fallback username. - u.label.SetLabelUnsafe(session.Name()) + u.State.Name.BindNamer(u.main, "destroy", session) // Reveal the name if it's not empty. u.SetRevealChild(true) // Does messenger implement Nicknamer? If yes, use it. if nicknamer := messenger.AsNicknamer(); nicknamer != nil { - u.label.AsyncSetLabel(nicknamer.Nickname, "Error fetching server nickname") - } - - // Does session implement an icon? Update if yes. - if iconer := session.AsIconer(); iconer != nil { - u.avatar.AsyncSetIconer(iconer, "Error fetching session icon URL") + u.State.Name.BindNamer(u.main, "destroy", nicknamer) } } -// GetLabel is not thread-safe. -func (u *Container) GetLabel() text.Rich { - return u.label.GetLabel() +// Label returns the underlying label. +func (u *Container) Label() text.Rich { + return u.State.Name.Label() } -// GetLabelMarkup is not thread-safe. +// LabelMarkup returns the underlying label's markup. func (u *Container) GetLabelMarkup() string { - return u.label.Label.GetLabel() -} - -// SetLabel is thread-safe. -func (u *Container) SetLabel(content text.Rich) { - gts.ExecAsync(func() { - u.label.SetLabelUnsafe(content) - - // Reveal if the name is not empty. - u.SetRevealChild(true) - }) -} - -// SetIcon is thread-safe. -func (u *Container) SetIcon(url string) { - gts.ExecAsync(func() { - u.avatar.SetIconUnsafe(url) - - // Reveal if the icon URL is not empty. We don't touch anything if the - // URL is empty, as the name might not be. - u.SetRevealChild(true) - }) -} - -// GetIconURL is not thread-safe. -func (u *Container) GetIconURL() string { - return u.avatar.URL() + return u.label.Output().Markup } diff --git a/internal/ui/messages/memberlist/memberlist.go b/internal/ui/messages/memberlist/memberlist.go index 7ed87b6..ad3b778 100644 --- a/internal/ui/messages/memberlist/memberlist.go +++ b/internal/ui/messages/memberlist/memberlist.go @@ -3,7 +3,6 @@ package memberlist import ( "context" "fmt" - "strings" "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/gts" @@ -128,20 +127,22 @@ func (c *Container) SetSectionsUnsafe(sections []cchat.MemberSection) { // to this function instead of Reset to not halt for too long. primitives.RemoveChildren(c.Main) - var newSections = make([]*Section, len(sections)) + newSections := make([]*Section, len(sections)) + oldSections := c.Sections for i, section := range sections { sc, ok := c.Sections[section.ID()] if !ok { sc = NewSection(section, &c.eventQueue) } else { - sc.Update(section.Name(), section.Total()) + sc.Update(section) } newSections[i] = sc } // Remove all old sections. + for id := range c.Sections { delete(c.Sections, id) } @@ -152,6 +153,16 @@ func (c *Container) SetSectionsUnsafe(sections []cchat.MemberSection) { c.Sections[section.ID] = section } + // Destroy old sections. + for _, section := range oldSections { + _, notOld := c.Sections[section.ID] + if notOld { + continue + } + + section.Destroy() + } + c.ctrl.MemberListUpdated(c) } @@ -173,7 +184,7 @@ type Section struct { ID string // state - name text.Rich + name rich.NameContainer total int Header *rich.Label @@ -197,26 +208,40 @@ var sectionBodyCSS = primitives.PrepareClassCSS("section-body", ` `) func NewSection(sect cchat.MemberSection, evq EventQueuer) *Section { - header := rich.NewLabel(text.Rich{}) - header.Show() - sectionHeaderCSS(header) + section := &Section{ + ID: sect.ID(), + name: rich.NameContainer{}, + } - body, _ := gtk.ListBoxNew() - body.SetSelectionMode(gtk.SELECTION_NONE) - body.SetActivateOnSingleClick(true) - body.SetSortFunc(listSortNameAsc) // A-Z - body.Show() - sectionBodyCSS(body) + section.Header = rich.NewLabel(§ion.name) + section.Header.Show() + sectionHeaderCSS(section.Header) - box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0) - box.PackStart(header, false, false, 0) - box.PackStart(body, false, false, 0) - box.Show() + section.Header.SetRenderer(func(rich text.Rich) markup.RenderOutput { + out := markup.RenderCmplx(rich) + if section.total > 0 { + out.Markup += fmt.Sprintf("—%d", section.total) + } + + return out + }) + + section.Body, _ = gtk.ListBoxNew() + section.Body.SetSelectionMode(gtk.SELECTION_NONE) + section.Body.SetActivateOnSingleClick(true) + section.Body.SetSortFunc(listSortNameAsc) // A-Z + section.Body.Show() + sectionBodyCSS(section.Body) + + section.Box, _ = gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0) + section.Box.PackStart(section.Header, false, false, 0) + section.Box.PackStart(section.Body, false, false, 0) + section.Box.Show() var members = map[string]*Member{} // On row click, show the mention popup if any. - body.Connect("row-activated", func(_ *gtk.ListBox, r *gtk.ListBoxRow) { + section.Body.Connect("row-activated", func(_ *gtk.ListBox, r *gtk.ListBoxRow) { var i = r.GetIndex() // Cold path; we can afford searching in the map. for _, member := range members { @@ -226,32 +251,20 @@ func NewSection(sect cchat.MemberSection, evq EventQueuer) *Section { } }) - section := &Section{ - ID: sect.ID(), - Box: box, - Header: header, - Body: body, - Members: members, - } - - section.Update(sect.Name(), sect.Total()) + section.name.QueueNamer(context.Background(), sect) + section.Header.Connect("destroy", section.name.Stop) return section } -func (s *Section) Update(name text.Rich, total int) { - s.name = name - s.total = total +func (s *Section) Destroy() { + s.name.Stop() + s.Box.Destroy() +} - var content = s.name.Content - if total > 0 { - content += fmt.Sprintf("—%d", total) - } - - s.Header.SetLabelUnsafe(text.Rich{ - Content: content, - Segments: s.name.Segments, - }) +func (s *Section) Update(sect cchat.MemberSection) { + s.total = sect.Total() + s.name.QueueNamer(context.Background(), sect) } func (s *Section) SetMember(member cchat.ListMember) { @@ -292,14 +305,16 @@ type Member struct { *gtk.ListBoxRow Main *gtk.Box - Avatar *rich.Icon - Name *gtk.Label - output markup.RenderOutput + Avatar *roundimage.StillImage + Name *rich.Label + name rich.LabelState + second text.Rich + status cchat.Status parent *gtk.ListBox } -const AvatarSize = 34 +const AvatarSize = 32 var memberRowCSS = primitives.PrepareClassCSS("member-row", ` .member-row { @@ -320,46 +335,61 @@ var avatarMemberCSS = primitives.PrepareClassCSS("avatar-member", ` `) func NewMember(member cchat.ListMember) *Member { + m := Member{} + evb, _ := gtk.EventBoxNew() evb.AddEvents(int(gdk.EVENT_ENTER_NOTIFY) | int(gdk.EVENT_LEAVE_NOTIFY)) evb.Show() - img, _ := roundimage.NewStaticImage(evb, 0) - img.Show() + m.Avatar = roundimage.NewStillImage(evb, 9999) + m.Avatar.SetSize(AvatarSize) + m.Avatar.SetPlaceholderIcon("user-info-symbolic", AvatarSize) + m.Avatar.Show() + avatarMemberCSS(m.Avatar) - icon := rich.NewCustomIcon(img, AvatarSize) - icon.SetPlaceholderIcon("user-info-symbolic", AvatarSize) - icon.Show() - avatarMemberCSS(icon) + rich.BindRoundImage(m.Avatar, &m.name, true) - lbl, _ := gtk.LabelNew("") - lbl.SetUseMarkup(true) - lbl.SetXAlign(0) - lbl.SetEllipsize(pango.ELLIPSIZE_END) - lbl.Show() + m.Name = rich.NewLabel(&m.name) + m.Name.SetUseMarkup(true) + m.Name.SetXAlign(0) + m.Name.SetEllipsize(pango.ELLIPSIZE_END) + m.Name.Show() - box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) - box.PackStart(icon, false, false, 0) - box.PackStart(lbl, true, true, 0) - box.Show() - memberBoxCSS(box) + m.Name.SetRenderer(func(rich text.Rich) markup.RenderOutput { + out := markup.RenderCmplx(rich) - evb.Add(box) + if m.status != cchat.StatusUnknown { + out.Markup = fmt.Sprintf( + ` %s`, + statusColors(member.Status()), out.Markup, + ) + } - r, _ := gtk.ListBoxRowNew() - memberRowCSS(r) - r.Add(evb) + if !m.second.IsEmpty() { + out.Markup += fmt.Sprintf( + "\n"+`%s`, + markup.Render(m.second), + ) + } - m := &Member{ - ListBoxRow: r, - Main: box, - Avatar: icon, - Name: lbl, - } + return out + }) + + m.Main, _ = gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) + m.Main.PackStart(m.Avatar, false, false, 0) + m.Main.PackStart(m.Name, true, true, 0) + m.Main.Show() + memberBoxCSS(m.Main) + + evb.Add(m.Main) + + m.ListBoxRow, _ = gtk.ListBoxRowNew() + m.ListBoxRow.Add(evb) + memberRowCSS(m.ListBoxRow) m.Update(member) - return m + return &m } var noMentionLinks = markup.RenderConfig{ @@ -368,38 +398,22 @@ var noMentionLinks = markup.RenderConfig{ } func (m *Member) Update(member cchat.ListMember) { + m.status = member.Status() + m.second = member.Secondary() + + m.name.SetLabel(member.Name()) m.ListBoxRow.SetName(member.Name().Content) - - if iconer := member.AsIconer(); iconer != nil { - m.Avatar.AsyncSetIconer(iconer, "Failed to get member list icon") - } - - m.output = markup.RenderCmplxWithConfig(member.Name(), noMentionLinks) - - txt := strings.Builder{} - txt.WriteString(fmt.Sprintf( - ` %s`, - statusColors(member.Status()), m.output.Markup, - )) - - if bot := member.Secondary(); !bot.IsEmpty() { - txt.WriteByte('\n') - txt.WriteString(fmt.Sprintf( - `%s`, - markup.Render(bot), - )) - } - - m.Name.SetMarkup(txt.String()) } // Popup pops up the mention popover if any. func (m *Member) Popup(evq EventQueuer) { - if len(m.output.Mentions) == 0 { + out := m.Name.Output() + + if len(out.Mentions) == 0 { return } - p := labeluri.NewPopoverMentioner(m, m.output.Input, m.output.Mentions[0]) + p := labeluri.NewPopoverMentioner(m, out.Input, out.Mentions[0]) if p == nil { return } diff --git a/internal/ui/messages/message/author.go b/internal/ui/messages/message/author.go index 88e0daa..c1fb252 100644 --- a/internal/ui/messages/message/author.go +++ b/internal/ui/messages/message/author.go @@ -1,50 +1,36 @@ package message import ( + "context" + "github.com/diamondburned/cchat" + "github.com/diamondburned/cchat-gtk/internal/ui/rich" "github.com/diamondburned/cchat/text" ) // Author implements cchat.Author. It effectively contains a copy of // cchat.Author. type Author struct { - id cchat.ID - name text.Rich - avatarURL string + ID cchat.ID + Name rich.NameContainer } -var _ cchat.Author = (*Author)(nil) - // NewAuthor creates a new Author that is a copy of the given author. -func NewAuthor(author cchat.Author) Author { - a := Author{} - a.Update(author) +func NewAuthor(author cchat.User) Author { + a := Author{ID: author.ID()} + a.Name.QueueNamer(context.Background(), author) return a } // NewCustomAuthor creates a new Author from the given parameters. -func NewCustomAuthor(id cchat.ID, name text.Rich, avatar string) Author { +func NewCustomAuthor(id cchat.ID, name text.Rich) Author { return Author{ - id, - name, - avatar, + ID: id, + Name: rich.NameContainer{LabelState: *rich.NewLabelState(name)}, } } -func (a *Author) Update(author cchat.Author) { - a.id = author.ID() - a.name = author.Name() - a.avatarURL = author.Avatar() -} - -func (a Author) ID() string { - return a.id -} - -func (a Author) Name() text.Rich { - return a.name -} - -func (a Author) Avatar() string { - return a.avatarURL +// Update sets a new name. +func (author *Author) Update(user cchat.Namer) { + author.Name.QueueNamer(context.Background(), user) } diff --git a/internal/ui/messages/message/message.go b/internal/ui/messages/message/message.go index 5318ce0..bc8344f 100644 --- a/internal/ui/messages/message/message.go +++ b/internal/ui/messages/message/message.go @@ -1,6 +1,7 @@ package message import ( + "context" "time" "github.com/diamondburned/cchat" @@ -8,70 +9,65 @@ import ( "github.com/diamondburned/cchat-gtk/internal/ui/primitives/menu" "github.com/diamondburned/cchat-gtk/internal/ui/rich" "github.com/diamondburned/cchat-gtk/internal/ui/rich/labeluri" + "github.com/diamondburned/cchat-gtk/internal/ui/rich/parser/markup" "github.com/diamondburned/cchat/text" "github.com/gotk3/gotk3/gtk" "github.com/gotk3/gotk3/pango" ) +// Container describes a message container that wraps a state. These methods are +// made for containers to override; methods not meant to be override are not +// exposed and will be done directly on the State. type Container interface { - ID() cchat.ID - Time() time.Time - Author() cchat.Author - Nonce() string + // Unwrap unwraps the message container and, if revert is true, revert the + // state to a clean version. Containers must implement this method by + // itself. + Unwrap(revert bool) *State - UpdateAuthor(cchat.Author) - UpdateContent(c text.Rich, edited bool) - UpdateTimestamp(time.Time) + // UpdateContent updates the underlying content widget. + UpdateContent(content text.Rich, edited bool) + + // SetReferenceHighlighter sets the reference highlighter into the message. + SetReferenceHighlighter(refer labeluri.ReferenceHighlighter) } -// FillContainer sets the container's contents to the one from MessageCreate. -func FillContainer(c Container, msg cchat.MessageCreate) { - c.UpdateAuthor(msg.Author()) - c.UpdateContent(msg.Content(), false) - c.UpdateTimestamp(msg.Time()) -} - -// RefreshContainer sets the container's contents to the one from -// GenericContainer. This is mainly used for transferring between different -// containers. -func RefreshContainer(c Container, gc *GenericContainer) { - c.UpdateTimestamp(gc.time) -} - -// GenericContainer provides a single generic message container for subpackages +// State provides a single generic message container for subpackages // to use. -type GenericContainer struct { - *gtk.Box - row *gtk.ListBoxRow // contains Box +type State struct { + gtk.Box + Row *gtk.ListBoxRow // contains Box class string - id string - time time.Time - author Author - nonce string + ID cchat.ID + Time time.Time + Nonce string + Author *Author Content *gtk.Box ContentBody *labeluri.Label ContentBodyStyle *gtk.StyleContext - menuItems []menu.Item + MenuItems []menu.Item } -var _ Container = (*GenericContainer)(nil) +// NewState creates a new message state with the given ID and nonce. It does not +// update the widgets, so FillContainer should be called afterwards. +func NewState(msg cchat.MessageCreate) *State { + author := msg.Author() -// NewContainer creates a new message container with the given ID and nonce. It -// does not update the widgets, so FillContainer should be called afterwards. -func NewContainer(msg cchat.MessageCreate) *GenericContainer { - c := NewEmptyContainer() - c.id = msg.ID() - c.time = msg.Time() - c.nonce = msg.Nonce() - c.author.Update(msg.Author()) + c := NewEmptyState() + c.Author.ID = author.ID() + c.Author.Name.QueueNamer(context.Background(), author) + c.ID = msg.ID() + c.Time = msg.Time() + c.Nonce = msg.Nonce() return c } -func NewEmptyContainer() *GenericContainer { +// NewEmptyState creates a new empty message state. The author should be set +// immediately afterwards; it is invalid once the state is used. +func NewEmptyState() *State { ctbody := labeluri.NewLabel(text.Rich{}) ctbody.SetVExpand(true) ctbody.SetHAlign(gtk.ALIGN_START) @@ -100,9 +96,10 @@ func NewEmptyContainer() *GenericContainer { row.Show() primitives.AddClass(row, "message-row") - gc := &GenericContainer{ - Box: box, - row: row, + gc := &State{ + Box: *box, + Row: row, + Author: &Author{}, Content: ctbox, ContentBody: ctbody, @@ -110,81 +107,49 @@ func NewEmptyContainer() *GenericContainer { // Time is important, as it is used to sort messages, so we have to be // careful with this. - time: time.Now(), + Time: time.Now(), } + // This may either work, or it may cause memory leaks. + row.Connect("destroy", func() { gc.Author.Name.Stop() }) + // Bind the custom popup menu to the content label. gc.ContentBody.Connect("populate-popup", func(l *gtk.Label, m *gtk.Menu) { menu.MenuSeparator(m) - menu.MenuItems(m, gc.menuItems) + menu.MenuItems(m, gc.MenuItems) }) return gc } -// Row returns the internal list box row. It is used to satisfy MessageRow. -func (m *GenericContainer) Row() *gtk.ListBoxRow { return m.row } - // SetClass sets the internal row's class. -func (m *GenericContainer) SetClass(class string) { +func (m *State) SetClass(class string) { if m.class != "" { - primitives.RemoveClass(m.row, m.class) + primitives.RemoveClass(m.Row, m.class) } - primitives.AddClass(m.row, class) + primitives.AddClass(m.Row, class) m.class = class } // SetReferenceHighlighter sets the reference highlighter into the message. -func (m *GenericContainer) SetReferenceHighlighter(r labeluri.ReferenceHighlighter) { +func (m *State) SetReferenceHighlighter(r labeluri.ReferenceHighlighter) { m.ContentBody.SetReferenceHighlighter(r) } -func (m *GenericContainer) ID() string { - return m.id -} - -func (m *GenericContainer) Time() time.Time { - return m.time -} - -func (m *GenericContainer) Author() cchat.Author { - return m.author -} - -func (m *GenericContainer) Nonce() string { - return m.nonce -} - -func (m *GenericContainer) UpdateTimestamp(t time.Time) { - m.time = t -} - -func (m *GenericContainer) UpdateAuthor(author cchat.Author) { - m.author.Update(author) -} - -func (m *GenericContainer) UpdateContent(content text.Rich, edited bool) { - m.ContentBody.SetLabelUnsafe(content) +// UpdateContent replaces the internal content and the widget. +func (m *State) UpdateContent(content text.Rich, edited bool) { + m.ContentBody.SetLabel(content) if edited { - markup := m.ContentBody.Output().Markup - markup += " " + rich.Small("(edited)") - m.ContentBody.SetMarkup(markup) + m.ContentBody.SetRenderer(func(content text.Rich) markup.RenderOutput { + output := markup.RenderCmplx(content) + output.Markup += rich.Small(text.Plain("(edited)")).Markup + return output + }) } } -// AttachMenu connects signal handlers to handle a list of menu items from -// the container. -func (m *GenericContainer) AttachMenu(newItems []menu.Item) { - m.menuItems = newItems -} - -// MenuItems returns the list of menu items for this message. -func (m *GenericContainer) MenuItems() []menu.Item { - return m.menuItems -} - -func (m *GenericContainer) Focusable() gtk.IWidget { +func (m *State) Focusable() gtk.IWidget { return m.Content } diff --git a/internal/ui/messages/message/sending.go b/internal/ui/messages/message/sending.go index c79b550..b84bc42 100644 --- a/internal/ui/messages/message/sending.go +++ b/internal/ui/messages/message/sending.go @@ -4,8 +4,8 @@ import ( "fmt" "html" + "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/humanize" - "github.com/diamondburned/cchat-gtk/internal/ui/messages/input" "github.com/diamondburned/cchat-gtk/internal/ui/messages/input/attachment" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" "github.com/gotk3/gotk3/gtk" @@ -16,33 +16,51 @@ var EmptyContentPlaceholder = fmt.Sprintf( `%s`, html.EscapeString(""), ) -type PresendContainer interface { - SetDone(id string) +// Presender describes actions doable on a presend message container. +type Presender interface { + SendingMessage() PresendMessage + SetDone(id cchat.ID) SetLoading() SetSentError(err error) } -// PresendGenericContainer is the generic container with extra methods -// implemented for stateful mutability of the generic message container. -type GenericPresendContainer struct { - *GenericContainer +// PresendMessage is an interface for any message about to be sent. +type PresendMessage interface { + cchat.MessageHeader + cchat.SendableMessage + cchat.Noncer + + // These methods are reserved for internal use. + + Files() []attachment.File +} + +// PresendState is the generic state with extra methods implemented for stateful +// mutability of the generic message state. +type PresendState struct { + *State // states; to be cleared on SetDone() - presend input.PresendMessage + presend PresendMessage uploads *attachment.MessageUploader } -var _ PresendContainer = (*GenericPresendContainer)(nil) +var ( + _ Presender = (*PresendState)(nil) +) -func NewPresendContainer(msg input.PresendMessage) *GenericPresendContainer { - c := NewEmptyContainer() - c.nonce = msg.Nonce() - c.UpdateAuthor(msg.Author()) - c.UpdateTimestamp(msg.Time()) +type SendMessageData struct { +} - p := &GenericPresendContainer{ - GenericContainer: c, +// NewPresendState creates a new presend state. +func NewPresendState(self *Author, msg PresendMessage) *PresendState { + c := NewEmptyState() + c.Author = self + c.Nonce = msg.Nonce() + c.Time = msg.Time() + p := &PresendState{ + State: c, presend: msg, uploads: attachment.NewMessageUploader(msg.Files()), } @@ -51,14 +69,18 @@ func NewPresendContainer(msg input.PresendMessage) *GenericPresendContainer { return p } -func (m *GenericPresendContainer) SetSensitive(sensitive bool) { +func (m *PresendState) SendingMessage() PresendMessage { return m.presend } + +// SetSensitive sets the sensitivity of the content. +func (m *PresendState) SetSensitive(sensitive bool) { m.Content.SetSensitive(sensitive) } -func (m *GenericPresendContainer) SetDone(id string) { +// SetDone sets the status of the state. +func (m *PresendState) SetDone(id cchat.ID) { // Apply the received ID. - m.id = id - m.nonce = "" + m.ID = id + m.Nonce = "" // Reset the state to be normal. Especially setting presend to nil should // free it from memory. @@ -76,7 +98,8 @@ func (m *GenericPresendContainer) SetDone(id string) { m.SetSensitive(true) } -func (m *GenericPresendContainer) SetLoading() { +// SetLoading greys the message to indicate that it's loading. +func (m *PresendState) SetLoading() { m.SetSensitive(false) m.Content.SetTooltipText("") @@ -100,7 +123,8 @@ func (m *GenericPresendContainer) SetLoading() { } } -func (m *GenericPresendContainer) SetSentError(err error) { +// SetSentError sets the error into the message to notify the user. +func (m *PresendState) SetSentError(err error) { m.SetSensitive(true) // allow events incl right clicks m.Content.SetTooltipText(err.Error()) @@ -132,6 +156,6 @@ func (m *GenericPresendContainer) SetSentError(err error) { } // clearBox clears everything inside the content container. -func (m *GenericPresendContainer) clearBox() { +func (m *PresendState) clearBox() { primitives.RemoveChildren(m.Content) } diff --git a/internal/ui/messages/msgctrl.go b/internal/ui/messages/msgctrl.go index 574eff3..686846f 100644 --- a/internal/ui/messages/msgctrl.go +++ b/internal/ui/messages/msgctrl.go @@ -84,11 +84,11 @@ func (mc *MessageControl) Enable(msg container.MessageRow, names MessageItemName mc.SetSensitive(true) mc.SetRevealChild(true && !mc.hide) - items := msg.MenuItems() + unwrap := msg.Unwrap(false) - mc.Reply.bind(menu.FindItemFunc(items, names.Reply)) - mc.Edit.bind(menu.FindItemFunc(items, names.Edit)) - mc.Delete.bind(menu.FindItemFunc(items, names.Delete)) + mc.Reply.bind(menu.FindItemFunc(unwrap.MenuItems, names.Reply)) + mc.Edit.bind(menu.FindItemFunc(unwrap.MenuItems, names.Edit)) + mc.Delete.bind(menu.FindItemFunc(unwrap.MenuItems, names.Delete)) } // SetHidden sets whether or not the control should be hidden. diff --git a/internal/ui/messages/typing/state.go b/internal/ui/messages/typing/state.go index 1dfc4e2..b64253d 100644 --- a/internal/ui/messages/typing/state.go +++ b/internal/ui/messages/typing/state.go @@ -1,17 +1,25 @@ package typing import ( + "context" "sort" "time" "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/gts" + "github.com/diamondburned/cchat-gtk/internal/ui/rich" "github.com/pkg/errors" ) +type typer struct { + cchat.User + s *rich.NameContainer + t time.Time +} + type State struct { // states - typers []cchat.Typer + typers []typer timeout time.Duration canceler func() invalidated bool @@ -67,35 +75,54 @@ func (s *State) loop() { // Call the event handler if things are invalidated. if s.invalidated { - s.changed(s, len(s.typers) == 0) + s.update() s.invalidated = false } } +// update force-runs th callback. +func (s *State) update() { + s.changed(s, len(s.typers) == 0) +} + // invalidate sorts and invalidates the state. func (s *State) invalidate() { // Sort the list of typers again. sort.Slice(s.typers, func(i, j int) bool { - return s.typers[i].Time().Before(s.typers[j].Time()) + return s.typers[i].t.Before(s.typers[j].t) }) s.invalidated = true } // AddTyper is thread-safe. -func (s *State) AddTyper(typer cchat.Typer) { +func (s *State) AddTyper(user cchat.User) { + now := time.Now() + + ctx, cancel := context.WithTimeout(context.Background(), s.timeout) + + state := rich.NameContainer{} + state.QueueNamer(ctx, user) + gts.ExecAsync(func() { + defer cancel() defer s.invalidate() // If the typer already exists, then pop them to the start of the list. for i, t := range s.typers { - if t.ID() == typer.ID() { + if t.ID() == user.ID() { s.typers[i] = t return } } - s.typers = append(s.typers, typer) + state.OnUpdate(s.update) + + s.typers = append(s.typers, typer{ + User: user, + s: &state, + t: now, + }) }) } @@ -108,19 +135,24 @@ func (s *State) removeTyper(typerID string) { defer s.invalidate() for i, t := range s.typers { - if t.ID() == typerID { - // Remove the quick way. Sort will take care of ordering. - l := len(s.typers) - 1 - s.typers[i] = s.typers[l] - s.typers[l] = nil - s.typers = s.typers[:l] - - return + if t.ID() != typerID { + continue } + + // Invalidate the typer's label state. + t.s.Stop() + + // Remove the quick way. Sort will take care of ordering. + l := len(s.typers) - 1 + s.typers[i] = s.typers[l] + s.typers[l] = typer{} + s.typers = s.typers[:l] + + return } } -func filterTypers(typers []cchat.Typer, timeout time.Duration) ([]cchat.Typer, bool) { +func filterTypers(typers []typer, timeout time.Duration) ([]typer, bool) { // Fast path. if len(typers) == 0 || timeout == 0 { return nil, false @@ -130,14 +162,15 @@ func filterTypers(typers []cchat.Typer, timeout time.Duration) ([]cchat.Typer, b var cut int for _, t := range typers { - if now.Sub(t.Time()) < timeout { + if now.Sub(t.t) < timeout { typers[cut] = t cut++ } } for i := cut; i < len(typers); i++ { - typers[i] = nil + typers[i].s.Stop() + typers[i] = typer{} } var changed = cut != len(typers) diff --git a/internal/ui/messages/typing/typing.go b/internal/ui/messages/typing/typing.go index 5dbeda0..9b62765 100644 --- a/internal/ui/messages/typing/typing.go +++ b/internal/ui/messages/typing/typing.go @@ -137,8 +137,8 @@ func (c *Container) Unborrow() { } } -func (c *Container) RemoveAuthor(author cchat.Author) { - c.state.removeTyper(author.ID()) +func (c *Container) RemoveAuthor(userID cchat.ID) { + c.state.removeTyper(userID) } func (c *Container) TrySubscribe(svmsg cchat.Messenger) bool { @@ -155,7 +155,7 @@ var noMentionLinks = markup.RenderConfig{ NoMentionLinks: true, } -func render(typers []cchat.Typer) string { +func render(typers []typer) string { // fast path if len(typers) == 0 { return "" @@ -164,7 +164,7 @@ func render(typers []cchat.Typer) string { var builder strings.Builder for i, typer := range typers { - output := markup.RenderCmplxWithConfig(typer.Name(), noMentionLinks) + output := markup.RenderCmplxWithConfig(typer.s.Label(), noMentionLinks) builder.WriteString("") builder.WriteString(output.Markup) diff --git a/internal/ui/messages/view.go b/internal/ui/messages/view.go index 0dadc19..b6b7875 100644 --- a/internal/ui/messages/view.go +++ b/internal/ui/messages/view.go @@ -15,12 +15,16 @@ import ( "github.com/diamondburned/cchat-gtk/internal/ui/messages/container/cozy" "github.com/diamondburned/cchat-gtk/internal/ui/messages/input" "github.com/diamondburned/cchat-gtk/internal/ui/messages/memberlist" + "github.com/diamondburned/cchat-gtk/internal/ui/messages/message" "github.com/diamondburned/cchat-gtk/internal/ui/messages/sadface" "github.com/diamondburned/cchat-gtk/internal/ui/messages/typing" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" "github.com/diamondburned/cchat-gtk/internal/ui/primitives/autoscroll" "github.com/diamondburned/cchat-gtk/internal/ui/primitives/drag" "github.com/diamondburned/cchat-gtk/internal/ui/primitives/menu" + "github.com/diamondburned/cchat-gtk/internal/ui/rich" + "github.com/diamondburned/cchat-gtk/internal/ui/service/session" + "github.com/diamondburned/cchat-gtk/internal/ui/service/session/server" "github.com/diamondburned/cchat-gtk/internal/ui/service/session/server/traverse" "github.com/diamondburned/handy" "github.com/gotk3/gotk3/gtk" @@ -280,7 +284,7 @@ func (v *View) MemberListUpdated(c *memberlist.Container) { } // JoinServer is not thread-safe, but it calls backend functions asynchronously. -func (v *View) JoinServer(session cchat.Session, server cchat.Server, bc traverse.Breadcrumber) { +func (v *View) JoinServer(ses *session.Row, srv *server.ServerRow, bc traverse.Breadcrumber) { // Set the screen to loading. v.FaceView.SetLoading() v.ctrl.OnMessageBusy() @@ -289,19 +293,22 @@ func (v *View) JoinServer(session cchat.Session, server cchat.Server, bc travers v.reset() // Get the messenger once. - var messenger = server.AsMessenger() + var messenger = srv.Server.AsMessenger() // Exit if this server is not a messenger. if messenger == nil { return } // Bind the state. - v.state.bind(session, server, messenger) + v.state.bind(ses.Session, srv.Server, messenger) // We're setting this variable before actually calling JoinServer. This is // because new messages created by JoinServer will use this state for things // such as determinining if it's deletable or not. - v.InputView.SetMessenger(session, messenger) + v.InputView.SetMessenger(ses.Session, messenger) + + // Bind the container's self user to what we just set. + v.Container.SetSelf(v.InputView.Username.State) go func() { // We can use a background context here, as the user can't go anywhere @@ -363,79 +370,84 @@ func (v *View) FetchBacklog() { v.Container.Highlight(firstMsg) } + firstID := firstMsg.Unwrap(false).ID + gts.Async(func() (func(), error) { ctx, cancel := context.WithTimeout(context.TODO(), 3*time.Second) defer cancel() - err := backlogger.Backlog(ctx, firstMsg.ID(), v.Container) + err := backlogger.Backlog(ctx, firstID, v.Container) return done, errors.Wrap(err, "Failed to get messages before ID") }) } -func (v *View) AddPresendMessage(msg input.PresendMessage) func(error) { - var presend = v.Container.AddPresendMessage(msg) - - return func(err error) { - // Set the retry message. - presend.SetSentError(err) - // Only attach the menu once. Further retries do not need to be - // reattached. - presend.AttachMenu([]menu.Item{ - menu.SimpleItem("Retry", func() { - presend.SetLoading() - v.retryMessage(msg, presend) - }), - }) - } -} - // AuthorEvent should be called on message create/update/delete. -func (v *View) AuthorEvent(author cchat.Author) { +func (v *View) AuthorEvent(authorID cchat.ID) { // Remove the author from the typing list if it's not nil. - if author != nil { - v.Typing.RemoveAuthor(author) + if authorID != "" { + v.Typing.RemoveAuthor(authorID) } } // MessageAuthor returns the author from the message with the given ID. -func (v *View) MessageAuthor(msgID cchat.ID) cchat.Author { +func (v *View) MessageAuthor(msgID cchat.ID) *message.Author { msg := v.Container.Message(msgID, "") if msg == nil { return nil } - return msg.Author() + return msg.Unwrap(false).Author } // Author returns the author from the message list with the given author ID. -func (v *View) Author(authorID cchat.ID) cchat.Author { +func (v *View) Author(authorID cchat.ID) rich.LabelStateStorer { msg := v.Container.FindMessage(func(msg container.MessageRow) bool { - return msg.Author().ID() == authorID + return msg.Unwrap(false).Author.ID == authorID }) if msg == nil { return nil } - return msg.Author() + state := msg.Unwrap(false) + return &state.Author.Name } // LatestMessageFrom returns the last message ID with that author. -func (v *View) LatestMessageFrom(userID string) (msgID string, ok bool) { - return v.Container.LatestMessageFrom(userID) +func (v *View) LatestMessageFrom(userID cchat.ID) container.MessageRow { + return container.LatestMessageFrom(v.Container, userID) +} + +func (v *View) SendMessage(msg message.PresendMessage) { + state := message.NewPresendState(v.InputView.Username.State, msg) + msgr := v.Container.NewPresendMessage(state) + + v.retryMessage(msgr) } // retryMessage sends the message. -func (v *View) retryMessage(msg input.PresendMessage, presend container.PresendMessageRow) { +func (v *View) retryMessage(presend container.PresendMessageRow) { var sender = v.InputView.Sender if sender == nil { return } go func() { - if err := sender.Send(msg); err != nil { + if err := sender.Send(presend.SendingMessage()); err != nil { // Set the message's state to errored again, but we don't need to // rebind the menu. - gts.ExecAsync(func() { presend.SetSentError(err) }) + gts.ExecAsync(func() { + // Set the retry message. + presend.SetSentError(err) + // Only attach the menu once. Further retries do not need to be + // reattached. + state := presend.Unwrap(false) + state.MenuItems = []menu.Item{ + menu.SimpleItem("Retry", func() { + presend.SetLoading() + v.retryMessage(presend) + }), + } + }) } }() } @@ -449,33 +461,35 @@ var messageItemNames = MessageItemNames{ // BindMenu attaches the menu constructor into the message with the needed // states and callbacks. func (v *View) BindMenu(msg container.MessageRow) { + state := msg.Unwrap(false) + // Add 1 for the edit menu item. var mitems = []menu.Item{ menu.SimpleItem( - "Reply", func() { v.InputView.StartReplyingTo(msg.ID()) }, + "Reply", func() { v.InputView.StartReplyingTo(state.ID) }, ), } // Do we have editing capabilities? If yes, append a button to allow it. - if v.InputView.Editable(msg.ID()) { + if v.InputView.Editable(state.ID) { mitems = append(mitems, menu.SimpleItem( - "Edit", func() { v.InputView.StartEditing(msg.ID()) }, + "Edit", func() { v.InputView.StartEditing(state.ID) }, )) } // Do we have any custom actions? If yes, append it. if v.hasActions() { - var actions = v.actioner.Actions(msg.ID()) + var actions = v.actioner.Actions(state.ID) var items = make([]menu.Item, len(actions)) for i, action := range actions { - items[i] = v.makeActionItem(action, msg.ID()) + items[i] = v.makeActionItem(action, state.ID) } mitems = append(mitems, items...) } - msg.AttachMenu(mitems) + state.MenuItems = mitems } // makeActionItem creates a new menu callback that's called on menu item diff --git a/internal/ui/primitives/completion/completer.go b/internal/ui/primitives/completion/completer.go index 93f1759..82e8ff1 100644 --- a/internal/ui/primitives/completion/completer.go +++ b/internal/ui/primitives/completion/completer.go @@ -189,7 +189,7 @@ func (c *Completer) update() []gtk.IWidget { lbox.Show() // Label for the primary text. - l := rich.NewLabel(entry.Text) + l := rich.NewStaticLabel(entry.Text) l.Show() lbox.PackStart(l, false, false, 0) @@ -198,7 +198,7 @@ func (c *Completer) update() []gtk.IWidget { if !entry.Secondary.IsEmpty() { size = ImageLarge - s := rich.NewLabel(text.Rich{}) + s := rich.NewStaticLabel(text.Plain("")) s.SetMarkup(fmt.Sprintf( `%s`, markup.Render(entry.Secondary), diff --git a/internal/ui/primitives/primitives.go b/internal/ui/primitives/primitives.go index 2634ad2..6b82e40 100644 --- a/internal/ui/primitives/primitives.go +++ b/internal/ui/primitives/primitives.go @@ -1,7 +1,6 @@ package primitives import ( - "context" "runtime/debug" "github.com/diamondburned/cchat-gtk/internal/gts" @@ -179,27 +178,13 @@ func NewImageIconPx(icon string, sizepx int) *gtk.Image { } type ImageIconSetter interface { - SetProperty(name string, value interface{}) error - GetSizeRequest() (w, h int) - SetSizeRequest(w, h int) + SetFromIconName(string, gtk.IconSize) + SetPixelSize(int) } func SetImageIcon(img ImageIconSetter, icon string, sizepx int) { - // Prioritize SetSize() - if setter, ok := img.(interface{ SetSize(int) }); ok { - setter.SetSize(sizepx) - } else { - img.SetProperty("pixel-size", sizepx) - } - - // Prioritize SetIconName(). - if setter, ok := img.(interface{ SetIconName(string) }); ok { - setter.SetIconName(icon) - } else { - img.SetProperty("icon-name", icon) - } - - img.SetSizeRequest(sizepx, sizepx) + img.SetFromIconName(icon, gtk.ICON_SIZE_BUTTON) + img.SetPixelSize(sizepx) } func PrependMenuItems(menu interface{ Prepend(gtk.IMenuItem) }, items []gtk.IMenuItem) { @@ -240,12 +225,6 @@ type Connector interface { var _ Connector = (*glib.Object)(nil) -func HandleDestroyCtx(ctx context.Context, connector Connector) context.Context { - ctx, cancel := context.WithCancel(ctx) - connector.Connect("destroy", func(interface{}) { cancel() }) - return ctx -} - func OnRightClick(connector Connector, fn func()) { connector.Connect("button-press-event", func(c Connector, ev *gdk.Event) { if gts.EventIsRightClick(ev) { diff --git a/internal/ui/primitives/roundimage/avatar.go b/internal/ui/primitives/roundimage/avatar.go index b8c3196..460c774 100644 --- a/internal/ui/primitives/roundimage/avatar.go +++ b/internal/ui/primitives/roundimage/avatar.go @@ -28,6 +28,7 @@ type Avatar struct { pixbuf *gdk.Pixbuf url string size int + cancel context.CancelFunc } // Make a better API that allows scaling. @@ -49,6 +50,7 @@ func NewAvatar(size int) *Avatar { return &avatar } +// GetSizeRequest returns the virtual size. func (a *Avatar) GetSizeRequest() (int, int) { return a.size, a.size } @@ -66,7 +68,6 @@ func (a *Avatar) SetSizeRequest(w, h int) { } func (a *Avatar) loadFunc(size int) *gdk.Pixbuf { - // No URL, draw nothing. if a.url == "" { return nil } @@ -75,44 +76,54 @@ func (a *Avatar) loadFunc(size int) *gdk.Pixbuf { return a.pixbuf } - // Refetch and rescale. a.size = size - // Technically, this will recurse. However, we're changing the size, so - // eventually it should stop. - httputil.AsyncImage(context.Background(), a, a.url) + a.refetch() - if a.pixbuf == nil { - return nil + return nil +} + +func (a *Avatar) refetch() { + a.cancelCtx() + + ctx, cancel := context.WithCancel(context.Background()) + a.cancel = cancel + + httputil.AsyncImage(ctx, a, a.url) +} + +func (a *Avatar) cancelCtx() { + if a.cancel != nil { + a.cancel() + a.cancel = nil } - - // // Temporarily resize for now. - // p, err := a.pixbuf.ScaleSimple(size, size, gdk.INTERP_HYPER) - // if err != nil { - // p = a.pixbuf - // } - - return a.pixbuf } // SetRadius is a no-op. func (a *Avatar) SetRadius(float64) {} +// SetImageURL sets the avatar's source URL and reloads it asynchronously. func (a *Avatar) SetImageURL(url string) { a.url = url - a.Avatar.SetImageLoadFunc(a.loadFunc) + a.refetch() } // SetFromPixbuf sets the pixbuf. func (a *Avatar) SetFromPixbuf(pb *gdk.Pixbuf) { + a.cancelCtx() a.pixbuf = pb - a.Avatar.SetImageLoadFunc(a.loadFunc) + // a.Avatar.SetImageLoadFunc(a.loadFunc) + a.Avatar.QueueDraw() } +// SetFromAnimation sets the first frame of the animation. func (a *Avatar) SetFromAnimation(pa *gdk.PixbufAnimation) { + a.cancelCtx() a.pixbuf = pa.GetStaticImage() - a.Avatar.SetImageLoadFunc(a.loadFunc) + // a.Avatar.SetImageLoadFunc(a.loadFunc) + a.Avatar.QueueDraw() } +// GetPixbuf returns the underlying pixbuf. func (a *Avatar) GetPixbuf() *gdk.Pixbuf { return a.pixbuf } @@ -127,6 +138,7 @@ func (a *Avatar) GetImage() *gtk.Image { return nil } +// GetStorageType always returns IMAGE_PIXBUF. func (a *Avatar) GetStorageType() gtk.ImageType { return gtk.IMAGE_PIXBUF } diff --git a/internal/ui/primitives/roundimage/button.go b/internal/ui/primitives/roundimage/button.go index e14195d..01eb14e 100644 --- a/internal/ui/primitives/roundimage/button.go +++ b/internal/ui/primitives/roundimage/button.go @@ -5,6 +5,8 @@ import ( "github.com/gotk3/gotk3/gtk" ) +// TODO: move roundimage.Button to rich.ImageButton. + // Button implements a rounded button with a rounded image. This widget only // supports a full circle for rounding. type Button struct { @@ -20,7 +22,7 @@ var roundButtonCSS = primitives.PrepareClassCSS("round-button", ` `) func NewButton() (*Button, error) { - image, _ := NewImage(0) + image := NewImage(0) image.Show() b := NewEmptyButton() @@ -38,7 +40,7 @@ func NewEmptyButton() *Button { } // NewCustomButton creates a new rounded button with the given Imager. If the -// given Imager implements the Connector interface (aka *StaticImage), then the +// given Imager implements the Connector interface (aka *StillImage), then the // function will implicitly connect its handlers to the button. func NewCustomButton(img Imager) (*Button, error) { b := NewEmptyButton() diff --git a/internal/ui/primitives/roundimage/roundimage.go b/internal/ui/primitives/roundimage/roundimage.go index cac0188..9ab853f 100644 --- a/internal/ui/primitives/roundimage/roundimage.go +++ b/internal/ui/primitives/roundimage/roundimage.go @@ -2,10 +2,12 @@ package roundimage import ( "context" + "log" "math" "github.com/diamondburned/cchat-gtk/internal/gts/httputil" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" + "github.com/diamondburned/handy" "github.com/diamondburned/imgutil" "github.com/gotk3/gotk3/cairo" "github.com/gotk3/gotk3/gdk" @@ -39,83 +41,201 @@ type Imager interface { GetImage() *gtk.Image } +// Image represents an image with abstractions for asynchronously fetching +// images from a URL as well as having interchangeable fallbacks. type Image struct { - *gtk.Image + gtk.Image Radius float64 + + style *gtk.StyleContext + procs []imgutil.Processor + ifNone func(context.Context) + + icon struct { + name string + size int + } + + cancel context.CancelFunc + imgURL string + show bool } var _ Imager = (*Image)(nil) // NewImage creates a new round image. If radius is 0, then it will be half the // dimensions. If the radius is less than 0, then nothing is rounded. -func NewImage(radius float64) (*Image, error) { +func NewImage(radius float64) *Image { i, err := gtk.ImageNew() if err != nil { - return nil, err + log.Panicln("failed to create new roundimage.Image:", err) } - image := &Image{Image: i, Radius: radius} + style, _ := i.GetStyleContext() + + image := &Image{ + Image: *i, + Radius: radius, + style: style, + } // Connect to the draw callback and clip the context. i.Connect("draw", image.drawer) - // Backup plan if Cairo's Surface is weird. - - // var width, height int - // i.Connect("size-allocate", func(i *gtk.Image) { - // w := i.GetAllocatedWidth() - // h := i.GetAllocatedHeight() - - // if width != w || height != h { - // log.Println("Image allocate", width, height, i.GetScaleFactor()) - // width, height = w, h - // } - // }) - - return image, nil + return image } +// NewSizedImage creates a new square image with the given square. +func NewSizedImage(radius float64, size int) *Image { + img := NewImage(radius) + img.SetSizeRequest(size, size) + return img +} + +// AddProcessor adds image processors that will be processed on fetched images. +// Images generated internally, such as initials, won't use it. func (i *Image) AddProcessor(procs ...imgutil.Processor) { i.procs = append(i.procs, procs...) } +// GetImage returns the underlying image widget. func (i *Image) GetImage() *gtk.Image { - return i.Image + return &i.Image } +// Size returns the minimum side's length. This method is used when Image is +// supposed to be a square/circle. +func (i *Image) Size() int { + w, h := i.GetSizeRequest() + if w > h { + return h + } + return w +} + +// SetSIze sets the iamge's physical size. It is a convenient function for +// SetSizeRequest. +func (i *Image) SetSize(size int) { + i.SetSizeRequest(size, size) +} + +// SetIfNone sets the callback to be used if an empty URL is given to the image. +// If nil is given, then a fallback icon is used. +func (i *Image) SetIfNone(ifNone func(context.Context)) { + i.ifNone = ifNone +} + +// UpdateIfNone updates the image if the image currently does not have one +// fetched from the URL. It does nothing otherwise. +func (i *Image) UpdateIfNone() { + if i.ifNone == nil || i.imgURL != "" { + return + } + + i.SetImageURL("") +} + +// SetPlaceholderIcon sets the placeholder icon onto the image. The given icon +// size does not affect the image's physical size. +func (i *Image) SetPlaceholderIcon(iconName string, iconPx int) { + i.icon.name = iconName + i.icon.size = iconPx + + if i.imgURL == "" { + i.SetImageURL("") + } +} + +// GetImageURL gets the image's URL. It returns an empty string if the image +// does not have a URL set. +func (i *Image) GetImageURL() string { + return i.imgURL +} + +// SetImageURL sets the image's URL. If the URL is empty, then the placeholder +// icon is used, or the IfNone callback is called, or the pixbuf is cleared. func (i *Image) SetImageURL(url string) { - // No dynamic sizing support; yolo. - httputil.AsyncImage(context.Background(), i, url, i.procs...) + i.SetImageURLInto(url, i) } +// SetImageURLInto is SetImageURL, but the image container is given as an +// argument. It is used by other widgets that extend on this Image. +func (i *Image) SetImageURLInto(url string, otherImage httputil.ImageContainer) { + i.imgURL = url + + // TODO: fix this context leak: cancel not being called on all paths. + ctx := i.resetCtx() + + if url != "" { + // No dynamic sizing support; yolo. + httputil.AsyncImage(ctx, otherImage, url, i.procs...) + return + } + + if i.icon.name != "" { + primitives.SetImageIcon(i, i.icon.name, i.icon.size) + goto noImage + } + + if i.ifNone != nil { + i.ifNone(ctx) + return + } + +noImage: + i.Image.SetFromPixbuf(nil) + i.cancel() +} + +func (i *Image) resetCtx() context.Context { + if i.cancel != nil { + i.cancel() + i.cancel = nil + } + + // TODO: fix this context leak: cancel not being called on all paths. + ctx, cancel := context.WithCancel(context.Background()) + i.cancel = cancel + + return ctx +} + +// SetRadius sets the radius to be drawn with. If 0 is given, then a full circle +// is drawn, which only works best for images guaranteed to be square. +// Otherwise, the radius is either the number given or the minimum of either the +// width or height. func (i *Image) SetRadius(r float64) { i.Radius = r + i.QueueDraw() } -func (i *Image) drawer(_ interface{}, cc *cairo.Context) bool { - var w = float64(i.GetAllocatedWidth()) - var h = float64(i.GetAllocatedHeight()) +func (i *Image) drawer(image *gtk.Image, cc *cairo.Context) bool { + // Don't round if we're displaying a stock icon. + if i.imgURL == "" && i.icon.name != "" { + return false + } - var min = w - // Use the smallest side for radius calculation. - if h < w { + a := image.GetAllocation() + w := float64(a.GetWidth()) + h := float64(a.GetHeight()) + + min := w + // Use the largest side for radius calculation. + if h > w { min = h } - // Copy the variables in case we need to change them. - var r = i.Radius - switch { // If radius is less than 0, then don't round. - case r < 0: + case i.Radius < 0: return false // If radius is 0, then we have to calculate our own radius.:This only // works if the image is a square. - case r == 0: + case i.Radius == 0: // Calculate the radius by dividing a side by 2. - r = (min / 2) + r := (min / 2) // Draw an arc from 0deg to 360deg. cc.Arc(w/2, h/2, r, 0, circle) @@ -129,10 +249,13 @@ func (i *Image) drawer(_ interface{}, cc *cairo.Context) bool { // If radius is more than 0, then we have to calculate the radius from // the edges. - case r > 0: + case i.Radius > 0: // StackOverflow is godly. // https://stackoverflow.com/a/6959843. + // Copy the variables so we can change them later. + r := i.Radius + // Radius should be largest a single side divided by 2. if max := min / 2; r > max { r = max @@ -157,3 +280,25 @@ func (i *Image) drawer(_ interface{}, cc *cairo.Context) bool { return false } + +// UseInitialsIfNone sets the given image to render an initial image if the +// image doesn't have a URL. +func (i *Image) UseInitialsIfNone(initialsFn func() string) { + i.SetIfNone(func(ctx context.Context) { + size := i.Size() + scale := i.GetScaleFactor() + + a := handy.AvatarNew(size, initialsFn(), true) + p := a.DrawToPixbuf(size, scale) + + if scale > 1 { + surface, _ := gdk.CairoSurfaceCreateFromPixbuf(p, scale, nil) + i.SetFromSurface(surface) + } else { + // Potentially save a copy. + i.SetFromPixbuf(p) + } + }) + + i.UpdateIfNone() +} diff --git a/internal/ui/primitives/roundimage/static.go b/internal/ui/primitives/roundimage/static.go index 2ecfc98..09ffbea 100644 --- a/internal/ui/primitives/roundimage/static.go +++ b/internal/ui/primitives/roundimage/static.go @@ -1,49 +1,44 @@ package roundimage import ( - "context" - "github.com/diamondburned/cchat-gtk/internal/gts/httputil" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" "github.com/gotk3/gotk3/cairo" "github.com/gotk3/gotk3/gdk" ) -// StaticImage is an image that only plays a GIF if it's hovered on top of. -type StaticImage struct { +// StillImage is an image that only plays a GIF if it's hovered on top of. +type StillImage struct { *Image animating bool animation *gdk.PixbufAnimation } var ( - _ Imager = (*StaticImage)(nil) - _ Connector = (*StaticImage)(nil) - _ httputil.ImageContainer = (*StaticImage)(nil) + _ Imager = (*StillImage)(nil) + _ Connector = (*StillImage)(nil) + _ httputil.ImageContainer = (*StillImage)(nil) ) -func NewStaticImage(parent primitives.Connector, radius float64) (*StaticImage, error) { - i, err := NewImage(radius) - if err != nil { - return nil, err - } +// NewStillImage creates a new static that binds to the parent's handler so +// that the image only animates when parent is hovered over. +func NewStillImage(parent primitives.Connector, radius float64) *StillImage { + i := NewImage(radius) - var s = &StaticImage{i, false, nil} - if parent != nil { - s.ConnectHandlers(parent) - } + s := StillImage{i, false, nil} + s.ConnectHandlers(parent) - return s, nil + return &s } -func (s *StaticImage) ConnectHandlers(connector primitives.Connector) { - connector.Connect("enter-notify-event", func(interface{}) { +func (s *StillImage) ConnectHandlers(connector primitives.Connector) { + connector.Connect("enter-notify-event", func() { if s.animation != nil && !s.animating { s.animating = true s.Image.SetFromAnimation(s.animation) } }) - connector.Connect("leave-notify-event", func(interface{}) { + connector.Connect("leave-notify-event", func() { if s.animation != nil && s.animating { s.animating = false s.Image.SetFromPixbuf(s.animation.GetStaticImage()) @@ -51,26 +46,26 @@ func (s *StaticImage) ConnectHandlers(connector primitives.Connector) { }) } -func (s *StaticImage) SetImageURL(url string) { - // No dynamic sizing support; yolo. - httputil.AsyncImage(context.Background(), s, url, s.Image.procs...) +// SetImageURL sets the image's URL. +func (s *StillImage) SetImageURL(url string) { + s.Image.SetImageURLInto(url, s) } -func (s *StaticImage) SetFromPixbuf(pb *gdk.Pixbuf) { +func (s *StillImage) SetFromPixbuf(pb *gdk.Pixbuf) { s.animation = nil s.Image.SetFromPixbuf(pb) } -func (s *StaticImage) SetFromSurface(sf *cairo.Surface) { +func (s *StillImage) SetFromSurface(sf *cairo.Surface) { s.animation = nil s.Image.SetFromSurface(sf) } -func (s *StaticImage) SetFromAnimation(anim *gdk.PixbufAnimation) { +func (s *StillImage) SetFromAnimation(anim *gdk.PixbufAnimation) { s.animation = anim s.Image.SetFromPixbuf(anim.GetStaticImage()) } -func (s *StaticImage) GetAnimation() *gdk.PixbufAnimation { +func (s *StillImage) GetAnimation() *gdk.PixbufAnimation { return s.animation } diff --git a/internal/ui/rich/image.go b/internal/ui/rich/image.go index 24af0c5..1c744e0 100644 --- a/internal/ui/rich/image.go +++ b/internal/ui/rich/image.go @@ -1,219 +1,35 @@ package rich -import ( - "context" - - "github.com/diamondburned/cchat" - "github.com/diamondburned/cchat-gtk/internal/gts" - "github.com/diamondburned/cchat-gtk/internal/gts/httputil" - "github.com/diamondburned/cchat-gtk/internal/ui/primitives" - "github.com/diamondburned/cchat-gtk/internal/ui/primitives/roundimage" - "github.com/diamondburned/cchat/text" - "github.com/gotk3/gotk3/gdk" - "github.com/gotk3/gotk3/gtk" - "github.com/pkg/errors" -) - -type IconerFn = func(context.Context, cchat.IconContainer) (func(), error) - -type RoundIconContainer interface { - gtk.IWidget - - primitives.ImageIconSetter - roundimage.RadiusSetter +import "log" +// ImageURLSetter describes an image that can be set a URL. +type ImageURLSetter interface { SetImageURL(url string) - - GetStorageType() gtk.ImageType - GetPixbuf() *gdk.Pixbuf - GetAnimation() *gdk.PixbufAnimation } -var ( - _ RoundIconContainer = (*roundimage.Image)(nil) - _ RoundIconContainer = (*roundimage.StaticImage)(nil) -) - -// Icon represents a rounded image container. -type Icon struct { - *gtk.Revealer // TODO move out - - Image RoundIconContainer - - // state - url string +type tooltipSetter interface { + SetTooltipText(text string) } -const DefaultIconSize = 16 +// BindRoundImage binds a round image to a rich label state store. +func BindRoundImage(img ImageURLSetter, state LabelStateStorer, tooltip bool) { + var setTooltip func(string) -var _ cchat.IconContainer = (*Icon)(nil) - -func NewIcon(sizepx int) *Icon { - img, _ := roundimage.NewImage(0) - img.Show() - return NewCustomIcon(img, sizepx) -} - -func NewCustomIcon(img RoundIconContainer, sizepx int) *Icon { - if sizepx == 0 { - sizepx = DefaultIconSize - } - - rev, _ := gtk.RevealerNew() - rev.Add(img) - rev.SetRevealChild(false) - rev.SetTransitionType(gtk.REVEALER_TRANSITION_TYPE_SLIDE_RIGHT) - rev.SetTransitionDuration(50) - - i := &Icon{ - Revealer: rev, - Image: img, - } - i.SetSize(sizepx) - - return i -} - -// URL is not thread-safe. -func (i *Icon) URL() string { - return i.url -} - -func (i *Icon) CopyPixbuf(dst httputil.ImageContainer) { - switch i.Image.GetStorageType() { - case gtk.IMAGE_PIXBUF: - dst.SetFromPixbuf(i.Image.GetPixbuf()) - case gtk.IMAGE_ANIMATION: - dst.SetFromAnimation(i.Image.GetAnimation()) - } -} - -// Thread-unsafe setter methods should only be called right after construction. - -// SetPlaceholderIcon is not thread-safe. -func (i *Icon) SetPlaceholderIcon(iconName string, iconSzPx int) { - i.Image.SetRadius(-1) // square - i.SetRevealChild(true) - - if iconName != "" { - primitives.SetImageIcon(i.Image, iconName, iconSzPx) - } -} - -// SetSize is not thread-safe. -func (i *Icon) SetSize(szpx int) { - i.Image.SetSizeRequest(szpx, szpx) -} - -// Size returns the minimum of the image size. It is not thread-safe. -func (i *Icon) Size() int { - w, h := i.Image.GetSizeRequest() - if h < w { - return h - } - return w -} - -// SetIcon is thread-safe. -func (i *Icon) SetIcon(url string) { - gts.ExecAsync(func() { i.SetIconUnsafe(url) }) -} - -func (i *Icon) AsyncSetIconer(iconer cchat.Iconer, errwrap string) { - // Reveal to show the placeholder. - i.SetRevealChild(true) - - // I have a hunch this will never work; as long as Go keeps a reference with - // iconer.Icon, then destroy will never be triggered. - ctx := primitives.HandleDestroyCtx(context.Background(), i) - gts.Async(func() (func(), error) { - f, err := iconer.Icon(ctx, i) - if err != nil { - return nil, errors.Wrap(err, "failed to load iconer") + if tooltip { + tooltipper, ok := img.(tooltipSetter) + if !ok { + log.Panicf("img of type %T is not tooltipSetter", img) } - return func() { i.Connect("destroy", func(interface{}) { f() }) }, nil + setTooltip = tooltipper.SetTooltipText + } + + state.OnUpdate(func() { + image := state.Image() + img.SetImageURL(image.URL) + + if setTooltip != nil { + setTooltip(state.Label().String()) + } }) } - -// SetIconUnsafe is not thread-safe. -func (i *Icon) SetIconUnsafe(url string) { - // Setting the radius here since we resetted it for a placeholder icon. - i.Image.SetRadius(0) - i.SetRevealChild(true) - i.url = url - i.Image.SetImageURL(i.url) -} - -// type EventIcon struct { -// *gtk.EventBox -// Icon *Icon -// } - -// func NewEventIcon(sizepx int) *EventIcon { -// icn := NewIcon(sizepx) -// return WrapEventIcon(icn) -// } - -// func WrapEventIcon(icn *Icon) *EventIcon { -// icn.Show() -// evb, _ := gtk.EventBoxNew() -// evb.Add(icn) - -// return &EventIcon{ -// EventBox: evb, -// Icon: icn, -// } -// } - -type ToggleButtonImage struct { - gtk.ToggleButton - Labeler - cchat.IconContainer - - Label *gtk.Label - Image *Icon - - Box *gtk.Box -} - -var ( - _ gtk.IWidget = (*ToggleButton)(nil) - _ cchat.LabelContainer = (*ToggleButton)(nil) -) - -func NewToggleButtonImage(content text.Rich) *ToggleButtonImage { - img, _ := roundimage.NewStaticImage(nil, 0) - img.Show() - return NewCustomToggleButtonImage(img, content) -} - -func NewCustomToggleButtonImage(img RoundIconContainer, content text.Rich) *ToggleButtonImage { - l := NewLabel(content) - l.Show() - - i := NewCustomIcon(img, 0) - i.Show() - - box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) - box.PackStart(i, false, false, 0) - box.PackStart(l, true, true, 5) - box.Show() - - b, _ := gtk.ToggleButtonNew() - b.Add(box) - - if connector, ok := img.(roundimage.Connector); ok { - connector.ConnectHandlers(b) - } - - return &ToggleButtonImage{ - ToggleButton: *b, - Labeler: l, // easy inheritance of methods - IconContainer: i, - - Label: &l.Label, - Image: i, - Box: box, - } -} diff --git a/internal/ui/rich/label.go b/internal/ui/rich/label.go index 8c17022..3ed4ece 100644 --- a/internal/ui/rich/label.go +++ b/internal/ui/rich/label.go @@ -1,134 +1,94 @@ package rich import ( - "context" - - "github.com/diamondburned/cchat" - "github.com/diamondburned/cchat-gtk/internal/gts" - "github.com/diamondburned/cchat-gtk/internal/ui/primitives" "github.com/diamondburned/cchat-gtk/internal/ui/rich/parser/markup" "github.com/diamondburned/cchat/text" "github.com/gotk3/gotk3/gtk" "github.com/gotk3/gotk3/pango" - "github.com/pkg/errors" ) -type Labeler interface { - // thread-safe - cchat.LabelContainer // thread-safe +// LabelRenderer is the input/output function to render a rich text segment to +// Pango markup. +type LabelRenderer = func(text.Rich) markup.RenderOutput - // not thread-safe - SetLabelUnsafe(text.Rich) - GetLabel() text.Rich - GetText() string -} - -// SuperLabeler represents a label that inherits the current labeler. -type SuperLabeler interface { - SetLabelUnsafe(text.Rich) -} - -type LabelerFn = func(context.Context, cchat.LabelContainer) (func(), error) - -type Label struct { - gtk.Label - Current text.Rich - - // super unexported field for inheritance - super SuperLabeler -} - -var ( - _ gtk.IWidget = (*Label)(nil) - _ Labeler = (*Label)(nil) -) - -func NewLabel(content text.Rich) *Label { - label, _ := gtk.LabelNew("") - label.SetMarkup(markup.Render(content)) - label.SetXAlign(0) // left align - label.SetEllipsize(pango.ELLIPSIZE_END) - - l := &Label{ - Label: *label, - Current: content, - } - - return l -} - -// NewInheritLabel creates a new label wrapper for structs that inherit this -// label. -func NewInheritLabel(super SuperLabeler) *Label { - l := NewLabel(text.Rich{}) - l.super = super - return l -} - -func (l *Label) validsuper() bool { - _, ok := l.super.(*Label) - // supers must not be the current struct and must not be nil. - return !ok && l.super != nil -} - -func (l *Label) AsyncSetLabel(fn LabelerFn, info string) { - ctx := primitives.HandleDestroyCtx(context.Background(), l) - gts.Async(func() (func(), error) { - f, err := fn(ctx, l) - if err != nil { - return nil, errors.Wrap(err, "failed to load iconer") - } - - return func() { l.Connect("destroy", func(interface{}) { f() }) }, nil +// RenderSkipImages is a label renderer that skips images. +func RenderSkipImages(rich text.Rich) markup.RenderOutput { + return markup.RenderCmplxWithConfig(rich, markup.RenderConfig{ + SkipImages: true, + NoMentionLinks: true, }) } -// SetLabel is thread-safe. -func (l *Label) SetLabel(content text.Rich) { - gts.ExecAsync(func() { l.SetLabelUnsafe(content) }) +// Label provides an abstraction around a regular GTK label that can be +// self-updated. Widgets that extend off of this (such as ToggleButton) does not +// need to manually +type Label struct { + gtk.Label + label text.Rich + output markup.RenderOutput + render LabelRenderer } -// SetLabelUnsafe sets the label in the current thread, meaning it's not -// thread-safe. If this label has a super, then it will call that struct's -// SetLabelUnsafe instead of its own. -func (l *Label) SetLabelUnsafe(content text.Rich) { - l.Current = content +var _ gtk.IWidget = (*Label)(nil) - if l.validsuper() { - l.super.SetLabelUnsafe(content) - } else { - l.SetMarkup(markup.Render(content)) +// NewStaticLabel creates a static, non-updating label. +func NewStaticLabel(rich text.Rich) *Label { + label, _ := gtk.LabelNew("") + label.SetXAlign(0) // left align + label.SetEllipsize(pango.ELLIPSIZE_END) + + if !rich.IsEmpty() { + label.SetMarkup(markup.Render(rich)) } + + return &Label{Label: *label} } -// GetLabel is NOT thread-safe. -func (l *Label) GetLabel() text.Rich { - return l.Current +// NewLabel creates a self-updating label. +func NewLabel(state LabelStateStorer) *Label { + return NewLabelWithRenderer(state, nil) } -// GetText is NOT thread-safe. -func (l *Label) GetText() string { - return l.Current.Content +// NewLabelWithRenderer creates a self-updating label using the given renderer. +func NewLabelWithRenderer(state LabelStateStorer, r LabelRenderer) *Label { + l := NewStaticLabel(text.Plain("")) + l.render = r + state.OnUpdate(func() { l.SetLabel(state.Label()) }) + return l } -type ToggleButton struct { - gtk.ToggleButton - Label +// Output returns the rendered output. +func (l *Label) Output() markup.RenderOutput { + return l.output } -var ( - _ gtk.IWidget = (*ToggleButton)(nil) - _ cchat.LabelContainer = (*ToggleButton)(nil) -) +// SetLabel sets the label in the current thread, meaning it's not thread-safe. +func (l *Label) SetLabel(content text.Rich) { + // Save a call if the content is empty. + if content.IsEmpty() { + l.label = content + l.output = markup.RenderOutput{} -func NewToggleButton(content text.Rich) *ToggleButton { - l := NewLabel(content) - l.Show() + return + } - b, _ := gtk.ToggleButtonNew() - primitives.BinLeftAlignLabel(b) + l.label = content - b.Add(l) + var out markup.RenderOutput + if l.render != nil { + out = l.render(content) + } else { + out = markup.RenderCmplx(content) + } - return &ToggleButton{*b, *l} + l.output = out + l.SetMarkup(out.Markup) + l.SetTooltipMarkup(out.Markup) +} + +// SetRenderer sets a custom renderer. If the given renderer is nil, then the +// default markup renderer is used instead. The label is automatically updated. +func (l *Label) SetRenderer(renderer LabelRenderer) { + l.render = renderer + l.SetLabel(l.label) } diff --git a/internal/ui/rich/labeluri/labeluri.go b/internal/ui/rich/labeluri/labeluri.go index 7365655..8c1e55d 100644 --- a/internal/ui/rich/labeluri/labeluri.go +++ b/internal/ui/rich/labeluri/labeluri.go @@ -31,69 +31,35 @@ const ( MaxHeight = 500 ) -type WidgetConnector interface { - gtk.IWidget - primitives.Connector -} - -var _ WidgetConnector = (*gtk.Label)(nil) - -// Labeler implements a rich label that stores an output state. -type Labeler interface { - WidgetConnector - rich.Labeler - Output() markup.RenderOutput -} +// // Labeler implements a rich label that stores an output state. +// type Labeler interface { +// WidgetConnector +// rich.Labeler +// Output() markup.RenderOutput +// } // Label implements a label that's already bounded to the markup URI handlers. type Label struct { *rich.Label *BoundBox - output markup.RenderOutput } -var ( - _ Labeler = (*Label)(nil) - _ rich.SuperLabeler = (*Label)(nil) -) +// var ( +// _ Labeler = (*Label)(nil) +// _ rich.SuperLabeler = (*Label)(nil) +// ) func NewLabel(txt text.Rich) *Label { l := &Label{} - l.Label = rich.NewInheritLabel(l) - l.Label.SetLabelUnsafe(txt) // test + l.Label = rich.NewStaticLabel(txt) // Bind and return. - l.BoundBox = BindRichLabel(l) + l.BoundBox = BindRichLabel(l.Label) return l } func (l *Label) Reset() { - l.output = markup.RenderOutput{} -} - -func (l *Label) SetLabelUnsafe(content text.Rich) { - l.output = markup.RenderCmplx(content) - l.SetMarkup(l.output.Markup) -} - -// Output returns the label's markup output. This function is NOT -// thread-safe. -func (l *Label) Output() markup.RenderOutput { - return l.output -} - -// SetOutput sets the internal output and label. It preserves the tail if -// any. -func (l *Label) SetOutput(o markup.RenderOutput) { - l.output = o - l.SetMarkup(o.Markup) -} - -// SetUnderlyingOutput sets the output state without changing the label's -// markup. This is useful for internal use cases where the label is updated -// separately. -func (l *Label) SetUnderlyingOutput(o markup.RenderOutput) { - l.output = o + l.Label.SetLabel(text.Plain("")) } type ReferenceHighlighter interface { @@ -103,11 +69,11 @@ type ReferenceHighlighter interface { // BoundBox is a box wrapping elements that can be interacted with from the // parsed labels. type BoundBox struct { - label Labeler + label *rich.Label refer ReferenceHighlighter } -func BindRichLabel(label Labeler) *BoundBox { +func BindRichLabel(label *rich.Label) *BoundBox { bound := BoundBox{label: label} bind(label, bound.activate) return &bound @@ -206,7 +172,7 @@ func NewPopoverMentioner(rel gtk.IWidget, input string, segment text.Segment) *g l.Show() // Enable images??? - BindActivator(l) + BindImagePreview(l) // Make a scrolling text. scr := scrollinput.NewVScroll(PopoverWidth) @@ -259,13 +225,23 @@ func popoverImg(url string, round bool) gtk.IWidget { return btn } -func BindActivator(connector WidgetConnector) { +// WidgetConnector describes a connector that is also a widget. +type WidgetConnector interface { + gtk.IWidget + primitives.Connector +} + +var _ WidgetConnector = (*gtk.Label)(nil) + +// BindImagePreview binds activate-link to the label callback so that images +// have a popover preview. +func BindImagePreview(connector WidgetConnector) { bind(connector, nil) } // bind connects activate-link. If activator returns true, then nothing is done. // Activator can be nil. -func bind(connector WidgetConnector, activator func(uri string, r gdk.Rectangle) bool) { +func bind(c WidgetConnector, activator func(uri string, r gdk.Rectangle) bool) { // This implementation doesn't seem like a good idea. First off, is the // closure really garbage collected? If it's not, then we have some huge // issues. Second, if the closure is garbage collected, then when? If it's @@ -273,11 +249,11 @@ func bind(connector WidgetConnector, activator func(uri string, r gdk.Rectangle) // message, but we're also keeping alive the widget. var x, y float64 - connector.Connect("motion-notify-event", func(_ interface{}, ev *gdk.Event) { + c.Connect("motion-notify-event", func(_ interface{}, ev *gdk.Event) { x, y = gdk.EventMotionNewFromEvent(ev).MotionVal() }) - connector.Connect("activate-link", func(c WidgetConnector, uri string) bool { + c.Connect("activate-link", func(c WidgetConnector, uri string) bool { // Make a new rectangle to use in the popover. r := gdk.Rectangle{} r.SetX(int(x)) @@ -297,8 +273,8 @@ func bind(connector WidgetConnector, activator func(uri string, r gdk.Rectangle) if !round { img, _ = gtk.ImageNew() } else { - r, _ := roundimage.NewImage(0) - img = r.Image + r := roundimage.NewImage(0) + img = &r.Image } img.SetSizeRequest(w, h) diff --git a/internal/ui/rich/parser/markup/markup.go b/internal/ui/rich/parser/markup/markup.go index 724f354..1cacd49 100644 --- a/internal/ui/rich/parser/markup/markup.go +++ b/internal/ui/rich/parser/markup/markup.go @@ -123,6 +123,10 @@ type RenderConfig struct { // mentions. NoReferencing bool + // SkipImages skips rendering any image markup. This is useful for widgets + // that already render an outside image. + SkipImages bool + // AnchorColor forces all anchors to be of a certain color. This is used if // the boolean is true. Else, all mention links will not work and regular // links will be of the default color. @@ -197,7 +201,7 @@ func RenderCmplxWithConfig(content text.Rich, cfg RenderConfig) RenderOutput { } // Only inline images if start == end per specification. - if start == end { + if !cfg.SkipImages && start == end { if imager := segment.AsImager(); imager != nil { appended.Open(start, composeImageMarkup(imager)) } diff --git a/internal/ui/rich/rich.go b/internal/ui/rich/rich.go index d016599..6d69a64 100644 --- a/internal/ui/rich/rich.go +++ b/internal/ui/rich/rich.go @@ -1,22 +1,236 @@ package rich import ( + "context" "html" + "image" + "runtime" + "sync" + "github.com/diamondburned/cchat" + "github.com/diamondburned/cchat-gtk/internal/gts" + "github.com/diamondburned/cchat-gtk/internal/log" + "github.com/diamondburned/cchat-gtk/internal/ui/primitives" + "github.com/diamondburned/cchat-gtk/internal/ui/rich/parser/markup" "github.com/diamondburned/cchat/text" + "github.com/pkg/errors" ) -func Small(text string) string { - return `` + text + "" +// Small is a renderer that makes the plain text small. +func Small(content text.Rich) markup.RenderOutput { + v := `` + html.EscapeString(content.Content) + "" + return markup.RenderOutput{ + Markup: v, + Input: content.Content, + } } -func MakeRed(content text.Rich) string { - return `` + html.EscapeString(content.Content) + `` +// MakeRed is a renderer that makes the plain text red. +func MakeRed(content text.Rich) markup.RenderOutput { + v := `` + html.EscapeString(content.Content) + `` + return markup.RenderOutput{ + Markup: v, + Input: content.Content, + } } -// used for grabbing text without changing state -type nullLabel struct { - text.Rich +// LabelStateStorer is an interface for LabelState. +type LabelStateStorer interface { + Label() text.Rich + Image() LabelImage + OnUpdate(func()) (remove func()) } -func (n *nullLabel) SetLabel(t text.Rich) { n.Rich = t } +var _ LabelStateStorer = (*LabelState)(nil) + +// NameContainer contains a reusable LabelState for cchat.Namer. +type NameContainer struct { + LabelState + state *containerState // for alignment +} + +type containerState struct { + // stop is the stored callback. + stop func() + // current is the context stopper being used. + current context.CancelFunc +} + +// Stop stops the name container. Calling Stop twice when no new namers are set +// will do nothing. +func (namec *NameContainer) Stop() { + if namec.state != nil { + namec.state.Stop() + namec.LabelState.setLabel(text.Plain("")) + } +} + +func (state *containerState) Stop() { + if state.current != nil { + state.current() + state.current = nil + } + + if state.stop != nil { + state.stop() + state.stop = nil + } +} + +// QueueNamer tries using the namer in the background and queue the setter onto +// the next GLib loop iteration. +func (namec *NameContainer) QueueNamer(ctx context.Context, namer cchat.Namer) { + if namec.state == nil { + namec.state = &containerState{} + runtime.SetFinalizer(namec.state, (*containerState).Stop) + } + + namec.Stop() + + ctx, cancel := context.WithCancel(ctx) + namec.state.current = cancel + + go func() { + stop, err := namer.Name(ctx, namec) + if err != nil { + log.Error(errors.Wrap(err, "failed to activate namer")) + } + + gts.ExecAsync(func() { + namec.state.current() + namec.state.current = nil + namec.state.stop = stop + }) + }() +} + +// BindNamer binds a destructor signal to the name container to cancel a +// context. +func (namec *NameContainer) BindNamer(w primitives.Connector, sig string, namer cchat.Namer) { + namec.QueueNamer(context.Background(), namer) + + // TODO: I have a hunch that everything below this will leak to hell. Just a + // hunch. + + // namec.Stop() + + // ctx, cancel := context.WithCancel(context.Background()) + // namec.current = cancel + + // // TODO: this might leak, because namec.Stop references the fns list which + // // might reference w indirectly. + // w.Connect(sig, namec.Stop) + + // go func() { + // stop, err := namer.Name(ctx, namec) + // if err != nil { + // log.Error(errors.Wrap(err, "failed to activate namer")) + // } + + // gts.ExecAsync(func() { + // namec.current() + // namec.current = nil + // namec.stop = stop // nil is OK. + // }) + // }() +} + +// LabelState provides a container for labels that allow other containers to +// extend upon. A zero-value instance is a valid instance. +type LabelState struct { + // don't copy LabelState. + _ [0]sync.Mutex + + label text.Rich + + fns map[int]func() + serial int +} + +var _ cchat.LabelContainer = (*LabelState)(nil) + +// NewLabelState creates a new label state. +func NewLabelState(l text.Rich) *LabelState { + return &LabelState{label: l} +} + +// String returns the inside label in plain text. +func (state *LabelState) String() string { + return state.label.Content +} + +// Label returns the inside label. +func (state *LabelState) Label() text.Rich { + return state.label +} + +// OnUpdate subscribes the given callback. The returned callback removes the +// given callback from the registry. +func (state *LabelState) OnUpdate(fn func()) (remove func()) { + if state.fns == nil { + state.fns = make(map[int]func(), 1) + } + + id := state.serial + state.fns[id] = fn + state.serial++ + + if !state.label.IsEmpty() { + fn() + } + + return func() { delete(state.fns, id) } +} + +// SetLabel is called by cchat to update the state. The internal subscribed +// callbacks will be called in the main thread. +func (state *LabelState) SetLabel(label text.Rich) { + gts.ExecAsync(func() { state.setLabel(label) }) +} + +func (state *LabelState) setLabel(label text.Rich) { + state.label = label + + for _, fn := range state.fns { + fn() + } +} + +// LabelImage is the first image from a label. If +type LabelImage struct { + URL string + Text string + Size image.Point + Avatar bool +} + +// HasImage returns true if the label has an image. +func (labelImage LabelImage) HasImage() bool { + return labelImage.URL != "" +} + +// Image returns the image, if any. Otherwise, an empty string is returned. +func (state *LabelState) Image() LabelImage { + for _, segment := range state.label.Segments { + if imager := segment.AsImager(); imager != nil { + return LabelImage{ + URL: imager.Image(), + Text: imager.ImageText(), + Size: image.Pt(imager.ImageSize()), + } + } + + if avatarer := segment.AsAvatarer(); avatarer != nil { + size := avatarer.AvatarSize() + + return LabelImage{ + URL: avatarer.Avatar(), + Text: avatarer.AvatarText(), + Size: image.Pt(size, size), + Avatar: true, + } + } + } + + return LabelImage{} +} diff --git a/internal/ui/service/config/config.go b/internal/ui/service/config/config.go index 16ec120..2062a63 100644 --- a/internal/ui/service/config/config.go +++ b/internal/ui/service/config/config.go @@ -4,15 +4,12 @@ package config import ( "fmt" - "hash/fnv" - "io" - "strconv" "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/gts" "github.com/diamondburned/cchat-gtk/internal/ui/config" "github.com/diamondburned/cchat-gtk/internal/ui/primitives/menu" - "github.com/diamondburned/cchat/text" + "github.com/diamondburned/cchat-gtk/internal/ui/rich" "github.com/gotk3/gotk3/gtk" "github.com/pkg/errors" ) @@ -31,17 +28,17 @@ func Restore(conf Configurator) { gts.Async(func() (func(), error) { c, err := conf.Configuration() if err != nil { - return nil, errors.Wrapf(err, "failed to get %s config", conf.Name()) + return nil, errors.Wrapf(err, "failed to get %s config", conf.ID()) } file := serviceFile(conf) if err := config.UnmarshalFromFile(file, &c); err != nil { - return nil, errors.Wrapf(err, "failed to unmarshal %s config", conf.Name()) + return nil, errors.Wrapf(err, "failed to unmarshal %s config", conf.ID()) } if err := conf.SetConfiguration(c); err != nil { - return nil, errors.Wrapf(err, "failed to set %s config", conf.Name()) + return nil, errors.Wrapf(err, "failed to set %s config", conf.ID()) } return nil, nil @@ -52,16 +49,16 @@ func Spawn(conf Configurator) error { gts.Async(func() (func(), error) { c, err := conf.Configuration() if err != nil { - return nil, errors.Wrapf(err, "failed to get %s config", conf.Name()) + return nil, errors.Wrapf(err, "failed to get %s config", conf.ID()) } file := serviceFile(conf) err = config.UnmarshalFromFile(file, &c) - err = errors.Wrapf(err, "failed to unmarshal %s config", conf.Name()) + err = errors.Wrapf(err, "failed to unmarshal %s config", conf.ID()) return func() { - spawn(conf.Name().String(), c, func(finalized bool) error { + spawn(conf, c, func(finalized bool) error { if err := conf.SetConfiguration(c); err != nil { return err } @@ -81,16 +78,10 @@ func Spawn(conf Configurator) error { } func serviceFile(conf Configurator) string { - return fmt.Sprintf("service-%s.json", dumbHash(conf.Name())) + return fmt.Sprintf("services/%s.json", conf.ID()) } -func dumbHash(name text.Rich) string { - hash := fnv.New32a() - io.WriteString(hash, name.String()) - return strconv.FormatUint(uint64(hash.Sum32()), 36) -} - -func spawn(name string, conf map[string]string, apply func(final bool) error) { +func spawn(c Configurator, conf map[string]string, apply func(final bool) error) { container := newContainer(conf, func() error { return apply(false) }) container.Grid.SetVAlign(gtk.ALIGN_START) @@ -107,20 +98,25 @@ func spawn(name string, conf map[string]string, apply func(final bool) error) { b.PackStart(container.ErrHeader, false, false, 0) b.Show() - var title = "Configure " + name - h, _ := gtk.HeaderBarNew() - h.SetTitle(title) + h.SetTitle("Configure " + c.ID()) h.SetShowCloseButton(true) h.Show() + var state rich.NameContainer + state.OnUpdate(func() { + h.SetTitle("Configure " + state.String()) + }) + d, _ := gts.NewEmptyModalDialog() d.SetDefaultSize(400, 300) d.Add(b) - d.SetTitle(title) d.SetTitlebar(h) - d.Connect("destroy", func(*gtk.Dialog) { apply(true) }) + // Bind the title. + state.BindNamer(d, "response", c) + // Bind the updater. + d.Connect("response", func(*gtk.Dialog) { apply(true) }) d.Show() } diff --git a/internal/ui/service/header.go b/internal/ui/service/header.go index f7d7bde..7018db7 100644 --- a/internal/ui/service/header.go +++ b/internal/ui/service/header.go @@ -131,7 +131,10 @@ type sizeBinder interface { var _ sizeBinder = (*List)(nil) func (h *Header) AppMenuBindSize(c sizeBinder) { - c.Connect("size-allocate", func(c sizeBinder) { + update := func(c sizeBinder) { h.AppMenu.SetSizeRequest(c.GetAllocatedWidth(), -1) - }) + } + + c.Connect("size-allocate", update) + update(c) } diff --git a/internal/ui/service/list.go b/internal/ui/service/list.go index 47e0f39..67474ed 100644 --- a/internal/ui/service/list.go +++ b/internal/ui/service/list.go @@ -35,7 +35,8 @@ var _ ListController = (*List)(nil) var listCSS = primitives.PrepareClassCSS("service-list", ` .service-list { padding: 0; - background-color: mix(@theme_bg_color, @theme_fg_color, 0.03); + background-color: @theme_bg_color; + /* background-color: mix(@theme_bg_color, @theme_fg_color, 0.03); */ } `) diff --git a/internal/ui/service/service.go b/internal/ui/service/service.go index 9894d48..dc59743 100644 --- a/internal/ui/service/service.go +++ b/internal/ui/service/service.go @@ -1,6 +1,7 @@ package service import ( + "context" "fmt" "github.com/diamondburned/cchat" @@ -11,7 +12,6 @@ import ( "github.com/diamondburned/cchat-gtk/internal/ui/primitives/drag" "github.com/diamondburned/cchat-gtk/internal/ui/primitives/roundimage" "github.com/diamondburned/cchat-gtk/internal/ui/rich" - "github.com/diamondburned/cchat-gtk/internal/ui/rich/parser/markup" "github.com/diamondburned/cchat-gtk/internal/ui/service/config" "github.com/diamondburned/cchat-gtk/internal/ui/service/session" "github.com/diamondburned/cchat-gtk/internal/ui/service/session/server" @@ -19,7 +19,7 @@ import ( "github.com/gotk3/gotk3/gtk" ) -const IconSize = 48 +const IconSize = 42 type ListController interface { // ClearMessenger is called when a nil slice of servers is set. @@ -43,13 +43,14 @@ type Service struct { *gtk.Box Button *gtk.ToggleButton - Icon *rich.Icon + Icon *roundimage.StillImage Menu *actions.Menu BodyRev *gtk.Revealer // revealed BodyList *session.List // not really supposed to be here service cchat.Service // state + Name rich.NameContainer Configurator cchat.Configurator } @@ -67,7 +68,7 @@ var serviceCSS = primitives.PrepareClassCSS("service", ` var serviceButtonCSS = primitives.PrepareClassCSS("service-button", ` .service-button { - padding: 2px; + padding: 6px; margin: 0; } @@ -78,58 +79,51 @@ var serviceButtonCSS = primitives.PrepareClassCSS("service-button", ` .service-button:checked { border-radius: 14px 14px 0 0; - background-color: alpha(@theme_fg_color, 0.2); + /* background-color: alpha(@theme_fg_color, 0.2); */ } `) -var serviceIconCSS = primitives.PrepareClassCSS("service-icon", ` - .service-icon { padding: 4px } -`) +var serviceIconCSS = primitives.PrepareClassCSS("service-icon", ``) func NewService(svc cchat.Service, svclctrl ListController) *Service { - service := &Service{ + service := Service{ service: svc, ListController: svclctrl, } + service.Name.QueueNamer(context.Background(), svc) - service.BodyList = session.NewList(service) + service.BodyList = session.NewList(&service) service.BodyList.Show() service.BodyRev, _ = gtk.RevealerNew() service.BodyRev.SetRevealChild(false) // TODO persistent state - service.BodyRev.SetTransitionDuration(50) + service.BodyRev.SetTransitionDuration(100) service.BodyRev.SetTransitionType(gtk.REVEALER_TRANSITION_TYPE_SLIDE_DOWN) service.BodyRev.Add(service.BodyList) service.BodyRev.Show() // TODO: have it so the button changes to the session avatar when collapsed - avatar := roundimage.NewAvatar(IconSize) - avatar.SetText(svc.Name().String()) - avatar.Show() - - service.Icon = rich.NewCustomIcon(avatar, IconSize) - service.Icon.Show() - // potentially nonstandard - service.Icon.SetPlaceholderIcon("text-html-symbolic", IconSize) - // TODO: hover for name. We use tooltip for now. - service.Icon.SetTooltipMarkup(markup.Render(svc.Name())) - serviceIconCSS(service.Icon) - - if iconer := svc.AsIconer(); iconer != nil { - service.Icon.AsyncSetIconer(iconer, "Failed to set service icon") - } - service.Button, _ = gtk.ToggleButtonNew() - service.Button.Add(service.Icon) service.Button.SetRelief(gtk.RELIEF_NONE) service.Button.Show() + serviceButtonCSS(service.Button) + + service.Icon = roundimage.NewStillImage(service.Button, 0) + service.Icon.SetSize(IconSize) + service.Icon.UseInitialsIfNone(service.Name.String) + service.Icon.Show() + serviceIconCSS(service.Icon) + + rich.BindRoundImage(service.Icon, &service.Name, true) + // TODO: hover for name. We use tooltip for now. + + service.Button.Add(service.Icon) service.Button.Connect("clicked", func(tb *gtk.ToggleButton) { revealed := !service.GetRevealChild() service.SetRevealChild(revealed) tb.SetActive(revealed) }) - serviceButtonCSS(service.Button) // Bind session.* actions into row. service.Menu = actions.NewMenu("service") @@ -153,9 +147,9 @@ func NewService(svc cchat.Service, svclctrl ListController) *Service { serviceCSS(service.Box) // Bind a drag and drop on the button instead of the entire box. - drag.BindDraggable(service, "network-workgroup", svclctrl.MoveService, service.Button) + drag.BindDraggable(&service, "network-workgroup", svclctrl.MoveService, service.Button) - return service + return &service } // SetRevealChild sets whether or not the service should reveal all sessions. @@ -204,7 +198,7 @@ func (s *Service) AddSession(ses cchat.Session) *session.Row { } func (s *Service) ID() string { - return s.service.Name().Content + return s.service.ID() } func (s *Service) Service() cchat.Service { @@ -232,7 +226,7 @@ func (s *Service) MoveSession(id, movingID string) { } func (s *Service) Breadcrumb() string { - return s.service.Name().Content + return s.Name.String() } func (s *Service) ParentBreadcrumb() traverse.Breadcrumber { @@ -241,15 +235,13 @@ func (s *Service) ParentBreadcrumb() traverse.Breadcrumber { func (s *Service) SaveAllSessions() { var sessions = s.BodyList.Sessions() - var keyrings = make([]keyring.Session, 0, len(sessions)) + var keyrings = keyring.NewService(s.service, len(sessions)) - for _, s := range sessions { - if k := keyring.ConvertSession(s.Session); k != nil { - keyrings = append(keyrings, *k) - } + for _, session := range sessions { + keyrings.Add(session.Session, s.Name.String()) } - keyring.SaveSessions(s.service, keyrings) + keyrings.Save() } func (s *Service) RestoreSession(row *session.Row, id string) { @@ -265,7 +257,7 @@ func (s *Service) RestoreSession(row *session.Row, id string) { log.Error(fmt.Errorf( "Missing keyring for service %s, session ID %s", - s.service.Name().Content, id, + s.service.ID(), id, )) } @@ -276,8 +268,10 @@ func (s *Service) restoreAll() { return } - // Session is not a pointer, so we can pass it into arguments safely. - for _, ses := range keyring.RestoreSessions(s.service) { + service := keyring.Restore(s.service) + + for _, ses := range service.Sessions { + // Session is not a pointer, so we can pass it into arguments safely. row := s.AddLoadingSession(ses.ID, ses.Name) row.RestoreSession(rs, ses) } diff --git a/internal/ui/service/session/server/button/button.go b/internal/ui/service/session/server/button/button.go index e598132..5e0e8b8 100644 --- a/internal/ui/service/session/server/button/button.go +++ b/internal/ui/service/session/server/button/button.go @@ -1,11 +1,9 @@ package button import ( - "github.com/diamondburned/cchat" - "github.com/diamondburned/cchat-gtk/internal/gts" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" + "github.com/diamondburned/cchat-gtk/internal/ui/primitives/roundimage" "github.com/diamondburned/cchat-gtk/internal/ui/rich" - "github.com/diamondburned/cchat/text" "github.com/gotk3/gotk3/gtk" ) @@ -13,20 +11,32 @@ const UnreadColorDefs = ` @define-color mentioned rgb(240, 71, 71); ` -type ToggleButtonImage struct { - *rich.ToggleButtonImage +const IconSize = 38 +type ToggleButton struct { + gtk.ToggleButton + Label *rich.Label + labelRev *gtk.Revealer + + // These fields are nil if image is false. + Image *roundimage.StillImage + imageRev *gtk.Revealer + + Box *gtk.Box + + state rich.LabelStateStorer clicked func(bool) readcss primitives.ClassEnum - err error - icon string // whether or not the button has an icon - iconSz int + icon string // whether or not the button has an icon + label bool } -var _ cchat.IconContainer = (*ToggleButtonImage)(nil) - var serverButtonCSS = primitives.PrepareClassCSS("server-button", ` + .server-button { + min-width: 0px; + } + .selected-server { border-left: 2px solid mix(@theme_base_color, @theme_fg_color, 0.1); background-color: mix(@theme_base_color, @theme_fg_color, 0.1); @@ -34,14 +44,14 @@ var serverButtonCSS = primitives.PrepareClassCSS("server-button", ` } .read { - color: alpha(@theme_fg_color, 0.5); + /* color: alpha(@theme_fg_color, 0.5); */ border-left: 2px solid transparent; } .unread { color: @theme_fg_color; border-left: 2px solid alpha(@theme_fg_color, 0.75); - background-color: alpha(@theme_fg_color, 0.05); + /* background-color: alpha(@theme_fg_color, 0.05); */ } .mentioned { @@ -52,34 +62,55 @@ var serverButtonCSS = primitives.PrepareClassCSS("server-button", ` `+UnreadColorDefs) -func NewToggleButtonImage(content text.Rich) *ToggleButtonImage { - b := rich.NewToggleButtonImage(content) - return WrapToggleButtonImage(b) -} +// NewToggleButton creates a new toggle button. +func NewToggleButton(state rich.LabelStateStorer) *ToggleButton { + label := rich.NewLabelWithRenderer(state, rich.RenderSkipImages) + label.SetMarginStart(5) + label.Show() -func WrapToggleButtonImage(b *rich.ToggleButtonImage) *ToggleButtonImage { - b.Show() + labelRev, _ := gtk.RevealerNew() + labelRev.Add(label) + labelRev.SetRevealChild(true) + labelRev.SetTransitionType(gtk.REVEALER_TRANSITION_TYPE_SLIDE_RIGHT) + labelRev.SetTransitionDuration(100) + labelRev.Show() - tb := &ToggleButtonImage{ - ToggleButtonImage: b, - clicked: func(bool) {}, - } - - type activeGetter interface { - GetActive() bool + box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) + box.SetHAlign(gtk.ALIGN_START) + box.PackStart(labelRev, false, false, 0) + box.Show() + + button, _ := gtk.ToggleButtonNew() + button.SetRelief(gtk.RELIEF_NONE) + button.Add(box) + button.Show() + + tb := &ToggleButton{ + ToggleButton: *button, + Label: label, + labelRev: labelRev, + Box: box, + state: state, + clicked: func(bool) {}, } + tb.SetShowLabel(true) tb.Connect("clicked", func(w *gtk.ToggleButton) { tb.clicked(w.GetActive()) }) serverButtonCSS(tb) + // Ensure that we display an icon when we receive one. + state.OnUpdate(func() { + if state.Image().HasImage() { + tb.ensureImage() + } + }) + return tb } -func (b *ToggleButtonImage) SetSelected(selected bool) { - // Set the clickability the opposite as the boolean. - // b.SetSensitive(!selected) - b.SetInconsistent(selected) - +// SetSelected sets the button's intermediate state and appearance to look +// like it's clicked without triggering the callback. +func (b *ToggleButton) SetSelected(selected bool) { if selected { primitives.AddClass(b, "selected-server") } else { @@ -92,11 +123,36 @@ func (b *ToggleButtonImage) SetSelected(selected bool) { } } -func (b *ToggleButtonImage) SetClicked(clicked func(bool)) { +// SetShowLabel sets whether or not to show the button's label. If the button +// does not have an image, then the label is always shown. +func (b *ToggleButton) SetShowLabel(showLabel bool) { + b.label = showLabel + + // Enforce particular rules that are unfeasible at the moment. When these + // conditions change elsewhere, this function will be called again. + if b.imageRev != nil { + showLabel = showLabel || !b.imageRev.GetRevealChild() + } else { + showLabel = true + } + + // Expand the box when we're showing the label. + b.SetHExpand(showLabel) + b.labelRev.SetRevealChild(showLabel) +} + +// GetShowLabel gets whether or not the label is being shown. +func (b *ToggleButton) GetShowLabel() bool { + return b.labelRev.GetRevealChild() || b.label +} + +// SetClicked sets the callback to run when clicked. It overrides the previous +// callback. +func (b *ToggleButton) SetClicked(clicked func(bool)) { b.clicked = clicked } -func (b *ToggleButtonImage) SetClickedIfTrue(clickedIfTrue func()) { +func (b *ToggleButton) SetClickedIfTrue(clickedIfTrue func()) { b.clicked = func(clicked bool) { if clicked { clickedIfTrue() @@ -104,33 +160,74 @@ func (b *ToggleButtonImage) SetClickedIfTrue(clickedIfTrue func()) { } } -func (b *ToggleButtonImage) SetNormal() { - b.SetLabelUnsafe(b.GetLabel()) - // b.menu.SetItems(b.extraMenu) +func (b *ToggleButton) ensureImage() { + if b.Image != nil { + return + } - if b.icon != "" { - b.Image.SetPlaceholderIcon(b.icon, b.Image.Size()) + b.Image = roundimage.NewStillImage(b, 0) + b.Image.SetSizeRequest(IconSize, IconSize) + b.Image.Show() + + // TODO: tooltip false once hover is implemented. + rich.BindRoundImage(b.Image, b.state, true) + + b.imageRev, _ = gtk.RevealerNew() + b.imageRev.Add(b.Image) + b.imageRev.SetRevealChild(true) + b.imageRev.SetTransitionType(gtk.REVEALER_TRANSITION_TYPE_SLIDE_RIGHT) + b.imageRev.SetTransitionDuration(75) + b.imageRev.Show() + + b.Box.PackStart(b.imageRev, false, false, 0) + b.Box.ReorderChild(b.imageRev, 0) + + // Set the callback to render the user's initials if there is no name. + b.Image.UseInitialsIfNone(func() string { + return b.state.Label().String() + }) + + // Restore the label's visible state now that we have an image. + b.SetShowLabel(b.label) +} + +// UseEmptyIcon forces the ToggleButton to show an icon, even if it's a +// placeholder. +func (b *ToggleButton) UseEmptyIcon() { + b.ensureImage() +} + +// SetNormal sets the button's state to normal from either loading or failed. +func (b *ToggleButton) SetNormal() { + b.Label.SetRenderer(rich.RenderSkipImages) + b.SetSensitive(true) + + if b.Image != nil && b.icon != "" { + b.SetPlaceholderIcon(b.icon, b.Image.Size()) } } -func (b *ToggleButtonImage) SetLoading() { - b.SetLabelUnsafe(b.GetLabel()) +// SetLoading sets the button's state to loading. +func (b *ToggleButton) SetLoading() { + b.Label.SetRenderer(rich.RenderSkipImages) + b.SetSensitive(false) - if b.icon != "" { - b.Image.SetPlaceholderIcon("content-loading-symbolic", b.Image.Size()) + if b.Image != nil && b.icon != "" { + b.SetPlaceholderIcon("content-loading-symbolic", b.Image.Size()) } } -func (b *ToggleButtonImage) SetFailed(err error, retry func()) { - b.Label.SetMarkup(rich.MakeRed(b.GetLabel())) +func (b *ToggleButton) SetFailed(err error, retry func()) { + b.Label.SetRenderer(rich.MakeRed) + b.SetSensitive(true) // If we have an icon set, then we can use the failed icon. - if b.icon != "" { - b.Image.SetPlaceholderIcon("computer-fail-symbolic", b.Image.Size()) + if b.Image != nil && b.icon != "" { + b.SetPlaceholderIcon("computer-fail-symbolic", b.Image.Size()) } } -func (b *ToggleButtonImage) SetUnreadUnsafe(unread, mentioned bool) { +func (b *ToggleButton) SetUnreadUnsafe(unread, mentioned bool) { switch { // Prioritize mentions over unreads. case mentioned: @@ -142,16 +239,8 @@ func (b *ToggleButtonImage) SetUnreadUnsafe(unread, mentioned bool) { } } -func (b *ToggleButtonImage) SetPlaceholderIcon(iconName string, iconSzPx int) { +func (b *ToggleButton) SetPlaceholderIcon(iconName string, iconSzPx int) { b.icon = iconName + b.ensureImage() b.Image.SetPlaceholderIcon(iconName, iconSzPx) } - -func (b *ToggleButtonImage) SetIcon(url string) { - gts.ExecAsync(func() { b.SetIconUnsafe(url) }) -} - -func (b *ToggleButtonImage) SetIconUnsafe(url string) { - b.icon = "" - b.Image.SetIconUnsafe(url) -} diff --git a/internal/ui/service/session/server/button/label.go b/internal/ui/service/session/server/button/label.go new file mode 100644 index 0000000..90541ef --- /dev/null +++ b/internal/ui/service/session/server/button/label.go @@ -0,0 +1,3 @@ +package button + +type CollapsibleLabel struct{} diff --git a/internal/ui/service/session/server/children.go b/internal/ui/service/session/server/children.go index bfeec25..0032cb2 100644 --- a/internal/ui/service/session/server/children.go +++ b/internal/ui/service/session/server/children.go @@ -13,22 +13,28 @@ import ( ) type Controller interface { + ClearMessenger() MessengerSelected(*ServerRow) + // SelectColumnatedLister is called when the user clicks a server lister + // with its with Columnate method returning true. If lister is nil, then the + // impl should clear it. + SelectColumnatedLister(*ServerRow, cchat.Lister) } // Children is a children server with a reference to the parent. By default, a // children will contain hollow rows. They are rows that do not yet have any // widgets. This changes as soon as Row's Load is called. type Children struct { - *gtk.Box + gtk.Box + Controller load *loading.Button // only not nil while loading loading bool - Rows []*ServerRow + Rows []*ServerRow + expand bool - Parent traverse.Breadcrumber - rowctrl Controller + Parent traverse.Breadcrumber // Unreadable state for children rows to use. The parent row that has this // Children will bind a handler to this. @@ -37,8 +43,6 @@ type Children struct { var childrenCSS = primitives.PrepareClassCSS("server-children", ` .server-children { - margin: 0; - margin-top: 3px; border-radius: 0; } `) @@ -47,8 +51,8 @@ var childrenCSS = primitives.PrepareClassCSS("server-children", ` // widgets. func NewHollowChildren(p traverse.Breadcrumber, ctrl Controller) *Children { return &Children{ - Parent: p, - rowctrl: ctrl, + Parent: p, + Controller: ctrl, } } @@ -60,7 +64,7 @@ func NewChildren(p traverse.Breadcrumber, ctrl Controller) *Children { } func (c *Children) IsHollow() bool { - return c.Box == nil + return c.Box.Object == nil } // Init ensures that the children container is not hollow. It does nothing after @@ -70,10 +74,13 @@ func (c *Children) IsHollow() bool { // Nothing but ServerRow should call this method. func (c *Children) Init() { if c.IsHollow() { - c.Box, _ = gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0) - c.Box.SetMarginStart(ChildrenMargin) - c.Box.SetHExpand(true) - childrenCSS(c.Box) + box, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0) + box.SetMarginStart(ChildrenMargin) + c.Box = *box + childrenCSS(box) + + // Show all margins by default. + c.SetExpand(true) // Check if we're still loading. This is effectively restoring the // state that was set before we had widgets. @@ -90,7 +97,7 @@ func (c *Children) Init() { func (c *Children) Reset() { // If the children container isn't hollow, then we have to remove the known // rows from the container box. - if c.Box != nil { + if c.Box.Object != nil { // Remove old servers from the list. for _, row := range c.Rows { if row.IsHollow() { @@ -104,6 +111,26 @@ func (c *Children) Reset() { c.Rows = nil } +// SetExpand sets whether or not to expand the margin and show the labels. +func (c *Children) SetExpand(expand bool) { + AssertUnhollow(c) + c.expand = expand + + if expand { + primitives.AddClass(c, "expand") + } else { + primitives.RemoveClass(c, "expand") + } + + for _, row := range c.Rows { + // Ensure that the row is initialized. If we're expanded, then show the + // label. + if row.Button != nil { + row.SetShowLabel(expand) + } + } +} + // setLoading shows the loading circle as a list child. If hollow, this function // will only update the state. func (c *Children) setLoading() { @@ -168,7 +195,7 @@ func (c *Children) SetServersUnsafe(servers []cchat.Server) { if server == nil { log.Panicln("one of given servers in SetServers is nil at ", i) } - c.Rows[i] = NewHollowServer(c, server, c.rowctrl) + c.Rows[i] = NewHollowServer(c, server, c) } // We should not unhollow everything here, but rather on uncollapse. @@ -205,7 +232,7 @@ func (c *Children) UpdateServerUnsafe(update cchat.ServerUpdate) { prevID, replace := update.PreviousID() // TODO: I don't think this code unhollows a new server. - var newServer = NewHollowServer(c, update, c.rowctrl) + var newServer = NewHollowServer(c, update, c) var i, oldRow = c.findID(prevID) // If we're appending a new row, then replace is false. @@ -246,23 +273,13 @@ func (c *Children) LoadAll() { // Restore expansion if possible. savepath.Restore(row, row.Button) } +} - // Check if we have icons. - var hasIcon bool - +// ForceIcons forces all of the children's row to show icons. +func (c *Children) ForceIcons() { for _, row := range c.Rows { - if row.HasIcon() { - hasIcon = true - break - } - } - - // If we have an icon, then show all other possibly empty icons. HdyAvatar - // will generate a placeholder. - if hasIcon { - for _, row := range c.Rows { - row.UseEmptyIcon() - } + row.UseEmptyIcon() + row.SetShowLabel(c.expand) } } diff --git a/internal/ui/service/session/server/commander/buffer.go b/internal/ui/service/session/server/commander/buffer.go index abf90ba..c4275fb 100644 --- a/internal/ui/service/session/server/commander/buffer.go +++ b/internal/ui/service/session/server/commander/buffer.go @@ -5,19 +5,20 @@ import ( "fmt" "github.com/diamondburned/cchat" + "github.com/diamondburned/cchat-gtk/internal/ui/rich" "github.com/gotk3/gotk3/gtk" ) // Buffer represents an unbuffered API around the text buffer. type Buffer struct { *gtk.TextBuffer - name string + name rich.LabelStateStorer cmder cchat.Commander } // NewBuffer creates a new buffer with the given SessionCommander, or returns // nil if cmder is nil. -func NewBuffer(name string, cmder cchat.Commander) *Buffer { +func NewBuffer(name rich.LabelStateStorer, cmder cchat.Commander) *Buffer { if cmder == nil { return nil } diff --git a/internal/ui/service/session/server/commander/commander.go b/internal/ui/service/session/server/commander/commander.go index 80b719f..e2fa567 100644 --- a/internal/ui/service/session/server/commander/commander.go +++ b/internal/ui/service/session/server/commander/commander.go @@ -39,10 +39,14 @@ func SpawnDialog(buf *Buffer) { s.Show() h, _ := gtk.HeaderBarNew() - h.SetTitle("Commander: " + buf.name) h.SetShowCloseButton(true) h.Show() + rm := buf.name.OnUpdate(func() { + h.SetTitle("Commander: " + buf.name.Label().Content) + }) + h.Connect("destroy", rm) + d, _ := gts.NewEmptyModalDialog() d.SetDefaultSize(450, 250) d.SetTitlebar(h) diff --git a/internal/ui/service/session/server/server.go b/internal/ui/service/session/server/server.go index ed8096e..1489964 100644 --- a/internal/ui/service/session/server/server.go +++ b/internal/ui/service/session/server/server.go @@ -1,25 +1,24 @@ package server import ( + "context" + "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/gts" "github.com/diamondburned/cchat-gtk/internal/log" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" "github.com/diamondburned/cchat-gtk/internal/ui/primitives/actions" - "github.com/diamondburned/cchat-gtk/internal/ui/primitives/roundimage" "github.com/diamondburned/cchat-gtk/internal/ui/rich" "github.com/diamondburned/cchat-gtk/internal/ui/service/savepath" "github.com/diamondburned/cchat-gtk/internal/ui/service/session/server/button" "github.com/diamondburned/cchat-gtk/internal/ui/service/session/server/commander" "github.com/diamondburned/cchat-gtk/internal/ui/service/session/server/traverse" - "github.com/diamondburned/cchat/text" "github.com/gotk3/gotk3/gdk" "github.com/gotk3/gotk3/gtk" "github.com/pkg/errors" ) -const ChildrenMargin = 24 -const IconSize = 32 +const ChildrenMargin = 0 // refer to style.css func AssertUnhollow(hollower interface{ IsHollow() bool }) { if hollower.IsHollow() { @@ -27,14 +26,21 @@ func AssertUnhollow(hollower interface{ IsHollow() bool }) { } } +// ParentController controls ServerRow's container, which is the Children +// struct. +type ParentController interface { + Controller + ForceIcons() +} + type ServerRow struct { *gtk.Box - Avatar *roundimage.Avatar - Button *button.ToggleButtonImage + Button *button.ToggleButton ActionsMenu *actions.Menu Server cchat.Server - ctrl Controller + name rich.NameContainer + ctrl ParentController parentcrumb traverse.Breadcrumber @@ -46,10 +52,12 @@ type ServerRow struct { childrev *gtk.Revealer children *Children serverList cchat.Lister + serverStop func() // State that's updated even when stale. Initializations will use these. unread bool mentioned bool + showLabel bool // callback to cancel unread indicator cancelUnread func() @@ -59,25 +67,28 @@ var serverCSS = primitives.PrepareClassCSS("server", ` /* Ignore first child because .server-children already covers this */ .server:not(:first-child) { margin: 0; - margin-top: 3px; border-radius: 0; } + + .server.active-column { + background-color: mix(@theme_bg_color, @theme_selected_bg_color, 0.25); + } `) // NewHollowServer creates a new hollow ServerRow. It will automatically create // hollow children containers and rows for the given server. -func NewHollowServer(p traverse.Breadcrumber, sv cchat.Server, ctrl Controller) *ServerRow { - var serverRow = &ServerRow{ +func NewHollowServer(p traverse.Breadcrumber, sv cchat.Server, ctrl ParentController) *ServerRow { + serverRow := ServerRow{ parentcrumb: p, ctrl: ctrl, Server: sv, cancelUnread: func() {}, } - var ( - lister = sv.AsLister() - messenger = sv.AsMessenger() - ) + serverRow.name.QueueNamer(context.Background(), sv) + + lister := sv.AsLister() + messenger := sv.AsMessenger() switch { case lister != nil: @@ -87,7 +98,7 @@ func NewHollowServer(p traverse.Breadcrumber, sv cchat.Server, ctrl Controller) case messenger != nil: if unreader := messenger.AsUnreadIndicator(); unreader != nil { gts.Async(func() (func(), error) { - c, err := unreader.UnreadIndicate(serverRow) + c, err := unreader.UnreadIndicate(&serverRow) if err != nil { return nil, errors.Wrap(err, "Failed to use unread indicator") } @@ -97,7 +108,7 @@ func NewHollowServer(p traverse.Breadcrumber, sv cchat.Server, ctrl Controller) } } - return serverRow + return &serverRow } // Init brings the row out of the hollow state. It loads the children (if any), @@ -108,19 +119,13 @@ func (r *ServerRow) Init() { } // Initialize the row, which would fill up the button and others as well. - r.Avatar = roundimage.NewAvatar(IconSize) - r.Avatar.SetText(r.Server.Name().Content) - r.Avatar.Show() - btn := rich.NewCustomToggleButtonImage(r.Avatar, r.Server.Name()) - btn.Show() - - r.Button = button.WrapToggleButtonImage(btn) - r.Button.Box.SetHAlign(gtk.ALIGN_START) - r.Button.SetRelief(gtk.RELIEF_NONE) + r.Button = button.NewToggleButton(&r.name) + r.Button.SetShowLabel(r.showLabel) r.Button.Show() r.Box, _ = gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0) + r.Box.SetHAlign(gtk.ALIGN_FILL) r.Box.PackStart(r.Button, false, false, 0) serverCSS(r.Box) @@ -131,9 +136,6 @@ func (r *ServerRow) Init() { // Ensure errors are displayed. r.childrenSetErr(r.childrenErr) - // Try to set an icon. - r.SetIconer(r.Server) - // Connect the destroyer, if any. r.Connect("destroy", func(interface{}) { r.cancelUnread() }) @@ -141,7 +143,7 @@ func (r *ServerRow) Init() { r.Button.SetUnreadUnsafe(r.unread, r.mentioned) // update with state if cmder := r.Server.AsCommander(); cmder != nil { - r.cmder = commander.NewBuffer(r.Server.Name().String(), cmder) + r.cmder = commander.NewBuffer(&r.name, cmder) r.ActionsMenu.AddAction("Command Prompt", r.cmder.ShowDialog) } @@ -152,13 +154,21 @@ func (r *ServerRow) Init() { } }) + // Bring up the icons of all the current level's rows if we have one. + r.name.OnUpdate(func() { + if r.name.Image().HasImage() { + r.ctrl.ForceIcons() + } + }) + var ( lister = r.Server.AsLister() + columnate = lister != nil && lister.Columnate() messenger = r.Server.AsMessenger() ) switch { - case lister != nil: + case lister != nil && !columnate: primitives.AddClass(r, "server-list") r.children.Init() r.children.Show() @@ -171,15 +181,35 @@ func (r *ServerRow) Init() { r.Box.PackStart(r.childrev, false, false, 0) r.Button.SetClicked(r.SetRevealChild) + case lister != nil && columnate: + primitives.AddClass(r, "server-list") + primitives.AddClass(r, "server-columnate") + r.Button.SetClicked(func(active bool) { + if active { + r.ctrl.SelectColumnatedLister(r, lister) + } else { + r.ctrl.SelectColumnatedLister(r, nil) + } + }) + case messenger != nil: primitives.AddClass(r, "server-message") - r.Button.SetClicked(func(bool) { r.ctrl.MessengerSelected(r) }) + r.Button.SetClicked(func(active bool) { + if active { + r.ctrl.MessengerSelected(r) + } else { + r.ctrl.ClearMessenger() + } + }) } + + // Restore the label visibility state. + r.SetShowLabel(r.showLabel) } -// GetActiveServerMessage returns true if the row is currently selected AND it +// IsActiveServerMessage returns true if the row is currently selected AND it // is a message row. -func (r *ServerRow) GetActiveServerMessage() bool { +func (r *ServerRow) IsActiveServerMessage() bool { // If the button is nil, then that probably means we're still in a hollow // state. This obviously means nothing is being selected. if r.Button == nil { @@ -196,7 +226,7 @@ func (r *ServerRow) SetUnread(unread, mentioned bool) { func (r *ServerRow) SetUnreadUnsafe(unread, mentioned bool) { // We're never unread if we're reading this current server. - if r.GetActiveServerMessage() { + if r.IsActiveServerMessage() { unread, mentioned = false, false } @@ -243,12 +273,14 @@ func (r *ServerRow) load(finish func(error)) { } go func() { - var err = list.Servers(children) + stop, err := list.Servers(children) if err != nil { log.Error(errors.Wrap(err, "Failed to get servers")) } gts.ExecAsync(func() { + r.serverStop = stop + // Announce that we're not loading anymore. r.children.setNotLoading() @@ -273,6 +305,11 @@ func (r *ServerRow) Reset() { r.children.Destroy() } + if r.serverStop != nil { + r.serverStop() + r.serverStop = nil + } + // Reset the state. r.ActionsMenu.Reset() r.serverList = nil @@ -298,14 +335,36 @@ func (r *ServerRow) childrenSetErr(err error) { // UseEmptyIcon forces the row to show a placeholder icon. func (r *ServerRow) UseEmptyIcon() { AssertUnhollow(r) - - r.Button.Image.SetSize(IconSize) - r.Button.Image.SetRevealChild(true) + r.Button.UseEmptyIcon() } // HasIcon returns true if the current row has an icon. func (r *ServerRow) HasIcon() bool { - return !r.IsHollow() && r.Button.Image.GetRevealChild() + return !r.IsHollow() && r.Button.Image != nil +} + +// SetShowLabel sets whether or not to show the button's (and its children's, if +// any)'s icons. +func (r *ServerRow) SetShowLabel(showLabel bool) { + r.showLabel = showLabel + + if r.IsHollow() { + return + } + + r.Button.SetShowLabel(showLabel) + + // We'd want the button to be wide if we're showing the label. Otherwise, + // it can be small. + if r.Button.GetShowLabel() { + r.Box.SetHAlign(gtk.ALIGN_FILL) + } else { + r.Box.SetHAlign(gtk.ALIGN_START) + } + + if r.children != nil && !r.children.IsHollow() { + r.children.SetExpand(showLabel) + } } func (r *ServerRow) ParentBreadcrumb() traverse.Breadcrumber { @@ -316,28 +375,18 @@ func (r *ServerRow) Breadcrumb() string { if r.IsHollow() { return "" } - return r.Button.GetText() + + return r.name.String() } +// ID returns the server ID. func (r *ServerRow) ID() cchat.ID { return r.Server.ID() } -func (r *ServerRow) SetLabelUnsafe(name text.Rich) { - AssertUnhollow(r) - - r.Button.SetLabelUnsafe(name) - r.Avatar.SetText(name.Content) -} - -// SetIconer takes in a Namer for AsIconer. -func (r *ServerRow) SetIconer(v cchat.Namer) { - AssertUnhollow(r) - - if iconer := v.AsIconer(); iconer != nil { - r.Button.Image.SetSize(IconSize) - r.Button.Image.AsyncSetIconer(iconer, "Error getting server icon URL") - } +// Name returns the name state. +func (r *ServerRow) Name() rich.LabelStateStorer { + return &r.name } // SetLoading is called by the parent struct. @@ -357,7 +406,6 @@ func (r *ServerRow) SetFailed(err error, retry func()) { r.SetSensitive(true) r.SetTooltipText(err.Error()) r.Button.SetFailed(err, retry) - r.Button.Label.SetMarkup(rich.MakeRed(r.Button.GetLabel())) r.ActionsMenu.Reset() r.ActionsMenu.AddAction("Retry", retry) } @@ -372,14 +420,6 @@ func (r *ServerRow) SetDone() { r.SetTooltipText("") } -// func (r *ServerRow) SetNormalExtraMenu(items []menu.Item) { -// AssertUnhollow(r) - -// r.Button.SetNormalExtraMenu(items) -// r.SetSensitive(true) -// r.SetTooltipText("") -// } - // SetSelected is used for highlighting the current message server. func (r *ServerRow) SetSelected(selected bool) { AssertUnhollow(r) @@ -411,6 +451,12 @@ func (r *ServerRow) SetRevealChild(reveal bool) { // Save the path. savepath.Update(r, reveal) + if reveal { + primitives.AddClass(r, "expanded") + } else { + primitives.RemoveClass(r, "expanded") + } + // If this isn't a reveal, then we don't need to load. if !reveal { return diff --git a/internal/ui/service/session/server/traverse/traverse.go b/internal/ui/service/session/server/traverse/traverse.go index d55adc4..142d6f4 100644 --- a/internal/ui/service/session/server/traverse/traverse.go +++ b/internal/ui/service/session/server/traverse/traverse.go @@ -22,6 +22,8 @@ type Breadcrumber interface { type BreadcrumbNamer interface { // Breadcrumb returns the breadcrumb name. Breadcrumb() string + + // TODO: make BreadcrumbNamer return LabelState. } // Traverse traverses the given breadcrumber recursively. If traverser returns diff --git a/internal/ui/service/session/serverpane/serverpane.go b/internal/ui/service/session/serverpane/serverpane.go new file mode 100644 index 0000000..95cc8e6 --- /dev/null +++ b/internal/ui/service/session/serverpane/serverpane.go @@ -0,0 +1,64 @@ +package serverpane + +import ( + "github.com/gotk3/gotk3/gtk" +) + +// Paned replaces gtk.Paned or gtk.Box to allow an optional second pane. +type Paned struct { + gtk.IWidget + Box *gtk.Box + + orien gtk.Orientation + + w1 gtk.IWidget + w2 gtk.IWidget +} + +// NewPaned creates a new empty pane. +func NewPaned(w1 gtk.IWidget, o gtk.Orientation) *Paned { + // box holds either paned or w1. + box, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) + box.PackStart(w1, true, true, 0) + + return &Paned{ + IWidget: box, + Box: box, + + orien: o, + w1: w1, + } +} + +func (p *Paned) Destroy() { + p.Box.Destroy() + *p = Paned{} +} + +func (p *Paned) Show() { + p.Box.Show() +} + +// AddSide adds a side widget. If a second widget is already added, then it is +// removed from the pane. +func (p *Paned) AddSide(w gtk.IWidget) { + if p.w2 != nil { + p.Box.Remove(p.w2) + } + + p.w2 = w + p.Box.PackStart(p.w2, true, true, 0) + p.Box.SetChildPacking(p.w1, false, false, 0, gtk.PACK_START) +} + +// Remove removes either w1 or w2. If neither matches, then nothing is done. +func (p *Paned) Remove(w gtk.IWidget) { + switch w { + case p.w1: + panic("p.w1 must not be removed") + case p.w2: + p.Box.Remove(p.w2) + p.w2 = nil + p.Box.SetChildPacking(p.w1, true, true, 0, gtk.PACK_START) + } +} diff --git a/internal/ui/service/session/servers.go b/internal/ui/service/session/servers.go index 2040e5e..7579378 100644 --- a/internal/ui/service/session/servers.go +++ b/internal/ui/service/session/servers.go @@ -10,6 +10,7 @@ import ( "github.com/diamondburned/cchat-gtk/internal/ui/primitives/spinner" "github.com/diamondburned/cchat-gtk/internal/ui/service/session/server" "github.com/diamondburned/cchat-gtk/internal/ui/service/session/server/traverse" + "github.com/diamondburned/cchat-gtk/internal/ui/service/session/serverpane" "github.com/gotk3/gotk3/gtk" "github.com/gotk3/gotk3/pango" ) @@ -20,59 +21,102 @@ const ListWidth = 200 // SessionController extends server.Controller to add needed methods that the // specific top-level servers container needs. type SessionController interface { - server.Controller ClearMessenger() + MessengerSelected(*server.ServerRow) } -// Servers wraps around a list of servers inherited from Children. It's the -// container that's displayed on the right of the service sidebar. +// Servers wraps around a list of servers inherited from Children to display a +// Lister in its own box instead of as a nested list. It's the container that's +// displayed on the right of the service sidebar. type Servers struct { - *gtk.Box + gtk.Stack + SessionController + + spinner *spinner.Boxed + // Main is the horizontal box containing the current struct's list of + // servers columnated with the same level. The second item in the box should + // be the selected server. + Main *serverpane.Paned + + // Lister is the current lister belonging to this server. + Lister cchat.Lister + stopLs func() + + // Children is main's lhs. Children *server.Children - spinner *spinner.Boxed // non-nil if loading. - ctrl SessionController - - // state - ServerList cchat.Lister + // NextColumn is main's rhs. + NextColumn *Servers // nil + detachNext func() } var toplevelCSS = primitives.PrepareClassCSS("top-level", ` .top-level { - margin: 0 3px; - margin-top: 3px; } `) +// NewServers creates a new Servers instance that holds only the given column +// number and its children. Any servers with a different columnate ID will be in +// the children pane. func NewServers(p traverse.Breadcrumber, ctrl SessionController) *Servers { - c := server.NewChildren(p, ctrl) - c.SetMarginStart(0) // children is top level; there is no main row - c.SetVExpand(true) - c.Show() - toplevelCSS(c) - - b, _ := gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) - - return &Servers{ - Box: b, - Children: c, - ctrl: ctrl, + servers := Servers{ + SessionController: ctrl, } + + servers.Children = server.NewChildren(p, &servers) + servers.Children.SetVExpand(true) + servers.Children.Show() + toplevelCSS(servers.Children) + + servers.Main = serverpane.NewPaned(servers.Children, gtk.ORIENTATION_VERTICAL) + servers.Main.Show() + + stack, _ := gtk.StackNew() + servers.Stack = *stack + servers.Stack.SetVAlign(gtk.ALIGN_START) + servers.Stack.SetTransitionType(gtk.STACK_TRANSITION_TYPE_CROSSFADE) + servers.Stack.SetTransitionDuration(75) + servers.Stack.AddNamed(servers.Main, "main") + servers.Stack.Show() + + return &servers +} + +// Destroy destroys and invalidates this instance permanently. +func (s *Servers) Destroy() { + s.Reset() + s.Stack.Destroy() } func (s *Servers) Reset() { // Reset isn't necessarily called while loading, so we do a check. if s.spinner != nil { - s.spinner.Stop() + s.spinner.Destroy() s.spinner = nil } + // Close the right server column if any. + if s.NextColumn != nil { + if s.detachNext != nil { + s.detachNext() + } + + s.Main.Remove(s.NextColumn) + s.NextColumn.Destroy() + s.NextColumn = nil + } + + // Call the destructor if any. + if s.stopLs != nil { + s.stopLs() + s.stopLs = nil + } + // Reset the state. - s.ServerList = nil - // Remove all children. - primitives.RemoveChildren(s) + s.Lister = nil // Reset the children container. s.Children.Reset() + s.Stack.SetVisibleChild(s.Main) } // IsLoading returns true if the servers container is loading. @@ -83,8 +127,12 @@ func (s *Servers) IsLoading() bool { // SetList indicates that the server list has been loaded. Unlike // server.Children, this method will load immediately. func (s *Servers) SetList(slist cchat.Lister) { - primitives.RemoveChildren(s) - s.ServerList = slist + if s.stopLs != nil { + s.stopLs() + s.stopLs = nil + } + + s.Lister = slist s.load() } @@ -98,11 +146,12 @@ func (s *Servers) load() { s.setLoading() go func() { - err := s.ServerList.Servers(s) + stop, err := s.Lister.Servers(s) gts.ExecAsync(func() { if err != nil { s.setFailed(err) } else { + s.stopLs = stop s.setDone() } }) @@ -114,8 +163,8 @@ func (s *Servers) SetServers(servers []cchat.Server) { gts.ExecAsync(func() { s.Children.SetServersUnsafe(servers) - if len(servers) == 0 { - s.ctrl.ClearMessenger() + if servers == nil { + s.ClearMessenger() return } @@ -131,37 +180,38 @@ func (s *Servers) UpdateServer(update cchat.ServerUpdate) { // setDone changes the view to show the servers. func (s *Servers) setDone() { - primitives.RemoveChildren(s) + s.SetVisibleChild(s.Main) // stop the spinner. - s.spinner.Stop() + s.spinner.Destroy() s.spinner = nil - - s.Add(s.Children) } // setLoading shows a loading spinner. Use this after the session row is // connected. func (s *Servers) setLoading() { - primitives.RemoveChildren(s) - s.spinner = spinner.New() s.spinner.SetSizeRequest(FaceSize, FaceSize) s.spinner.Show() s.spinner.Start() - s.Add(s.spinner) + s.AddNamed(s.spinner, "spinner") + s.SetVisibleChildName("spinner") } // setFailed shows a sad face with the error. Use this when the session row has // failed to load. func (s *Servers) setFailed(err error) { - primitives.RemoveChildren(s) - - // stop the spinner. Let this SEGFAULT if nil, as that's undefined behavior. - s.spinner.Stop() + // stop the spinner. Let this SEGFAULT if nil. + s.spinner.Destroy() s.spinner = nil + // Remove existing error widgets. + w, err := s.Stack.GetChildByName("error") + if err == nil { + s.Stack.Remove(w) + } + // Create a BLANK label for padding. ltop, _ := gtk.LabelNew("") ltop.Show() @@ -182,7 +232,49 @@ func (s *Servers) setFailed(err error) { lerr.Show() // Add these items into the box. - s.PackStart(ltop, false, false, 0) - s.PackStart(btn, false, false, 10) // pad - s.PackStart(lerr, false, false, 0) + b, _ := gtk.BoxNew(gtk.ORIENTATION_VERTICAL, 0) + b.PackStart(ltop, false, false, 0) + b.PackStart(btn, false, false, 10) // pad + b.PackStart(lerr, false, false, 0) + b.Show() + + s.Stack.AddNamed(b, "error") + s.Stack.SetVisibleChildName("error") +} + +// SelectColumnatedLister is called by children servers to open up a server list +// on the right. +func (s *Servers) SelectColumnatedLister(srv *server.ServerRow, lst cchat.Lister) { + if s.detachNext != nil { + s.Main.Remove(s.NextColumn) // run the deconstructor + s.detachNext() + s.NextColumn.Destroy() + } + + if lst == nil { + return + } + + s.NextColumn = NewServers(srv, s) + s.NextColumn.SetList(lst) + s.Main.AddSide(s.NextColumn) + + update := func(box *gtk.Box) { + a := box.GetAllocation() + // Align the next column to the selected item. + s.NextColumn.SetMarginTop(a.GetY()) + } + + s.Children.SetExpand(false) + primitives.AddClass(srv, "active-column") + + update(srv.Box) + sizeHandle := srv.Box.Connect("size-allocate", update) + + s.detachNext = func() { + srv.Box.HandlerDisconnect(sizeHandle) + + s.Children.SetExpand(true) + primitives.RemoveClass(srv, "active-column") + } } diff --git a/internal/ui/service/session/session.go b/internal/ui/service/session/session.go index 9c0b68c..e7b9103 100644 --- a/internal/ui/service/session/session.go +++ b/internal/ui/service/session/session.go @@ -1,6 +1,8 @@ package session import ( + "context" + "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/gts" "github.com/diamondburned/cchat-gtk/internal/keyring" @@ -9,9 +11,7 @@ import ( "github.com/diamondburned/cchat-gtk/internal/ui/primitives/actions" "github.com/diamondburned/cchat-gtk/internal/ui/primitives/drag" "github.com/diamondburned/cchat-gtk/internal/ui/primitives/roundimage" - "github.com/diamondburned/cchat-gtk/internal/ui/primitives/spinner" "github.com/diamondburned/cchat-gtk/internal/ui/rich" - "github.com/diamondburned/cchat-gtk/internal/ui/rich/parser/markup" "github.com/diamondburned/cchat-gtk/internal/ui/service/session/server" "github.com/diamondburned/cchat-gtk/internal/ui/service/session/server/button" "github.com/diamondburned/cchat-gtk/internal/ui/service/session/server/commander" @@ -55,9 +55,9 @@ type Controller interface { // Row represents a session row entry in the session List. type Row struct { *gtk.ListBoxRow - avatar *roundimage.Avatar + name rich.NameContainer iconBox *gtk.EventBox - icon *rich.Icon // nillable + icon *roundimage.StillImage // nillable ctrl Controller parentcrumb traverse.Breadcrumber @@ -80,6 +80,10 @@ type Row struct { var rowCSS = primitives.PrepareClassCSS("session-row", button.UnreadColorDefs+` + .session-row { + padding: 6px; + } + .session-row:last-child { border-radius: 0 0 14px 14px; } @@ -117,32 +121,21 @@ var rowCSS = primitives.PrepareClassCSS("session-row", } `) -var rowIconCSS = primitives.PrepareClassCSS("session-icon", ` - .session-icon { - padding: 4px; - margin: 0; - } -`) +var rowIconCSS = primitives.PrepareClassCSS("session-icon", ``) -const IconSize = 48 -const IconName = "face-plain-symbolic" - -func newIcon(img rich.RoundIconContainer) *rich.Icon { - icon := rich.NewCustomIcon(img, IconSize) - icon.SetPlaceholderIcon(IconName, IconSize) - icon.ShowAll() - rowIconCSS(icon) - return icon -} +const ( + IconSize = 42 + IconName = "face-plain-symbolic" +) func New(parent traverse.Breadcrumber, ses cchat.Session, ctrl Controller) *Row { - row := newRow(parent, text.Rich{}, ctrl) + row := newRow(parent, text.Plain(""), ctrl) row.SetSession(ses) return row } func NewLoading(parent traverse.Breadcrumber, id, name string, ctrl Controller) *Row { - row := newRow(parent, text.Rich{Content: name}, ctrl) + row := newRow(parent, text.Plain(name), ctrl) row.sessionID = id row.SetLoading() return row @@ -154,17 +147,32 @@ func newRow(parent traverse.Breadcrumber, name text.Rich, ctrl Controller) *Row parentcrumb: parent, } - row.avatar = roundimage.NewAvatar(IconSize) - row.avatar.SetText(name.Content) - row.avatar.Show() + if !name.IsEmpty() { + row.name.LabelState = *rich.NewLabelState(name) + } row.iconBox, _ = gtk.EventBoxNew() row.iconBox.Show() + row.icon = roundimage.NewStillImage(row.iconBox, 0) + row.icon.SetSizeRequest(IconSize, IconSize) + row.icon.SetPlaceholderIcon(IconName, IconSize/2) + row.icon.Show() + rowIconCSS(row.icon) + + row.iconBox.Add(row.icon) + rich.BindRoundImage(row.icon, &row.name, true) + row.ListBoxRow, _ = gtk.ListBoxRowNew() + row.ListBoxRow.Add(row.iconBox) row.ListBoxRow.Show() rowCSS(row.ListBoxRow) + row.name.OnUpdate(func() { + // TODO: proper popovers instead of tooltips. + row.ListBoxRow.SetTooltipText(row.name.String()) + }) + // TODO: commander button row.Servers = NewServers(row, row) @@ -216,6 +224,11 @@ func NewAddButton() *gtk.ListBoxRow { return row } +// Name returns the session row's name container. +func (r *Row) Name() rich.LabelStateStorer { + return &r.name +} + // Reset extends the server row's Reset function and resets additional states. // It resets all states back to nil, but the session ID stays. func (r *Row) Reset() { @@ -223,14 +236,10 @@ func (r *Row) Reset() { r.ActionsMenu.Reset() // wipe menu items r.ActionsMenu.AddAction("Remove", r.RemoveSession) - if r.icon == nil { - r.icon = newIcon(r.avatar) - r.iconBox.Add(r.icon) - } - // Set a lame placeholder icon. r.icon.SetPlaceholderIcon("folder-remote-symbolic", IconSize) + r.name.Stop() r.Session = nil r.cmder = nil } @@ -243,7 +252,8 @@ func (r *Row) Breadcrumb() string { if r.Session == nil { return "" } - return r.Session.Name().Content + + return r.name.String() } func (r *Row) ClearMessenger() { @@ -273,25 +283,11 @@ func (r *Row) Activate() { func (r *Row) SetLoading() { // Reset the state. r.Session = nil - - // Reset the icon. - primitives.RemoveChildren(r.iconBox) - r.icon = nil - - // Remove everything from the row, including the icon. - primitives.RemoveChildren(r) + r.name.Stop() // Remove the failed class. primitives.RemoveClass(r, "failed") - // Add a loading circle. - spin := spinner.New() - spin.SetSizeRequest(IconSize, IconSize) - spin.Start() - spin.Show() - rowIconCSS(spin) - - r.Add(spin) r.SetSensitive(false) // no activate } @@ -303,18 +299,8 @@ func (r *Row) SetFailed(err error) { r.Session = nil // Re-enable the row. r.SetSensitive(true) - // Remove everything off the row. - primitives.RemoveChildren(r) // Mark the row as failed. primitives.AddClass(r, "failed") - - if r.icon == nil { - r.icon = newIcon(r.avatar) - r.iconBox.Add(r.icon) - } - - // Add the icon. - r.Add(r.iconBox) // Set the button to a retry icon. r.icon.SetPlaceholderIcon("view-refresh-symbolic", IconSize) } @@ -338,25 +324,11 @@ func (r *Row) SetSession(ses cchat.Session) { // Set the states. r.Session = ses r.sessionID = ses.ID() - r.SetTooltipMarkup(markup.Render(ses.Name())) - r.avatar.SetText(ses.Name().Content) - - if r.icon == nil { - r.icon = newIcon(r.avatar) - r.iconBox.Add(r.icon) - } - r.icon.SetPlaceholderIcon(IconName, IconSize) - - // If the session has an icon, then use it. - if iconer := ses.AsIconer(); iconer != nil { - r.icon.AsyncSetIconer(iconer, "failed to set session icon") - } + r.name.QueueNamer(context.Background(), ses) // Update to indicate that we're done. - primitives.RemoveChildren(r) r.SetSensitive(true) - r.Add(r.iconBox) // Bind extra menu items before loading. These items won't be clickable // during loading. @@ -368,7 +340,7 @@ func (r *Row) SetSession(ses cchat.Session) { // returns nil. As such, we assert with an ignored ok bool, allowing cmd to // be nil. if cmder := ses.AsCommander(); cmder != nil { - r.cmder = commander.NewBuffer(ses.Name().String(), cmder) + r.cmder = commander.NewBuffer(&r.name, cmder) // Show the command button if the session actually supports the // commander. r.ActionsMenu.AddAction("Command Prompt", r.ShowCommander) diff --git a/internal/ui/service/view.go b/internal/ui/service/view.go index a1264c9..655a379 100644 --- a/internal/ui/service/view.go +++ b/internal/ui/service/view.go @@ -3,8 +3,6 @@ package service import ( "github.com/diamondburned/cchat" "github.com/diamondburned/cchat-gtk/internal/ui/primitives" - "github.com/diamondburned/cchat-gtk/internal/ui/primitives/singlestack" - "github.com/diamondburned/cchat-gtk/internal/ui/primitives/spinner" "github.com/diamondburned/cchat-gtk/internal/ui/service/session" "github.com/diamondburned/cchat-gtk/internal/ui/service/session/server" "github.com/gotk3/gotk3/gtk" @@ -36,10 +34,6 @@ type View struct { Services *List ServerView *gtk.ScrolledWindow - - ServerStack *singlestack.Stack - - // Servers *session.Servers // nil by default; use .Servers } func NewView(ctrller Controller) *View { @@ -52,18 +46,10 @@ func NewView(ctrller Controller) *View { view.Header.AppMenuBindSize(view.Services) view.Header.Show() - // Make a stack for the middle panel. - view.ServerStack = singlestack.NewStack() - view.ServerStack.SetSizeRequest(150, -1) // min width - view.ServerStack.SetTransitionDuration(50) - view.ServerStack.SetTransitionType(gtk.STACK_TRANSITION_TYPE_CROSSFADE) - view.ServerStack.SetHomogeneous(true) - view.ServerStack.Show() - primitives.AddClass(view.ServerStack, "server-stack") - view.ServerView, _ = gtk.ScrolledWindowNew(nil, nil) view.ServerView.SetPolicy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) - view.ServerView.Add(view.ServerStack) + view.ServerView.SetHExpand(true) + view.ServerView.SetVExpand(true) view.ServerView.Show() view.BottomPane, _ = gtk.BoxNew(gtk.ORIENTATION_HORIZONTAL, 0) @@ -95,14 +81,8 @@ func (v *View) SessionSelected(svc *Service, srow *session.Row) { } } - // !!!: SHITTY HACK!!! - // We can do this, as we're keeping all the server lists in memory by Go's - // reference anyway. In fact, cchat REQUIRES us to do so. - if srow.Session != nil { - v.ServerStack.SetVisibleChild(srow.Servers) - } else { - v.ServerStack.SetVisibleChild(spinner.NewVisible()) - } + primitives.RemoveChildren(v.ServerView) + v.ServerView.Add(srow.Servers) v.Header.SetSessionMenu(srow) v.Header.SetBreadcrumber(srow) diff --git a/internal/ui/style.css b/internal/ui/style.css new file mode 100644 index 0000000..e2e1fb1 --- /dev/null +++ b/internal/ui/style.css @@ -0,0 +1,51 @@ +/* + * Global CSS + */ + +/* Make CSS more consistent across themes */ +headerbar { padding-left: 0 } + +/* .appmenu { margin: 0 20px } */ + +popover > *:not(stack):not(button) { margin: 6px } + +/* Hack to fix the input bar being high in Adwaita */ +.input-field * { min-height: 0 } + +/* Hide all scroll undershoots */ +undershoot { background-size: 0 } + +/* + * Server CSS + */ + +.top-level .server-list.expanded { + background-color: @borders; +} + +.top-level .server-button { + border-radius: 0; + background-color: transparent; +} + +/* .top-level .server-button:checked + revealer { */ +/* border-left: 2px solid alpha(@borders, 0.75); */ +/* } */ + +.top-level .server-children { + transition: margin-left 100ms; +} + +.top-level.expand .server-button:checked + revealer > .server-children { + margin-left: 18px; +} + +/* Keep this consistent with server.go's background-color. */ +.top-level + stack .top-level { + background-color: alpha(@theme_selected_bg_color, 0.25); +} + +/* Prevent inconsistent color when hovering over an active button. */ +.server.active-column .server-button:focus { + box-shadow: none; +} diff --git a/internal/ui/ui.go b/internal/ui/ui.go index dbce92e..07aa154 100644 --- a/internal/ui/ui.go +++ b/internal/ui/ui.go @@ -17,28 +17,20 @@ import ( "github.com/gotk3/gotk3/glib" "github.com/gotk3/gotk3/gtk" "github.com/pkg/errors" + + _ "embed" ) +//go:embed style.css +var styleCSS string + func init() { // Load the local CSS. - gts.LoadCSS("main", ` - /* Make CSS more consistent across themes */ - headerbar { padding-left: 0 } - - /* .appmenu { margin: 0 20px } */ - - popover > *:not(stack):not(button) { margin: 6px } - - /* Hack to fix the input bar being high in Adwaita */ - .input-field * { min-height: 0 } - - /* Hide all scroll undershoots */ - undershoot { background-size: 0 } - `) + gts.LoadCSS("main", styleCSS) } // constraints for the left panel -const leftCurrentWidth = 300 +const leftCurrentWidth = 350 func clamp(n, min, max int) int { switch { @@ -186,7 +178,7 @@ func (app *App) MessengerSelected(ses *session.Row, srv *server.ServerRow) { app.lastSelector = srv.SetSelected app.lastSelector(true) - app.MessageView.JoinServer(ses.Session, srv.Server, srv) + app.MessageView.JoinServer(ses, srv, srv) } // MessageView methods. @@ -207,8 +199,8 @@ func (app *App) OnMessageDone() { } func (app *App) AuthenticateSession(list *service.List, ssvc *service.Service) { - var svc = ssvc.Service() - auth.NewDialog(svc.Name(), svc.Authenticate(), func(ses cchat.Session) { + svc := ssvc.Service() + auth.NewDialog(ssvc.Name.Label(), svc.Authenticate(), func(ses cchat.Session) { ssvc.AddSession(ses) }) } @@ -219,14 +211,12 @@ func (app *App) Close() { // done, the application would exit immediately. There's no need to update // the GUI. for _, s := range app.Services.Services.Services { - var service = s.Service().Name() - for _, session := range s.BodyList.Sessions() { if session.Session == nil { continue } - log.Printlnf("Disconnecting %s session %s", service, session.ID()) + log.Printlnf("Disconnecting %s session %s", s.ID(), session.ID()) if err := session.Session.Disconnect(); err != nil { log.Error(errors.Wrap(err, "Failed to disconnect "+session.ID())) diff --git a/main.go b/main.go index 614e7ad..89812ba 100644 --- a/main.go +++ b/main.go @@ -10,11 +10,7 @@ import ( "github.com/diamondburned/cchat-gtk/internal/ui/config" "github.com/diamondburned/cchat/services" - // _ "github.com/diamondburned/gotk3-tcmalloc" - // "github.com/diamondburned/gotk3-tcmalloc/heapprofiler" - _ "github.com/diamondburned/cchat-discord" - _ "github.com/diamondburned/cchat-mock" ) func init() { diff --git a/profile.go b/profile.go new file mode 100644 index 0000000..1450c3c --- /dev/null +++ b/profile.go @@ -0,0 +1,15 @@ +// Code generated by goprofiler. DO NOT EDIT. + +package main + +import ( + "net/http" + _ "net/http/pprof" +) + +func init() { + go func() { + println("Serving HTTP at 127.0.0.1:48574 for profiler at /debug/pprof") + panic(http.ListenAndServe("127.0.0.1:48574", nil)) + }() +} diff --git a/shell.nix b/shell.nix index 2266e6c..5cfc805 100644 --- a/shell.nix +++ b/shell.nix @@ -1,31 +1,11 @@ { pkgs ? import {} }: -let nostrip = pkg: pkgs.enableDebugging (pkg.overrideAttrs(old: { - dontStrip = true; - doCheck = false; - NIX_CFLAGS_COMPILE = (old.NIX_CFLAGS_COMPILE or "") + " -g"; - })); - - libhandy = pkgs.libhandy.overrideAttrs(old: { - name = "libhandy-1.0.1"; - src = builtins.fetchGit { - url = "https://gitlab.gnome.org/GNOME/libhandy.git"; - rev = "5cee0927b8b39dea1b2a62ec6d19169f73ba06c6"; - }; - patches = []; - - buildInputs = old.buildInputs ++ (with pkgs; [ - (nostrip gnome3.librsvg) - (nostrip gdk-pixbuf) - ]); - }); - -in pkgs.stdenv.mkDerivation rec { +pkgs.stdenv.mkDerivation rec { name = "cchat-gtk"; version = "0.0.2"; buildInputs = [ - libhandy + pkgs.libhandy pkgs.gnome3.gspell pkgs.gnome3.glib pkgs.gnome3.gtk