diff --git a/.github/auto-assignees.yml b/.github/auto-assignees.yml index d798ce4d56..ddca227743 100644 --- a/.github/auto-assignees.yml +++ b/.github/auto-assignees.yml @@ -9,7 +9,6 @@ reviewers: groups: maintainers: - - zubron - dsu-igeek - jenting - sseago diff --git a/changelogs/unreleased/4748-ywk253100 b/changelogs/unreleased/4748-ywk253100 new file mode 100644 index 0000000000..0b6ea993ff --- /dev/null +++ b/changelogs/unreleased/4748-ywk253100 @@ -0,0 +1 @@ +Refactor schedule controller with kubebuilder \ No newline at end of file diff --git a/config/crd/v1/bases/velero.io_schedules.yaml b/config/crd/v1/bases/velero.io_schedules.yaml index afb7b14a07..9fe76d7b56 100644 --- a/config/crd/v1/bases/velero.io_schedules.yaml +++ b/config/crd/v1/bases/velero.io_schedules.yaml @@ -16,7 +16,27 @@ spec: singular: schedule scope: Namespaced versions: - - name: v1 + - additionalPrinterColumns: + - description: Name of the schedule + jsonPath: .metadata.name + name: Name + type: string + - description: Status of the schedule + jsonPath: .status.phase + name: Status + type: string + - description: A Cron expression defining when to run the Backup + jsonPath: .spec.schedule + name: Schedule + type: string + - description: The last time a Backup was run for this schedule + jsonPath: .status.lastBackup + name: LastBackup + type: date + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 schema: openAPIV3Schema: description: Schedule is a Velero resource that represents a pre-scheduled @@ -393,6 +413,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 cb45808fcb..a87995de86 100644 --- a/config/crd/v1/crds/crds.go +++ b/config/crd/v1/crds/crds.go @@ -37,7 +37,7 @@ var rawCRDs = [][]byte{ []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\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\xb3%&4ۣ\xd1Uy\x05\xed\v?\xa8\xc6\xc4SqW\x8f\xe7G\xb9\xb4\xee\xe7\xde\xe3O\xd2:~U\xe6\x95\x11yg>~j\xa5z\xacra\xda\xe7g\x006\xd1%^\xc1g\x9a\xaa\x14\t\xa6g\x005a<\xf5\xaaF}\xf7\xde\xc3H2,\x84\xc7\t@\x97\xa8>|\xb9}\xf8\xfd]\xef1@\x8a61\xb2t̞\x80\x1eH\v\x02\x1e\x98@0\xb5(\xc0e\u0081\xc1ҠE\xe5\xa8Gip\x150L\x1b\x90\x00\xda@\x89F\xeaT&\xf0\xa3H\x9e\xaa\xd2\x0f\xb6\x99\xae\xf2\x146\b\xa6R\xebf@it\x89\xc6\xc9\xc0B\xdf:*\xd3y:\xc0\xf8\x1d\x11\xe5{AJ\xba\x82\x16\\\x86\x811\x98\xd6|\x00\xbd\x05\x97I\xdb\xe2\xcf\xe2\xef\x01\x06\xea$\x14\xe8\xcd\xdf1qk\xb8CC`\x02։V;4āD?*\xf9\xcf\x06\xb6\x05\xa7y\xd2\\8\xac\xe5\xda6\xa9\x1c\x1a%r؉\xbc\xc2\v\x10*\x85B\xec\xc1 \xcd\x02\x95\xea\xc0\xe3.v\r\u007f\xd6\x06A\xaa\xad\xbe\x82̹\xd2^]^>J\x17\x96J\xa2\x8b\xa2R\xd2\xed/Y\xeb\xe5\xa6r\xda\xd8\xcb\x14w\x98_Z\xf9\xb8\x12&ɤ\xc3\xc4U\x06/E)W\x8c\xba\xe2\xe5\xb2.\xd2\xff\v\x12\xb5\xefz\xb8\xba=\xe9\x97uF\xaa\xc7\xce\vV\xe8#\x12 \xcd\xf6\n\xe3\x87z*ZF\xd3#\xe2\xceכ\xbb\xfb\xae2I;\xe4>\xf3\xbd\xa3a\xad\b\x88aRm\xd1x!n\x8d.\x18&\xaa\xb4\xd4R9\xfe\x91\xe4\x12Ր\xfd\xb6\xda\x14ґ\xdc\xffQ\xa1u$\xab5\\\xb3\xfd =\xac\xcaT8L\xd7p\xab\xe0Z\x14\x98_\v\x8b\xdf]\x00\xc4i\xbb\"\xc6Ɖ\xa0k\xfa\x86\x9d=\xd7:/\x82\x99\x9a\x90WX\xe3w%&\xbd%C\xe3\xe4V&\xbc0`\xabMk\x02lך\x856\xbej\xa16=\xd4}\xf8\xfc\xa8\xb5\xb96Z\x01\xbe\x90\xec\xdb\xd5L\xba\U000dc862\x15f*Ex\x1e\xc0\x84\xdaĬ\x0f\xdeLp\x93_aQ\xd2r\x9dA\xf1\xbe\xeeF(\x12\x8f\xd2\xc6\x1dy\x83\x82\x8dyӵU\x83\x03\xa3\xc2\xd3eH\xfc\xdaɴ\xb6\x1a\a\xdc<\xceQ\x8f\xd8VT\xb9{\xd0yU\xa0\xbd\xd7_\xd1:\x99\x8c\xf5\x1c\x10\xf1qt`\x907Z\xe2\xb0\xcb\xd0\xd0\xe2\xe4\x17l\xefF\xe1\x02\xaf\x19\x8b)\x9b<\xf1\x84 `\xe39@\xb63ϡ\xd4)\xec\xfcL\xb0\xd9\a\xa4\x0fe\xd3\xcag\xa3u\x8eb\x8ck\xf8\x92\xe4U\x8ai\xe3\xf2F\xf92\xa0\xf6\xe6`\x10\a\aB*\xd22rń\xaaj\xdeN\xd0\xc9\xfeJ\x18\x042\x14Ry\x98 Y\x05k\x92lj\x92\x0e\x8b\t<\x8fj\xa4o\x14\x84\x88M\x8eW\xe0L5\xa6\xeb\x01\x860F\xec\x8f\xf0,\x04PKX\u058c\xa9\xcdy.\x13$f5F\x9b\xb9Ƭ\x99\xa0\xef\u007f\x90a\x99\xd6O1L\xfa\x13\xf5k\x9d\x13$\x1c\xa7\xc2\x063\xb1\x93\xda\xd8a\x84\x83/\x98T\x0e\xa7֑p\x90\xca\xed\x16\r\xc1*3a\xd1\x06\x93r\x8cY\xc7M\x045s\\\xf0\at\xb5B'\xe117\xa6HaS<\t\x15\x18q\xb2\xd8U\tR\xa5r'\xd3J\xe4 \x95uB%\x9e>\xd1\xe07N\x1f\xcc)\xc4\x01\xfe\xde\x00\a*HJ=Ϧ\x15R8Zh3\xae\x1c\xa1\x1d\x82\x99f\xc3F\x90\x05\xd4S\xee\xa8m\x86\"\xfa\x1a\x95\x94]jkw.ZI\xf9\xa00\x17\x1b\xcc\xc1b\x8e\x89\xd3f\x9a=1J\xe0[\xac\xfd\x9c\xe0\xec\x88%m}\x06)\xea\xac\x11m\x9b\xd3\xf0\x9c\xc9$\xf3\xf1\x1bi\x19ÂT\xa3e\x8b!\xca2\xdf\x1f#\x1ab4\xa3\x9el\xceh\xb4-\xc2|\f\xe1N\x19\x92\xb6E\xda\xe0\xb6\xcdX\xe3>\xd7\x1b\xb5ycz\x0fM\xf5M\xca~{0\xfc\xf5\x95\x9d\xd8-i\u007fw\xbb\x05,J\xb7\xbf\x00\xe9\xc2\xd3\x18\xa8\x14`\xb5x\xfc\xc6\x04w\xdaj\xb9\x1d\x8e~\xf5\xd5\xf2*Rk\xd0\xf8\x8d\b\x8d\x9d\xd5]\xed\xab\x16\t\xecSw\xe4\x05\xc8m#\xb0\xf4\x02\xb62wȱ\xd4\x1c\xa2\x9d@gVr\xafɠX\xdfK\xad\x10.\xc9n\x9a-mĈ\x01\xaf\x86\x00|\\\x1e\xf60,\x83\b\x90\xd0\x04\x15\x9c\x05\x91\x06\v\x9f]\xb9\xe7\xf5\xd1>\xe1\b\xf0\xc3珘α\f\xe25\xf5\x80\xa8\x0f\x83H\xa7\x8b\x02\x13\x18\x05\xb2C\x14\x87i\xcd\x1e\xcf\xe7\xd0.@\xc0\x13\xee}d5\xba\xb9\x1ck$Zр4\xc8\t=6#O\xb8gPu\x86.\n\xde\x12U\xf1\xed\t\xf7\xb1]\aL%\xfc\xea\x1c\x85\xe7.=`*b\x96R\xdb\x1a\xa6\xd6k\a\x9c\x8e#\x16\x96\x19\xa5\xd0\x02\xc7O$\xbb\x11X/-\xfd\x84\xfbw\u058b\x8fVM&\xcb\x05\x1c \x83\r\x16y\x85\x85|\xec\x83\xc8e\xdaL\xc6\xebd\x01\xc4[u\x01\x9f\xb5\xa3?7/\xd2\x12\x8a*\x85\x8f\x1a\xedg\xed\xf8\xc9we\xb1'\xe2D\x06\xfb\xc1\xbc,\x95w\vėE\xf3\xb78\xb0\v%\x15m\xc4&-\xdc*ڟy\xfe,\x11S\x86\x019\x8fVQY\xce\xe8*\xadV\xec\xa6\xc3l\v\x80v\xf1\xaaE\xa5MOR\x17\v!\x8e\xa2X\xa3wO\xdeʿ9ȅ\x1fk\x06\xcb\\$\x98BZq\xbe\x9d\x13\xef\xc2\xe1\xa3L\xa0@\xf3\x88P\x92߈W\xaa\x05\x96ܷ\x13\xb40>\xb4\b\xadv\vi\x1cb+Z\xf5\x91=\x83\x98\xa3\xbaOdُw\x8f\xa3\x92\xdd;\xc7CQ\xdc\x17iʩg\x91\u007fY\xe8Y\x16\xca\xeb0\x06\xf1H\xfa\xf0\xa3\x10\x9c\xec\xfd\x17\xb9WV\xef\u007f\xc7yC!\x8d]\xc3\a>\xdc̱;>d\t;SE\x81$L\xa4\x05ғ\x9d\xc8)| \xe3\xad\x00s\x1fL\xe8\xedA\x04\x15gb\x9e3m\xbd\xcf\xdfJ\xcc\xf9t\xeb\xfc\t\xf7\xe7\x17\a\xd6\xeb\xfcV\x9d\xc7\xc1$\x9b\u007f`\xb4\x9a\xa8E\xab|\x0f\xe7\xfc\xee\x9c\x03\xb3%K\xe4\x84\xe0m\x81VGw\xe5\xe3\xe7%[\x01\xdak\x87\xa8\x85\x067\x87\xb4\x14\xc2\xcfQ\x11\xadӥ\xb6n\x11Z_\xb4u>\x01\xd8\v\xb7G2\x841\xbb\xbf:k\bb\xebЀuڄ\x03Q2\xbb\x83\x049I\xde\xce˞D\xddd#=`\xdad\x9e\xb7\x16\xc2\xdb\xf4s\u007fRJ\xff\xcf\xc3L8Xbإ\xd1\tZ;\xafJ\x91\x9ec&a\xdb$k\x85\u07fcm\xa3LsL*9\xb4e\xa18\xb1\xf6\x84\x8d\xcd\xcdK'\xefLf\x88~Ǩ\xf2)8\x02\x17\xbd\x14\x85\x18\x1e\xceG\xa3{\xedG\x87\x05X\x03\xf3\x1b&\xf3X\xb1QY\x167\xd7*\xf9k\v<\n\xa9ny\"x\xff݂\x15\b\xa6\x1cO\xdd\xca\\\x87\xf1\xad@\x9a\a\xb1\xfbW\bG͚\xcfj\f\xf6${x\x92\x11/)\xa0`Zi\xd7M\xd6\xd43\xbd\xb3\xb0\x95ƺ\x16\xe1\x05P\xa5\xe5\xe3\xe4\xef\xbb\xc7T7Ɯ\xbc\xc5\xfcŏ\xee\xa4\x153\xfd\\\x17F,\xd9X\a\xe6gb\x87 \xb7 \x1d\xa0Jt\xa58\xe1E悦Y\x00\xd1\v\xd1;\x93H\x9f\xd9\x19\xac\xaa\"\x9e!+\xd6N\xa9f\xb3c\xdd!?\t\x19\x97\x9d\x82\xd3\xc4\xead\x81\xba\x9au\xedm\xebWv\xf8ѽ\n\x98B\xbcȢ*@\x14$\x96%\xfb\xc6-cӔ\xcbxY?\v\xe9\xf8Џ`\x93x\x96Y\xd3D\x17e\x8e\x0ea\x83[m\xd8\x1eX\x99b\x13>\xd4\xf2\x1f\xad7\x99j\x02\xb6B\xe6\x95Y`\xa3\x17Kf龭6O\xaf\xbf\x19\x8bGd\xc5̌L\xba/\b\x9a\xe7\xfdGi\x96\x85\xcc_\f\xbe~hZ\x1aIZ\xaa\xe7\xa2\xd3Y\x98\x1c\xbd\xf6\xa3\xd3Zy\x85\xdaO\x85\xa7\xb3P\x19\x93\xb7\xf0\xb4io\xe1\xe9[x\xfa\x16\x9e\x0e\xda[x\xfa\x16\x9e\xbe\x85\xa7\xe3\xed-<\xed\xb4\xb7\xf04\xda\u007f\xc4`\xe8\xbf::\xd2!\n\xab\xc8\x12\x8c9\xb4g\xe6\xaa+\x8d\xae\xf3\xca:4K*\xa4o\xc7G\x8e\xd4\xd0'\xbeˊ\xbf֚Қ\xb6t\xa5uzM\xc94-ɰ\x98\xfc\xb7\x18\x11Qxt\x19\xf4t\xb5}l\x01\xdd\\\xd9\\\xbfv\xbc)W\xf3\xffM0\xc4\xe90}-=\xff\x8dO\xb7\xe6\xaa_\xfb\xc6\xfb\x80\x80\U0006fcae<\xb2\xacm\xa6\x98\xedx!\xfe\x94\x87\x0f\xbc\x1c\x1c.\xf4\x99iz\x85߿j^FT\x9bMטէ\x96\xe8\xc4\xee\xfd\xba\xff\xc6\xe9\xba\xe2l\x82\xb2g\xe92\xff\xfd\x11m]\xd5c\xb7\xac=\xe8i\xfd\xedߐ\xc7\x13\x10\xb5\x01%s/\x80\x00\xa1\xc7~\xf8\xa5\xf4[\xe4\x93\xd7\xf9\xfcF-\xbe.mi5ZS?4\xefU\xbe\xa1\x06m\xd9\a\x02\xb3\xf5f1HCL\x95\xd9x\xfd\xd8\f\xd4%\xb5e\xb1{\xf0\x88:\xb2\xf8\xea\xb18\xf6\x00\u007f\xb1\x1b[3\x16\x1d\xb5\xc5և}\x9f\xaa\xb0\xc8Z\xb0N\x85\xd7,\xc8\x13+\xc0\xa2\x19\x16W\xed\x15]\xe3թܚ\xe7֑ʮ\xf1z\xadY\x90c\xf5\\1UZQ\xb8F\xd7f5\x15W\xf3\x99\xc4o\xaa\xc8z\xfd\xda\xef\u05cc\xf3\x8f\xd7WEUUE\xed\x05\xe6q\x8e\xaa\x9bZZ-\x15\xc5ե\x95QM\xd5ӑ\x89\xa3\xea\xa1\x0ek\x9d\x8e\x912[\x055]\xe1t\f\xecX\xedSD]\xd3\x11\x90݊\xa7\xc5a\xc0\xac6\xcdt\x18\xff\xaa>\xb4y_\x9b\xff74\xf0[\x89\xd6&E3\xbb+Y\x82\xfa,\xda\xfd|\xe5`\xfe\xc1\xe7:\xe1cr\xea\xd5\xdd\xf1LEQ\xba\xf9|$\x81\x9f\xa5J\xbd&\xd1b\xe9\xc44|C\x05\x17\x985a\xd6t\xc5m\x1b\xd1\x0ev[\x16KAF=\x85\xcd\xdeg\x85\xec\x1anD\x925\x1d' \xf2̙\xb0\xb4\xb3/\x84\x83\xf3f\x1b{\x19Fғ\xf35\xc0O\xba\xc9 t>\x0f\x9d\x80keQ\xe6{\xa8,\xc2y\x1fз\xed\xc2&u\xc7*Q\xdaL\x87\x9b\x04\"6bw\xfd\x11#\xf9\x92p\x8f@\x92\xeb*mf8\"n\xa1\xf6\xf0\xe5\x81#9\xfez:i\xbf2\xaf#\xb5\xb0\xaf\x1a|\x84>\x01r\xea\xf2\x88E,\x9bΪX\xa7\x8dx\xc4O\xda߫\x11ó\xfe\x88\xde\xd5*\xb5]\r9ֺhrR\x93=mC\x80\xed\xd1K\xbd\xda\xda$\x14a;ergֹsy\x04q\xf7\xf7\x9f\xb2\xb3Y\xee\b\xf1XNLo'a\tku\"\xd9\x16q\x8a\x82OX\xbe\xdf\x1d\v\xc7\"\xb2#&\xa3\xb2\xf8˳B\xf35,T{\xab\xbc\xa4fn]\xf9\xcb\xc1\xc0 \xe01\xf3A\xf6o\xd0}\xcc署A\xd6\xdf\xfd\xe5\xcd83.\xdcCsȺ\x99\xf5?\xbd\xf6\xc7#\xea\xd5\xf8\xd5/\xab\xe66\x9a\xb3\b\xceZ'\\ec.\xf8᎐\x88\xd2U\xa6v\xafIe\xf8\xc2\t\x02\x82\xfe>\x86Ӯ\xf8ɅuQ\xb2\xfc\xd4tl3\f\xd6\xf9\xf3\xa8`\xa0\xe0YX\xbe;ǟF\x8d\xba\xe6沠\xc9\xdbs\xbcw\xbd\x82T8\\\x11\xfc\xd3\xc49\xba\x0e\xf8\x82\x8e\x19J\xbfP\x9f\xe6t\xbcf4\x0f\f\x17{\xdcM\xa1>~ܹ\x82\xcf\xf8<\xf2\xf4F\x11\x11\x87\x9bQ\u007f\xa6\x89)g(Ʈ7;J\xe2\xae\x19\xc5\a\xca#֢o\xe6\x06\xdd\a\x99j\x91\xe7\x1d\x88\xfe\xf0xL\xac\xff/\xb7>m\x94\x10M\xbf;\xe81i\xb8\x8e\x1a\xad)\x835\xba\xa4\x0e\x1eZ4;L;JR\xfb\xf0\xfaI\xbb\x00E\x92`\xe9\xeaÏ\xee\xed\u007f\xe7\xe7\xfc#\\\xee\xc7?\x13\xad|Lm\xaf\xe0\xaf\u007f;\x83\xda\xd7>\x84\x1b\xfc\xe8\xe1\u007f\x02\x00\x00\xff\xff_q\xf0n+Q\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec\\_oܸ\x11\u007f\xf7\xa7\x18\xb8\x0fi\x01\xef\xfa\x82>\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#9\xb8S\x1d\xda;\xc5\xf8\xbf' 2\xcde$\xf6m)\x98Nѹpfm\xf20\x8e\xb9\x1b\xf9Z\xe9\xeem\x8f:f0\x92\x18\xb5Mktj\x0fh=\x81ZS\xa9ބ$i\xfcK,\xc3$\xc9hf\xf3%\xf6\xe7\xebh\xd6\xc7Iz9(\xc6\xf9\xe5\f\xd3C\x94\x99\xfb\xb7\xa6E}\xd2\x16\xb3\x89N\xd64ׯύڀ\xfc\xbf\xd9\x1b\xb7\bw\x1eY\x96J\xff\xb0騞\f\xe8\xc1\x10Pp.\xf6\xedbB& \xf3I\xbe\x901\x82\xdd\n\x9aU<\x9f\\\xeb\xd3&\xa0\xa2c%\xb9\x9fpH\xf6\xe0'\xe3Z1x;\xd7\xf9,\x87כ\b\xcd'\xfdI\xff\x9br\x1c7\x86p\xd5w\x99P\xad>D\x8fk\x8c\xaf\xf7׀2X\xabv\x16k\x10\nK\xed\xac\xab\x88\xd4i^5c\xa9]\xf6\xa9W\nh\xa1\x10\xfb\xe4\xe5\x80\xeeV7\xc0\x8b\x9aO\xf9+ϰ;\xddR\xbd;/\x87˖ʥ[C\x9cݥ\x98\x15\xce\xdeD\xcaj\xf6rI\xafn\x1e\vB\xb6S\xd9qf\\\xb5Ƹ\x88,c\xb8\ta5ً\xcbd\xbe\x99\x84\xc7\xe2I\xed\xa7\x01s\u061d\xff\xf4c \xc3H\x86?\xff*.\xd39.s\xbd`s?߂߽\xbbZgӧ\xf6\xae1y\x89\x87\x9f\u007f)\xb2cl\x9e\xc6\x1d4^\xfe\x1d\x00\x00\xff\xff;,8\xce>\f\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xb4VM\x8f\xdb6\x10\xbd\xebW\f\xd2C.\x95\x9c\xa0\x87\x16\xba\x05n\x0fA\xd3`\x11\xa7\xbe\x14=\xd0\xe4Ȟ.E\xb2\x9c\xa1\xdb\xed\xaf/HQ돕\xb7Y\xa0э\xc3\xe1\x9b7o>\xec\xa6m\xdbF\x05\xdabd\xf2\xae\a\x15\b\xff\x16t\xf9\xc4\xdd\xfd\x0fܑ_\x1d\xdf6\xf7\xe4L\x0f\xeb\xc4\xe2\xc7O\xc8>E\x8d?\xe2@\x8e\x84\xbckF\x14e\x94\xa8\xbe\x01P\xceyQ\xd9\xcc\xf9\b\xa0\xbd\x93\xe8\xad\xc5\xd8\xee\xd1u\xf7i\x87\xbbD\xd6`,\xe0s\xe8\xe3\x9b\xee\xfb\xeeM\x03\xa0#\x96\xe7\x9fiD\x165\x86\x1e\\\xb2\xb6\x01pj\xc4\x1e\x8eަ\x11٩\xc0\a/\xd6\xeb)XwD\x8b\xd1w\xe4\x1b\x0e\xa8s\xec}\xf4)\xf4p\xba\x98 *\xaf)\xa7mA\xdbT\xb4\x0f\x15\xad8Xb\xf9\xf9\x19\xa7\x0f\xc4R\x1c\x83MQٛ̊\x0f\x93\xdb'\xab\xe2-\xaf\x06\x80\xb5\x0f\xd8\xc3\xc7L1(\x8d\xa6\x01\xa8\xf2\x14\xca\xed,\xc0\xdb\tQ\x1fpTS.\x00>\xa0{w\xf7~\xfb\xdd\xe6\xc2\f`\x90u\xa4 E\xe4\xe5D\x80\x18\x14\xccL\xe0\xaf\x03F\x84mQ\rX|D\xae\xa4\x1fA\x01f\xfe\xdc=\x1aC\xf4\x01\xa3\xd0,\xf0\xf4\x9d\xb5י\xf5\x8a\xd7\xebL}\xf2\x02\x93\xfb\n\x19\xe4\x80s\xfahj\xb6\xe0\a\x90\x031D\f\x11\x19\x9d\x9c\xcau\xfa\xfc\x00ʁ\xdf\xfd\x81Z:\xd8`\xcc0\xc0\a\x9f\xac\xc9\xedx\xc4(\x10Q\xfb\xbd\xa3\u007f\x1e\xb1\x19ė\xa0V\t\xd6ʞ>r\x82\xd1)\vGe\x13~\v\xca\x19\x18\xd5\x03D\xccQ \xb93\xbc\xe2\xc2\x1d\xfc\xe2#\x02\xb9\xc1\xf7p\x10\tܯV{\x92y\xac\xb4\x1f\xc7\xe4H\x1eVeBh\x97\xc4G^\x19<\xa2]1\xed[\x15\xf5\x81\x04\xb5\xa4\x88+\x15\xa8-\xd4\xdd\xd4\xed\xa3\xf9&\xd6A\xe4\xd7\x17\\\xe5!w\x11K$\xb7?\xbb(\xed\xfeL\x05r\xa7O\x8d0=\x9d\xb28\t\x9dMY\x9dO?m>\xc3\x1c\xba\x14\xe3Z\xfd\xa2\xfb\xe9!\x9fJ\x90\x05#7`\x9c\x8a8D?\x16Lt&xrR\x0e\xda\x12\xbak\xf99\xedF\x92\\\xf7?\x13\xb2\xe4Zu\xb0.\xbb\x06v\b)\x18%h:x\xef`\xadF\xb4k\xc5\xf8\xd5\v\x90\x95\xe66\v\xfbe%8_\x93\xd7Γj\xe7\x03V\x97؍z-O\xf2&\xa0\xbe\x18\xa0\x8cB\x03\xd5\xc9\x1e|\xbc\xd2U\xcds\xbe\x8c\xd7]\xb8/\x0f8L;~\xa0\xfd\xb5\x15@\x19S~!\x94\xbd\xbb\xf9\xf6\x19\xc1\x16\xf2^\x97H\xb9Q\a\x1f3\xa3#\x19\x8c\xed\x9cge\x92bM\x98\xd0\x1a\xee\x9e@\xdeм&Y \x9fҼ\xe0qW\xdd2\x93,\xf4\xfcl\xdaPX\x17fY\x9fj\x8f\xb7\x18,d\x9c;\x9c\"^\xcdj\xfb\x18\xe0\x8bzG\x94$~y\xf7\x94g\xd5sW;H\xa7\x18\xd1I\xc5\\ش\xffO\a\x85\x83b\xfc\x0f͗#\xdc\xe5\x97s\x19,\r\xa8\x1f\xb4\xc5\t\x10\xfc\xb0\xd0m/\xa2\x9c?ti|ʭ\x85wGEV\xed,.\xdc\xfd\xea\xd4\xcdۛ\xc5_\xac\xe7\x13#\xe7ujz\x90\x98&\xec\xdae\xd5r\xaa\xbe\xd2\x1a\x83\xa0\xf9x\xfd\xaf\xe7ի\x8b?.娽\x9b\x86\x95{\xf8\xed\xf7fBE\xb3\x9d\xff\x81d\xe3\xbf\x01\x00\x00\xff\xff\xbf\xca\xff\xa71\n\x00\x00"), } diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index c261775693..2de1d49868 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -4,8 +4,14 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: creationTimestamp: null - name: manager-role + name: velero-perms rules: +- apiGroups: + - velero.io + resources: + - backups + verbs: + - create - apiGroups: - velero.io resources: @@ -46,6 +52,26 @@ rules: - get - patch - update +- apiGroups: + - velero.io + resources: + - schedules + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - velero.io + resources: + - schedules/status + verbs: + - get + - patch + - update - apiGroups: - velero.io resources: diff --git a/hack/update-generated-crd-code.sh b/hack/update-generated-crd-code.sh index e3355be487..d1c3eb0d53 100755 --- a/hack/update-generated-crd-code.sh +++ b/hack/update-generated-crd-code.sh @@ -49,6 +49,7 @@ ${GOPATH}/src/k8s.io/code-generator/generate-groups.sh \ controller-gen \ crd:crdVersions=v1\ paths=./pkg/apis/velero/v1/... \ + rbac:roleName=velero-perms \ paths=./pkg/controller/... \ output:crd:artifacts:config=config/crd/v1/bases diff --git a/pkg/apis/velero/v1/schedule.go b/pkg/apis/velero/v1/schedule.go index 1f2f84d45e..52cac8255a 100644 --- a/pkg/apis/velero/v1/schedule.go +++ b/pkg/apis/velero/v1/schedule.go @@ -77,8 +77,18 @@ type ScheduleStatus struct { ValidationErrors []string `json:"validationErrors,omitempty"` } +// TODO(2.0) After converting all resources to use the runtime-controller client, the genclient and k8s:deepcopy markers will no longer be needed and should be removed. // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root +// +kubebuilder:object:generate=true +// +kubebuilder:storageversion +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Name",type="string",JSONPath=".metadata.name",description="Name of the schedule" +// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.phase",description="Status of the schedule" +// +kubebuilder:printcolumn:name="Schedule",type="string",JSONPath=".spec.schedule",description="A Cron expression defining when to run the Backup" +// +kubebuilder:printcolumn:name="LastBackup",type="date",JSONPath=".status.lastBackup",description="The last time a Backup was run for this schedule" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" // Schedule is a Velero resource that represents a pre-scheduled or // periodic Backup that should be run. @@ -96,6 +106,7 @@ type Schedule struct { } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root // ScheduleList is a list of Schedules. type ScheduleList struct { diff --git a/pkg/cmd/server/server.go b/pkg/cmd/server/server.go index 5a00648c4a..89a115e16a 100644 --- a/pkg/cmd/server/server.go +++ b/pkg/cmd/server/server.go @@ -654,22 +654,6 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string } } - scheduleControllerRunInfo := func() controllerRunInfo { - scheduleController := controller.NewScheduleController( - s.namespace, - s.veleroClient.VeleroV1(), - s.veleroClient.VeleroV1(), - s.sharedInformerFactory.Velero().V1().Schedules(), - s.logger, - s.metrics, - ) - - return controllerRunInfo{ - controller: scheduleController, - numWorkers: defaultControllerWorkers, - } - } - gcControllerRunInfo := func() controllerRunInfo { gcController := controller.NewGCController( s.logger, @@ -771,7 +755,6 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string enabledControllers := map[string]func() controllerRunInfo{ controller.BackupSync: backupSyncControllerRunInfo, controller.Backup: backupControllerRunInfo, - controller.Schedule: scheduleControllerRunInfo, controller.GarbageCollection: gcControllerRunInfo, controller.BackupDeletion: deletionControllerRunInfo, controller.Restore: restoreControllerRunInfo, @@ -843,6 +826,10 @@ func (s *server) runControllers(defaultVolumeSnapshotLocations map[string]string s.logger.Fatal(err, "unable to create controller", "controller", controller.BackupStorageLocation) } + if err := controller.NewScheduleReconciler(s.namespace, s.logger, s.mgr.GetClient(), s.metrics).SetupWithManager(s.mgr); err != nil { + s.logger.Fatal(err, "unable to create controller", "controller", controller.Schedule) + } + if _, ok := enabledRuntimeControllers[controller.ServerStatusRequest]; ok { r := controller.ServerStatusRequestReconciler{ Scheme: s.mgr.GetScheme(), diff --git a/pkg/controller/schedule_controller.go b/pkg/controller/schedule_controller.go index e5f48814f3..f75c7d95ea 100644 --- a/pkg/controller/schedule_controller.go +++ b/pkg/controller/schedule_controller.go @@ -18,27 +18,22 @@ package controller import ( "context" - "encoding/json" "fmt" "time" - jsonpatch "github.com/evanphx/json-patch" "github.com/pkg/errors" "github.com/robfig/cron" "github.com/sirupsen/logrus" - apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/clock" - "k8s.io/client-go/tools/cache" + "sigs.k8s.io/cluster-api/util/patch" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" - api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/builder" - velerov1client "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/typed/velero/v1" - velerov1informers "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions/velero/v1" - velerov1listers "github.com/vmware-tanzu/velero/pkg/generated/listers/velero/v1" "github.com/vmware-tanzu/velero/pkg/metrics" + "github.com/vmware-tanzu/velero/pkg/util/kube" kubeutil "github.com/vmware-tanzu/velero/pkg/util/kube" ) @@ -46,160 +41,100 @@ const ( scheduleSyncPeriod = time.Minute ) -type scheduleController struct { - *genericController - - namespace string - schedulesClient velerov1client.SchedulesGetter - backupsClient velerov1client.BackupsGetter - schedulesLister velerov1listers.ScheduleLister - clock clock.Clock - metrics *metrics.ServerMetrics +type scheduleReconciler struct { + client.Client + namespace string + logger logrus.FieldLogger + clock clock.Clock + metrics *metrics.ServerMetrics } -func NewScheduleController( +func NewScheduleReconciler( namespace string, - schedulesClient velerov1client.SchedulesGetter, - backupsClient velerov1client.BackupsGetter, - schedulesInformer velerov1informers.ScheduleInformer, logger logrus.FieldLogger, + client client.Client, metrics *metrics.ServerMetrics, -) *scheduleController { - c := &scheduleController{ - genericController: newGenericController(Schedule, logger), - namespace: namespace, - schedulesClient: schedulesClient, - backupsClient: backupsClient, - schedulesLister: schedulesInformer.Lister(), - clock: clock.RealClock{}, - metrics: metrics, +) *scheduleReconciler { + return &scheduleReconciler{ + Client: client, + namespace: namespace, + logger: logger, + clock: clock.RealClock{}, + metrics: metrics, } +} - c.syncHandler = c.processSchedule - c.resyncFunc = c.enqueueAllEnabledSchedules - c.resyncPeriod = scheduleSyncPeriod - - schedulesInformer.Informer().AddEventHandler( - cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { - schedule := obj.(*api.Schedule) - - switch schedule.Status.Phase { - case "", api.SchedulePhaseNew, api.SchedulePhaseEnabled: - // add to work queue - default: - c.logger.WithFields(logrus.Fields{ - "schedule": kubeutil.NamespaceAndName(schedule), - "phase": schedule.Status.Phase, - }).Debug("Schedule is not new, skipping") - return - } - - key, err := cache.MetaNamespaceKeyFunc(schedule) - if err != nil { - c.logger.WithError(errors.WithStack(err)).WithField("schedule", schedule).Error("Error creating queue key, item not added to queue") - return - } - c.queue.Add(key) - scheduleName := schedule.GetName() - c.logger.Info("Creating schedule ", scheduleName) - //Init Prometheus metrics to 0 to have them flowing up - metrics.InitSchedule(scheduleName) - }, - }, - ) - - return c +func (c *scheduleReconciler) SetupWithManager(mgr ctrl.Manager) error { + s := kube.NewPeriodicalEnqueueSource(c.logger, mgr.GetClient(), &velerov1.ScheduleList{}, scheduleSyncPeriod) + return ctrl.NewControllerManagedBy(mgr). + For(&velerov1.Schedule{}). + Watches(s, nil). + Complete(c) } -func (c *scheduleController) enqueueAllEnabledSchedules() { - schedules, err := c.schedulesLister.Schedules(c.namespace).List(labels.NewSelector()) - if err != nil { - c.logger.WithError(errors.WithStack(err)).Error("Error listing Schedules") - return - } +// +kubebuilder:rbac:groups=velero.io,resources=schedules,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=velero.io,resources=schedules/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=velero.io,resources=backups,verbs=create - for _, schedule := range schedules { - if schedule.Status.Phase != api.SchedulePhaseEnabled { - continue - } +func (c *scheduleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + log := c.logger.WithField("schedule", req.String()) - key, err := cache.MetaNamespaceKeyFunc(schedule) - if err != nil { - c.logger.WithError(errors.WithStack(err)).WithField("schedule", schedule).Error("Error creating queue key, item not added to queue") - continue - } - c.queue.Add(key) + log.Debug("Getting schedule") + schedule := &velerov1.Schedule{} + if err := c.Get(ctx, req.NamespacedName, schedule); err != nil { + c.logger.WithError(err).Error("error getting schedule") + return ctrl.Result{}, nil } -} -func (c *scheduleController) processSchedule(key string) error { - log := c.logger.WithField("key", key) - - log.Debug("Running processSchedule") - ns, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - return errors.Wrap(err, "error splitting queue key") + if schedule.Status.Phase != "" && + schedule.Status.Phase != velerov1.SchedulePhaseNew && + schedule.Status.Phase != velerov1.SchedulePhaseEnabled { + c.logger.Debugf("the schedule phase isn't %s or %s, skip", velerov1.SchedulePhaseNew, velerov1.SchedulePhaseEnabled) + return ctrl.Result{}, nil } - log.Debug("Getting Schedule") - schedule, err := c.schedulesLister.Schedules(ns).Get(name) - if err != nil { - // schedule no longer exists - if apierrors.IsNotFound(err) { - log.WithError(err).Debug("Schedule not found") - return nil - } - return errors.Wrap(err, "error getting Schedule") - } + c.metrics.InitSchedule(schedule.Name) - switch schedule.Status.Phase { - case "", api.SchedulePhaseNew, api.SchedulePhaseEnabled: - // valid phase for processing - default: - return nil + patchHelper, err := patch.NewHelper(schedule, c.Client) + if err != nil { + c.logger.WithError(err).Error("error new patch helper") + return ctrl.Result{}, nil } - log.Debug("Cloning schedule") - // store ref to original for creating patch - original := schedule - // don't modify items in the cache - schedule = schedule.DeepCopy() - // validation - even if the item is Enabled, we can't trust it // so re-validate currentPhase := schedule.Status.Phase cronSchedule, errs := parseCronSchedule(schedule, c.logger) if len(errs) > 0 { - schedule.Status.Phase = api.SchedulePhaseFailedValidation + schedule.Status.Phase = velerov1.SchedulePhaseFailedValidation schedule.Status.ValidationErrors = errs } else { - schedule.Status.Phase = api.SchedulePhaseEnabled + schedule.Status.Phase = velerov1.SchedulePhaseEnabled } // update status if it's changed if currentPhase != schedule.Status.Phase { - updatedSchedule, err := patchSchedule(original, schedule, c.schedulesClient) - if err != nil { - return errors.Wrapf(err, "error updating Schedule phase to %s", schedule.Status.Phase) + if err = patchHelper.Patch(ctx, schedule); err != nil { + c.logger.WithError(err).Errorf("error updating schedule phase to %s", schedule.Status.Phase) + return ctrl.Result{}, nil } - schedule = updatedSchedule } - if schedule.Status.Phase != api.SchedulePhaseEnabled { - return nil + if schedule.Status.Phase != velerov1.SchedulePhaseEnabled { + c.logger.Debug("the schedule's phase is %s, isn't %s, skip", schedule.Status.Phase, velerov1.SchedulePhaseEnabled) + return ctrl.Result{}, nil } // check for the schedule being due to run, and submit a Backup if so - if err := c.submitBackupIfDue(schedule, cronSchedule); err != nil { - return err + if err := c.submitBackupIfDue(ctx, schedule, cronSchedule); err != nil { + c.logger.WithError(err).Error("error running submitBackupIfDue") } - return nil + return ctrl.Result{}, nil } -func parseCronSchedule(itm *api.Schedule, logger logrus.FieldLogger) (cron.Schedule, []string) { +func parseCronSchedule(itm *velerov1.Schedule, logger logrus.FieldLogger) (cron.Schedule, []string) { var validationErrors []string var schedule cron.Schedule @@ -239,7 +174,7 @@ func parseCronSchedule(itm *api.Schedule, logger logrus.FieldLogger) (cron.Sched return schedule, nil } -func (c *scheduleController) submitBackupIfDue(item *api.Schedule, cronSchedule cron.Schedule) error { +func (c *scheduleReconciler) submitBackupIfDue(ctx context.Context, item *velerov1.Schedule, cronSchedule cron.Schedule) error { var ( now = c.clock.Now() isDue, nextRunTime = getNextRunTime(item, cronSchedule, now) @@ -259,23 +194,24 @@ func (c *scheduleController) submitBackupIfDue(item *api.Schedule, cronSchedule // lead to performance issues). log.WithField("nextRunTime", nextRunTime).Info("Schedule is due, submitting Backup") backup := getBackup(item, now) - if _, err := c.backupsClient.Backups(backup.Namespace).Create(context.TODO(), backup, metav1.CreateOptions{}); err != nil { + if err := c.Create(ctx, backup); err != nil { return errors.Wrap(err, "error creating Backup") } - original := item - schedule := item.DeepCopy() - - schedule.Status.LastBackup = &metav1.Time{Time: now} + patchHelper, err := patch.NewHelper(item, c.Client) + if err != nil { + return errors.Wrap(err, "error creating patch helper") + } + item.Status.LastBackup = &metav1.Time{Time: now} - if _, err := patchSchedule(original, schedule, c.schedulesClient); err != nil { - return errors.Wrapf(err, "error updating Schedule's LastBackup time to %v", schedule.Status.LastBackup) + if err := patchHelper.Patch(ctx, item); err != nil { + return errors.Wrapf(err, "error updating Schedule's LastBackup time to %v", item.Status.LastBackup) } return nil } -func getNextRunTime(schedule *api.Schedule, cronSchedule cron.Schedule, asOf time.Time) (bool, time.Time) { +func getNextRunTime(schedule *velerov1.Schedule, cronSchedule cron.Schedule, asOf time.Time) (bool, time.Time) { var lastBackupTime time.Time if schedule.Status.LastBackup != nil { lastBackupTime = schedule.Status.LastBackup.Time @@ -288,7 +224,7 @@ func getNextRunTime(schedule *api.Schedule, cronSchedule cron.Schedule, asOf tim return asOf.After(nextRunTime), nextRunTime } -func getBackup(item *api.Schedule, timestamp time.Time) *api.Backup { +func getBackup(item *velerov1.Schedule, timestamp time.Time) *velerov1.Backup { name := item.TimestampedName(timestamp) backup := builder. ForBackup(item.Namespace, name). @@ -297,27 +233,3 @@ func getBackup(item *api.Schedule, timestamp time.Time) *api.Backup { return backup } - -func patchSchedule(original, updated *api.Schedule, client velerov1client.SchedulesGetter) (*api.Schedule, error) { - origBytes, err := json.Marshal(original) - if err != nil { - return nil, errors.Wrap(err, "error marshalling original schedule") - } - - updatedBytes, err := json.Marshal(updated) - if err != nil { - return nil, errors.Wrap(err, "error marshalling updated schedule") - } - - patchBytes, err := jsonpatch.CreateMergePatch(origBytes, updatedBytes) - if err != nil { - return nil, errors.Wrap(err, "error creating json merge patch for schedule") - } - - res, err := client.Schedules(original.Namespace).Patch(context.TODO(), original.Name, types.MergePatchType, patchBytes, metav1.PatchOptions{}) - if err != nil { - return nil, errors.Wrap(err, "error patching schedule") - } - - return res, nil -} diff --git a/pkg/controller/schedule_controller_test.go b/pkg/controller/schedule_controller_test.go index 5900e673e9..a678dc210f 100644 --- a/pkg/controller/schedule_controller_test.go +++ b/pkg/controller/schedule_controller_test.go @@ -17,7 +17,6 @@ limitations under the License. package controller import ( - "encoding/json" "testing" "time" @@ -25,21 +24,22 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/clock" - core "k8s.io/client-go/testing" - "k8s.io/client-go/tools/cache" + "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" "github.com/vmware-tanzu/velero/pkg/builder" - "github.com/vmware-tanzu/velero/pkg/generated/clientset/versioned/fake" - informers "github.com/vmware-tanzu/velero/pkg/generated/informers/externalversions" "github.com/vmware-tanzu/velero/pkg/metrics" velerotest "github.com/vmware-tanzu/velero/pkg/test" ) -func TestProcessSchedule(t *testing.T) { +func TestReconcileOfSchedule(t *testing.T) { + require.Nil(t, velerov1.AddToScheme(scheme.Scheme)) + newScheduleBuilder := func(phase velerov1api.SchedulePhase) *builder.ScheduleBuilder { return builder.ForSchedule("ns", "name").Phase(phase) } @@ -49,45 +49,34 @@ func TestProcessSchedule(t *testing.T) { scheduleKey string schedule *velerov1api.Schedule fakeClockTime string - expectedErr bool expectedPhase string expectedValidationErrors []string expectedBackupCreate *velerov1api.Backup expectedLastBackup string }{ { - name: "invalid key returns error", - scheduleKey: "invalid/key/value", - expectedErr: true, - }, - { - name: "missing schedule returns early without an error", + name: "missing schedule triggers no backup", scheduleKey: "foo/bar", - expectedErr: false, }, { - name: "schedule with phase FailedValidation does not get processed", - schedule: newScheduleBuilder(velerov1api.SchedulePhaseFailedValidation).Result(), - expectedErr: false, + name: "schedule with phase FailedValidation triggers no backup", + schedule: newScheduleBuilder(velerov1api.SchedulePhaseFailedValidation).Result(), }, { name: "schedule with phase New gets validated and failed if invalid", schedule: newScheduleBuilder(velerov1api.SchedulePhaseNew).Result(), - expectedErr: false, expectedPhase: string(velerov1api.SchedulePhaseFailedValidation), expectedValidationErrors: []string{"Schedule must be a non-empty valid Cron expression"}, }, { name: "schedule with phase gets validated and failed if invalid", schedule: newScheduleBuilder(velerov1api.SchedulePhase("")).Result(), - expectedErr: false, expectedPhase: string(velerov1api.SchedulePhaseFailedValidation), expectedValidationErrors: []string{"Schedule must be a non-empty valid Cron expression"}, }, { name: "schedule with phase Enabled gets re-validated and failed if invalid", schedule: newScheduleBuilder(velerov1api.SchedulePhaseEnabled).Result(), - expectedErr: false, expectedPhase: string(velerov1api.SchedulePhaseFailedValidation), expectedValidationErrors: []string{"Schedule must be a non-empty valid Cron expression"}, }, @@ -95,24 +84,14 @@ func TestProcessSchedule(t *testing.T) { name: "schedule with phase New gets validated and triggers a backup", schedule: newScheduleBuilder(velerov1api.SchedulePhaseNew).CronSchedule("@every 5m").Result(), fakeClockTime: "2017-01-01 12:00:00", - expectedErr: false, expectedPhase: string(velerov1api.SchedulePhaseEnabled), expectedBackupCreate: builder.ForBackup("ns", "name-20170101120000").ObjectMeta(builder.WithLabels(velerov1api.ScheduleNameLabel, "name")).Result(), expectedLastBackup: "2017-01-01 12:00:00", }, - { - name: "schedule with phase Enabled gets re-validated and triggers a backup if valid", - schedule: newScheduleBuilder(velerov1api.SchedulePhaseEnabled).CronSchedule("@every 5m").Result(), - fakeClockTime: "2017-01-01 12:00:00", - expectedErr: false, - expectedBackupCreate: builder.ForBackup("ns", "name-20170101120000").ObjectMeta(builder.WithLabels(velerov1api.ScheduleNameLabel, "name")).Result(), - expectedLastBackup: "2017-01-01 12:00:00", - }, { name: "schedule that's already run gets LastBackup updated", schedule: newScheduleBuilder(velerov1api.SchedulePhaseEnabled).CronSchedule("@every 5m").LastBackupTime("2000-01-01 00:00:00").Result(), fakeClockTime: "2017-01-01 12:00:00", - expectedErr: false, expectedBackupCreate: builder.ForBackup("ns", "name-20170101120000").ObjectMeta(builder.WithLabels(velerov1api.ScheduleNameLabel, "name")).Result(), expectedLastBackup: "2017-01-01 12:00:00", }, @@ -121,134 +100,48 @@ func TestProcessSchedule(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { var ( - client = fake.NewSimpleClientset() - sharedInformers = informers.NewSharedInformerFactory(client, 0) - logger = velerotest.NewLogger() - ) - - c := NewScheduleController( - "namespace", - client.VeleroV1(), - client.VeleroV1(), - sharedInformers.Velero().V1().Schedules(), - logger, - metrics.NewServerMetrics(), - ) - - var ( + client = (&fake.ClientBuilder{}).Build() + logger = velerotest.NewLogger() testTime time.Time err error ) + + reconciler := NewScheduleReconciler("namespace", logger, client, metrics.NewServerMetrics()) + if test.fakeClockTime != "" { testTime, err = time.Parse("2006-01-02 15:04:05", test.fakeClockTime) require.NoError(t, err, "unable to parse test.fakeClockTime: %v", err) } - c.clock = clock.NewFakeClock(testTime) + reconciler.clock = clock.NewFakeClock(testTime) if test.schedule != nil { - sharedInformers.Velero().V1().Schedules().Informer().GetStore().Add(test.schedule) - - // this is necessary so the Patch() call returns the appropriate object - client.PrependReactor("patch", "schedules", func(action core.Action) (bool, runtime.Object, error) { - var ( - patch = action.(core.PatchAction).GetPatch() - patchMap = make(map[string]interface{}) - res = test.schedule.DeepCopy() - ) - - if err := json.Unmarshal(patch, &patchMap); err != nil { - t.Logf("error unmarshalling patch: %s\n", err) - return false, nil, err - } - - // these are the fields that may be updated by the controller - phase, found, err := unstructured.NestedString(patchMap, "status", "phase") - if err == nil && found { - res.Status.Phase = velerov1api.SchedulePhase(phase) - } - - lastBackupStr, found, err := unstructured.NestedString(patchMap, "status", "lastBackup") - if err == nil && found { - parsed, err := time.Parse(time.RFC3339, lastBackupStr) - if err != nil { - t.Logf("error parsing status.lastBackup: %s\n", err) - return false, nil, err - } - res.Status.LastBackup = &metav1.Time{Time: parsed} - } - - return true, res, nil - }) - } - - key := test.scheduleKey - if key == "" && test.schedule != nil { - key, err = cache.MetaNamespaceKeyFunc(test.schedule) - require.NoError(t, err, "error getting key from test.schedule: %v", err) + require.Nil(t, client.Create(ctx, test.schedule)) } - err = c.processSchedule(key) - - assert.Equal(t, test.expectedErr, err != nil, "got error %v", err) + _, err = reconciler.Reconcile(ctx, ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "ns", Name: "name"}}) + require.Nil(t, err) - actions := client.Actions() - index := 0 - - type PatchStatus struct { - ValidationErrors []string `json:"validationErrors"` - Phase velerov1api.SchedulePhase `json:"phase"` - LastBackup time.Time `json:"lastBackup"` - } - - type Patch struct { - Status PatchStatus `json:"status"` + schedule := &velerov1api.Schedule{} + err = client.Get(ctx, types.NamespacedName{"ns", "name"}, schedule) + if len(test.expectedPhase) > 0 { + require.Nil(t, err) + assert.Equal(t, test.expectedPhase, string(schedule.Status.Phase)) } - - decode := func(decoder *json.Decoder) (interface{}, error) { - actual := new(Patch) - err := decoder.Decode(actual) - - return *actual, err + if len(test.expectedValidationErrors) > 0 { + require.Nil(t, err) + assert.EqualValues(t, test.expectedValidationErrors, schedule.Status.ValidationErrors) } - - if test.expectedPhase != "" { - require.True(t, len(actions) > index, "len(actions) is too small") - - expected := Patch{ - Status: PatchStatus{ - ValidationErrors: test.expectedValidationErrors, - Phase: velerov1api.SchedulePhase(test.expectedPhase), - }, - } - - velerotest.ValidatePatch(t, actions[index], expected, decode) - - index++ + if len(test.expectedLastBackup) > 0 { + require.Nil(t, err) + assert.Equal(t, parseTime(test.expectedLastBackup).Unix(), schedule.Status.LastBackup.Unix()) } - if created := test.expectedBackupCreate; created != nil { - require.True(t, len(actions) > index, "len(actions) is too small") - - action := core.NewCreateAction( - velerov1api.SchemeGroupVersion.WithResource("backups"), - created.Namespace, - created) - - assert.Equal(t, action, actions[index]) - - index++ - } - - if test.expectedLastBackup != "" { - require.True(t, len(actions) > index, "len(actions) is too small") - - expected := Patch{ - Status: PatchStatus{ - LastBackup: parseTime(test.expectedLastBackup), - }, - } - - velerotest.ValidatePatch(t, actions[index], expected, decode) + backups := &velerov1api.BackupList{} + require.Nil(t, client.List(ctx, backups)) + if test.expectedBackupCreate == nil { + assert.Equal(t, 0, len(backups.Items)) + } else { + assert.Equal(t, 1, len(backups.Items)) } }) } diff --git a/pkg/util/kube/periodical_enqueue_source.go b/pkg/util/kube/periodical_enqueue_source.go new file mode 100644 index 0000000000..bb89295b47 --- /dev/null +++ b/pkg/util/kube/periodical_enqueue_source.go @@ -0,0 +1,88 @@ +/* +Copyright the Velero contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kube + +import ( + "context" + "reflect" + "time" + + "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/util/workqueue" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/predicate" +) + +func NewPeriodicalEnqueueSource(logger logrus.FieldLogger, client client.Client, objList client.ObjectList, period time.Duration) *PeriodicalEnqueueSource { + return &PeriodicalEnqueueSource{ + logger: logger.WithField("resource", reflect.TypeOf(objList).String()), + Client: client, + objList: objList, + period: period, + } +} + +// PeriodicalEnqueueSource is an implementation of interface sigs.k8s.io/controller-runtime/pkg/source/Source +// It reads the specific resources from Kubernetes/cache and enqueues them into the queue to trigger +// the reconcile logic periodically +type PeriodicalEnqueueSource struct { + client.Client + logger logrus.FieldLogger + objList client.ObjectList + period time.Duration +} + +func (p *PeriodicalEnqueueSource) Start(ctx context.Context, h handler.EventHandler, q workqueue.RateLimitingInterface, pre ...predicate.Predicate) error { + go wait.Until(func() { + p.logger.Debug("enqueueing resources ...") + if err := p.List(ctx, p.objList); err != nil { + p.logger.WithError(err).Error("error listing resources") + return + } + if meta.LenList(p.objList) == 0 { + p.logger.Debug("no resources, skip") + return + } + if err := meta.EachListItem(p.objList, func(object runtime.Object) error { + obj, ok := object.(metav1.Object) + if !ok { + p.logger.Error("%s's type isn't metav1.Object", object.GetObjectKind().GroupVersionKind().String()) + return nil + } + q.Add(ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: obj.GetNamespace(), + Name: obj.GetName(), + }, + }) + p.logger.Debugf("resource %s/%s enqueued", obj.GetNamespace(), obj.GetName()) + return nil + }); err != nil { + p.logger.WithError(err).Error("error enqueueing resources") + return + } + }, p.period, ctx.Done()) + + return nil +} diff --git a/pkg/util/kube/periodical_enqueue_source_test.go b/pkg/util/kube/periodical_enqueue_source_test.go new file mode 100644 index 0000000000..2264729f7f --- /dev/null +++ b/pkg/util/kube/periodical_enqueue_source_test.go @@ -0,0 +1,64 @@ +/* +Copyright the Velero contributors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kube + +import ( + "testing" + "time" + + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" + "golang.org/x/net/context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" +) + +func TestStart(t *testing.T) { + require.Nil(t, velerov1.AddToScheme(scheme.Scheme)) + + ctx, cancelFunc := context.WithCancel(context.TODO()) + client := (&fake.ClientBuilder{}).Build() + queue := workqueue.NewRateLimitingQueue(workqueue.DefaultItemBasedRateLimiter()) + source := NewPeriodicalEnqueueSource(logrus.WithContext(ctx), client, &velerov1.ScheduleList{}, 1*time.Second) + + require.Nil(t, source.Start(ctx, nil, queue)) + + // no resources + time.Sleep(1 * time.Second) + require.Equal(t, queue.Len(), 0) + + // contain one resource + require.Nil(t, client.Create(ctx, &velerov1.Schedule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "schedule", + }, + })) + time.Sleep(2 * time.Second) + require.Equal(t, queue.Len(), 1) + + // context canceled, the enqueue source shouldn't run anymore + item, _ := queue.Get() + queue.Forget(item) + require.Equal(t, queue.Len(), 0) + cancelFunc() + time.Sleep(2 * time.Second) + require.Equal(t, queue.Len(), 0) +}