From c2c211fefbfa9a02f2ef4aa4f7c57541ae88b1f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wenkai=20Yin=28=E5=B0=B9=E6=96=87=E5=BC=80=29?= Date: Thu, 23 Dec 2021 14:42:22 +0800 Subject: [PATCH] Convert Pod Volume Restore resource/controller to the Kubebuilder framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert Pod Volume Restore resource/controller to the Kubebuilder framework Fixes #4134 Signed-off-by: Wenkai Yin(尹文开) --- Tiltfile | 2 +- changelogs/unreleased/4655-ywk253100 | 1 + .../v1/bases/velero.io_podvolumerestores.yaml | 34 +- config/crd/v1/crds/crds.go | 2 +- config/rbac/role.yaml | 38 ++ ..._restore.go => pod_volume_restore_type.go} | 14 + pkg/cmd/cli/restic/server.go | 125 ++--- pkg/cmd/cli/restic/server_test.go | 3 +- .../pod_volume_backup_controller.go | 6 +- .../pod_volume_restore_controller.go | 466 +++++++----------- .../pod_volume_restore_controller_test.go | 355 +++---------- pkg/util/kube/utils.go | 15 +- pkg/util/kube/utils_test.go | 14 +- 13 files changed, 381 insertions(+), 694 deletions(-) create mode 100644 changelogs/unreleased/4655-ywk253100 rename pkg/apis/velero/v1/{pod_volume_restore.go => pod_volume_restore_type.go} (72%) diff --git a/Tiltfile b/Tiltfile index ba36e3346..02da1df56 100644 --- a/Tiltfile +++ b/Tiltfile @@ -103,7 +103,7 @@ local_resource( local_resource( "restic_binary", - cmd = 'cd ' + '.' + ';mkdir -p _tiltbuild/restic; BIN=velero GOOS=linux GOARCH=amd64 RESTIC_VERSION=0.12.0 OUTPUT_DIR=_tiltbuild/restic ./hack/download-restic.sh', + cmd = 'cd ' + '.' + ';mkdir -p _tiltbuild/restic; BIN=velero GOOS=linux GOARCH=amd64 RESTIC_VERSION=0.13.1 OUTPUT_DIR=_tiltbuild/restic ./hack/download-restic.sh', ) # Note: we need a distro with a bash shell to exec into the Velero container diff --git a/changelogs/unreleased/4655-ywk253100 b/changelogs/unreleased/4655-ywk253100 new file mode 100644 index 000000000..cfc440fe7 --- /dev/null +++ b/changelogs/unreleased/4655-ywk253100 @@ -0,0 +1 @@ +Convert Pod Volume Restore resource/controller to the Kubebuilder framework \ No newline at end of file diff --git a/config/crd/v1/bases/velero.io_podvolumerestores.yaml b/config/crd/v1/bases/velero.io_podvolumerestores.yaml index 2ca79c571..c07c1c25f 100644 --- a/config/crd/v1/bases/velero.io_podvolumerestores.yaml +++ b/config/crd/v1/bases/velero.io_podvolumerestores.yaml @@ -16,7 +16,37 @@ spec: singular: podvolumerestore scope: Namespaced versions: - - name: v1 + - additionalPrinterColumns: + - description: Namespace of the pod containing the volume to be restored + jsonPath: .spec.pod.namespace + name: Namespace + type: string + - description: Name of the pod containing the volume to be restored + jsonPath: .spec.pod.name + name: Pod + type: string + - description: Name of the volume to be restored + jsonPath: .spec.volume + name: Volume + type: string + - description: Pod Volume Restore status such as New/InProgress + jsonPath: .status.phase + name: Status + type: string + - description: Pod Volume Restore status such as New/InProgress + format: int64 + jsonPath: .status.progress.totalBytes + name: TotalBytes + type: integer + - description: Pod Volume Restore status such as New/InProgress + format: int64 + jsonPath: .status.progress.bytesDone + name: BytesDone + type: integer + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 schema: openAPIV3Schema: properties: @@ -136,6 +166,8 @@ spec: type: object served: true storage: true + subresources: + status: {} status: acceptedNames: kind: "" diff --git a/config/crd/v1/crds/crds.go b/config/crd/v1/crds/crds.go index 54838c355..c1b8f96ea 100644 --- a/config/crd/v1/crds/crds.go +++ b/config/crd/v1/crds/crds.go @@ -34,7 +34,7 @@ var rawCRDs = [][]byte{ []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xb4V=s\xe36\x10\xed\xf9+v.\xc55\x11u7)\x92Q\x97\xf8\xae\xf0$\xf1x\xec\x1b7\x99\x14\x10\xb0\x127&\x01dw!\xc7\xf9\xf5\x19\x00\xa4%Q\xf4\xc5)\u008e\xfb\x85\x87\xf7v\x97lV\xabUc\"= \v\x05\xbf\x01\x13\t\xffR\xf4\xf9M\xda\xc7\x1f\xa4\xa5\xb0>|l\x1eɻ\r\\%\xd10ܡ\x84\xc4\x16?\xe1\x8e<)\x05\xdf\f\xa8\xc6\x195\x9b\x06\xc0x\x1f\xd4d\xb3\xe4W\x00\x1b\xbcr\xe8{\xe4\xd5\x1e}\xfb\x98\xb6\xb8M\xd4;\xe4R|:\xfa\xf0\xa1\xfd\xbe\xfd\xd0\x00Xƒ\xfe\x85\x06\x145C܀O}\xdf\x00x3\xe0\x06\x1c\xf6\xa8\xb85\xf61E\xc6?\x13\x8aJ{\xc0\x1e9\xb4\x14\x1a\x89h\xf3\xc1{\x0e)n\xe0\xe8\xa8\xf9#\xa8z\xa1O\xa5\xd4O\xa5\xd4]-U\xbc=\x89\xfe\xfcZ\xc4/4F\xc5>\xb1\xe9\x97\x01\x95\x00!\xbfO\xbd\xe1Ő\x06@l\x88\xb8\x81\x9b\f+\x1a\x8b\xae\x01\x18\xf9(0W\xe3\x8d\x0f\x1fk9\xdb\xe1`*~\x80\x10\xd1\xffx{\xfd\xf0\xdd\xfd\x99\x19\xc0\xa1X\xa6\xa8\x85\xd5\x05\xfc@\x02\x06F\x14\xa0a\x04\a\xc1#\x04\x86!0BE*\xedK\xd1\xc8!\"+M\xfc\xd5\xe7\xa4uN\xac3\b\xef3\xca\x1a\x05.\xf7\f\nh\x87\xd3Mэ\x17\x83\xb0\x03\xedH\x8012\n\xfa\xdaEg\x85!\a\x19\x0fa\xfb\aZm\xe1\x1e9\x97\x01\xe9B\xea]n\xb5\x03\xb2\x02\xa3\r{O\u007f\xbfԖ|\xcf|hot\x12\xf9\xf8\x90Wdoz8\x98>\xe1\xb7`\xbc\x83\xc1<\x03c>\x05\x92?\xa9WB\xa4\x85_3M\xe4wa\x03\x9dj\x94\xcdz\xbd'\x9dFƆaH\x9e\xf4y]\xba\x9f\xb6I\x03\xcb\xda\xe1\x01\xfb\xb5\xd0~e\xd8v\xa4h51\xaeM\xa4U\x81\xee\xcbش\x83\xfb\x86\xc7!\x93\xf7gX\xf597\x8c(\x93ߟ8J7\u007fE\x81\xdc\xcbU\xf6\x9aZoq$:\x9b2;w\x9f\xef\xbf\xc0tt\x11c\xce~\xe1\xfd\x98(G\t2a\xe4w\xc8U\xc4\x1d\x87\xa1\xd4D\xefb \xaf\xe5\xc5\xf6\x84~N\xbf\xa4\xed@*SKf\xadZ\xb8*{\x04\xb6\b):\xa3\xe8Z\xb8\xf6pe\x06쯌\xe0\xff.@fZV\x99طIp\xba\x02\xe7\xc1\x95\xb5\x13Ǵ\xa3^\xd1kah\xef#ڬ`&1gӎl\x19\x0f\xd8\x05\x86\xa7\x8el7\r\xed\x8cݗ\x01o\xcf\x1c\xcb\x03\x9d\x9fZ&/\xa5\xb9\xe7\xd5\xcbCю\x18g]\xb8:)\xf6&^\xd4h\x92\xff\xc8Lə\xb8\xb1\x89\x19\xbd\x8e\x95ʶXJz+\x17\xc8\x1c\xf8\xc2:\x03\xf5\xb9\x04\x95\xef\x9c!/`\xfc\xf3\x98\b\xda\x19\x85'\xe4<\x066\xa4\xbcgЁK\x17\xfc\x8d\xb4tX\xc5\xca\xc2F\x0e\x16Eڋ8R\x1c\x160}E\x9d\xfc\xe4o\xa8\xd9\xf6\xb8\x01儯(k\x98\xcd\xf3\xcc\x17;#\v\xadpF\xc1m\x8eY\xd2\x00\xebV\xc7\u007f\x17\xa1\xd0\xed\xd3py\xd2\nn\xf0i\xc1z\xedo9\xec\x19e\xde\xf2\xd9y[\xd9+\xdf\xd47\xb2\xb4ؔ\x17F\xc9\xfbΝ\xb0(\x1a\xd8\xec'^\x8f-l\xacŨ\xe8n\xe6\u007f\x1d\xefޝ\xfd>\x94W\x1b\xbc\xa3\xfa\xd3\x04\xbf\xfd\xdeԪ\xe8\x1e\xa6\xbf\x81l\xfc'\x00\x00\xff\xff\x8c\xdb\x1fܮ\t\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xb4WM\x8f\xdc6\f\xbd\xfbW\x10\xe9!-\x10{\x12\xf4\xd0bn\xed&\x87\xa0i\x10\xec\xa6{)z\xd0\xc8\x1c[]YREj6ۢ\xff\xbd\xa0dχdz\xbb9T7K\x14\xf5D>>\xd1U]ו\n\xe6\x16#\x19\xef֠\x82\xc1/\x8cN\xbe\xa8\xb9\xfb\x91\x1a\xe3W\xbb7՝q\xed\x1a\xae\x12\xb1\x1f\xae\x91|\x8a\x1a\xdf\xe2\xd68\xc3ƻj@V\xadb\xb5\xae\x00\x94s\x9e\x95L\x93|\x02h\xef8zk1\xd6\x1d\xba\xe6.mp\x93\x8cm1f\xe7\xd3ѻ\xd7\xcd\x0f\xcd\xeb\n@G\xcc\xdb?\x9b\x01\x89\xd5\x10\xd6\xe0\x92\xb5\x15\x80S\x03\xae\xa1\xf5\xf7\xcez\xd5F\xfc+!15;\xb4\x18}c|E\x01\xb5\x1c\xdaE\x9f\xc2\x1a\x0e\ve\xef\b\xa8\\\xe6\xed\xe8溸\xc9+\xd6\x10\xff\xb2\xb4\xfa\xc1\x8c\x16\xc1\xa6\xa8\xec9\x88\xbcH\xc6uɪx\xb6\\\x01\x90\xf6\x01\xd7\xf0Q`\x04\xa5\xb1\xad\x00ƻgX\xf5x\xbbݛ\xe2J\xf78\xa8\x82\x17\xc0\at?}z\u007f\xfb\xfd\xcd\xc94@\x8b\xa4\xa3\t\x9c#8\xc3\f\x86@\xc1\x88\x00\xd8\xefA\x81r\xa0\"\x9b\xad\xd2\f\xdb\xe8\a\xd8(}\x97\xc2\xde+\x80\xdf\xfc\x89\x9a\x81\xd8G\xd5\xe1+\xa0\xa4{P⯘\x82\xf5\x1dl\x8d\xc5f\xbf)D\x1f0\xb2\x99\xa2\\\xc6\x11\xb9\x8efg\xc0_\xca݊\x15\xb4\xc2*$\xe0\x1e\xa7\xf8`;\x86\x03\xfc\x16\xb87\x04\x11CDBWxv\xe2\x18\xc4H\xb9\xf1\x06\r\xdc`\x147@\xbdO\xb6\x152\xee02DԾs\xe6\xef\xbdo\x92\bɡV\xf1D\x87\xc30\x8e1:ea\xa7l\xc2W\xa0\\\v\x83z\x80\x889N\xc9\x1d\xf9\xcb&\xd4\xc0\xaf>\"\x18\xb7\xf5k\xe8\x99\x03\xadW\xab\xce\xf0TT\xda\x0fCr\x86\x1fV\xb9>\xcc&\xb1\x8f\xb4jq\x87vE\xa6\xabUԽaԜ\"\xaeT0u\x86\xeera5C\xfbM\x1cː^\x9e`\xe5\a\xa1\x19q4\xae;ZȜ\u007f$\x03\xc2\xfaB\x98\xb2\xb5\xdc\xe2\x10h\x99\x92\xe8\\\xbf\xbb\xf9\f\xd3\xd19\x19\xf3\xe8\x17\xe6\xec7\xd2!\x05\x120\xe3\xb6\x18K\x123\xf3\xc4'\xba6x\xe38\u007fhk\xd0\xcd\xc3Oi3\x18\xa6\x89̒\xab\x06\xae\xb2\xd2\xc0\x06!\x85V1\xb6\r\xbcwp\xa5\x06\xb4W\x8a\xf0\u007fO\x80D\x9aj\t\xec\xf3Rp,\x92s\xe3\x12\xb5\xa3\x85I\xc9.\xe4kV\xea7\x01\xb5dO\x02(;\xcd\xd6\xe8\\\x1a\xb0\xf5\x11ԡ\xf2\xc7\x006'\x9e\x97+7\x83S\xb1C\x9e\xcfΰ|\xceFr\xfc}\xafN\x85\xe6[l\xbaF\xb4\x82F E=\xbek\xce<^\xc6\x00\x8b\xec]D2\x91X\xc2 q\x15)\x10\x91:\xc6t~\xb4\ftiX>\xa0\x86\x9f3\xe6\x0f\xbe{t\xfd\xca;\x16\xba?jt\xebm\x1a\xf0Ʃ@\xbd\u007f\xc2\xf6=\xe3\xf0<\xcb\xe9A\xde?R\xe7\x86\xd7(R\x8e\x97/1\x1a\\#%{\xe1\xb8\v\xb4\x9eF~\xbe\x9eΑ<\x80S\x8edK\xd1t\x04i\v\xa2CF:\xc8˽\xe1~\xd1#\xc0}ot\x9f7\xe6\x04\x8br\x11ym\xb2\x0e|=|\xa9\v\x13q\x81du&\xdf´\x80?\x9b\xbeP͗\x0e\xa8\xc7\n{\x96\"\xb0\xe2D_\xa1\t\xd9~\n\xb5N1\xa2\xe3\xd1K~#\xe7\x1b\x9e+\nS%\xfdv\xfd\xe1\tex{\xb0\xcc]\xa02\xae\xa0\t\x11k2\x9d\xbc\xec\xb2&ڐk\xf6<\x18e\x9cv\x1a\xa7\x81Z\xcc(~\t&f\x05|\x02\u2efda\x110t\xe5q\x9a\xf7R\xd9!R~\xf8\xb5\x9a\xb7\x1c26\b-Zdla\xf3P\x94\xf8\x81\x18\x87s\xdc[\x1f\a\xc5k\x90G\xabf\xb3@#\xe9w\xd5\xc6\xe2\x1a8\xa6K,[\xbcx\xe8\x15-\x94\xe1ɝ?\x89\xcd\x121\xf6\xc5\xf8(3\xe0\xa2^\xd6\xf0\x11\xef\x17f?E\xaf\x91\b\xcf\xcb\xe8\xe2M\x16\x8b\xe0l\x92\xa4\xb3h\x8f\xa246\xac\xc73i\xb3\xef\x94&\xc4c)\xc1?\xffV\x87\xaaRZc`l?\xce\u007f\x14^\xbc8\xe9\xfc\xf3\xa7\xf6\xae5\xe5\x1f\a~\xff\xa3*\ac{;5\xf42\xf9_\x00\x00\x00\xff\xff\xcbT\xc3P]\r\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4YKs#\xb7\x11\xbe\xf3Wt\xad\x0f\x8a\xab\x96C\xdbI%)\xdev\xa58\xa5\xc4֪č.[{\x00\a\xcd!\xac\x19\x00\x010\xe42.\xff\xf7T\xe31\x9c\aHJ\xaa\xac3\x17\x89x4>4\xfa\xf150\x9b\xcf\xe73\xa6\xc5#\x1a+\x94\\\x02\xd3\x02\xbf8\x94\xf4\xcb\x16O\u007f\xb5\x85P\x8b\xdd\xf7\xb3'!\xf9\x12\xae[\xebT\xf3\x80V\xb5\xa6\xc4\x1b\xdc\b)\x9cPr֠c\x9c9\xb6\x9c\x010)\x95c\xd4l\xe9'@\xa9\xa43\xaa\xae\xd1\xcc+\x94\xc5S\xbb\xc6u+j\x8e\xc6\vOK\xef\xbe+\xfeR|7\x03(\r\xfa\xe9\x1fE\x83ֱF/A\xb6u=\x03\x90\xac\xc1%h\xc5w\xaan\x1b\\\xb3\xf2\xa9ն\xd8a\x8dF\x15Bͬƒ\x16\xad\x8cj\xf5\x12\x8e\x1dan\x04\x146s\xaf\xf8\xa3\x17\xf3ދ\xf1=\xb5\xb0\ue7f9ޟ\x84u~\x84\xae[\xc3\xea)\b\xdfi\x85\xacښ\x99I\xf7\f\xc0\x96J\xe3\x12\xee\b\x86f%\xf2\x19@ܻ\x875\aƹ\xd7&\xab\uf350\x0e\xcd5IHZ\x9c\x03G[\x1a\xa1\x9d\xd7ֽ\xe2\x10\x00B@\b\xd61\xd7Z\xb0m\xb9\x05f\xe1\x0e\xf7\x8b[yoTe\xd0\x06x\x00\xbfX%\xef\x99\xdb.\xa1\b\xc3\v\xbde\x16coP\xef\xcaw\xc4&w \xd0\xd6\x19!\xab\x1c\f:#\xd8oQ\x82\xdb\n\va\xb7\xb0g\x96\xe0\x18\xe7w\x99_\xd8\xf7wG<@pM\x06\xd0M\r\x108s\x98\x03\xd0\xe9\x13\xd4\x06\xdc\x16I\xf3\xde☐BV\xbe)\x9c\x048\x05k\xf4\x10\x91C\xab3\xc84\x96\x85V\xbc\x90I\xe8\x00\xd6ݨ\xf5\x92nh\xfc\xff\x1a\xd5\x00н⯀\xf2\xa2u\xc3\xe0\xc1\xaa\x8f\xfd\xa6K\v?\xa0u\xa2\x04\x83ZY\xe1\x949\x80\xe0(\x9d\xd8\b4\xb0Q\xa6o6' \xd0\xdc\xdbn\xd2\x00J\x94\xfe\x80Z\xbdB\x11\xd1oVN\x19V!\xfc\xa4J\x1fvȜ\r\x0e\xec\xd9nU[sX\xa7]\x03X\xa7Lָ\tq\x98\x15\xe5&\xb1#\x1f\x1b\xaey\x1a}Ov\n\xb2\xc5$@\x0ed\xbf\xab0\xef9\xa1{\xf7}\bU\xe5\x16\x1b\xb6\x8c#\x95F\xf9\xee\xfe\xf6\xf1\x8f\xabA3\x806J\xa3q\"\x85\xce\xf0\xf52F\xaf\x15\x86\xaa\xbe\"\x81a\x14pJ\x15h\x83\xfd\x856\xe4\x11C8\x0ea\xc9H\fZ\x94\xae\xaf\x92\xf4\xa9\r0\tj\xfd\v\x96\xae\x80\x15\x1a\x12\x93\x0e\xa6Tr\x87Ɓ\xc1RUR\xfc\xa7\x93m\xc9\xcciњ9\x8c\x11\xfc\xf8\xf9 +Y\r;V\xb7\xf8\x16\x98\xe4а\x03\x18\xa4U\xa0\x95=y~\x88-\xe0ge\x10\x84ܨ%l\x9d\xd3v\xb9XT¥LY\xaa\xa6i\xa5p\x87\x85Ozb\xdd:e\xec\x82\xe3\x0e\xeb\x85\x15՜\x99r+\x1c\x96\xae5\xb8`Z\xcc=t\xe9\xb3e\xd1\xf0oḼ\xf6j\x80ub\x18\xe1\xf3\x89\xec\xcc\tP*\x03a\x81ũa\x17GE\xa7P\xf4\xf0\xb7\xd5GHK\xfb\xc3\x18k\xdf\xeb\xfd8\xd1\x1e\x8f\x80\x14&\xe4\x06\xa3+o\x8cj\xbcL\x94\\+!\x9d\xffQ\xd6\x02\xe5X\xfd\xb6]7\xc2ѹ\xff\xbbE\xeb\xe8\xac\n\xb8\xf6\xf4\x81BS\xab\xc9ry\x01\xb7\x12\xaeY\x83\xf55\xb3\xf8\xd5\x0f\x804m\xe7\xa4\xd8\xe7\x1dA\x9f\xf9\x8c\a\a\xad\xf5:\x12=9q^#α\xd2X\xd2\xe9\x91\x02i\xa6؈\x18\xa1(p\xb2\xf1\xf0b 8\xef\xb8\xf4e\xa3\xd3x\xd0\b\xd9\xfbܜ\x84M\xf6bj\n\x98a\xe4D(@=\x8e\xb2d\x8e\x93\x1cac\x80-&\x12N\x1c\x03}Rq\xbc\xb0\x8f;\xc51\a\x9b\xa6\x82۲`\xadĭ(\x1e\xb5RNW\xa1O\xc9\x17\x01ӊ_\xc0\x15Wd`p\x83\x06e\x89)p\x9d#\x0e\x19d\xfd\x94>\xc5x\xda(\xe0LT\xcf\"~w\u007f\x9b\"yRb\xc4\xee\xa6\xeb^\xd0\x0f}\x1b\x815\xf7\x89\xee\xf2\xdaW\xb7\x9b\xb0\x98\x8fiN\x01\x03-0P\xc0.I\x80\x90\xd6!\xe3\xa06Y\x89T\xa8\x009\xbe\xc18\xe3m\x88`1T\x1eS\v\xe9\x1e\x18\xc5N\xc1\xe1\x1f\xab\x0fw\x8b\xbf\xe7T\xdf\xed\x02XY\xa2\xf5\f\xd8a\x83ҽ\xedH9G+\fr\xa2\xd8X4L\x8a\rZW\xc45\xd0\xd8O?|\xcek\x0f\xe0Ge\x00\xbf\xb0F\xd7\xf8\x16D\xd0x\x17\x96\x93\xd1\b\x1b\xd4\xd1I\x84\xbdp[1N\xa6\x9d\x06ȼ\xe2\xb6\xf7~\xbb\x8e=!\xa8\xb8\xdd\x16\xa1\x16O\xb8\x847\x9e\xd6\x1ca\xfeJ\xbe\xf3ۛ\x13R\xff\x10\\\xfb\r\rz\x13\xc0uy\xb8\xeftG\x90\xc1\xf3\x8c\xa8*<\xb2\xaa\xf1\xe7\x93\n\x85\xeaoA\x19ҀT=\x11^0\x9d^\b\x94\xc8'\xa0?\xfd\xf0\xf9$⡾@H\x8e_\xe0\a\x10\xb1\xacъ\u007f[\xc0Go\x1d\a\xe9\xd8\x17Z\xa9\xdc*\x8b\xa74\xabd}\xa0=o\xd9\x0e\xc1**\x92\xb0\xae\xe7\x81\aqس\x03i!\x1d\x1c\xd9\x1b\x03͌;k\xad\x89\xfd|\xfcp\xf3a\x19\x90\x91AU>\x12S\xd6\xdc\bb3DcB.\xf6\xd68I\xe6\xe9\xb3m0\x1f\xa7\xa0\xdc2Ya\xd8/¦\xa5\xecX\\\xbdƏ\xa7\x94$}\x19j2\x0e\x1c\xff\xb7\xe4\xfe\xcc\xcdy\x06\xfd\x8c\xcd\xf5\xab\x8c\xb3\x9b{j\xd7h$:\xf4\xfb㪴\xb4\xb5\x12\xb5\xb3\v\xb5C\xb3\x13\xb8_\xec\x95y\x12\xb2\x9a\x93i\u0383\r\u0605/Q\x17\xdf\xf8?\xafދ\xaff\x9f\xbb\xa1A\x95\xfd5wE\xeb\xd8ū6\x958\xec\xf3\xf3\xd8\xd5*2\xab\xf1\\r\x8b\xfdV\x94\xdbT\x9c\xc4\x18{\u0099\x041a\x1eB3\x93\x87\xafnʤ\xd0\xd6\x10\xa2\xc3<^\xb0͙\xe4\xf4\xbf\x15\xd6Q\xfb\xab4؊g\xb9\xef\xbfno~\x1f\x03oū|\xf5\x04\x01\x0f6ҿO\xb8@\xcc\x1e\x06\x83\x13u\xcc0\xd6n̋\x98\xa1cU\x86\x8a\xf5/\x02\xcf\x11\xb6\xb3\x1a\x18^ӱ\xca\x023\b\f\x1a\xa6\xe9\xe4\x9e\xf00\x0f)^3A\xf9\x99Rpw\xcf\x01L\xebZdSqL䑄F\xbeO\x856\xab쩽g\xcf!H\xb8\xa0\xffxř\xa1\xec\x11@\xe07\x1dm\xf7\xb7Z9^|\x9a\x14\x9f\xd4\"ե\xc4ֆ\x10\xe7\xf9\x02j4\x86\n\x8aQ\x93V|Ԓ\xbd\xd9J\x9d\x83\x9b\xb7\xb3\xca\f\x17\xaa/\xa8+\xc3Eq\xd4i\x88\".]\x1f\x13\x85~meY*b\xa7ë\xfb\xf3\xc7{=\x9d\xe1/q\f\x0f\xe0\x9ch\xc8f{\xd7\xcaq\x8d\\i\b=qa\xa6\x8f\xdb$\r\xb9\xa7\x8e\xc4l7L\xd4\xc8!\xbd\x1d\x8c\xe7d\xa4\xf6\xa5\xacqCA\xaeյb<\x15d\x11^GϨ^\xf7\xb7#W\xf6\x8c\xcc\xd6\"\xf7\x95|F\tSʶQ\xa6a.\xdc\xe6ͳBe[\xd7l]\xe3\x12\x9ci\xa7\xddg\x82E\x83ֲ\xea\x92+\xfe\x1cF\x85:5N\x01\xb6V\xad\xeb\n\xd5AP\xb8\xb2Ѧ^V+gK\xc0\xa193\xa2\xe86Rպ\xf6s\xfa\x81\xe0\xf8\xe0\xe4Q\xad1\x9f\xea^\x13\x13\x00\xfc\x83\xc9%\x844&\xe7`]\xf4:\xeba\xf4\xa1l\x9b\xe9*s\xb8\xc3}\xa6u\xf2\xd0\xd3\xef\xbcN.\x93\xe9\xfb\xd1{Ë\xf6\x1f\x17\xba\xa4\x828\f\xb6\xaaNά\x1c\xabA\xb6\xcd\x1a\r\xe9a}ph\x87\xe1n\xe6r\xd0\n53\xe4\xe9\xfe&\xfcz\xfcT\xf3\x16\xac\xf0\xd7{ķ\x02\x01\vŷ\xa5\xe4D\xc4R\x19̄L\x98\xa6\x95A\x12\x19\xc2\xff=\xf3G\xd6N&\x8d\x1e9\xefɎW\xc4\xfd\x96v\xdd=\u007f\xa4Ê\xdc\x06~\xfdmv\xa49\xac\xa4\x02\x02\xf9\xdd\xf8I\xffM\xb8\xe0Io\xf4\xfeg\xa9d`\xd3v\t\x9f>\xcf\xd2\xd3\xddczz\xa7\xc6\xff\x06\x00\x00\xff\xff\xb6\xe8a\xa8\a!\x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4YKs\xe3\xb8\x11\xbe\xebWty\x0f\xceV\r\xa9\xddI*I\xe9\xb6kgSJv=\xae\x913\x97\xa99@DS\xec\x98\x04\x18\xa0)YI忧\x1a \xf4\xa4\x1ev\xd5Lx\xb1\x85G\xe3\xeb\xaf\x1f\xe8&GY\x96\x8dTK\x9f\xd0y\xb2f\x02\xaa%|a4\xf2\xcb\xe7\xcf\u007f\xf69\xd9\xf1\xf2\xc7\xd13\x19=\x81\xbbγm>\xa2\xb7\x9d+\xf0\x1eK2\xc4dͨAVZ\xb1\x9a\x8c\x00\x941\x96\x95\f{\xf9\tPX\xc3\xce\xd65\xbal\x81&\u007f\xee\xe68\xef\xa8\xd6\xe8\x82\xf0t\xf4\xf2\x87\xfcO\xf9\x0f#\x80\xc2a\xd8\xfeD\rzVM;\x01\xd3\xd5\xf5\b\xc0\xa8\x06'\xd0Z\xbd\xb4uנC\xcf֡ϗX\xa3\xb39ّo\xb1\x90S\x17\xcev\xed\x04\xb6\x13qs\x8f(j\xf3h\xf5\xa7 \xe7c\x94\x13\xa6j\xf2\xfc\xf7\xc1\xe9_\xc9sX\xd2֝S\xf5\x00\x8e0\xeb\xc9,\xbaZ\xb9\xe3\xf9\x11\x80/l\x8b\x13x\x10(\xad*P\x8f\x00z\x02\x02\xb4\xacWq\xf9c\x94UTب\x88\x19\xc0\xb6h~z\x9c~\xfa\xfdlo\x18\xa0u\xb6EǔԋώYwF\x014\xfa\xc2Qˁ\xf4[\x11\x18W\x81\x16{\xa2\a\xae0\x81B\xddc\x00[\x02W\xe4\xc1a\xebУ\x89\x16\xde\x13\f\xb2H\x19\xb0\xf3\u007fb\xc19\xccЉ\x18\xf0\x95\xedj-n\xb0D\xc7ర\vC\xff\xde\xc8\xf6\xc06\x1cZ+ƞ\xe3\xedC\x86\xd1\x19U\xc3R\xd5\x1d\xbe\x03e44j\r\x0e\xe5\x14\xe8̎\xbc\xb0\xc4\xe7\xf0\x9bu\bdJ;\x81\x8a\xb9\xf5\x93\xf1xA\x9cܹ\xb0M\xd3\x19\xe2\xf58x&\xcd;\xb6Ώ5.\xb1\x1e{Zd\xca\x15\x151\x16\xdc9\x1c\xab\x96\xb2\x00\xdd\x04\x97\xce\x1b\xfd\x9d\xeb\x03\xc0\xdf\xeea\xe5\xb5\xd8ֳ#\xb3ؙ\b\xcev\xc6\x02\xe2m@\x1eT\xbf5j\xb1%Z\x86\x84\x9d\x8f\u007f\x99=A::\x18\xe3\x90\xfd\xc0\xfbv\xa3ߚ@\b#S\xa2\x8bF,\x9dm\x82L4\xba\xb5d8\xfc(jBsH\xbf\xef\xe6\r\xb1\xd8\xfd_\x1dz\x16[\xe5p\x17b\x1c\xe6\b]\xab\x15\xa3\xceaj\xe0N5X\xdf)\x8f_\xdd\x00´τ\xd8\xebL\xb0\x9b\x9e\x0e\x17G\xd6v&R\n9a\xafô0k\xb1\x10\xf3\t\x83\xb2\x95J*Bl@i\x1d\xa8\xa3\xf5\xf9\x9e\xe8\xe1Еg\xae\x8a箝\xb1uj\x81\xbf\xda(\xf3p\xd1\x01\xb6\x9f\x87\xf6$p\x92Yb\x18c/\x1c|\\y$\x14\xa0N\x9bW\x15:\f{$\x8bQ!\xeee=\xb1uk\x11\x1cT\xd2\xf9\x91\x84\x13\x86\b*[}A\x8dG\xdb\a\x84\xc3\x12\x1d\x1aq\xf7\x98!Z\x1b\xf2\b+2),b\x8a\x05\xb6\x03Z\xcc#\xeaa\x88\xa7\xa9\x873\xd9s\x10\xf0O\x8fӔ1\x13\xc3=t>>\xf7\x02=\U00094135~T\\]q\xf6\xed\xb4\x8c\x87\x85\xdc\xc1\x16\x14\xb4\x84\x05\xee%c \xe3\x19\x95\x06[\x0eJ\x94[\x1b$\xc0\x1c\xf6;\xde\xc5Lѧ\xa4m\n\x17\xeaAI\x8e\"\r\u007f\x9b}x\x18\xffu\x88\xf9\x8d\x16\xa0\x8a\x02\xbd\bR\x8c\r\x1a~\a\xbe+*P^\xd4 \x87z&3y\xa3\f\x95\xe89\xef\xcf@\xe7?\xbf\xff2\xcc\x1e\xc0/\xd6\x01\xbe\xa8\xa6\xad\xf1\x1dPd|\x93\xfe\x92ϐ\x8ftl$\u008a\xb8\xa2\xc3KkÀxW\xaf\xf6*\xa8\xcb\xea\x19\xc1\xf6\xeav\b5=\xe3\x04n$\xcaw`\xfeG\x02\xeb\xbf7'\xa4\xfe.\x06Ѝ,\xba\x89\xe06\xf7\xddnDnAr\xa5\x18\xd8\xd1b\x81.\x14\bCOHޒ\x12\xbf\a\xeb\x84\x01cwD\x04\xc1b\xbd\x98\x8fP\x1f\x81\xfe\xfc\xfe\xcbI\xc4\xfb|\x01\x19\x8d/\xf0\x1e\xc8DnZ\xab\xbf\xcf\xe1)x\xc7ڰz\x91\x93\x8a\xcaz<Ŭ5\xf5Zt\xae\xd4\x12\xc1\xdb\x06a\x85u\x9d\xc5zC\xc3J\xad\x85\x85d8\xf17\x05\xadr|\xd6[S\x95\xf1\xf4\xe1\xfe\xc3$\"\x13\x87Z\x84|'\xb7SIR5H\xb9\x10\xef\xbc\xe0\x8dG\x97fz|\x17݇-\x14\x952\v\x8c\xfa\"\x94\x9d\xdcB\xf9\xed[\xe2\xf8\xf8\xeaO\xcf@\tp\x988\xfeo\x97\xe8\x95ʅJ\xf5\n\xe5\x1ev\xbc\xfc\xacr\xd2\x188\x83\x8cA?m\v/\xaa\x15ز\x1f\xdb%\xba%\xe1j\xbc\xb2\xee\x99\xcc\"\x13\xd7̢\x0f\xf8q(\xed\xc7߅?o\xd6%\x14\xe4\xd7*\x14\x16\u007f\v\xad\xe4\x1c?~\x93R\xa9V\xbc\xfe\x1e\xbb\x9d\xf5\x05\xcc\xe1^\t\x8bUEE\x95\x9a\x80>Ǟ\b&\x92\x8aS\xc7Ԭ\xcc\xfa\xab\xbb\xb2\x10\xda9A\xb4\xce\xfan3SF\xcb\xff\x9e<\xcb\xf8\x9b\x18\xec\xe8\xaa\xf0\xfd\xc7\xf4\xfe\xdb8xGo\x8a\xd5\x13\x85n\xf4\x91\xd6N\xb5PY\x12\xba\vu\xd9ǽũ\xae\x1c\xa8\v7k^U\x18z\xa3Z_Y\x9e\xde_\xc01\xdb,L\x18\xb6\x06\xe8\xcb\xc1$K\x1c\xf7l\x15x\x06O\x14u\x01K\xac\xed\x87j\xec\x1eI\xac9\u0088Ե\x01\xcfp\xb0\xbe\x16\xa1\xb4dR@\xed#̆;\x87\x835\xad\xd5\a#\xfb\x9ep0\xb95\xcd\xc1DT\U000aad8a\x15w\xfe5\x8dUؐ\x98\x8d\xf1ͽ\x98Pܾ\xb9\xb5*\xac\x14\x8e\xfb\xaf\x98\xce[\xf9\xeexGx\x8f\xe1tD\xc7\xd4`\xe8W\x02\x0eX)\x9f\x0e\x19\xb2(\xecȋ[CN\x15q\xa8CY'Ug\xa9\xa8F\r\x9b\x97\\\xf0$\x1dfh\xe8o\x87\xaa\x98$\xa8\xf3\xa8C\xef9\x00\xfax_i]\xa3x\x02\xd2\xc6g\"\xe2h\x85\xe9\xeaZ\xcdk\x9c\x00\xbb\xeex\xfaL\x005\xe8\xbdZ\\\x8a\xa0\xdf\xe2\xaa\xd8\xf1\xf5[@\xcdmǛ\x96\xaf\x0f\xa5\x9e\x8a[\xdf{\xc1\xeb\xda\xceJ\xf9KP\x1ee͐\xc7m\x82\xfa\xbc\xcbɃ\xa6k\x8e\x8f\xc9\xe0\x01W\x03\xa3S\xf3\xe8\xec¡?\xb6L\x96\f8\xd0\x04d\xf0K\xf0\x8eW\x11\xd0\x1ft\x89\x83~\x19T\xb6N\xdemY\xd5`\xbaf\x8eN\x88\x98\xaf\x19}b$\xa5\x86\xa1\x1e:\xd4\xde[&\xb7\x12R\xb6\x8b\xa2\xfan\xa2P&\xbcR\x12\xffe\v\x9a|[\xab\xf5\x80ܤI\xb8^\xc5}%\x8e\xb6\x1e\x93\xa2P\xc2?̽\xb6\xf7\x0f\xa0\xee\xad9Q\r\xa6\x90!\xc3\u007f\xfcÙۘ\f\xe3\xe2 \x95\xf6\xf3B\xe8\xcfr\xca\xd79\xe1̅\xefY9\xbe6\xed\xcd\xf6\x16_\xcaxA\xf4p\xbe\xdbM]ljj\xff\x98o\x99\xa3\x06\x89:\x1a\f\xc8\xf5\x8e\xec\xfe\xbdY?\xb2\xbd\xd9T!\xc5\x1c\xea\x87\xc3O\r77{_\x0e\xc2\xcf\xc2\x1aM\xf13\t|\xfe2\x82\xfe]ڧ\xf49@\x06\xff\x17\x00\x00\xff\xffñ\x1b\xae\xa0\x19\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4Y[s\x1b\xb7\x15~\xe7\xaf8\xe3<\xa8\x991\x97\x89\xdbi;|\xb3\xa5\xa6\xa36\x915\xa6\xaa\x17\x8f\x1f\xc0\xc5\xe1.\xa2]`\x8b\x83%\xcdf\xf2\xdf;\a\x17ro\x14%M\x94\xec\x8b-\\\x0e>|8w\xce\xe6\xf3\xf9L4\xea\x1e-)\xa3\x97 \x1a\x85_\x1dj\xfe\x8b\xb2\x87\xbfS\xa6\xccb\xfb\xfd\xecAi\xb9\x84˖\x9c\xa9?!\x99\xd6\xe6x\x85\x1b\xa5\x95SF\xcfjtB\n'\x963\x00\xa1\xb5q\x82\x87\x89\xff\x04ȍv\xd6T\x15\xday\x81:{h\u05f8nU%\xd1z\xe1\xe9\xe8\xedw\xd9߲\xeff\x00\xb9E\xbf\xfdN\xd5HN\xd4\xcd\x12t[U3\x00-j\\Bc\xe4\xd6Tm\x8d\x16\xc9\x19\x8b\x94m\xb1Bk2ef\xd4`Χ\x16ִ\xcd\x12\x8e\x13asD\x14nsk佗\xf3)\xc8\xf1S\x95\"\xf7\xef\xc9\xe9\x1f\x159\xbf\xa4\xa9Z+\xaa\t\x1c~\x96\x94.\xdaJ\xd8\xf1\xfc\f\x80r\xd3\xe0\x12n\x18J#r\x943\x80H\x80\x876\a!\xa5\xa7TT\xb7Vi\x87\xf6\x92E$*\xe7 \x91r\xab\x1a\xe7);\xc8\x01\xb3\x01W\"\x1f\xe9\xe9\x16J+]\xf8\xa1\x00\x01\x9c\x815BD\"\xbd0\x80\x9f\xc9\xe8[\xe1\xca%dL\\\xd6\x18\x99\xe9$3\xae\t\x9c\xdf\fFݞ\xefA\xce*]\x9cB\xf6\x1b\x83\xea\xe1\xb95\xf2\x05H\x9eslX\xdb;\xf4\xbe;t\xee\xdc[#\xe3\x06\x88\n\x04\xe4\x84k\t\xa8\xcdK\x10\x047\xb8[\\\xeb[k\n\x8bD\x130\xfc\xf2\xac)\x05\xf5q\xac\xfc\xc4\xeb\xe2\xd8\x18[\v\xb7\x04\xa5\xdd_\xffr\x1a[ܔ9\xe3D\xf5a\xef\x90zH\xef\x86\xc3\x01-+v\x81\xf6\x8f\x83\xbbfHWF\xf7y\xfd0\x18\x9d\x02\xdb\x11\x9a\x9c^6rX=\xa9\uf2fe<)\\\x18\b\xd3\xdb\xef\x83\xdb\xc8K\xac\xc52\xae4\r\xea\xf7\xb7\xd7\xf7\u007f^\xf5\x86\x01\x1ak\x1a\xb4N%O\x16\xbe\x8e\a\xef\x8cB\x9f\xd9\v\x16\x18V\x81d\u05cd\x14\x8c\"\x8c\xa1\x8c\x18\x82\xb1(\x02\x8b\x8dEB\x1d\x9cyO0\xf0\"\xa1\xc1\xac\u007f\xc6\xdce\xb0B\xcbb\x80J\xd3V\xdeڷh\x1dX\xccM\xa1\xd5\xff\x0e\xb2\x89m\x8f\x0f\xad\x84\xc3\xe8N\x8f\x9f\xf7wZT\xb0\x15U\x8boAh\t\xb5\u0603E>\x05Zݑ\xe7\x97P\x06?\xb1\x86(\xbd1K(\x9dkh\xb9X\x14ʥȕ\x9b\xban\xb5r\xfb\x85\x0fBj\xdd:ci!q\x8bՂT1\x176/\x95\xc3ܵ\x16\x17\xa2Qs\x0f]\xfb\xe8\x95\xd5\xf2\x1b\x1bc\x1d]\xf4\xb0\x8e\x8c.|>\xae<\xf2\x02\x1cX@\x11\x88\xb85\xdc\xe2Htr\x8f\x9f\xfe\xb1\xba\x83t\xb4\u007f\x8c!\xfb\x9e\xf7\xe3F:>\x01\x13\xa6\xf4\x06mxč5\xb5\x97\x89Z6Fi\xe7\xff\xc8+\x85zH?\xb5\xebZ9~\xf7\xff\xb6H\x8e\xdf*\x83K\x1f\xce\xd9_\xb6\rk\xae\xcc\xe0Zå\xa8\xb1\xba\x14\x84\xaf\xfe\x00\xcc4͙ا=A7\x13\x19.\x0e\xacu&R\xb6p⽆\x19\xc0\xaa\xc1\x9c\x9f\x8f\x19\xe4\xadj\xa3ro\x1b\xec~@\x8c\xd6g=\xd1Ӧ\xcb\xdfZ\xe4\x0fm\xb3rƊ\x02\u007f4A\xe6p\xd1\x00ۇ\xa9=\t\x9c\xeeļ \x1c(\xac\x1c\t\x05\xa8\xd2\xe6]\x89\x16\xfd\x1e\x0e\x8d*g\xf52\xa4\x9c\xb1{\x16\x1c\xa2e6\x92p\xe2!\xfc\x95\x8d\xde,\xfe9\xc5\xfc\xe1\x16 \xf2\x1c\x89|\xbc\xc6\x1a\xb5{{\x88\xd9\x12IY\x94\x9c\xb8`V\v\xad6H.\x8bg\xa0\xa5\xcf\xef\xbeL\xb3\a\xf0\x83\xb1\x80_E\xddT\xf8\x16T`\xfc\xe0\xfe\x92\xce(\nt\x1c$\xc2N\xb9R\r\x83ց\x01֮x흿\xae\x13\x0f\b&^\xb7E\xa8\xd4\x03.\xe1\x8d\xcf\x04\x8f0\u007fa\xc3\xfa\xf5\xcd\t\xa9\u007f\n\x06\xf4\x86\x17\xbd\t\xe0\x0e\xf1\xaek\x91G\x90\xae\x14\x0e\x9cUE\x81\xc7Dt\xf8y\xe7\xcd.\xf1[0\x96\x19Ц#\xc2\v\xe6\xd7\v\xfe\b\xe5\b\xf4\xe7w_N\"\xee\xf3\x05JK\xfc\n\xef@\xe9\xc0Mc\xe4\xb7\x19\xdcy\xed\xd8k'\xbe\xf2Iyi\bO1kt\xb5\xe7;\x97b\x8b@\xa6F\xd8aU\xcdC\xbe!a'\xf6\xccBz8\xd67\x01\x8d\xb0\xeeQmMY\xc6\xddǫ\x8fˀ\x8c\x15\xaa\xf0\xfe\x8e\xa3\xd3Fq\xd6\xc0\xe9B\x88y^\x1bGA3}\xd4\x06\xf5q\x06\xf2R\xe8\x02\xc3}\x116-G\xa1\xec\xe2%v<\x0e\xfd\xe9\x9bH\x01\x86\x8e\xe3\x0f\v\xa2O\xbc\x9c\xcfT\x9fp\xb9n\xad\xf5\xe8\xe5\x1e\xda5Z\x8d\x0e\xfd\xfd\xa4ɉ\xaf\x96c\xe3ha\xb6h\xb7\nw\x8b\x9d\xb1\x0fJ\x17sV\xcdy\xd0\x01Z\xf8\xf2t\xf1\x8d\xff\xe7\xc5w\xf1\x95\xecS/\xd4+\xb0_\xf3V|\x0e-^t\xa9\x94+>=\x8e]\xacb\x023\xdc\xcbf\xb1+U^\xa6\" \xfa\xd8\x13Ƥ8\xe3\x94\xc15\v\xbd\u007fuUfB[ˈ\xf6\xf3\xd8X\x9a\v-\xf9\xff\xa4\xc8\xf1\xf8\x8b\x18lՓ\xcc\xf7?\xd7W\xbf\x8f\x82\xb7\xeaE\xb6z\"\xd1\r:Ҙk\xc9Tn\x14\xda3y٧\xde\xe2\x94WN䅇5\xcfJ\fI\x8b\x86J㮯\xce\xe0X\x1d\x16&\f\xc7\a\x88\xe9`\x925h\xeb<\vO\x10u\x06KlKL\xe4\xd8\x11I\xc89\xfc\b\xe7\xb5\x1eϴ\xb1>\x17!\x97d\x9c@\xf5\x11Χ+\x87\xc1\x9a\xc6\xc8\xc1H_\x13\x06\x93ǧ\x19L\xf4\x1ab]\xbc\xe3\xb2\xcaw[\x9eSX\x85\x0eOd6طK}\x1fNn_\\Z\xe5\x86\x13\xc7~7\xf9\xf1W\xbe\x1c\xef\xf0}\f+\x03:\xa7j\xf4\xf5JhN\xed\x04\xa5C\xa6^\x14:\xf2\xc2V\xefSY\x1cJ\x9f\xd6qֹ\x11\xaaB\t\x87~6\xdcq\x85\xe9\v\xfa\x8b\xa9,&\tj\t\xa5\xaf='@\x8f\xf7\xa5\x1e\x19\x97\xf1s\x161Z\xa1۪\x12\xeb\n\x97\xe0l;\x9e~Āj$\x12\xc59\v\xfa)\xac\n\x15_\xdc\x02bmZw(\xf9\xa2)E*.(j\xc1\xf3\xca\xceR\xd09(\xb7\xbcfJ\xe3\x0eF\xfd\xb8\xca\U00047ead\xc7\xc7\xcc\xe1\x06w\x13\xa3\xa3\x9eew\xf22\xa9\xd0\xc4\xdc\x0f^;\x9eE@<\xe8\x1c\aq\x19\x94\xa6J\xdam\x9c\xa8@\xb7\xf5\x1a-\x13\xe1\x1b\xa5\x89\x91\xe4\x1a\xa6jh\x9f{\x1f\x99j\x92\xa8ѠG.;\xb2c߬;Ү\x0f]\xe1Dj\x8cx\xf0˯\xb3c\xf0\x139\xe7{(o\x86?<\xbe\t\xf5x\xfa\x1d\xd1\xff\x99\x1b\x1d~\xf8\xa3%|\xfe2\x83\xd8n\xbbO?\x0e\xf2\xe0\xff\x03\x00\x00\xff\xff\x8c\x89\xe8@\xae\x1d\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xb4W\xc1n\xe36\x10\xbd\xfb+\x06\xdb\xc3^*y\x17=\xb4ЭM[ h\x12,\x9cE.E\x0f\x145\xb2\xa7\xa1H\x96\x1c:u\xbf\xbe\x18J\x8aeY\x897\v\xacn&g\x1e\xdf̛\x19ҫ\xa2(V\xca\xd3\x03\x86H\xceV\xa0<ῌV~\xc5\xf2\xf1\xa7X\x92[\xef?\xae\x1e\xc96\x15\\\xa5Ȯ\xdb`t)h\xfc\x15[\xb2\xc4\xe4\xec\xaaCV\x8dbU\xad\x00\x94\xb5\x8e\x95,G\xf9\t\xa0\x9d\xe5\xe0\x8c\xc1Plі\x8f\xa9\xc6:\x91i0d\xf0\xf1\xe8\xfd\x87\xf2\xc7\xf2\xc3\n@\a\xcc\ue7e9\xc3Ȫ\xf3\x15\xd8d\xcc\n\xc0\xaa\x0e+\b\x18\x99t@\xef\"\xb1\v\x84\xb1ܣ\xc1\xe0Jr\xab\xe8Q˱\xdb\xe0\x92\xaf\xe0\xb8\xd1{\x0f\x94\xfap6\x19h3\x02\x1d\xf2\x96\xa1\xc8\u007f,n\xdfP\xe4l\xe2M\n\xca,\x11\xc9ۑ\xec6\x19\x15\xce\f䀨\x9d\xc7\n\ue10bW\x1a\x9b\x15\xc0\x90\x82̭\x18\x82\xdc\u007f\xec\xb1\xf4\x0e;Փ\x06p\x1e\xedϟ\xae\x1f~\xb8?Y\x06\xf0\xc1y\fLc|\xfd7\x11v\xb2\n\xd0`ԁ<紿\x17\xc0\xde\n\x1aQ\x14#\xf0\x0eGR\xd8\f\x1c\xc0\xb5\xc0;\x8a\x10\xd0\a\x8ch{\x8dO\x80A\x8c\x94\x05W\xff\x8d\x9aK\xb8\xc7 0\x10w.\x99F\na\x8f\x81!\xa0v[K\xff=cG`\x97\x0f5\x8aqH\xf2\xf1#\xcb\x18\xac2\xb0W&\xe1\xf7\xa0l\x03\x9d:@@9\x05\x92\x9d\xe0e\x93X\u00ad\v\bd[W\xc1\x8e\xd9\xc7j\xbd\xde\x12\x8f\x05\xad]\xd7%K|X\xe7ڤ:\xb1\vq\xdd\xe0\x1e\xcd:ҶPA\xef\x88Qs\n\xb8V\x9e\x8aL\xdd\xe6\xa2.\xbb\xe6\xbb0\xb4@|\u007f\u0095\x0f\xa2m\xe4@v;\xd9\xc8\xd5\xf6\x8a\x02Rn@\x11\xd4\xe0\xdaGqL\xb4,Iv6\xbf\xdd\u007f\x86\xf1\xe8,\xc6<\xfb9\xefG\xc7x\x94@\x12F\xb6\xc5Ћ\xd8\x06\xd7eL\xb4\x8dwd9\xffІ\xd0\xce\xd3\x1fS\xdd\x11\x8b\xee\xff$\x8c,Z\x95p\x95\xbb\x1cj\x84\xe4\x1b\xc5ؔpm\xe1Juh\xaeT\xc4o.\x80d:\x16\x92\xd8/\x93`:\xa0\xe6\xc6}\xd6&\x1b\xe3\fyA\xaf\xf9\\\xb8\xf7\xa8E>ɠ\xb8RK:\xf7\x06\xb4.\x80:\xb3/O\xa0\x97[W\xbeZ\xe9\xc7\xe4\xef\xd9\x05\xb5\xc5\x1b\xd7c\u038df\xdc~Y\xf2\x19\xc9\xc9d\xe9\xdb\x18\x97\rϰ\x01x\xa7xҿ\xac\xc8>\x8f\x81\xc5x^\x11!\v\xa1\xa4\x9d\xad\xb2\x1a\u007f\xcf\x15e\xf5\xe1BL\xb7\v.\x12\xd2\xce=\x81k\x19\xed\x14t\xe0\xba\x10I\x8d\x10\x92}\x13\xd9~~_7Rx-a\xb8@t33\x1f\xf3\xde&c\x06\xacB\xbb\xce+\xa6\xda\xe0\xf2\x91\xf2I\xd9P\x8fr\xe8{\xff\xeb\xf3\xbdw&u\xf8|\xdd\\\x88\xe0\xe1\xd4zZ8\xfd\xc2@EB\x81pzq\x9e~C\xadD\xf0\xae\x19H\f\x05\x1d%\xbe7\xc4 \x92S\xc0\xd9\x04-\x96\xdbcf\xb3Tm3\x93\xb9Ƴ\xedY\xfe\xbeh|\xb0\xe2\x14\xdf2@\xb2Øl\x9dB@\xcb\x03L\xbeQ\xbfz\x84\x18\x15y\xd2>\xf2\xa2\xbaP\x017\xe7\x1e#1\x01\x03\x96\x85i\xbf=\xa9\xf9-\x94E[\xea\xb4օNq\x05ra\x14\x02tf!\xef-\xacnP5\xe7}\\\xc0\x9d\xe3\xe5\xad\x17#\\슳\xc5(\xef\x92f\xa2s\xec\x1byX9\xf6\x90\xd2\x1a=cs7\u007f\xbd\xbf{w\xf2\x18\xcf?\xb5\xb3\r\xf5\u007f=\xe0ϿV=*6\x0f\xe3\x03[\x16\xff\x0f\x00\x00\xff\xff\x83\xf9\xd9\xe0\xf4\f\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec\xbd}s#\xb7\x910\xfe\xbf?\x05Jq\xfd$]Dʛ\\\xf2\xbb\xdbJ=)eWvT\xf6jU+e\xfd\xa4\x1c\x9f\x0f\x9ci\x928\x81\xc0\x04\xc0P\xe2\x9d\xef\xbb?\x85\x060/\xe4\x90\"0Ծ\u0603\xab\xbax\xa9\x99\x1e\xa0\xd1\xe8wtӂ\xbd\a\xa5\x99\x14/\t-\x18<\x1a\x10\xf6_z|\xffoz\xcc\xe4\xf9\xf2\xc5\x17\xf7L\xe4/ɫR\x1b\xb9x\aZ\x96*\x83\xd70e\x82\x19&\xc5\x17\v04\xa7\x86\xbe\xfc\x82\x10*\x844\xd4\xfe\xac\xed?\tɤ0Jr\x0ej4\x031\xbe/'0)\x19\xcfA!\xf0\xf0\xe9\xe5W\xe3\xff\u007f\xfc\xd5\x17\x84d\n\xf0\xf5;\xb6\x00m\xe8\xa2xID\xc9\xf9\x17\x84\b\xba\x80\x97D\x816R\x81\x1e/\x81\x83\x92c&\xbf\xd0\x05d\xf6c3%\xcb\xe2%\xa9\xff\xe0\xde\xf1\x13q\x8bx\xe7^\xc7_8\xd3\xe6\xdb\xe6\xaf\xdf1m\xf0/\x05/\x15\xe5\xf5\xc7\xf0G\xcdĬ\xe4TU?\u007fA\x88\xced\x01/ɵ\xfdLA3ȿ į\t?;\xf2\xb3^\xbep \xb29,\xa8\x9b\x0f!\xb2\x00qqs\xf5\xfe\xf7\xb7\xad\x9f\t\xc9Ag\x8a\x15\x061\xe3\xe7F\x98&\x94\xbcǵ\xd9\t\xe0&\x103\xa7\x86((\x14h\x10F\x133\aB\x8b\x82\xb3\f\x91XA$DN\xab\xb74\x99*\xb9\xa8\xa1Mhv_\x16\xc4HB\x89\xa1j\x06\x86|[N@\t0\xa0I\xc6Km@\x8d+X\x85\x92\x05(\xc3\x02b\xddh\xd0Q\xe3\u05f5\xb5\x1c\xdb座Hn\t\bܔ=\xca \xf7\x18\xb2\xb35s\xa6륭/\xc7/\x89\n\"'\xff\x05\x99\x19\x93[P\x16\f\xd1sY\xf2\xdc\xd2\xdd\x12\x94EN&g\x82\xfdw\x05[ۅڏrj\xc0\xefw=\x980\xa0\x04\xe5dIy\tg\x84\x8a\x9c,\xe8\x8a(\xb0_!\xa5h\xc0\xc3G\xf4\x98\xbc\xc1\xed\x11S\xf9\x92̍)\xf4\xcb\xf3\xf3\x193\xe1\xfcdr\xb1(\x053\xabs<\nlR\x1a\xa9\xf4y\x0eK\xe0\xe7\x9a\xcdFTesf 3\xa5\x82sZ\xb0\x11N]\xe0\x19\x1a/\xf2\xdfT\xdbvܚ\xabYY\xca\xd3F11k\xfc\x01\xc9|\xc7\x0eX\x82w\xb4\xe4^u\xab\xa8\x11m\u007f\xb2\xd8ywy{פ3\xa6ױ\x8fxo\x10_\xbd\x05\x16aLLA\xb9MDj\xb30A\xe4\x85d\xc2\xe0?2\xce@\xac\xa3_\x97\x93\x053v\xdf\xffY\x82\xb6\x04-\xc7\xe4\x152\x152\x01R\x1695\x90\x8fɕ \xaf\xe8\x02\xf8+\xaa\xe1\xd97\xc0bZ\x8f,b\xf7ۂ&?\\\u007f\xd8a\xad\xf1\x87\xc0\xbc\xb6\xec\x97?\xfd\xb7\x05d\xad\x13c_cS\u007f\xcc\xc9T\xaa\x16s\xb0\xaf\x8c[@\xbb\x0f\xad\x1d\xee\xf4[\x0e\xb6\xfe\x97\xb5\xa9\xfc\xa5z\xd0ҏ\x9dD)\xd8?K@\x16\xe7N,l\xb0\x94\r\x90$\xcc\x0f\xc9b\xbc\xf1\xf7-8\xb5\x03\x1e3^\xe6\x90W\xdcvc-k3\xbe\xdcx\x01\xc5\x11e\xc2ҿe\xffvڢ\xfe\xabe\xa7\x1d3\xa6\n\x88\xa5@&\x1c<\xc2\x04.\xb6\x13\xd3v0\x03\x8b\x8e\xc9\xed\\\x1dA9G'\x1c^\x12\xa3J\u0602\x19\xaa\x14]mAL\x90\xcd\xfb\xe2\xa5z\xde3\x04\xce2h\n\n\x87\x1a'd\xa8ڜ\x11\xf9\xa4\xb12\x97\xf2\xfe)L\xfc\xd5>S\xf30\x92\xa1\x8eC&0\xa7K&\x95_\xbb\x17)\x13 \xf0\bYiP\xcco\xc0-\x91\x9dJE\n\xa9\xcdv,l?\x89\xc4\x1d\x8em[\xb8\x13\x85\x1b+\xf3\x8c#l\xb1]h\x8b\x89H\x01v\xae\v{\x12\xebg\x95,ݳ\xebܾ\x81\xf0n\x8c\x90\tՐ\x13\xe9i\xa0\xe4\xa0\xfd\xb7rdO\xf5);\xdb\n\xbaZ\xbc\x93\xbb\x9cN\x80\x13\r\x1c2#\xd5&&\xf7\xc1\xa7\x1b\xfbp\x8e-x\xec\xe0!\x9e\xf7zN\\/l\aHb\x95\x8e\x879\xcb\xe6N$Z\xdaD8$\x97\xa0\xf1\x18Y\xb5m\xb5m\x91䩽\xf7\x1f\xd9u\x90\xea\xf1đZ\x87\xd7u\xb8\xea\xb1\a\xf3\xa9\xc7\x13l\xa8\x8d\xd9Z_\xed\x94#\xf5\xf8e\"6\xf0\xd5\x04\xa2\xbd\xdax\xf5\xb0D\x8b&\x86U}\xaf\xa6\x04\x16\x85Y\x9d\x11f¯OA\xa4\x9c7\xbe\xff\x19oL<\xc5_\xad\xbfyP\x8a߹+OA\xb4\xbbR}\xfe3\xdc\x14\x14\x16\xb7^V\xec\xbd!\xdf5\xdf:#lZmH~F\xa6\x8c\x1bPk;\xd3\xeb\xbc\x1c\x02\x19\xfb\xc8;;\x16\xd4d\xf3\xcbG\xab\xd9\xe8\xda\x1d\xb3'^\xd6_v\nbИۂ\xf9\t\xb8\x04\x8d9\xa6`\xe1\x8c\xc4;\xc4f\xfd\vj\xd7\x17ׯ!߅\x1e\xb2\x1f\xe5m,\xe4bm\xb2\xcdO{\xadw\xdfexէ\xb2 \x9c\xf9\u007fF(\xb9\x87\x95\xd3X\xa8 vs\xa8\xfd\xd0\x16[b\x139\xe8\x87@\"\xbb\x87\x15\x82\xf1\x8e\x85'\xdfޗ\x14ܸ\x87\xd5>\x8f\xad!\xd0\xceɛ{\x0e\x93\xf6\aD\x04\x9a\xa1\xfb#\x8f\xa0\x93(\xf0\xa2\xa7\x17G\xf6g$a\x04\xdc',\xb3ڶ\x863\r7\xf6X\xbb-\xb2\xa7`Ί=\x17\x8a\xbe4\rxZ\x82\x9b\xe8=\xe5,\xaf>\xe4\xe8\xfeJl׆\xdb\xe3Z\x9a+qF.\x1f\x99\xb6S\x139y-A_K\x83\xbf<\v:\xdd\xc4\x13\x90\xe9^\xc4\xe3%\x1c۶xh\xfa\x9b\xf6 n7\xae\x9c[\xa1\xda\x1e\xa6ɕ\xb0\x86\x8b\xc7\az\x0f\xdd\xe7vˇ\xf6X\x94\x1a\x1dJB\x8a\x11\x8a\xcaqח\x1c\xb2\xf7\x04)UkG6\xa7V}\xd4}pO\xb0wV\x92\xb8\xf7\x9d?\x94\xd3\f\xf2`m\xa2\x17\x8f\x1a\x98\xb1\x8c,@\xcdv\t\x8e\xe6(,\u007f\xdfo\n{r]7\")l?\xd1\x1e\x86g\xdd\xf9ӓ\x19ٓ\xbb\xc7Sa\xb3\x9f|t\x8b\xf3n\xfb\xa3O\xaf\bE,\xea\x1fOb\x97\xe69FZ(\xbf\x89\xe0\xf8\x11{\xb1)\xfb\xddĜ\x84\\\xd0\u009e\xdf\xff\xb1b\x0e\t\xfa\u007fIA\x99\xda\xe3\f_`ЄC\xeb]\xef&j~\xc6~\x81ib\xf7wI\xf9\xa6[\xb8cq\xd2\xf2\x16\xe0N\x90\xcb\xe9\x86\xc6rF\x1e\xe6R;\x99:e\xc0\xbb\\6\xed\xc149\xba\x87\xd5\xd1\xd9\x06\x1f8\xba\x12GN\xc0G\xb3\x9bJ[\x90\x82\xaf\xc8\x11\xbe{\xd4G\tړ\x12\xf7zLt:}\xeb\xd1\"\x8b\xa6\xe3\xb7\xf6\xf8z5w\u05ec\xf7\xa2\xc3Bj\xf3\xd7n\x87ݖ\xf9܄7ںi\x87\xdf\xebI\x9d\xdd\xfb\xb0*\xa6j5\xb9\xa9\x01\xe5\x9dx\x8e\xd1\x06\v\xa0\xa7m\xf4\x94\x93\xaer\xd0\xd1\xcaQn\x11\xfc\x04U\xb8\x00\xc0>S\x8c\xd1\x1a-^\"\xf5\xed\xcbdž\x8fўP\xfb\xef\xe6B\x0e\xad\xd5fr\xb1\xa0\xeb!\xaf\xbd\xa6\xfaʽ\x19h\xda\x03r\xbb\xaff%\x9e\xcb\xfdս@C\x18\xecz`f\xce\x04\xa1\xe1\xf8\x83\xf2\x04EI!\x9f\xe6Dn̩&\x13\x00\x11\xd0\xf7$kp\xe3y\xe5\xf5\x82\x89+\xfc\x00yqp\xf9Njt%mg@u\xb5\xa1\xd5\x0f(q\xf6U\x8ddN\x1e栠E\x15\x9b\x0eo\xab1\xee\tRH\xd3\xf4+X\xb8\x85̏5\x992\xa5Ms\xa2\xfb\x12\\\xa9\xf7%\x87\xc8\x1d\xb6\xab\xbbc\v\x90\xa5I\u0603\xcb\xfa\xedV\xb4rA\x1f٢\\\x10\xba\x90\xe5\x1e\xc2\xdd\r+_آ\n)\xfa\x1dx\xa0\xcc \xbb\xb3p\xd1\xc3b\xa4ݥ\x82\x83\xd9w\x8b'0\xb5\xec(\x93B\xb3\x1cT\by\xbb\x9de\xd2\x1e\xdc)e\xbc\xec\n\xdft\x8dX3U\\*\x95d\xa5\xbeuo6\xbc\x86s\xf9\xd0F\xd0\xde(\x98\xd3%\x106%\xcc\x10\x10\x99\xdd\x17P\x8ee\xe3'<2\x105{\x93\xe5~\f\xde\x0e\x10\xe5b?\x04\x8c\xf0d3\xb1\xd3)\xd6|\xfck\xca\xf8sl\x9b\xa5\xbc\xf4\xa3\xf1}\xfd\xf6\a9\x1a\x15S\xd9_\x84M\x80\xbc\x03\x9a\xaf\xc2\xf9\xa0\xc6XS\x15i@\x12U\x8a&G|\x86\x93\x11c\xdf\xf9Y\x1c\xd2pc\x82\xed\xb1\xb1k\xfe|f\x9aڎ\x05\xf1\xacڎ\xfd@%\xe8R\\3W-\x00VT\x06\xc5\x19\xe7^QM\x84\xe63\x01k\xa0B\xee\x9c^V|z=\xda%\xf2l\t\x83w\xae.FuYs\xf3zC\xb3\x91\xfc\x16}\x04\xbc\x83w%K\xf2@\x85\tD_)s\x85ܓ\xeacw\xd5\r\xaaf\x11Ood\xd6\x05\x955\xa4\xb7\x810j\x85\xe9V\xfbN\xda\rk\x9a\xe62\xbb\xb7\xeaȂ\xce\xe0\xf8X\x93Wo^[R\xb1Z\x87\x15\x19\x11\x12\xc1\r\xe6\"\xb1\x85\x92K\x96[\xd5\xe9=U\x8cN\xb85\x82\xa7\xa0@d\xa0ɗ'\xef/\xde\xfdt}\xf1\xe6\xf24\n\xb85\x9dᱠ\xc2\xd2`\xa9\x834\xafv\xdf.\x00Ē)),\x82\xe2\xb0q5%\x94,\xc3l\xb3*\x13͚Z|鵹(\x88Պ\x83#\x84\x89\xa24\xc1;\xfa\xc08'\x938\x88\xa5\xc8\xe6T\xcc,^_\xcb\xd2\xce\xf3\xcb/\x11+\n\xf22\xf3\a3\n\xa2?L_\x9e\xf9p\x16\xe5\\>h\x94-\xa03Zx\x1cG\xc1ll/\xd1+a\xe8\xe3K\xc2\xc60&G_6\xfet\x14\x05\x13\xb1U(i\x97\xe9\xe2\x11\x0e\x8b\x9c\x19P\x94\x93\xa3&不\xbf\xb4넼I\xa0\xf85\x01KP\xce\x0ep$\xb7\xaf\x03\xdf\r\x053\xaar\x0eZ[\x9e\xfb0\a3\a\xe5\xddJ\x9e\xc8 \xc6\xeb\xec\x86T\xf6|ufJֹ\x91Q\x10C\x1e\xe5}\x95\b7T\xdf\xebs&\xacH\x1d\xe5\xd4\xd0Q\x83\xe9\x9e;i8\xf2\xf2y\x14,\xe9Qu\x1c\xcf\u007f\xa3J!\x98\x98\x8dh\xf5\x14\x13#:\xd2s\xe0\xfc8b\x96Q\xe2\u008dh{\xb7\xf9ZL\x80!\xd21\xe1F\x9b\xa3_V\f\xdc}yL\xae\xa5ٕ\x81\xb6}T\"\fq<\xee\xe4\xf1\x97\xd7w\xef\xfe~\xf3\xf6\xea\xfa.\x96\xb57\xc5\xc2vV\x9f\xc6$[b\xa1\x83\xd5\xc7\xed\xfe.\xb1\xd0f\xf5Qp\xb7\x88\x85\rV\x1f\x87\xd8\x0e\xb1\xb0\xc9\xea\xe3X\xf0\xa6X\xd8\xc2\xea\xa3\xc0\xae\x8b\x85\xad\xac>\nj[,lc\xf5Q \xbb\xc5B\a\xab\x8f\x17B\x9bb\xa1\xcd\xea\xe3 n\x17\vk\xac>\nl\xb7X\x18X}\xc7kq\xac\x1e\xc42\x99\xcd\u007f\xe7ͯ\x06+\xaa\xf6<\x8e\x0e\x8dČ\x03&\xda|\xaeK+x^̷]\x82b\xf9\x9e\xb6\xd3*Ds\xb1Q\x90I}\x1cB\xc66\x8a\xb5ʢ\x8dc1)V\x9a\x1bOEκ\xc7f<\xcdߚH\xc7\ai\xe0dL\xde\xf8\f\x03J^\xfdt\xf5\xfa\xf2\xfa\xee\xea\xeb\xab\xcbwqH!\xe9g\x87\x84\xa4\x91\x9e\xa89\xee0\x0f\x13\xf0\xb2[s\x88\x16\xc8n\x14\n\x96L\x96\x9a\xaf\xaa\xf4\xf6\xfeG\u05cd\xf5\x93\xebS\xcaVD\x83Z\xb2,e\xb6\x9dS\xeb\xa3\xea\xb8\xf1\xa4\u0093\xbe\xfa'Ԟ\x04\xc0\xdbmb\xaf\xfc\xa4\x90\xd6!-c\x0f\xf2\x19\xecc7\x9e\xb0\x92\x13 \x1eV\x81j\xccr\xa7\x1a\x95\x00t\xb7\x8dM\xf6N\\l\x0eT\xbf^Ô\x96\xdcyێ\x8e\xc61\xba\x8c\x1b}Y\xec\xd7J\xee\x19@i\x8e\x16\x9b\xbdu\x97\xbcB\xc4\xe00B\xe8\xd8'ƶ\xd4\x0e\x1di\xaf\xba\xc1|\xeed\xb0)\xa3\xf2\xe6\xea\x91.\xe5\x89\vIO\xd9\xec\r-\xbe\x85\xd5;\x98\xa6\x80XG;\xe6\xcc\xfa\xf4\xd2XӠ\x1e\xa8\xf5\xb8\xa9\xa5pžx!1\x19\xc5]\xa3\x85\x93;\x9f\xfd\x8c:\xacEOڒH\xbf\x83\x15F\x9av\x17F[\x95i\xa8y\xc9\x10+\u007f\x88\xd9\xd7pˤȠ0\xfa\\.\xad\xee\x00\x0f\xe7\x0fR\xdd[K쁙\xf9\xc8\xc5\xc3\xf49^\xc39\xff\r\xfeO\x8f\xd9ݽ}\xfd\xf6%\xb9\xc8s\"\x91Ֆ\x1a\xa6%wiw{g\xfav\x8d\xba\xa8\xc0\x19^l?#%\xcb\xff\x1c\xcfl\xc38\x00m\xc8\xc2eb\x1e\x88>n1\x92\xbf\nR\xaa\a\xae,\v\xaf8\x02\x91\n\xc3o\xfb\xa4\xc1n\x1f!a\xd9+\xba=\xd1>\x91\x92\x03]/\xe2\xb0\xdf\xd8?4\xdc5\xf6K\a\xee\x1a\x11\xe1㮁'\xe00R\xe3\xb8\x16\x1b\xfb\xa5\xb3v\x0fop\x162\u007fItY\x14R\x19]\x15,\x18[F\x10\x17ϨG\v\b\xde\xed;#\xffY\xfd\x88wG\xf4\x0f\xc7\xc7\u007f\xfa\xf6\xf2\xef\xff\xe7\xf8\xf8\xc7\xffL\xfdN\r\xb3Qk\xe6\x10\x80u\x01\xd9X\xc8\x1c,\xcb>s\xff\xf4\x96\xd7E\x86\t2\xd7=У\r5\xa5\x1eϥ6W7gៅ̯nz\x82D\x18:A\x05%\aQ\x02\xb6\x15~\x89\x19-J\x0f\x05bz\vM_K\xc6\xd2\xfb\xd7\xf6\xc8\xdcP3\xdf?Ůk<(f\f\b\xb4UA-4\x91\xd33\xcb\x1d\xd1\x14\xe8û%9Z\xbe\x88\x8cP\xb6\x00\xf4\x17lӀ\xa2\x03m#b۳\x9b>\x1c\x8b\x04צe\u007f\xc1KPeS\xf6\x00zqs\x15\n\x0f}D\xc4\xf7\x95lն}\f\xf9\x16\x12ο~\x169\x17\xa0\xf7\x13uuN\xb1\xbb\x83\xb1\xdfM\xde\xed\x833\xacPDE^W):q?\x8e\xb3\xa2Le\xe6\x1e\xc2\x02\x16R\xad\xce\xc2?\xa1\x98\xc3\x02\x14\xe5#m\xa4\xa2\xb3d\xf1\x13\xa6\x8aS\xac\xff\xe5>\x97\xca\xf9\x1b(\u061ci\\\x12O\x03\xaa\x02\x92\x95\xcaZ;|\x15t\x14\xc8?\x9a|\xab觻DҾ\xa3M\xe4u\xb2z?[\xb3\xe6\x1f\xe8\xc6YJ^.@\x9fUVJ\x0f\xc0\xe8\xd2\x14K\xb2\xa4J\u007fT\x8b+gK\xa6\xf7M\x97\xee\x1aT\xac\xde&\xb2&\x82<\xd6-\x82\t\x03\xb3\x1e&\xda\xe8\x10\xc8\xe84\x1f}\xf9\x88\x1e\x9b-KS\x94\x98<\xbc\xa0\xa6\x8aJ=\x162\xcds\x17F\xa3\xa0O\xdet\x98\xbeHqc\xbbQPc@\x89\x97\xe4?N\xfe\xf1۟G\xa7\u007f>9\xf9\xe1\xabѿ\xff\xf8ۓ\u007f\x8c\xf1?\xfe\xe5\xf4ϧ?\x87\u007f\xfc\xf6\xf4\xf4\xe4\xe4\x87o\xdf|sws\xf9#;\xfd\xf9\aQ.\xeeݿ~>\xf9\x01.\u007f\xdc\x13\xc8\xe9響L\x9e\xf2\xe3\xa8\xf6Ќ\x980#\xa9F\x8e\b\x9e,\xf6\xb0k\x04\xe4\x1e\x8a'\xbd\v\x9aH_\xc1K\x9a\x1a\xdbGd\x1d}U\xab^h\xe8\xa9Yi\xc8\x14\x98O\xcf\xe7\xec\xe6\x15\xd4pw\x8b\xa92\xf8\u007f1n\xe8\xfe\xa6\xa7CSm\xb7`\xb1C\x82\x01\xfa\x1e`1\xb4\xbf\xc4:\x12\xfe\v\xf7\x90\x10\x11\tcp\x95\x0f\xae\xf2m\xe3\x97\xee*\xbfu\xe7\xa7\xf6\x93\xa3\xb7\xbb\xdf\xd9\x1c\xfc\xe4I\xd2.\xf9\xe5\xb4պ\x9a\xdcQ\xaf$\xce01\x9706\xb4ߙOX\x17\x92#\x85,JN\xf7\xbe\x1d[\xcdc3sh3\xb90\n\xa6\x17\xafua\xd0:/ݥ\"D\x1f\xc1\xcd\\7r\xc19a\xc2\tI\xfc\xd8\x03\xe3qv0\xa659\xaf\x03\xa1._qi\xd1\xf00\a\x91t\xb7\xd2\r\xa6\x896T\x19&fc\xf2\xbd\x85\xe5\xb41\x9f\x8b\xc2\x04Y\x94ܰ\"2!\xa9\xb2\xb0\xaa\xda$\x84j-3F\x8d\xc7p\xb4@\xe5T\x9b\xb0%\x98\x96c\xe8=f\\f\x90\x83\xc8\x00kY\x95\x91r0\xec\xf9de1z)\x96nn\x94\xe4\xa5K)\x86h\xee\xd3=\xb7\x8f\x9d\xeej\x8f\xafO\xad\xa9\xb3^#\x99\"\xfa\xb8\x1d\f9\xadK\x89U\xf1\xdd8x\xe9*v\x95\xfd\x92d\x86l\xe8\xd6u|\xbaҌS\xa2\xaaJ.>p\x16P\xba\x9a\xbbUŭ\x15\xd5D}\xe1SSo\x9fE\xb5=\xa4Z\xdbS\xa5\xed\xa7\xce\xeeRe{X<\xf5\x89:D\xb2F?\x05\xb4\x87\x12X(\x98\xb2Ǟ\x1c\xe6BT{DX\x0e°)K\xb2\x13\xacΤ\xa0\x00\x81i\xc2@\xb3\xb9+\x83)\xdaI6)4\xfd\td\xe8;\xcf\xc1a\x18\xfa횟c\xe0\xe6\x037\xdf1\x06n\xbe{\xf8\xe3\xf4\x19\xb3\xf2\x0fh)\xe3\xcd\xe5\xf4\xebկ\x1b\xf7\x9f\x91#<\xc7]\xf9\xea\xbcօU\xce\xf1\x8bq\xc7\x12\x8b\xc0\xe2ѳVd%\xe4\\1}\xf9@\xe6l\x16\xeb\x11\xe3\xb0\x04\xee\xf5{\xb2\xa0\x82\xce\\)M#C\xa8.\xf6v\x84eI\x8a\xe5\xad\xc2k\xb8T+8-\x9b\xe2\x92\xc6\xd1r\xdd;N\x13\xce\ue07c\x86\x82˕\xaf\x98)rrk\xa8\xb1l\xe9\x16L\\\x02\\\x12\xf3\xc0\xd5ܔ\x9c\xdfHβ\xa8\x98C\x9b\xf4\xae\x90抒sR \xa81y+ 6,s\xc1\x1f\xe8J\x9f\x91kX\x82:#W\xd3kin\x9c\xb9Y\xdfO\x89;\xbc\xd2\x03%lJ^\xba\xfeh\xc4\xd0\x19\xba.\xaa\xfauqD\xa1Z\x13s\xc2\xe4\x81\xe9\xbevz\xb4\xc0\xdc8\x80\xbf\xc1\xafZ\xd1\xe9\xfe\xfd\xec\xe4\xc3\xd9\x14\xb2U\xc6\xd3y\xd6E\x86ɮu\xf9\xf5\xfa\xdcƹ\x8cV\xda\xc0\"\x94\rC\a\n\xc32\x93\x85\x14\x1a\\A\xbd\x14\x0fW\xb5B\xe70\xd3=\xf78U\xc9+\xa46\xb7\x86\xaa=˴գ}Jo\x02\x18K\xfe\x19\xe5\x1cr\xc2\x16\v\xc8\x195\xc0\xe3\xfd\xe4\xa1\x02h\xb3ܣkw\xe9\x8aI&\xe9\rs*r\x0e\n\xeb\x15z\x1f`\v\xbe\x01\xb5`\x82\xc6\x16\f!Uz\x17\xba,!'4ˤ\xca}-\xb8Pً\xaax\x8d\xbf\xe2x\xa8+5$\xcfz\xbe^4\xe4\t\x97ٽ&\xa50\x8c\xd7\xe5!CmHߨ1\x1aj\x12\x8b\xa9\xfesT\x9d\x89\x11\xf6#;\xffM\xfd'\xfc!V\xf9\xedc\xf9\xecW\xcfws\xacՠ\x04$\rL\xa6\x94\xf1b+\f\xcc\v\x96V}\xb1DU\xd7W\xad\x04M\x9a\x91\x81\x05\x88\xdb]u(\xb2M\xac\x8bF\xef#\xab\x90\xb8\xd17G!\xa1\x16Ps\xec([\x9c\x1ck\f\x85m9\x13Ь_̰&jz\b\xb3y\x82\x1d?\xf2\x16jz\x10\x98)\xec1\xb2jԶts\xef\x93̯\xa44\xe4\xe4\xf8\xfc\xf8t#\xa8u\x9c\x0eu\xca88\xe9\xea\x8a,e\xd5f%\x83\xd4lQ\xf0\x15\xee\xcfq\x8e\x1d\x9d\xfcuXU\xa6ň\t25\xbbˡ \xd4\x19ђ\x18EC\x97\x81\xf4\xb9Zh\x16\xb8Q\xa5\xd7UN\x8e\u007f>>#`\xb2\xd4|`B\x1e\xa486HFcr'I\xa9\xeb\x89'\xc3\\ɒ\bpu\x00\xe0\xb1\xe0,c\x86\xafP\xcc'Ô\xa5q\xc5\x17\xb1A\"\x16ں|d\xc6\xdf\xd3I\a;%_\xe1iw\xaa\x02\xa1\xd6\x18Z\xc2\xf9\x1c(7\xf3\xf4\xfb}\x96.\x85\x14\xa3\xff\x06%\xb1\x8c\x97\xf0\x10S\xbd;\t\xb1\xb3\xe68@\xc6I\x8a\x1ba\xfd\xed\xc4$\x06\xab |\x03\xd1*'\xd9\xe8Hzww\xf3\r\x98\xb6\bKB\x87\x9dQ\xc8\xcfG\x976\xa8\xa9T\x1d-w\x9f\x1e}\xe5\xdf\\\xea$̐\xcd~\xadڸ\xee\x13\xceH\x11i>g7\x8cl\xa7%\xfb\x8cFru\x93\x9e\x88\xf5wYZlM脯\xaa*\xb2\x1a\f9\xb2SOO{f\x02\xf7\xf3\xaf@s\xac\xdb+\xb4\x01\x9a\xa8\"\x1d\xe0\xa85\xe6r\x18\xa5\xc6\xf5ݝ;\x90=v\xb4Y\x02\xcb\xd3\xfe\x18\xcfT:\x9bt\x15^\x14\x14\x8e\xfd\xfa9~$&\xb9\xc1+\xdc.\xf8\xdf'\xbdr\x13ih\u007f\xec\x96\xe8k;'\x16\xef\b\x83\t\x9c&\x1e\x8a\x1e\xb3\xeb\x9f%Lzg\xab\x92\xae\b\x98\xc3U/\x98\xfe\xeee|Z\xda\xfa8\xc8\xfd\x92\xe4\x12^\xcd\xf1\x9ch\xc2\xe9}|<\xf5K\xb5$i\x89\x88\xed\xd7\xfba\xa2\xe7\r\x05\xd2[\xdf\xc2\xcb<\xc9\u05cd7/\x1b\x1bIh\x96\xa5\x15\x8ar\xc3w/G\x86\xa5A-c\x13\x1c\xebћ\xc4\n\x19\xef\xbf\f\xa3ׅ\xb7\xc3\\w;\xc8e\xb7\x8ez\x89\x8a\x88r1\xe9\xc1I\xaa\x02\x18\xca\xd4\x04\xe37\xbe\x873\xa5*\xb6y\x8d\xd3\v!\xdc>\xfa\x1e\xaa0T̀\xbc\xb03\xfd\xe3\x1f\xfe\xf0\xfb?\x8c\x11\r\xc9PC`\x99\nruq}\xf1\xd3\xed\xfbWX\xc4-\x95ʟ\xe5f\x1b\x96mH\x96?\xed\xc8<\x82\xb2\xd8+5\x16:\xeb\xb3\xc3\xd6\xd6\xf0\xfeo\xe7\\֩q\xb6\xe60\x12\xd9\xcdG\xe23}\x84\xd8\b\x0fч\xb6\xb3MV\xdc\xca\xec\xfe\x00\x96\xf6\xf1ݫ\x1b\a\xaa6\xb6\x93v\x81\x8a\xe0bfb)\xf9\xd2\xf5\v\xbc{u\x83\bJ\xdbY\xfb6\xc6\a\xd0շ\xb2s\f7\xe1]jN\x12T\xb6(|\xc7LJ\x14Pδa\x19~\xab\nS$\xda\xf7\xf2>%\x8b\xe7\x93\xf1+\x1c\xbf\r\xe9@\xe8bH>\xcdk\xae\x89\x96\x8b\xa1\x0f\x8bh\xb8&R\xaft\r\x1a\xc9\xc15\x12'\xea\xa5\xea\xa7\xc7\x0f\x1aɧ\xad\x91|n22\xf9\xd5B\xc1\xad\x91EϬ\t\a\xe4@9\x13\xa1\x13ݶ\xa4\x06\x92'l\xa9\xeb\x1d}qsUy\xc7e+\x11\x01\x93W\xa2\xa1\xea2\x9b\x87،\x00\xad\xcf1=\xa2,\x9c\xe7+4\x94\x8c\x8fX\x15\n\xb0\v\x9f\x14gUE\x02D\a\b\xf7#\x98,\xfe\xb4\xa0O\xc6\xe7\x8e\xf8xbخ\xbei\x18\x99\xa2z\x0eة\x02\x1e\x99ѡ\xdb5\xd5R\xb8\x10\xae\xdf>&\xe3\x03\x98L\x93\x82j\xed\x02w\xa6^\x84\xfbȍ̏\x13\xa2\xb7\x8d\t\x91\x99\xa2\x19\x90\x02\x14\x939\xc1\xaa\u007f\xb9|\x88\x9f\xe7\x04fL\xe8@\xbfv\xa2\xe1`X]\t\x92\"\xc2u\xe7\xd9w\xad.Rخ\xbc4\x99L\xe0\xc3\xfeu\x8f\xc5\xf5\x04\xa2諓8M{|J\xca\xf9\xaa>\xa8ᦧ9\xfc&mf\x12\xa5\"\xa1^\xf7z&Q|4\xb0\x95yd\x8fB\x9d\x95ԇ\xfc[\xd4ɴ=UټG\x9b/\x12\x9f\xbe<\xa46=9\x86Ԧ\xbdǐ\xda4\xa46\r\xa9MCjӐڴ\x17\x88!\xb5\xa9\x9aѐڴc\f\xa9MCj\xd3\xd3cHm\x1aR\x9b\xea1\xa46\xed5\x86Ԧ=Ɛ\xda4\xa46m\x1dC qHm\xfa5\x06\x12\x87Ԧ\xb8ׇԦ\x881\xa46\r\xa9Ma\f\xa9M\x91c\xd0H\x86Ԧ_\xa3F\xf2\xb9\xc9\xc8^\xd5\xc5\"_\vy<7JNz\x94\x19\xbb\xc1X=\xcb|\x1a\x90\x9c&\xd7\xd6q\xd3\x19\x93W\xad\xf4\f߄\xdfUi\x89\x82\xe8\x13}\xea\xf4\xa4\xbe\xf5z\xa2k2\x85\xa2`\xfa\xbc\x90\xee\xff\xd59\x05\x8dd\x02\xe7_\x8b\x11\x0e\xa9\xc27%\x8b\xe0\xa9\f\x82$^\xb7;{\x003\x01\xa2a\x1e2s\xa0\x8fv\xd3#c`G\xb6@\x00\x9b\xc4\\\xbb3\x05\xd6\"\xfeɩ >K`3\xda\xdf'\xe1\x02S\xe16\"\xfd\x89\x10\xab\xec\x80mQ\xfe4\x95\\\x1f>\xc2\xff\f\xd1\xfd\xc3G\xf6wD\xf5\xc9J\x96I0\xb7D\xf4}d>\x916;\xa3\xf9!*\x9f\x06\xb3;\x92ߊȧ\x12S\xaf(~\x8f\xe0TO\xe5:ݓ\x9c\xac)\xf9d㻹\x02=\x97<\x9a\u05f6\xf8\xec\x1b&آ\\X6\xa1-{d\xcb*\x9b9\x9eFB\x9e\x93\xd3:\\\x18\xce\x02f9`\x13K\xcaxJ\xa9:,\xad7\xa7\xe8\x9f\xd0e\x96\x01\xe4VN\xbe\xaeC\xe0\xd10\u007f?\xaeV\xee\xbaj0M^\xc4R\x9ek\xa8\x88\xf6\xdd\xef\u007f\x97\xb4\xfb)\x96ab\xc2\xc6\xd3\xc9\x1a\b9\x1a\x93\xfd\x135\xfa\xa8\x1b\xa9\x8e\x94\xe7I\xceؑ\x98A\xfe\x9e(\x1av$e\x10\x96&f\x0f\x94\x90ыs\xf6L\xc4ؑ\x84\xe1q\x94\xa8\x80l&`\xac'R\xa4\xa1<=\xf9\xa2\x87l{\xae\xa4\x8b\xed\t\x17\xa9$Iz'[\xf4O\xb48`\xb7\xc3:s\xa0ww\xfc^.\xba\x03x\x0e{&U<\x17Z\x0e\x91B\xf0\x11\xbb\xcf&\xefj\x9f䉞\x89\x13}\x92&R\x13&v$K\xf4\xf14\xf7L\x94\xe8E>\xa9\xe1\x88\xe4PD\xff0D\xef\x10Ď\x84\x88>=a;C\x0f\xa9\xfd\v\xc3h\x87\x1d\xd6\xc2\a\x89ja3\xe4p\xd0\xd0\xc1\xc1\xc3\x06\xe9I\f\xbb\x13\x18\x1a\x89\b\xa98\xdcL^蓄Ѓ\xa2S\x99\u007fRP%\x99i3\xc1\f\xa3\xfc5p\xba\xba\x85L\x8a\x13\xa2u\x1bsN}\xe7L\xc8Å\xda\x10\r\x89g\xad\xa8>\x12\x8aq\n\xbbzӾ=\xf9q\xe3\x16䣹\fܕ\xd2C\x10\xc1_\xe5\x03\x91S\x03\x82\x9c0\x11\xe8 ޏZ;\vj\u007fQu\xac\xed__|\x15Ϲ\xdcd>_\xc7\x0e\xba\xb6\xb4~>\xbf\x9e\xff\xc0\xe1\x1d{\x1e\xf0\xb4\x8c\xf7ѷ\x9c{\xceA\xd8\xe6\xefћW\xb7\xe1{\x81\xf3\x0e\xdc\x04\xbdԾlC\x02\xccϔ\xa8\x92\xd3ΞL9#\t\x9d\xc7v\xa5\x9bթc\xd1`\xb7\xa4\x9a\xd5ic\xf1\x13ݖf\x96\x942\xf6\xd1=\x9ckib\xe9\xe6\xe7\x96\x141\xaf\x9e%*\xf1\xc9\xe9a\x83\x1d\x169v\xa4\x81\rv\xd8'd\x87}\x1e\x16F\xa3\xd6\xc97\x8afps053\xb0+\x92\x97\x8az\x91\x11\x14\xbc${\xc32\x19\x01\x90;NU\x15\xae\xc1\x8a+Ӓ'\x14\xaf*\v)\xda՟\\NE\xb3\x88K4P\x9f\xedұj\xaf(\xa5\x9c\xd0BI\xa7\xf6\x11U\na\xa5\xae?K\x16)\xd6V\xd2i\x12\xb2Y\xb3G\xb3\x99\xdd.\xabba\x15\x1c\x96 _\x1e\xe6 \x82\x96\xe9'lg7\x95*c\x13\xbe\"s\xcaS\xc2/\x0f\xcc\xcc\t%\xf7\x8cs?\xcd1\xb9\x05C̜\xe9Dg*\x97b\x86\x9bA݄᱀̪\x1d\x19\a*\xca\"m\xfdVY]\xc9R\x85\xf5\xfb\xb6qa\x96)I\x1b\x82\xf1\xb3\xb0\xd5\xc7z\xf7\x81M@\xacKP,5\x84:M\x0fL\xc3Y\x1f̆6\xa3\xee\x1c\xb8u\x17J.Y\x0e9\x99\xac\xd2\xe8_樵\x8e\xc9{\x84\x17\xf8\xbe\x90b$`F\xadm\x14\u007fR\x9d\x10wg\xde\xcd\xd3գ\x109˨I\xb0\xb14\x16֫\xcb\xe9\x91%\xa3\x88\x85\x06\xe5F\x03=\x11\x92HT\x8aK\xc1\xcc\nc\xa3\xf3Ґ\\>\x88\xd31\xb6\x9eMaR\x94L\xc0P\u007f\xafյ\x12D\x81\xa5\t\b:\xe1)\xca\tf\xe2\xdeu\x12(\x99\x025eBw\xbf\x195\xd0\xe9\x0fp\xf4p\xd8\xe3\xc0\xb4\x8f\x80NI)4Dߟi؇\u007f\xfc\xd7\x0fg\x1f\xb2\x05\xc8\xd2|R\x0e\u00879\xcb\xe6M\u007f\x03[\x80&\xb2\xecsm\xcdH\xf2\xc2O\xab\x9b\"\x9e\xb9}\xe4/Ϋ\x98\xa45Ɔ\xd8;\xe2F\xeb\xd5\xfc\xaa\xc4\xe9\xa8uS\xcb\xc3^_\xdf\xfe\xf4\xdd\xc5_.\xbf\x1b\x93K\x9a͛eH\x05\xa1VnD\xc1D\xb92\xa7K \x94\x94\x82\xfd\xb3t\x9d\xc7\xc9I\xf5\x9dӐ\x83\x1f\x057-_?\xc9R\xb4\x82\"\x8a\t\xb46\xe8;\xa6\xb1\xd1+B\xf1\xe9\xacR\x03\x99*\xb9\x88cJ-\xeb\x91\\Z0\xce[\x84\x96\xe6\x1c\x14\x90\x19[F\nY\v\xd57G\xa6yH*\xc6#lO\x8f\xd5b\xe9D\x96\x91&\xd0\x1c\x88\x00cOw\x15\xe1\x92B\xb7jږ\x1at\\~\xf9\xa4\xc4T\xeaB\xb1\x05U\x8c\xaf\x9a\x93\xb4\xea\xeb\xb5\f~\xb8U\xac\xa8m\xa2\xf0\xf5\xdb\xcb[r\xfd\xf6\x8e\x14\n\xcbz\xba\x9c\xe1h\v\xd2n/\x99\x80\xdd \xb7\xe1\xf9\x98\\\x88\x95\xfb\x90\xe3\xe5\x91Z\x06g\xda\x00Z*ޕ\x10\x9a\xd6\x1f}5\xc6\xff;\xb2;\xa8bCDUzy\xb6q\xc9\xc6y.\xd8$\xf2\x1e).\xbdA\x03=\xef\xd8$\xa4z\xad]\x9a\xf0뺱\xa8WP\xb8\xbe\xec\xb1ҒV$\x8d[\x88\xccО?\x9e\xec\xd3Iw\x80f\xcd%\xc5{\xdd:\x1d^\xd3\xcaa\xe5\xe85\xc1\xdf#Eì\xba\xba\t\xe4\xe84j\x94\x04\t@-\x1dZ\x9d\x84\xe5n\x82.A\xe2\x8c|E\xfeD\x1eɟ\x12 \xfe\xf1\x0f\u007f\xf8\xfd\x1f\xe3\xfdY}\xf4\x89>ʨ\xf3v_\xdd\xf4\xdc\xe7\xef-\x1b\xb3\x90\xec\xce\x18I&,鎋\xb3\xec\r(+&<\xc5\xc4㲇\xc7\xd6.\xe1\x93${\x97\x85q5\xad\x95/g\xf4'@\xac\x9c\xb0[\b?\xc5\x17K\xfe\xe4\t\xdfN\xf1\xafR\x9bk\xcfΘn\xcc8\x89\"\xfc\xe1&\vj\xb2y\x9b\xdfZ\x13\"\xe9\xd8\xd7\xe5\x97I.1\x96\xe5\xae\x03\xcdYB\xbe\xf0\xc7;\xbai\xe9\xb3-Jݤ\xa8>\xactͭ\x8f~\n\xaf\x97\xbb\x82\xe5\x89<\xa1\x90\xb97\x18\xec\x92\U000c640c\xb5\x18\xdc\xd8b7\xf8(EZ\xf1\x97\xfab\xbe\xe5\x85\x19\x15\xee&\xf1\x14\x94\u009bf)(]a\xc6$\xcb \x81,{p\xc1BI#3\xc9Sh\v\xb5Ɨ\xe4\xeeU|\x19\xc5v機\x03\xfah]\xb4\xfaM2a\xfe\xed\xf5͙\x9d\xd2\x19\x91\x8aܾ\xba\xbb\xe9w\x95\x89\x90\xa3\xbbW7G\x1fpOҢS\xa3\xb6.\x17\xf9n\xa0\x828\xeb\xacOE\x81\xd8D\xe7V\b\xd0Z0\xa3\x05-F\xf7\xb0\x8a\xd2yӱ\x94\x84\xa3\xcdI\xbb\xc5/\xe8\xfe7\xc1\x14М}B\xc5\x14<\x97\xaa\xe7\xd5]Ua!\x97\x91N#\xb4\xf6\x02t\x10y!\x990\xba\xab\xd4B\x14\xd8M\x93\xf1\x93IY\x1cJ-t\x8c\xa1\xd4\xc2\xd61\x94Z\x18J-\f\xa5\x16\x86R\v\xddc(\xb50\x94Z\xf8\xac\x92\xa7\x87R\v\x8d1\x94ZH\x18C\xa9\x85mc(\xb5\xb0\xd7\x18J-l\x8e\xa1\xd4B\xe7\x18J-t\x8c\xa1\xd4¾c(\xb5P\x8d_\xce\x15\x9f\xa1\xd4§z\xc5g(\xb5\xb0\xcf\xf8<.B\r\xa5\x16\x86R\v\x01/C\xa9\x85\xa81\x94ZX\x1bC\xa9\x85ϕ\xa8\x86R\vC\xa9\x85\xa1\xd4B\xf7w\u007f\xedv\xd8Pj\xe1S\xb5\xc3>\x0f\vc(\xb50\x94Z\x18J-\f\xa5\x16\x86R\vC\xa9\x85\xa1\xd4\xc2Pja(\xb5\xf0+\xf2*&i\x8d\n\xb4,U\x16g\a\xb7\x89\xec\x95\\\x14\xa5\x01\xf2.\x80\xaa\x94娅\xa3,a\xbay\xa3\xff\xc3v\"̤\x98\xb2\x99W\xf4\xce\x17T\xd0\x19\x8c*\xfc\x8c\xea\xfbw\xe7\x1f\"7\x9e\xb3\x05\x8b+\xb2`G]\xb1ই\x87#Ѡ\xeekN\xf74\xa6\vj\f(\xf1\x92\xfc\xc7\xc9?~\xfb\xf3\xe8\xf4\xcf''?|5\xfa\xf7\x1f\u007f{\xf2\x8f1\xfeǿ\x9c\xfe\xf9\xf4\xe7\xf0\x8fߞ\x9e\x9e\x9c\xfc\xf0\xed\x9bo\xeen.\u007fd\xa7?\xff \xcaŽ\xfb\xd7\xcf'?\xc0\xe5\x8f{\x029=\xfd\xf3\x97\xd1S=\xb0q\xda>\x8f\xdf!\xe5\xd4)Eȷ\x17\xf4\xd12\xd8xRX\xc8R\x18w\xcb\xc6\x1d\xf3\xeaD\xb84\xac\xd8CI>\x95\x83I\xfa\x18\xda>\x1fm8\x9f\x11c8\x9f\xee|\xbe\xf3\xb4\xd3>\xa1\xd1s\\x\x95i\xc7\t\x8d\x86\x19\x047\x1a\xba\xd5<\x99&r\xc1\x8c5\xa7S\xae\x197\n\xa9\xe0\x95\x94\xa6\x8b\xda\xf1\xaax-o\xeanS0ݼ\xa0Ѹ\x14.\x83훢\x96RQ\xc7)\x90\xe7\x8cr\x982\x01\xb9SO\u007f}\xfc.\xe95\rY\xa9\x98Y\xbd\x92\xc2\xc0c\x94c\xbf}^nۀ\x88ی\xf8C\x13&Dd\xe1\xae\x1d\xadU\bÛ\u007fq*+\x10U\n\xf4g\xb9:\x17`\x9cs\a\xcdp\xbcٳ6\xf9(\xf0\xc1\xf5\xe2\xa8)\xb6\xe4\xaeO)\xd7ь<]\x1a[E\xe6\x8d5\xdf{\xedb\x05\x85\xe4 \xa4\xf1\x1e\xbf\xa4\xd3 \xa7\b\x8d8\x9fB\xe3\xb2@K\xe2%)\x99\xb50f:\xe0\xfc\xa6\x9a9F\x98\xe2S>4\xac\x9bq^\x18W^\x86\xa4\xa0\xbf\x02\x9acM\x99\x82\x9a\xb9\xcbS]P}\x0f\xb9\xfb!QǮB\xb2v\xc6\xd5\xd2\xefV\x05$\xc7SQ\xb7vٿ\x18\xe7\x8d\xf7\xc6\xf6(\xefE\U000f70af\xdeIi\xbe\xaeʘ\xf4\"\xe4オԎ\x03E#e\x8ee\xbb\xed\xfcF\xb8\x89X\xb6\xa5Yi\xc5S_\x8a\x95\xf0\x81\x19\x84*Ņ\xfeF\xc92Z\x15\xd8Pֿ\xb9z\x8d\xfc\xb2\xf4\x192¨\x15\x96\xa6Ja\x12\xed3W\xd9c\u007f\xf39MI\xd96\x15{\b\xe1z\xf2\x86\xae\b\xe5Zz\xc31!\x18\xdc\xe5!!\xdeU\x93r3z\"\xcd|ݧ\x83\xeca\xf3;\xf1\x05\x8c\xea\x04\x9bʓi\x97\xd0Dž\x84`\xe9=hR(\xc8 \a\x91ES\xef\xc7I\x83@ʿ\x96²\x97^\xb4\u007f\x15\xf2\u007f\x9c˸\x9fU\x8f\x99Jަ\xa7\x98\xaf\x84̥Ԡ\\r\x98*!m\xe3\xbf-'\xc0\xc18G\t\x16\xb9\xa5\xc6y\xfe\u0602\xce\xe2O\x135\x95(4\x92\x80Х\x02\xef47$\x97\tf\x80\xaf#e\x97\xfe\xb7\xab\xd7\xe4+rb\xd7~\x8a\xe4?\xa5\x8c\xa7T}\xc1\xdb\x1fk܄M\xc3\x14-J\xe3u\x02\x81ƾr\xac\xfa\x8c\bIt\x99\xcd\x03NS\xbcC\xc1y\xe5oH\xe1\x15\xb6\x815}\x02\xac\xa9\xa7`\xfd\x9b\x06\xd5[\xae\xfe\xed\x03\xc8\xd5>n0˛ڻ\x86\f\x85,\xc0М\x1a\x9a\x12|+E\xa3:\xe2\xdaQH\xa1\xdd\xddG\x01I;\x1a\xe6\xaf\xec(|\x1c)\xad\xe1;&\xcaGw;\xa0\xbfC\xf9\xf6\x12\xc1\x11\x1fJJ\x91(\x13 \xb4(8s\xe5\xfb\xd6Z\xc4\\\xb5H7m\xef7MM\x14\x0f\x94siՌ\x84\xf0\xb8\xa2\"\x97\x8b\x8d\xc5[C\x14h\x82U\xdcXp\xc7\xe1\xdcv\xd8\xe2ew}8\u007fm\x87\xad\x8f\xeb\x9e\xc3\x12\x12\xaa\x94\xaf7Q\xb2P\xacA\x1a\xa8\x06\xc1&y?9\x9d\x00w\xaa\xa1;9z\xf3\xe4${E\x13\x9d\xaaJ\xf2\xfe%/\xdeI\x0e.7> ɂ\xfd\xc5\xe0\b_\xee\x8b#\xf4>\xb5p\x94\xecE\xff\x14qT&hxd\x1dGVMl\xe3Ȃ\xfd\x85\xe0(9\x04\xa1!\xcb䢸Qr\xca\xe2\x0f\xeb\x86\xe8\xf7\xe0\xea\xe4\x9cx\xd1_j\xe8\xca\"G=\x12\x81\xc7k\xe4~2T5.=Q\xe3d\x9e\xbf\xc5\x15\r\xf4\xffk\xa8\x10ȵ\xcf\xd6\xf4\n\xff\xd5\xf8\xd96\xf3\x85\n\x99\a@\x1fT\xbaɌr\xecH\x94F\x17d\x9d6\xd6\x01\xf6\xb8\xcfE\\c;\x0f'\xe4\xf4aK\x16\xfc%\xc13@Bs?\x99C\xa3v\xbc\xbb\x80w\xe7\xee\xcbX\xd8I\x80õ8\xab\xa7\x84\xe4\xab<Į\xec\x17Ӧ+}\xa9\xec7UO%\x8bp\x10yj%\xa8\x82\x9a\xf9\x19Q\xc0\xf1\xe2^`h\xf7Ρu\x9c\xb6O\x8d\x05\a\xce\x106\x0e\xf5l&E\xda%v\\5\x86\x05\x82F\x947\xe5{\a.\x98Ιew\x86\x89YB\nF\xedQ\xa1\x9c\xb72\xf4\x0e\xe1R\t\x9c\xa0ꓺ\xe9:H\xf6\xd9;bn\xfb\x12{\xfb\x0f\xb6\xb87jwE\xbc3e\x87{ù+\xa2A~\x1c\xf7\xc6l\xa1\xe9+e\xbfk\x18\xe5\xb7E|\x87\x1f\xb2N\xcb\u07fc\xb9\xbdh\x83L\xe3\xec\x98\u05eb\x9czla\x12\x9a/\x98\xd6L\n\xf2\x00\x93\xb9\x94\xf7IpOB\xea\xfc\x8c\x99y9\x19gr\xd1Ȣ\x1fi6\xd3\xe7\xfed\x8f,vҚ\x9c0\xc1í\a\xe7!\x14F\x87\x88\x81]L\x9a\x96Ua\x15\t\xd0w*\xf4\t\xae\x9bh\xbfN-R\x857\x16>\xb8J\xb5I\x8a\u05c9\x05ş \xc7d\xbc\xf8\xea2\x8djO\x8e0\xeb}I\x13\xb7v/]\xe8\xe7÷\x11p\xa6Z\x06\xba\u007f\x1b\x81\xbfְH\x0e\xae8D\xa2\xddǦ\xad\x86\u07b5B\xe2\"ډ\xb6\xe41\xd6n\xf3S\xe5\xa2\x1f\x91\x1a\xb0o?\x8f%ی\f\xf16\x92\xb3\xe9\x14\xc2\r\xe7H\xb1WPE\x17\xd6p\xd0ħ\xfeN`\xc6\xdc5\xd3J\xb5\x8a\x8cPTE\xc2Μ\xba\xc7\fY\xb0\xd9\xdcyi\b\xc5R\x94\xf1\xe5&\x8d$\\Ҝ \x17\x97\x8a=4\x9f\xde{\fͧ\x87\xe6\xd3C\xf3\xe9\xd814\x9f\x1e\x9aO\xef=\x86\xe6\xd3C\xf3\xe9\xa1\xf9\xb4\x1bC\xf3\xe9\x8414\x9f\xde6\x86\xe6\xd3{\x8d\xa1\xf9\xf4\xe6\x18\x9aOw\x8e\xa1\xf9t\xc7\x18\x9aO\xef;\x86\xe6\xd3\xd5\xf8\xe54=\x1b\x9aO\u007f\xaaMφ\xe6\xd3\xfb\x8cϣ5\xdc\xd0|zh>\x1d\xf024\x9f\x8e\x1aC\xf3\xe9\xb514\x9f\xfe\\\x89jh>=4\x9f\x1e\x9aOw\u007f\xf7\xd7n\x87\rͧ?U;\xec\xf3\xb00\x86\xe6\xd3C\xf3\xe9\xa1\xf9\xf4\xd0|zh>=4\x9f\x1e\x9aO\x0fͧ\x87\xe6ӿ\"\xafb\xe2M\x91\x9cE\xb5lۣ[@J\xed\x93P\xbb\xd32\xb2r:\x05\x85\xc2\x17g\x17\x94\xa3\xb4K`\xa13T%\xba}F,6\nT@sW\xf3\"\xce/\xd89\xadP\x84\x14ۗ\xb9{\xa9\x91\xe1\x01r\xf9\xf6\xeb\xda\xe9\x9a\xd2\xea \xedv \xae\xe7\xad\xc8\xd2\xef\nՄ\xd0Q\x9d5\x0e\xb7.\x01?\xe3R\xfb{\xb2\x88\xeclN\x85\x00\xee\x95n\x16\x87\xd99\xd5d\x02 \x88,@8\xb5\x85\x12\xcdČ\x03\xa1\xc6\xd0l>\xb6+\x88\xf3\x9ey\"\xf0]\xeb\xea\x99j\xa3\x80.\x1c1(X\xc4\xf6\x19\xb4S$4SRk\xb2(\xb9aE5I\xa2\x01KeD&-]M\xeb\r\xc6$\xf1\xfa\x02\xeaY\xb5\x8a\xe89\xba2h\x8d3o\xa82g\xd8\x0evQ\x98\x95\xbbK\x15'\xf8\xb0k\xa7҆d\x9c\x810~ծ>#\xce\xf3\x8c\xc4\xe6\xc6\xe3\xf5]\xb7\vڣV\xe4\xe8\x15)\x8cv7}\xd2&꧘3\xed\xbdo\xfa\x8cP\x13\x04e4\xd1\aZB\xb2\x0f\n\x9c\x9b\xb5\xff)q\x9auI\u007f]_5\xab\x99\xe1\x94\xd38\xc500\xa5\xb3V-\x87\xda>\xc4$wd\xabQ`\xb1\xec\x90\xc3\x02\x1e\x1c\x01K\xcb? \x03\xb6D\u007f\x90\xe5\x8cQ\x10\u05f9\xe8\xb33ц\xee\xfa\x06\xb4\xa63\xb8\x89L\xb1\xd9\xe6 \xc6,\x9b\x9a\xb8\"\r.\xacFfdC\x87\xab/\xa0\xb4-\xd0(\xb0\v\xb7\xc6\xca\xe6|P\xcc\x18@\"\xc6\xceU\x98y\x18\x99\a\xbe1\xb9\xe6\xf5\x987\xe1\x83\xeeC\xb1Tk\xf5)\x91\xbbK\x1d\x13 \x13\xc5`J\xa6LP\xee\xefa\xc4]8\xc2~\x16T[ҤZ\x83B\x9f\x8bw;\x05\xdc\xc4\x11\xec\xf7\x1e\x91F\x95\"\xa3\x8d.\x97X\xfd\x8eM\xc9\f\xefzD\x1a\x13s*ȿ~\xf5\xef\u007f$\x93\x95Ղ\xd186\xd2P^m \a1\x8b\xac\xed\xef\xc5S\xbb\x0eYE\t\x9c-X\xac[\xc8\x1a\x03\xbf\xbb\x9f\xb4\x03\x8d\xe79,\xcf\x1b\xf49\xe2r\x16\x87\xd3W\xe1~eug2F\x91Or\xedw\xb0\x01\xc9Y\xb6Jf\x04\xa1y\x0e\x99\xcb\a\xe7\xca\xebyb\xeb+\x8e\x85,J\xeeR2\xbe\x0e\x95%\xa3@\x96\x1a6\xabau\xf2\xc1Xj\bS[\xef\x10\xee\xaeL\xf9\xa5\xc4)-\xbe\xf0\x9c\x0f\x8dW=s\xd0O\xfc5\xe5|B\xb3\xfb;\xf9\x9d\x9c\xe9\xb7\xe2R\xa9\xc86\xfbH\xfd\x01\x1f\x9cZ-f^\x8a{ly[\xd7\x1a\x96q\xd2V\x96\xa6(M\xb8\xe4\xddt\xef\x86͌\xae\aY)h\xc13\\\xcf\x0e\x1e\xed\xb9E\xf7l\x1c;\xf0\xc5w\x1cw\xe1rV\xcd[\af\x10{#\xe8w_\xfd\xeb\xbf9\x96E\xa4\"\xff\xf6\x15^\x19\xd5gN\x88\xa1n`\x15\xd9\x05\xe5<6\x98\xd5d0\x96\xe8\xc7\x1dL\xe2\xd9y\x84Ig\a\xcfbr\xdf\xdd\xfd\x1d\xedmf4\xf0陫=\x12<\x88Q@\x8fQ\x89;\xf6R\x16\x8b\xdc|\x04\x83v)y\xb9\x80װdY\\\x84\xbf\x85\xea\x16\x94\x10\t\xe2L\x1b\"\xe3\xaa@L\xb8\xcc\xeeI\xee\x015\xeef\xac\xf7\xb1\x8e\xc1L\xc2-\x94\xad\xab\xab\uf7d0\xd8fD\vZ\x14U-\aE\x1fZ\x8bE^\x12}\x01\x85\xa6\x06\xaaӳ:\xdctc\x15\xf6\xf0n\x03\xab5\xa0@0E\xac\xf4s\xc3\u07fc\xdehH\x15:\xe8%\xe5\x1a\xf8=qz\x9a\xdd9\xe4\xcc\xf1\xe1\xf5\x1eI\x0fiwzZ8\x16U\xae\xc0\x82\x1ao\xd3$\xe6\xcf \xd5\x16\xa04\xd3V\x81y\x8fg\xe2\x15\xa7l\x91~\xc3?\xa5!A\x8f\x16\xb0)y\t\xa3\x06\x9dF\xbe\x18\x8d\xe8^u\x8f\xe2\xee\xb68\x96\x86-}ӹ\xfe\x8d\xcc= dծ\r\xb35e\xa3\xc9a[\xa1\x87^\nG_\xb6\xff\xbe\xc6Q\x93\xeb\xbbu\xc6\x1fg<@\x0e\xa6g\xf6\x1f\x83}\xe3\xe4\x0f\xc0\xbd\x91o\xfbe\xf4\xad;\xd7t\xd8x\x82j\x98^\xdeG2v\xb9\xb1\t\xe0-\x05\xf9\xe9\x91\xe3\x97\xc7\x1f\x94\x87;t+Y\xd0\x19Z#=\xb1\xbe\x0e\xae_\xa1Yk&#Īg\f\u0085\xbc\xaam\x9e\x04\xd4]\xa8\xaf\xe5p0\x9f\xb0\xf2X\x02\xc4\a\xba\"T\xc9R\xe4.\xf6P\a\xa5ެ\xa1\xe3Z\x8a\x94)\xfb路4Uմ\xc54\x01&ȋ\xf1\x8b\xaf>7\xc1\x8f+Y\x13\xfc\x89\x85\x9f\x1b|\xeb\x83b!\xb4l\uf2497\xde\xc5ZwXO*;\xe9b@\b\xe4A1\xe3\xa9\xf9\x81i '\xb1^\xf30\xa4jֲ\x0e\xfc{\xd8\xe9\xfbj\xa1\xe3\x1eVU\xd8\x1d\xf1b\u007f\b\x01\xd0\x1a\x15\xbe\x8d\xfbnٿ3ʹ\x97\xbe\x11\xb0\xb6\xf7\xf4+4+\xb0\xc4\xe7HŮ\xe1X\xfbV\xcdR\xe89+\x9eJ\x8e\xa1\x98\xb2-\xa7\x01\xfbU\xf3^\a\xde\xd1ߕ8#\xd7\xd2\xd8\xff\xb9|d\xfa\x89\v9v/_K\xd0\xd7\xd2\xe0ӽ\x91㦶7j\xdc\xe3H\xd2\xc2\xf1H\xbc\xa4\x84ߨ\x96y\xf5\xf4\xfd\xf7\n\xc5L\x93+a\x19\x95\xc7AuYQ{\xf0\xcd;\x86\xc8\xd5vk\xa2\xee\xdb-\xf8\x0e\xad\xf6\x1bM\xcc5?\xb5\x1b\xe5\xadi\xb8)8\x8f\xb6\xfb\v&h\x17\x9cf\x90\xfb>\x13v㍢\x06flw\xfb\x81\x05\xa8\x19&\x1ad\xf3]\xab\xda#t\xb8\xa7\xe2}\b\x15y;\xab\x19Uh\u007f\x0e\x15\xda\xcb\x10\x14\x9f[\xb0\x11:\x89Q~\xf3$G{\x12c\x9b\xb2\xc8}\xda\vsZX\xca\xff\x1f˞\x91\x88\xfe\x97\x14\x94)=&\x17\xfe\x86ʖ\xef6\xdf\xf0\xbaN\x13\xb8\x85\xcb4\xb1\xbb\xb0\xa4\x1c\\\xa1b*\b\xec,\xbf\"\xa7\x1b\xd2\xf2\x8c<̥F\xc9P\a\x91\x8e\xeeaut\xd6:![ ڇ\xaf\xc4\xd1Y\x15/k\x1d\xcaJNa\b\xe3\b\xffv4\xde\x10\xb0[`?!vwRɎ?VZ\xf7\x1b\x97ڴ\xb9\xf3\xfb\xd2\xc7N\xdaب\xc0\xd8\xfcf\x8b8\x9a\xcaqˬ\xe8\xfa$U30]&\x88ט1\x95aL.\xc4j\x03.^\x8c\xebT\xb9\xbd\x11W\xd1Y\xd1j_\x84--1C\xa2\x01\xca'.\xe9nC\xd8>\xb8\xb9k;6\x05\x05\xa8Zµ\xcc\xe1F\xaa\xae\xfc\x8ev\xbcf\xfd\xf9\x0e\x8b\xb6\x81\x14\xc9s̳\xc7G;拺\xb1\u05cb\x0fi|\xfa\xef\u07fc\u007fj=\xef\xaa\aw/\x84bo\r\xb7_\x1d\xeb\xb0ﻻ6\x82\x16z.\r9\t\x97\xda3.\xcb\xdc\xdf\xecW\x1d\xf1\x9e\x1e\xab\xd4\xd9\x1c\xf2\x92Cw\xd3\xc1\x8d2\x95\xe1Ѡ\xfb\x95\x82\xfd\xb3l\xb7\xe8\r\x1e*\xfft\xd7A\xa8qR\x99\xd6\r\x8f\xaaeG\u007f\xc1\xfd\f_\xf2V\xa4\x87\xbc%\x15\xbe\tҝ\x05\xa9\r\xdeS\x12\xa6Qt-\x98\x9d\x99o\xcf\xe1\x1f\xef\xbcf\x17ְ\xed8t\xb0\x8fn\xe1:\xf2_݈\x88o9V.\x97\xbe\r\xa3\x8b\xe6n]\xce}F\vS\xaa\xd0\xfe\xbaT\xd8\x0f\xacnaB\x03\xe6<\x8aZ`\xb7\x1b\x06\xde/Ȥ\xb8c\vІ.\x8a'(\xe4\xd5\xe6\x1bv\x03\xa4\xcauU\xe9\xa4\xe9\"\xa8\x9bnuYŴn\xf5\x96\x8f\x1b\xb0\x1d\x18\xd4\xc9,h\xc8\t,A\x10\u007f\xc9\a#\xef\xce\x01\xd1\x01\xf4\x0e\x8d\x13\xb5\xc4X@\x80\x83\xf9\xbeS\xa9\bvի\xa6\xbeI\x11\xe1\xeaxN\r\x8c:o\x12\xeeu\x12;\xa5\x8e\xeb\x91\xfb\x04\x82/]#]\x94@\x19\xe6\x89\xd9\xed\xe5ܽ\x1dn\x1e\xf8\xab~\x0f\xa0\x80\xcc@X\x14wr\x1c\xafʺVO\x16\xb1\xfe\x04W\x0e\x9c;\xd7\x1d\xab\xa4<\xb4\xf0\xc5\n8A\xaalu\x99\xe1#\x9d\xb7\xacv]\xa0\xf77>\xde\x01\xd5]yK-D|\xdd|\xd6\xdb*\x0e\a\xb8\xf4\x8c\xba>y\xaec)S\xd0I\xfa~J\x12\xbf\x1cq\xc6\t)\xe6T?\xc5.o\xec3UK\xaeơ\xac8\xe5\xbb-s\x02Q.6\x81\x8f\xc85\xb4\xf0[\xce\xf1\xa1ƥ\xb9 v\xfdR\xf4\x81+\xcdZCȅu\xe0d\x81 \xea\x01\xe1YX\xe6a\xab\r\xb8L\xdayL\x88H\x8f[\xcf·a\xb5g(\x15\x0ekv\xc6dy\xa0\xfc=\x9a\xef\x1eq\x9c\x98\xffy\xf7֫h\x92a!\xaeꖺD\xf5\xee\xd3\xedß\xefz\xd50Ѓz\x96 -\bx\xe0\xf5\x03\xa6^\xe9\xe02\xe1\xc0 I\r\x95\xa3\x16\xa5\xc1U@&mH\x02h\x03%\x1a\xa9S\x99\x04D\xb9\xb3\xcdt\x95\xa7\xb0A\x02w\xddt(\x8d.\xd18\x19V\xa8/\x1d\x8bԩ\x1dp\xfc\x86&\xe5[y-BˊS\xaf;Lk\x1c\xbcnK\xdb\xf2\xcf\x00\xf7\b\x035\x12\n\xf4\xe6gL\xdc\x1a\xee\xd0\x10\x99\xc0u\xa2\xd5\x0e\r!\x90\xe8G%\xff\xd3ж\xa4\xb1\x8e\x15\xc9am6\xda\xc2\xeb\\\x89\x1cv\"\xaf\xf0\x02\x84J\xa1\x10{0H\xa3@\xa5:\xf4\xb8\x89]\xc3ߵA\x90j\xab\xaf s\xae\xb4W\x97\x97\x8f\xd2\x05K\x9c袨\x94t\xfbK6\xaarS9m\xece\x8a;\xcc/\xad|\\\t\x93d\xd2a\xe2*\x83\x97\xa2\x94+f]\xb15^\x17\xe9\x1f\x82D\xed\x9b\x1e\xaf\ak\xc5\x17\xb6\x97G$@\x86\xd3+\x8c\xef\xeag\xd1\x02MU\x84\xce盻\xfb\xae2I;D\x9fq\xefhX+\x02\x02L\xaa-֫qkt\xc14Q\xa5\xa5\x96\xca\xf1\x1fI.Q\r\xe1\xb7զ\x90\x8e\xe4\xfe\xef\n\xad#Y\xadᚷ'\xd2ê\xa4Փ\xae\xe1V\xc1\xb5(0\xbf\x16\x16\xbf\xb9\x00\bi\xbb\"`\xe3D\xd0\xddY\x87\x8d=j\x9d\x1f\xc2.8!\xaf\xb0\xc6\xefJLzK\x86\xfaɭLxa\xb0\xe5kL\xc0\xc0\xfa\xf92\xbej\xa16=\xd4|X\u007f\xd4\xda\xc4\xee\t\a4\xa161\xeb\x83_&\xd0䟰(i\xb9ΰx_7#\x16\t\xa3\xb4\xf1v\xc2f\x19̛\xae\xad\x1a\x1c\x18\x15\x1e.C\xc2k'\xd3\xdaj\x1c\xa0y\x1cQ\xcf\xd8VT\xb9{ \x97\x01\xed\xbd\xfe\x8c\xd6\xc9d\xac\xe5`\x12\xefG;\x06y\xa3%\x84]\x86\x86\x16'\xff\xc0\xf6n\x94.\U0001ac58\xb2\xc9\x13O\xb4en<\x02d;\xf3\x1cJ\x9d\xc2Ώ\x04\x9b}`\xfaP6\xad|6Z\xe7(\xc6P\xc3/I^\xa5\x986\x1e\xd5(.\x83\xd9\xde\x1ctb\xdfSHEZF\x9e\x1e\xb1\xaa\x9a_'\xe6\xc9\xfb\x950\bd(\xa4\xf24Az\xb7d3\xa1pT\xa4\xc3b\x82ϣ\x1a\xe9\v\xf9\xb8b\x93\xe3\x158S\x8d\xe9z\xa0!\x8c\x11\xfb#\x98\x05\xff|\tdM\x9fڜ\xe72a\x0f\xb41ڌ\x1aC31\xbf\xffC\xc02\xad\x9fb@\xfa\x1b\xb5k7'H\xf8\x18\x04\x1b\xcc\xc4Njc\x87\x1e\x0e~\xc1\xa4r8\xb5\x8e\x84\x83Tn\xb7h\x88\x16;ԍ\xff}\f\xac\xe3&\x82\x8a9.\xf8\x83y\xb5B'\xe11\x1aSSaSt{^\x80\xdc6\x02K/`+s\x87\xecK\xcd1\xdaqtf%\xf7\x92\x00\xc5\xee\xbdT\n\xe1\x92\xec\xa69\xd2F\xf4\x18`5$\xe0\xfd\xf2p\x86a\x19D\x90\x84Ʃ\xe0(\x884X\xf8\xe8\xca=\xaf\x8f\xb6\x86=\xc0w\x1f\xdfc:\a\x19\xc4k\xea\xc1\xa4\xde\r<\x9d.\v<\xc1(\x92\x9dI\xb1\x9b֜\xf1|\f\xed\x02\x04<\xe1\xde{V\xa3\x87˱B\xa2\x15\rI\x83\x1c\xd0c3\xf2\x84{&UG\xe8\xa2\xe8-Q\x15_\x9ep\x1f\xdbt\x00*\xf1W\xc7(<\xbaT\xc1\xb3\x88YJmi@\xad\xd7\x0e8\x1d7YXf\x94B\t\x88\x9f8\xedF`\xbd\xb0\xf4\x13\xee\xdfX/>Z5\x99,\x17 @\x06\x1b,\xf2\n\v\xf1\xd8\a\x91˴\x19\x8c\xd7\xc9\x02\x8a\xb7\xea\x02>jG\xff\xdc|\x91\x96XT)\xbc\xd7h?j\xc75\xdf\x14b?\x89\x13\x01\xf6\x9dyY*\xbf-\x10.\x8b\xc6oy\xe0-\x94T\xb4\x11\x9b\xb4p\xab\xe8|\xe6\xf1Y\"\xa6\f\x03s\x9e\xad\xa2\xb2\x1c\xd1UZ\xadx\x9b\x0e\xa3- \xda\xe5\xab\x16\x956=I],\xa48\xcab\xcd\xde=\xedV\xfe\x97\x83X\xf8\xb1b\xb0\xccE\x82)\xa4\x15\xc7\xdb9\xf0.\x1c>\xca\x04\n4\x8f\b%\xed\x1b\xf1J\xb5\xc0\x92\xfbr\x82\x16ƻ\x16\xa1\xd4\xdbB\x1a\xc7؊V}d\xcb \xe6\xa8\xe6\x13Q\xf6\xe3\xcd\xe3f\xc9\xdb;\xfbCQ\xe8wo\x8f\x97\xed,\v\xe5u\xe8\x83x&\xbd\xfbQ\b\x0e\xf6\xfeB\xdb+\xab\xf7\xafq\xbb\xa1\x90Ʈ\xe1\x1dߝ\xe7\xd8\xed\x1f\xa2\x84\x9d\xa1\xa2H\x12'\xd2\x02\xe9\xc9N\xe4\xe4>\x90\xf1V\x80\xb9w&\xf4\xf6\xc0\x83\x8a31ϙ\xb6~\xcf\xdfJ\xcc\xf9v\xeb\xfc\t\xf7\xe7\x17\a\xd6\xeb\xfcV\x9d\xc7\xd1$\x9b\u007f`\xb4\x1a\xafE\xab|\x0f\xe7\xfc\xdb9;fK\x96\xc8\t\xce\xdb\x02\xad\x8en\xca\xd7\xcfK\x8e\x02\x9c\xe1 \xdb\xe3usIK.\xfc\xdc,\xa2u\xba\xd4\xd6-b듶\xce\a\x00{\xee\xf6H\x840\xe6\xf4WG\rAl\x1d\x1a\xb0N\x9bp!Jfw\x10 '\xc9\xdbyٓ\xa8\x9bh\xa4'L\x87\xcc\xf3\xd6Bx\x9b~\xeeoJ\xe9\xff\xf34\x13v\x96\x98vit\x82\xd6ΫR\xe4\xce1\x13\xb0m\x82\xb5\xc2\x1f\u07b6Q\xa69&\x94\x1c\xca2W\x9c\xa0=\xe1`s\xf3\xa5\x13w&3D\u007fǨ\xf2)<\x02\xe7T\x15\x85\x18^\xceG\xb3{\xed{\x87\x05X\x13\xf3\a&\xf3X\xb1QY\xe67\xd7*\xf9[s<\n\xa9ny x\xfb͜\x15\b\xa6\x1cO=\xca\\\x87\xfe\xad@\x9a\x8a\xd8\xf3+\x84\xabf\xcdw5\x06{\x92=\xbcɈ\x97\x14\x903\xad\xb4\xeb\x06k\xea\x91\xdeX\xd8Jc]\xcb\xf0\x02\xaa\xd2\xf2u\xf2\xb7=c\xaa\x1bcN>b\xfe\xe4{w\u008a\x99~\xae\x13#\x96\x1c\xac\x03\xf8\x99\xd8!\xc8-H\a\xa8\x12])\x0ex\x91\xb9\xa0a\x16P\xf4B\xf4\x9bI\xe4\x9e\xd9鬪\"\x1e\x90\x15k\xa7T\xb3ѱn\x97\x1f\x84\x8c\x8bN\xc1ibu\xb2@]\xcdn\xedm\xe9gv\xf8\u07bd\f\x98B|\x91EU\x80(H,K\u038d[\x9f?\x18\xd2e\xbc\xac\x9f\x85tu\x06\xa1\xbfX]fM\x13]\x949:\x84\rn\xb5a{`e\x8a\x8d\xfbP\xcb\u007f4\xdfd\xaa\b\xd8\n\x99Wf\x81\x8d^,\x99\xa5\xe7\xb6\xda<\xbd\xfca,\x9e\x91\x15\x83\x19\x19t_\xe04\xcf\xef\x1f\xa5Y\xe62\u007f2\xf8\xf2\xaeii$i\xa9\x9e\xf3Ngi\xb2\xf7\xda\xf7Nk\xe5\x15j?\xe5\x9e\xceReN^\xddӦ\xbc\xba\xa7\xaf\xee\xe9\xab{:(\xaf\xee\xe9\xab{\xfaꞎ\x97W\xf7\xb4S^\xdd\xd3\xe8\xfd#\x86\xc3\x15t><;\x99\xab\xc8\x14\x8c9\xb6gƪ3\x8d\xae\xf3\xca:4K2\xa4o\xc7{\x8e\xe4\xd0'\xbeɊ?\x06\x9cҚ6u\xa5\xdd\xf4\x9a\x94iZ\x92a1\xf9o1\"\xbc\xf0\xe84\xe8\xe9l\xfb\xd8\x04\xba\xb9\xb4\xb9~\xeex\x93\xae\xe6\xff7\x01\x88\xd3a\xf8Zz\xfe\x1b\x9fn\xceU?\xf7\x8d\xcf\x01\x81\xe3\xdfd^ydZ\xdbL2\xdb\xf1D\xfc\xa9\x1d>`9\xb8\\\xe8\x83iz\x89߿i,#\xb2ͦs\xcc\xea[Ktb\xf7v\xdd\xff\xc5\xe9:\xe3lbf\xcf\xd2e\xfe\xfb#:\xba\xaa\xc7nZ{\xd0\xd3\xfaۿ!\xc6\x13\x14\xb5\x01%s/\x80@\xa1\a?\xfcT\xfa#\xf2\xc9\xeb|\xfe\xa0\x16\x9f\x97\xb64\x1b\xad\xc9\x1f\x9a\xdfU\xbe\"\am\xd9\a\x02\xb3\xf9f1LCL\x96\xd9x\xfe\xd8\f\xd5%\xb9e\xb1g\xf0\x88<\xb2\xf8\xec\xb18x\x80\xbf؍\xcd\x19\x8b\xf6\xdab\xf3þMVXd.X'\xc3k\x96\xe4\x89\x19`р\xc5e{E\xe7xu2\xb7\xe6\xd1:\x92\xd95\x9e\xaf5Kr,\x9f+&K+\x8a\xd7\xe8ܬ&\xe3j>\x92\xf8U\x19Y/\x9f\xfb\xfd\x92~\xfe\xf1\xfc\xaa\xa8\xac\xaa\xa8\xb3\xc0<\xcfQySK\xb3\xa5\xa2P]\x9a\x19\xd5d=\x1d\x198*\x1f\xea0\xd7\xe9\xd8Tf\xb3\xa0\xa63\x9c\x8e\x91\x1d\xcb}\x8a\xc8k:B\xb2\x9b\xf1\xb4\xd8\r\x98զ\x99\x06\xe3_Շ2\xbf\xd7\xe6\xff\v\r\xfc\xdaIk\x93\xa2\x99=\x95,a}\x96\xed~\xbcr0\xfe\xe0s\x9d\xf019\xb5\xea\x9ex\xa6\xbc(\xdd|>\x92\xc0\x8fR\xa5^\x93h\xb1t|\x1a~\xa1\x82\x13\xcc\x1a7k:\xe3\xb6\xf5h\a\xa7-\x8b\xa5 \xa3\x9e\xc2f\xef\xa3Bv\r7\"ɚ\x86\x13\x14y\xe4LX:\xd9\x17\xc2\xc1ys\x8c\xbd\f=\xa9\xe6|\r\xf0\x83n\"\b\x9d\xcfC'\xe8ZY\x94\xf9\x1e*\x8bp\xde'\xf4u\xa7\xb0IݱJ\x946\xd3\xe1%\x81\x88\x83\xd8]\xbf\xc7H\xbc$\xbc#\x90\xe4\xbaJ\x9b\x11\x8e\x88[\xa8=|z`O\x8e\xbf\x9eNگ\xcckO-\x9c\xab\x06\x1f\xa1O\x90\x9cz\xb6\xef\xa9\x1a 럖\xf3f\x9c\x81\v\xef\xd0\x1cB7\xb3\xfe\xa7\xd7\xfe\xb8G\xbd\x1a\u007f\xfaeռFs\x16\x81\xac\u007fo,\xe6\x81\x1f\xff\xa8[\"JW\x99z{M*\xc3\x0fN\x10\x11\xf4\xef1\x9c\xf6\xc4O\xfb\xdcٌ,\xdb\a\xd0\xda\b\xc3\xecsk#\xf2k\x1e\v\x9a|=\xc7\xef\xae\xfe9\xb4\x15\xd1?M\x9c\xa3\xeb\x80\x1f蘙\xe9'j\xd3\u070e\xd7@s\xc7\xf0\xb0\xc7\xdd\x14\xeb\xe3ם+\xf8\x88\xcf#\xb57\x8a&qx\x18\xf5w\x9a\x98r\x84b\xecy\xb3\xa3S\xdc5\xbd\xf8By\xc4Z\xf4\xcdܠ\xf9 R-\xf2\xbcC\xd1_\x1e\x8f\x89\xf5\x8fr\xeb\xc3F\t\xcd\xe9O\a-&\r\xd7Q\xa35e\xb0F\x97\xd4A\xa5E\xb3ô\xa3$\xf5\x1eޭ\xa96\a\xef\xac\xd4\v\x13~\xf9\xf5\xac]\xa3\"I\xb0t\xf5\xfdH\xf7\xfd\xc9\xf3s\xfe# 0 { - log.Warnf(`Init containers before the %s container may cause issues - if they interfere with volumes being restored: %s index %d`, restic.InitContainer, restic.InitContainer, resticInitContainerIndex) - } - - log.Debug("Enqueueing") - c.enqueue(obj) -} - -func (c *podVolumeRestoreController) podHandler(obj interface{}) { - pod := obj.(*corev1api.Pod) - log := c.logger.WithField("key", kube.NamespaceAndName(pod)) - - // the pod should always be for this node since the podInformer is filtered - // based on node, so this is just a failsafe. - if !isPodOnNode(pod, c.nodeName) { - return - } - - if !isResticInitContainerRunning(pod) { - log.Debug("Pod is not running restic-wait init container, not enqueuing restores for pod") - return - } - - resticInitContainerIndex := getResticInitContainerIndex(pod) - if resticInitContainerIndex > 0 { - log.Warnf(`Init containers before the %s container may cause issues - if they interfere with volumes being restored: %s index %d`, restic.InitContainer, restic.InitContainer, resticInitContainerIndex) - } - - selector := labels.Set(map[string]string{ - velerov1api.PodUIDLabel: string(pod.UID), - }).AsSelector() - - pvrs, err := c.podVolumeRestoreLister.List(selector) - if err != nil { - log.WithError(err).Error("Unable to list pod volume restores") - return - } - - if len(pvrs) == 0 { - return - } - - for _, pvr := range pvrs { - log := loggerForPodVolumeRestore(log, pvr) - if !isPVRNew(pvr) { - log.Debug("Restore is not new, not enqueuing") - continue + pvr := &velerov1api.PodVolumeRestore{} + if err := c.Get(ctx, types.NamespacedName{Namespace: req.Namespace, Name: req.Name}, pvr); err != nil { + if apierrors.IsNotFound(err) { + log.Warn("PodVolumeRestore not found, skip") + return ctrl.Result{}, nil } - log.Debug("Enqueuing") - c.enqueue(pvr) + log.WithError(err).Error("Unable to get the PodVolumeRestore") + return ctrl.Result{}, err } + log = log.WithField("pod", fmt.Sprintf("%s/%s", pvr.Spec.Pod.Namespace, pvr.Spec.Pod.Name)) + if len(pvr.OwnerReferences) == 1 { + log = log.WithField("restore", fmt.Sprintf("%s/%s", pvr.Namespace, pvr.OwnerReferences[0].Name)) + } + + shouldProcess, pod, err := c.shouldProcess(ctx, log, pvr) + if err != nil { + return ctrl.Result{}, err + } + if !shouldProcess { + return ctrl.Result{}, nil + } + + resticInitContainerIndex := getResticInitContainerIndex(pod) + if resticInitContainerIndex > 0 { + log.Warnf(`Init containers before the %s container may cause issues + if they interfere with volumes being restored: %s index %d`, restic.InitContainer, restic.InitContainer, resticInitContainerIndex) + } + + patchHelper, err := patch.NewHelper(pvr, c.Client) + if err != nil { + log.WithError(err).Error("Unable to new patch helper") + return ctrl.Result{}, err + } + + log.Info("Restore starting") + pvr.Status.Phase = velerov1api.PodVolumeRestorePhaseInProgress + pvr.Status.StartTimestamp = &metav1.Time{Time: c.clock.Now()} + if err = patchHelper.Patch(ctx, pvr); err != nil { + log.WithError(err).Error("Unable to update status to in progress") + return ctrl.Result{}, err + } + if err = c.processRestore(ctx, pvr, pod, log); err != nil { + pvr.Status.Phase = velerov1api.PodVolumeRestorePhaseFailed + pvr.Status.Message = err.Error() + pvr.Status.CompletionTimestamp = &metav1.Time{Time: c.clock.Now()} + if e := patchHelper.Patch(ctx, pvr); e != nil { + log.WithError(err).Error("Unable to update status to failed") + } + + log.WithError(err).Error("Unable to process the PodVolumeRestore") + return ctrl.Result{}, err + } + + pvr.Status.Phase = velerov1api.PodVolumeRestorePhaseCompleted + pvr.Status.CompletionTimestamp = &metav1.Time{Time: c.clock.Now()} + if err = patchHelper.Patch(ctx, pvr); err != nil { + log.WithError(err).Error("Unable to update status to completed") + return ctrl.Result{}, err + } + log.Info("Restore completed") + return ctrl.Result{}, nil +} + +func (c *PodVolumeRestoreReconciler) shouldProcess(ctx context.Context, log logrus.FieldLogger, pvr *velerov1api.PodVolumeRestore) (bool, *corev1api.Pod, error) { + if !isPVRNew(pvr) { + log.Debug("PodVolumeRestore is not new, skip") + return false, nil, nil + } + + // we filter the pods during the initialization of cache, if we can get a pod here, the pod must be in the same node with the controller + // so we don't need to compare the node anymore + pod := &corev1api.Pod{} + if err := c.Get(ctx, types.NamespacedName{Namespace: pvr.Spec.Pod.Namespace, Name: pvr.Spec.Pod.Name}, pod); err != nil { + if apierrors.IsNotFound(err) { + log.WithError(err).Debug("Pod not found on this node, skip") + return false, nil, nil + } + log.WithError(err).Error("Unable to get pod") + return false, nil, err + } + + if !isResticInitContainerRunning(pod) { + log.Debug("Pod is not running restic-wait init container, skip") + return false, nil, nil + } + + return true, pod, nil +} + +func (c *PodVolumeRestoreReconciler) SetupWithManager(mgr ctrl.Manager) error { + mgr.GetConfig() + + // The pod may not being scheduled at the point when its PVRs are initially reconciled. + // By watching the pods, we can trigger the PVR reconciliation again once the pod is finally scheduled on the node. + return ctrl.NewControllerManagedBy(mgr). + For(&velerov1api.PodVolumeRestore{}). + Watches(&source.Kind{Type: &corev1api.Pod{}}, handler.EnqueueRequestsFromMapFunc(c.findVolumeRestoresForPod)). + Complete(c) +} + +func (c *PodVolumeRestoreReconciler) findVolumeRestoresForPod(pod client.Object) []reconcile.Request { + list := &velerov1api.PodVolumeRestoreList{} + options := &client.ListOptions{ + LabelSelector: labels.Set(map[string]string{ + velerov1api.PodUIDLabel: string(pod.GetUID()), + }).AsSelector(), + } + if err := c.List(context.TODO(), list, options); err != nil { + c.logger.WithField("pod", fmt.Sprintf("%s/%s", pod.GetNamespace(), pod.GetName())).WithError(err). + Error("unable to list PodVolumeRestores") + return []reconcile.Request{} + } + requests := make([]reconcile.Request, len(list.Items)) + for i, item := range list.Items { + requests[i] = reconcile.Request{ + NamespacedName: types.NamespacedName{ + Namespace: item.GetNamespace(), + Name: item.GetName(), + }, + } + } + return requests } func isPVRNew(pvr *velerov1api.PodVolumeRestore) bool { return pvr.Status.Phase == "" || pvr.Status.Phase == velerov1api.PodVolumeRestorePhaseNew } -func isPodOnNode(pod *corev1api.Pod, node string) bool { - return pod.Spec.NodeName == node -} - func isResticInitContainerRunning(pod *corev1api.Pod) bool { // Restic wait container can be anywhere in the list of init containers, but must be running. i := getResticInitContainerIndex(pod) @@ -237,92 +220,6 @@ func getResticInitContainerIndex(pod *corev1api.Pod) int { return -1 } -func (c *podVolumeRestoreController) processQueueItem(key string) error { - log := c.logger.WithField("key", key) - log.Debug("Running processQueueItem") - - ns, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - log.WithError(errors.WithStack(err)).Error("error splitting queue key") - return nil - } - - req, err := c.podVolumeRestoreLister.PodVolumeRestores(ns).Get(name) - if apierrors.IsNotFound(err) { - log.Debug("Unable to find PodVolumeRestore") - return nil - } - if err != nil { - return errors.Wrap(err, "error getting PodVolumeRestore") - } - - // Don't mutate the shared cache - reqCopy := req.DeepCopy() - return c.processRestoreFunc(reqCopy) -} - -func loggerForPodVolumeRestore(baseLogger logrus.FieldLogger, req *velerov1api.PodVolumeRestore) logrus.FieldLogger { - log := baseLogger.WithFields(logrus.Fields{ - "namespace": req.Namespace, - "name": req.Name, - }) - - if len(req.OwnerReferences) == 1 { - log = log.WithField("restore", fmt.Sprintf("%s/%s", req.Namespace, req.OwnerReferences[0].Name)) - } - - return log -} - -func (c *podVolumeRestoreController) processRestore(req *velerov1api.PodVolumeRestore) error { - log := loggerForPodVolumeRestore(c.logger, req) - - log.Info("Restore starting") - - var err error - - // update status to InProgress - req, err = c.patchPodVolumeRestore(req, func(r *velerov1api.PodVolumeRestore) { - r.Status.Phase = velerov1api.PodVolumeRestorePhaseInProgress - r.Status.StartTimestamp = &metav1.Time{Time: c.clock.Now()} - }) - if err != nil { - log.WithError(err).Error("Error setting PodVolumeRestore startTimestamp and phase to InProgress") - return errors.WithStack(err) - } - - pod, err := c.podLister.Pods(req.Spec.Pod.Namespace).Get(req.Spec.Pod.Name) - if err != nil { - log.WithError(err).Errorf("Error getting pod %s/%s", req.Spec.Pod.Namespace, req.Spec.Pod.Name) - return c.failRestore(req, errors.Wrap(err, "error getting pod").Error(), log) - } - - volumeDir, err := kube.GetVolumeDirectory(log, pod, req.Spec.Volume, c.pvcLister, c.pvLister, c.kbClient) - if err != nil { - log.WithError(err).Error("Error getting volume directory name") - return c.failRestore(req, errors.Wrap(err, "error getting volume directory name").Error(), log) - } - - // execute the restore process - if err := c.restorePodVolume(req, volumeDir, log); err != nil { - log.WithError(err).Error("Error restoring volume") - return c.failRestore(req, errors.Wrap(err, "error restoring volume").Error(), log) - } - - // update status to Completed - if _, err = c.patchPodVolumeRestore(req, func(r *velerov1api.PodVolumeRestore) { - r.Status.Phase = velerov1api.PodVolumeRestorePhaseCompleted - r.Status.CompletionTimestamp = &metav1.Time{Time: c.clock.Now()} - }); err != nil { - log.WithError(err).Error("Error setting PodVolumeRestore completionTimestamp and phase to Completed") - return err - } - - log.Info("Restore completed") - - return nil -} - func singlePathMatch(path string) (string, error) { matches, err := filepath.Glob(path) if err != nil { @@ -336,7 +233,12 @@ func singlePathMatch(path string) (string, error) { return matches[0], nil } -func (c *podVolumeRestoreController) restorePodVolume(req *velerov1api.PodVolumeRestore, volumeDir string, log logrus.FieldLogger) error { +func (c *PodVolumeRestoreReconciler) processRestore(ctx context.Context, req *velerov1api.PodVolumeRestore, pod *corev1api.Pod, log logrus.FieldLogger) error { + volumeDir, err := kube.GetVolumeDirectory(ctx, log, pod, req.Spec.Volume, c.Client) + if err != nil { + return errors.Wrap(err, "error getting volume directory name") + } + // Get the full path of the new volume's directory as mounted in the daemonset pod, which // will look like: /host_pods//volumes// volumePath, err := singlePathMatch(fmt.Sprintf("/host_pods/%s/volumes/*/%s", string(req.Spec.Pod.UID), volumeDir)) @@ -346,8 +248,7 @@ func (c *podVolumeRestoreController) restorePodVolume(req *velerov1api.PodVolume credsFile, err := c.credentialsFileStore.Path(restic.RepoKeySelector()) if err != nil { - log.WithError(err).Error("Error creating temp restic credentials file") - return c.failRestore(req, errors.Wrap(err, "error creating temp restic credentials file").Error(), log) + return errors.Wrap(err, "error creating temp restic credentials file") } // ignore error since there's nothing we can do and it's a temp file. defer os.Remove(credsFile) @@ -360,11 +261,11 @@ func (c *podVolumeRestoreController) restorePodVolume(req *velerov1api.PodVolume ) backupLocation := &velerov1api.BackupStorageLocation{} - if err := c.kbClient.Get(context.Background(), client.ObjectKey{ + if err := c.Get(ctx, client.ObjectKey{ Namespace: req.Namespace, Name: req.Spec.BackupStorageLocation, }, backupLocation); err != nil { - return c.failRestore(req, errors.Wrap(err, "error getting backup storage location").Error(), log) + return errors.Wrap(err, "error getting backup storage location") } // if there's a caCert on the ObjectStorage, write it to disk so that it can be passed to restic @@ -381,7 +282,7 @@ func (c *podVolumeRestoreController) restorePodVolume(req *velerov1api.PodVolume env, err := restic.CmdEnv(backupLocation, c.credentialsFileStore) if err != nil { - return c.failRestore(req, errors.Wrap(err, "error setting restic cmd env").Error(), log) + return errors.Wrap(err, "error setting restic cmd env") } resticCmd.Env = env @@ -432,55 +333,18 @@ func (c *podVolumeRestoreController) restorePodVolume(req *velerov1api.PodVolume return nil } -func (c *podVolumeRestoreController) patchPodVolumeRestore(req *velerov1api.PodVolumeRestore, mutate func(*velerov1api.PodVolumeRestore)) (*velerov1api.PodVolumeRestore, error) { - // Record original json - oldData, err := json.Marshal(req) - if err != nil { - return nil, errors.Wrap(err, "error marshalling original PodVolumeRestore") - } - - // Mutate - mutate(req) - - // Record new json - newData, err := json.Marshal(req) - if err != nil { - return nil, errors.Wrap(err, "error marshalling updated PodVolumeRestore") - } - - patchBytes, err := jsonpatch.CreateMergePatch(oldData, newData) - if err != nil { - return nil, errors.Wrap(err, "error creating json merge patch for PodVolumeRestore") - } - - req, err = c.podVolumeRestoreClient.PodVolumeRestores(req.Namespace).Patch(context.TODO(), req.Name, types.MergePatchType, patchBytes, metav1.PatchOptions{}) - if err != nil { - return nil, errors.Wrap(err, "error patching PodVolumeRestore") - } - - return req, nil -} - -func (c *podVolumeRestoreController) failRestore(req *velerov1api.PodVolumeRestore, msg string, log logrus.FieldLogger) error { - if _, err := c.patchPodVolumeRestore(req, func(pvr *velerov1api.PodVolumeRestore) { - pvr.Status.Phase = velerov1api.PodVolumeRestorePhaseFailed - pvr.Status.Message = msg - pvr.Status.CompletionTimestamp = &metav1.Time{Time: c.clock.Now()} - }); err != nil { - log.WithError(err).Error("Error setting PodVolumeRestore phase to Failed") - return err - } - return nil -} - // updateRestoreProgressFunc returns a func that takes progress info and patches // the PVR with the new progress -func (c *podVolumeRestoreController) updateRestoreProgressFunc(req *velerov1api.PodVolumeRestore, log logrus.FieldLogger) func(velerov1api.PodVolumeOperationProgress) { +func (c *PodVolumeRestoreReconciler) updateRestoreProgressFunc(req *velerov1api.PodVolumeRestore, log logrus.FieldLogger) func(velerov1api.PodVolumeOperationProgress) { return func(progress velerov1api.PodVolumeOperationProgress) { - if _, err := c.patchPodVolumeRestore(req, func(r *velerov1api.PodVolumeRestore) { - r.Status.Progress = progress - }); err != nil { - log.WithError(err).Error("error updating PodVolumeRestore progress") + helper, err := patch.NewHelper(req, c.Client) + if err != nil { + log.WithError(err).Error("Unable to new patch helper") + return + } + req.Status.Progress = progress + if err = helper.Patch(context.Background(), req); err != nil { + log.WithError(err).Error("Unable to update PodVolumeRestore progress") } } } diff --git a/pkg/controller/pod_volume_restore_controller_test.go b/pkg/controller/pod_volume_restore_controller_test.go index 5503620c4..5af7e41ac 100644 --- a/pkg/controller/pod_volume_restore_controller_test.go +++ b/pkg/controller/pod_volume_restore_controller_test.go @@ -17,64 +17,64 @@ limitations under the License. package controller import ( + "context" "testing" "time" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "k8s.io/apimachinery/pkg/runtime" + + "github.com/sirupsen/logrus" + + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/stretchr/testify/assert" corev1api "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/util/sets" - corev1listers "k8s.io/client-go/listers/core/v1" - "k8s.io/client-go/tools/cache" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" - velerofake "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/fake" - veleroinformers "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions" - velerov1listers "github.com/vmware-tanzu/velero/pkg/generated/listers/velero/v1" "github.com/vmware-tanzu/velero/pkg/restic" - velerotest "github.com/vmware-tanzu/velero/pkg/test" ) -func TestPVRHandler(t *testing.T) { +func TestShouldProcess(t *testing.T) { controllerNode := "foo" tests := []struct { - name string - obj *velerov1api.PodVolumeRestore - pod *corev1api.Pod - shouldEnqueue bool + name string + obj *velerov1api.PodVolumeRestore + pod *corev1api.Pod + shouldProcessed bool }{ { - name: "InProgress phase pvr should not be enqueued", + name: "InProgress phase pvr should not be processed", obj: &velerov1api.PodVolumeRestore{ Status: velerov1api.PodVolumeRestoreStatus{ Phase: velerov1api.PodVolumeRestorePhaseInProgress, }, }, - shouldEnqueue: false, + shouldProcessed: false, }, { - name: "Completed phase pvr should not be enqueued", + name: "Completed phase pvr should not be processed", obj: &velerov1api.PodVolumeRestore{ Status: velerov1api.PodVolumeRestoreStatus{ Phase: velerov1api.PodVolumeRestorePhaseCompleted, }, }, - shouldEnqueue: false, + shouldProcessed: false, }, { - name: "Failed phase pvr should not be enqueued", + name: "Failed phase pvr should not be processed", obj: &velerov1api.PodVolumeRestore{ Status: velerov1api.PodVolumeRestoreStatus{ Phase: velerov1api.PodVolumeRestorePhaseFailed, }, }, - shouldEnqueue: false, + shouldProcessed: false, }, { - name: "Unable to get pvr's pod should not be enqueued", + name: "Unable to get pvr's pod should not be processed", obj: &velerov1api.PodVolumeRestore{ Spec: velerov1api.PodVolumeRestoreSpec{ Pod: corev1api.ObjectReference{ @@ -86,50 +86,10 @@ func TestPVRHandler(t *testing.T) { Phase: "", }, }, - shouldEnqueue: false, + shouldProcessed: false, }, { - name: "Empty phase pvr with pod not on node running init container should not be enqueued", - obj: &velerov1api.PodVolumeRestore{ - Spec: velerov1api.PodVolumeRestoreSpec{ - Pod: corev1api.ObjectReference{ - Namespace: "ns-1", - Name: "pod-1", - }, - }, - Status: velerov1api.PodVolumeRestoreStatus{ - Phase: "", - }, - }, - pod: &corev1api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "ns-1", - Name: "pod-1", - }, - Spec: corev1api.PodSpec{ - NodeName: "some-other-node", - InitContainers: []corev1api.Container{ - { - Name: restic.InitContainer, - }, - }, - }, - Status: corev1api.PodStatus{ - InitContainerStatuses: []corev1api.ContainerStatus{ - { - State: corev1api.ContainerState{ - Running: &corev1api.ContainerStateRunning{ - StartedAt: metav1.Time{Time: time.Now()}, - }, - }, - }, - }, - }, - }, - shouldEnqueue: false, - }, - { - name: "Empty phase pvr with pod on node not running init container should not be enqueued", + name: "Empty phase pvr with pod on node not running init container should not be processed", obj: &velerov1api.PodVolumeRestore{ Spec: velerov1api.PodVolumeRestoreSpec{ Pod: corev1api.ObjectReference{ @@ -162,7 +122,7 @@ func TestPVRHandler(t *testing.T) { }, }, }, - shouldEnqueue: false, + shouldProcessed: false, }, { name: "Empty phase pvr with pod on node running init container should be enqueued", @@ -202,220 +162,23 @@ func TestPVRHandler(t *testing.T) { }, }, }, - shouldEnqueue: true, + shouldProcessed: true, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - var ( - podInformer = cache.NewSharedIndexInformer(nil, new(corev1api.Pod), 0, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - c = &podVolumeRestoreController{ - genericController: newGenericController(PodVolumeRestore, velerotest.NewLogger()), - podLister: corev1listers.NewPodLister(podInformer.GetIndexer()), - nodeName: controllerNode, - } - ) - + builder := fake.NewClientBuilder() if test.pod != nil { - require.NoError(t, podInformer.GetStore().Add(test.pod)) + builder.WithObjects(test.pod) + } + c := &PodVolumeRestoreReconciler{ + logger: logrus.New(), + Client: builder.Build(), } - c.pvrHandler(test.obj) - - if !test.shouldEnqueue { - assert.Equal(t, 0, c.queue.Len()) - return - } - - require.Equal(t, 1, c.queue.Len()) - }) - } -} - -func TestPodHandler(t *testing.T) { - controllerNode := "foo" - - tests := []struct { - name string - pod *corev1api.Pod - podVolumeRestores []*velerov1api.PodVolumeRestore - expectedEnqueues sets.String - }{ - { - name: "pod on controller node running restic init container with multiple PVRs has new ones enqueued", - pod: &corev1api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "ns-1", - Name: "pod-1", - UID: types.UID("uid"), - }, - Spec: corev1api.PodSpec{ - NodeName: controllerNode, - InitContainers: []corev1api.Container{ - { - Name: restic.InitContainer, - }, - }, - }, - Status: corev1api.PodStatus{ - InitContainerStatuses: []corev1api.ContainerStatus{ - { - State: corev1api.ContainerState{ - Running: &corev1api.ContainerStateRunning{StartedAt: metav1.Time{Time: time.Now()}}, - }, - }, - }, - }, - }, - podVolumeRestores: []*velerov1api.PodVolumeRestore{ - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: "ns-1", - Name: "pvr-1", - Labels: map[string]string{ - velerov1api.PodUIDLabel: "uid", - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: "ns-1", - Name: "pvr-2", - Labels: map[string]string{ - velerov1api.PodUIDLabel: "uid", - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: "ns-1", - Name: "pvr-3", - Labels: map[string]string{ - velerov1api.PodUIDLabel: "uid", - }, - }, - Status: velerov1api.PodVolumeRestoreStatus{ - Phase: velerov1api.PodVolumeRestorePhaseInProgress, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: "ns-1", - Name: "pvr-4", - Labels: map[string]string{ - velerov1api.PodUIDLabel: "some-other-pod", - }, - }, - }, - }, - expectedEnqueues: sets.NewString("ns-1/pvr-1", "ns-1/pvr-2"), - }, - { - name: "pod on controller node not running restic init container doesn't have PVRs enqueued", - pod: &corev1api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "ns-1", - Name: "pod-1", - UID: types.UID("uid"), - }, - Spec: corev1api.PodSpec{ - NodeName: controllerNode, - InitContainers: []corev1api.Container{ - { - Name: restic.InitContainer, - }, - }, - }, - Status: corev1api.PodStatus{ - InitContainerStatuses: []corev1api.ContainerStatus{ - { - State: corev1api.ContainerState{}, - }, - }, - }, - }, - podVolumeRestores: []*velerov1api.PodVolumeRestore{ - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: "ns-1", - Name: "pvr-1", - Labels: map[string]string{ - velerov1api.PodUIDLabel: "uid", - }, - }, - }, - }, - }, - { - name: "pod not running on controller node doesn't have PVRs enqueued", - pod: &corev1api.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "ns-1", - Name: "pod-1", - UID: types.UID("uid"), - }, - Spec: corev1api.PodSpec{ - NodeName: "some-other-node", - InitContainers: []corev1api.Container{ - { - Name: restic.InitContainer, - }, - }, - }, - Status: corev1api.PodStatus{ - InitContainerStatuses: []corev1api.ContainerStatus{ - { - State: corev1api.ContainerState{ - Running: &corev1api.ContainerStateRunning{StartedAt: metav1.Time{Time: time.Now()}}, - }, - }, - }, - }, - }, - podVolumeRestores: []*velerov1api.PodVolumeRestore{ - { - ObjectMeta: metav1.ObjectMeta{ - Namespace: "ns-1", - Name: "pvr-1", - Labels: map[string]string{ - velerov1api.PodUIDLabel: "uid", - }, - }, - }, - }, - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - var ( - client = velerofake.NewSimpleClientset() - informers = veleroinformers.NewSharedInformerFactory(client, 0) - pvrInformer = informers.Velero().V1().PodVolumeRestores() - c = &podVolumeRestoreController{ - genericController: newGenericController(PodVolumeRestore, velerotest.NewLogger()), - podVolumeRestoreLister: velerov1listers.NewPodVolumeRestoreLister(pvrInformer.Informer().GetIndexer()), - nodeName: controllerNode, - } - ) - - if len(test.podVolumeRestores) > 0 { - for _, pvr := range test.podVolumeRestores { - require.NoError(t, pvrInformer.Informer().GetStore().Add(pvr)) - } - } - - c.podHandler(test.pod) - - require.Equal(t, len(test.expectedEnqueues), c.queue.Len()) - - itemCount := c.queue.Len() - - for i := 0; i < itemCount; i++ { - item, _ := c.queue.Get() - assert.True(t, test.expectedEnqueues.Has(item.(string))) - } + shouldProcess, _, _ := c.shouldProcess(context.Background(), c.logger, test.obj) + require.Equal(t, test.shouldProcessed, shouldProcess) }) } } @@ -437,17 +200,6 @@ func TestIsPVRNew(t *testing.T) { } } -func TestIsPodOnNode(t *testing.T) { - pod := &corev1api.Pod{} - assert.False(t, isPodOnNode(pod, "bar")) - - pod.Spec.NodeName = "foo" - assert.False(t, isPodOnNode(pod, "bar")) - - pod.Spec.NodeName = "bar" - assert.True(t, isPodOnNode(pod, "bar")) -} - func TestIsResticContainerRunning(t *testing.T) { tests := []struct { name string @@ -720,3 +472,44 @@ func TestGetResticInitContainerIndex(t *testing.T) { }) } } + +func TestFindVolumeRestoresForPod(t *testing.T) { + pod := &corev1api.Pod{} + pod.UID = "uid" + + scheme := runtime.NewScheme() + scheme.AddKnownTypes(velerov1api.SchemeGroupVersion, &velerov1api.PodVolumeRestore{}, &velerov1api.PodVolumeRestoreList{}) + clientBuilder := fake.NewClientBuilder().WithScheme(scheme) + + // no matching PVR + reconciler := &PodVolumeRestoreReconciler{ + Client: clientBuilder.Build(), + logger: logrus.New(), + } + requests := reconciler.findVolumeRestoresForPod(pod) + assert.Len(t, requests, 0) + + // contain one matching PVR + reconciler.Client = clientBuilder.WithLists(&velerov1api.PodVolumeRestoreList{ + Items: []velerov1api.PodVolumeRestore{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "pvr1", + Labels: map[string]string{ + velerov1api.PodUIDLabel: string(pod.GetUID()), + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "pvr2", + Labels: map[string]string{ + velerov1api.PodUIDLabel: "non-matching-uid", + }, + }, + }, + }, + }).Build() + requests = reconciler.findVolumeRestoresForPod(pod) + assert.Len(t, requests, 1) +} diff --git a/pkg/util/kube/utils.go b/pkg/util/kube/utils.go index ccda34ad3..24b2ef6c7 100644 --- a/pkg/util/kube/utils.go +++ b/pkg/util/kube/utils.go @@ -21,8 +21,6 @@ import ( "fmt" "time" - "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/pkg/errors" "github.com/sirupsen/logrus" corev1api "k8s.io/api/core/v1" @@ -35,7 +33,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/wait" corev1client "k8s.io/client-go/kubernetes/typed/core/v1" - corev1listers "k8s.io/client-go/listers/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" ) // These annotations are taken from the Kubernetes persistent volume/persistent volume claim controller. @@ -117,8 +115,7 @@ func EnsureNamespaceExistsAndIsReady(namespace *corev1api.Namespace, client core // GetVolumeDirectory gets the name of the directory on the host, under /var/lib/kubelet/pods//volumes/, // where the specified volume lives. // For volumes with a CSIVolumeSource, append "/mount" to the directory name. -func GetVolumeDirectory(log logrus.FieldLogger, pod *corev1api.Pod, volumeName string, pvcLister corev1listers.PersistentVolumeClaimLister, - pvLister corev1listers.PersistentVolumeLister, client client.Client) (string, error) { +func GetVolumeDirectory(ctx context.Context, log logrus.FieldLogger, pod *corev1api.Pod, volumeName string, cli client.Client) (string, error) { var volume *corev1api.Volume for _, item := range pod.Spec.Volumes { @@ -142,18 +139,20 @@ func GetVolumeDirectory(log logrus.FieldLogger, pod *corev1api.Pod, volumeName s } // Most common case is that we have a PVC VolumeSource, and we need to check the PV it points to for a CSI source. - pvc, err := pvcLister.PersistentVolumeClaims(pod.Namespace).Get(volume.VolumeSource.PersistentVolumeClaim.ClaimName) + pvc := &corev1api.PersistentVolumeClaim{} + err := cli.Get(ctx, client.ObjectKey{Namespace: pod.Namespace, Name: volume.VolumeSource.PersistentVolumeClaim.ClaimName}, pvc) if err != nil { return "", errors.WithStack(err) } - pv, err := pvLister.Get(pvc.Spec.VolumeName) + pv := &corev1api.PersistentVolume{} + err = cli.Get(ctx, client.ObjectKey{Name: pvc.Spec.VolumeName}, pv) if err != nil { return "", errors.WithStack(err) } // PV's been created with a CSI source. - isProvisionedByCSI, err := isProvisionedByCSI(log, pv, client) + isProvisionedByCSI, err := isProvisionedByCSI(log, pv, cli) if err != nil { return "", errors.WithStack(err) } diff --git a/pkg/util/kube/utils_test.go b/pkg/util/kube/utils_test.go index eea77b110..4a6db6069 100644 --- a/pkg/util/kube/utils_test.go +++ b/pkg/util/kube/utils_test.go @@ -17,6 +17,7 @@ limitations under the License. package kube import ( + "context" "encoding/json" "testing" "time" @@ -33,7 +34,6 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - kubeinformers "k8s.io/client-go/informers" "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/vmware-tanzu/velero/pkg/builder" @@ -202,22 +202,18 @@ func TestGetVolumeDirectorySuccess(t *testing.T) { csiDriver := storagev1api.CSIDriver{ ObjectMeta: metav1.ObjectMeta{Name: "csi.test.com"}, } - kbClient := fake.NewClientBuilder().WithLists(&storagev1api.CSIDriverList{Items: []storagev1api.CSIDriver{csiDriver}}).Build() for _, tc := range tests { - h := newHarness(t) - - pvcInformer := kubeinformers.NewSharedInformerFactoryWithOptions(h.KubeClient, 0, kubeinformers.WithNamespace("ns-1")).Core().V1().PersistentVolumeClaims() - pvInformer := kubeinformers.NewSharedInformerFactory(h.KubeClient, 0).Core().V1().PersistentVolumes() + clientBuilder := fake.NewClientBuilder().WithLists(&storagev1api.CSIDriverList{Items: []storagev1api.CSIDriver{csiDriver}}) if tc.pvc != nil { - require.NoError(t, pvcInformer.Informer().GetStore().Add(tc.pvc)) + clientBuilder = clientBuilder.WithObjects(tc.pvc) } if tc.pv != nil { - require.NoError(t, pvInformer.Informer().GetStore().Add(tc.pv)) + clientBuilder = clientBuilder.WithObjects(tc.pv) } // Function under test - dir, err := GetVolumeDirectory(logrus.StandardLogger(), tc.pod, tc.pod.Spec.Volumes[0].Name, pvcInformer.Lister(), pvInformer.Lister(), kbClient) + dir, err := GetVolumeDirectory(context.Background(), logrus.StandardLogger(), tc.pod, tc.pod.Spec.Volumes[0].Name, clientBuilder.Build()) require.NoError(t, err) assert.Equal(t, tc.want, dir)