From 2588426d064af2cc8b075cf2e7755056a8a13c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Rostagni?= Date: Tue, 1 Oct 2024 17:35:06 +0200 Subject: [PATCH] Add disabled PV re-provisioning by StorageClasses option on restore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clément Rostagni --- config/crd/v1/bases/velero.io_restores.yaml | 9 + config/crd/v1/crds/crds.go | 2 +- pkg/apis/velero/v1/restore_types.go | 7 + pkg/apis/velero/v1/zz_generated.deepcopy.go | 5 + pkg/builder/restore_builder.go | 6 + pkg/cmd/cli/restore/create.go | 52 +++--- pkg/cmd/cli/restore/create_test.go | 3 + pkg/cmd/util/output/restore_describer.go | 7 + pkg/restore/restore.go | 47 ++++- pkg/restore/restore_test.go | 189 ++++++++++++++++++++ 10 files changed, 301 insertions(+), 26 deletions(-) diff --git a/config/crd/v1/bases/velero.io_restores.yaml b/config/crd/v1/bases/velero.io_restores.yaml index e276172919..514135c2e1 100644 --- a/config/crd/v1/bases/velero.io_restores.yaml +++ b/config/crd/v1/bases/velero.io_restores.yaml @@ -46,6 +46,15 @@ spec: BackupName is the unique name of the Velero backup to restore from. type: string + disabledPVReprovisioningStorageClasses: + description: |- + DisabledPVReprovisioningStorageClasses is a slice of StorageClasses names. + PV without snaptshot and having one of these StorageClass will not be + re-provisionned (even when ReclaimPolicy is Delete). + items: + type: string + nullable: true + type: array excludedNamespaces: description: |- ExcludedNamespaces contains a list of namespaces that are not diff --git a/config/crd/v1/crds/crds.go b/config/crd/v1/crds/crds.go index 1089493430..b04c8cece1 100644 --- a/config/crd/v1/crds/crds.go +++ b/config/crd/v1/crds/crds.go @@ -36,7 +36,7 @@ var rawCRDs = [][]byte{ []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcWMs\xe36\f\xbd\xfbW`\xa6\x97vf%o\xa6=t|k\x9d=d6\xddf\xe2m\xee\x14\x05Il(\x92%Ag\xd3\xe9\x8f\uf014\xfc!ˎsY\xdd\f\x82\xe0\xc3\x03\xf0H\x17E\xb1\x10N=\xa1\x0fʚ\x15\b\xa7\xf0\x1b\xa1\xe1_\xa1|\xfe5\x94\xca.\xb77\x8bge\xea\x15\xacc \xdb?b\xb0\xd1K\xbc\xc5F\x19EʚE\x8f$jAb\xb5\x00\x10\xc6X\x12l\x0e\xfc\x13@ZC\xdej\x8d\xbehєϱ\xc2**]\xa3O\xc1ǣ\xb7\x1f˛_ʏ\v\x00#z\\Am_\x8c\xb6\xa2\xf6\xf8O\xc4@\xa1ܢFoKe\x17\xc1\xa1\xe4ح\xb7ѭ`\xbf\x90\xf7\x0e\xe7f̷C\x98\xc7\x1c&\xadh\x15\xe8\xf3\xdc\xea\xbd\x1a<\x9c\x8e^\xe8S\x10i1(\xd3F-\xfc\xc9\xf2\x02 H\xebp\x05_\x18\x86\x13\x12\xeb\x05\xc0\x90b\x82U\f\xd9mor(\xd9a/2^\x00\xeb\xd0\xfc\xf6p\xf7\xf4\xf3\xe6\xc8\fPc\x90^9JD\xfdW\xec\xec0M\x00T\x00\x01\x03\x1c \xbbC\b\u0080\xf0\xa4\x1a!\t\x1ao{\xa8\x84|\x8e\x0el\xf57J\x82@\u058b\x16?@\x88\xb2\x03\xc1Q\xb2\xc3\xc1Yڶ\xd0(\x8d\xe5\xce\xe6\xbcu\xe8I\x8d\x94\xe7\uf821\x0e\xac\x97\xb2\xe0\x8f\x13ϻ\xa0\xe6\xce\xc2\x00\xd4\xe1H\x1e\xd6\x03W`\x1b\xa0N\x05\xf0\xe8<\x064\xb9\xd7\xd8,̐M9\t\xbdA\xcfa t6\xea\x9a\x1br\x8b\x9e\xc0\xa3\xb4\xadQ\xff\xeeb\af\x8c\x0fՂ\x12\x99\x86\xd0\x1b\xa1a+t\xc4\x0f L=\x89܋W\xf0\x98\x18\x8c\xe6 ^\xda\x10\xa68\xfe\xb0\x1eA\x99Ʈ\xa0#ra\xb5\\\xb6\x8a\xc61\x93\xb6\xef\xa3Q\xf4\xbaL\x13\xa3\xaaHևe\x8d[\xd4ˠ\xdaBx\xd9)BI\xd1\xe3R8U\xa4DL\x1a\xb5\xb2\xaf\x7f\xf0\xc3`\x86\xa3c\xe9\x95\x1b2\x90W\xa6=XH\xd3\xf1\x8e\xf2\xf0\xbc\xe4\xeeʡr\x8a\xfb*\xb0\x89\xa9{\xfc\xb4\xf9\n#\x92\\\xa9\xa1\xc5v\xae'\xbc\x8c\xf5a6\x95i\xd0\xe7}\xa9M9&\x9a\xdaYe(\xfd\x90Z\xa1!\b\xb1\xea\x15\x85\xb1\u05f9tӰ\xeb$EP!DW\v\xc2z\xeapg`-z\xd4k\x11\xf0;\u05ca\xab\x12\n.\xc2U\xd5:\x14ةs\xa6\xf7`a\x94\xc73\xa5\x9dH\xc6ơ\xe4\xc22\xb7\xbcS5J\xe6\x91j\xac\a\xb1W\x90\x81\xe9c\xa2\xe6\x15 \x81\x13\xbeE\x9aZ'X\xbe&'>\xfe\xa5\x13ǂ\xf5#\x96mɚ\x13\x06 Y\x8f~\x9a\x16\xea\x12\x06\x98m\xf4Y$c\x7f3\r\xcc+\v\n\x8b\xdd!\xa6ӣ\xf9C\x13\xfb\xf9\x03\n\xf8=a\xbe\xb7\xed\xc5\xf5\xb55\xc4sq\xd1\xe9\xc9\xea\xd8\xe3\xc6\b\x17:\xfb\x86\xef\x1da\xff\xa7C\x9f\xafዮ\xe3m\xbe\xbb\xfa.8F}\xf6\xdcG\xe4\x1b\x04\xcfg:8\\\x15\xe5\nL\x83\xe7U\x89\xae7w\xef\xa1\xf0\x8c\xfb;\x8atg\x1a\xfbF\x8a{\xc7Y\xbf320~\xe9\r\xf1vO\xf3+d\xeciޒ\xefN\x84ϱBo\x900\xec\x95\xfaEQ7\x1b\x11\xe0\xa5S\xb2K\x1b\xd3@\xf0%\x10\x82\x95jNR\xaf\x80\xcf:\xa2<\xce\fe\x91\x86u\xc6\xcc\xe0O\xccg\xd4\xef\xdc\x01ŠHW)(\t\x8a\xe1\x1d\x1a\x9a\xfcG\xaae\xf4>]Q\xd9\xca/\x93\xe9\x86kEtT\x9e\xbf\x1e\xef\xdfP\xd2۽gzq\ve2\x1a\xe7\xb1\b\xaa\xe5\x17\x14\xaf\xb1\x96&\x8d;%#\x7f\xc7/\xbcc\xa2f+\x8aߜ\xca\x03\xf8\x06\xc4O;\xc7,\xf8h\xf2=?}æ\x80\x18\xf8\xb9\x05R\x98\x19\x8c\x15B\x8d\x1a\tk\xa8^\xf3\xcd\xf5\x1a\b\xfbS܍\xf5\xbd\xa0\x15\xf0\xfd_\x90\x9ai#\x13\xb5\x16\x95\xc6\x15\x90\x8f\xe7\xbal6q\u05c903\x86G9?\xb0\xcf\\c\xec\x86\xf1bg\xc0\xd9\xfb\xa5\x80/\xf82c}\xf0Vb\bx:Fg3\x99\x1d\x82\x13c\xe0GZ}\xc0\xd2\xf0\x97a\xb0\xfc\x1f\x00\x00\xff\xff\xc02\xee\xedJ\x0e\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4ZKs\x1b7\x12\xbe\xebWt)\x87$U\x1e2\xf6\xa6\xb6\xb6x\xb3\xe5͖v\x13Yeʾ\xa4r\x00\a=3\x88f\x00\x04\xc0\x90\xe2f\xf3߷\x1a\x0fr^$E:\xb1\xe7b\x13\x8f\xee\x0f\xfdFCY\x96]1->\xa2\xb1B\xc9\x050-\xf0ɡ\xa4_v\xf6\xf8\x0f;\x13j\xbe~y\xf5($_\xc0Mk\x9djޣU\xad\xc9\xf1-\x16B\n'\x94\xbcj\xd01\xce\x1c[\\\x010)\x95c4l\xe9'@\xae\xa43\xaa\xae\xd1d%\xca\xd9c\xbb\xc2U+j\x8e\xc6\x13O\xac\xd7\xdf\xcd^~?\xfb\xee\n@\xb2\x06\x17\xa0\x15_\xab\xbamp\xc5\xf2\xc7V\xdb\xd9\x1ak4j&ԕ\u0558\x13\xedҨV/`?\x11\xf6F\xbe\x01\xf3\xbd\xe2\x1f=\x997\x9e\x8c\x9f\xa9\x85u\xff\x99\x9a\xfdQX\xe7W\xe8\xba5\xac\x1e\x83\xf0\x93VȲ\xad\x99\x19M_\x01\xd8\\i\\\xc0\x1d\xc1\xd0,G~\x05\x10\x8f\xe8ae\xc08\xf7Bc\xf5\xbd\x11ҡ\xb9!\nIX\x19p\xb4\xb9\x11\xday\xa1\xdc+\x0e\x01 \x04\x84`\x1ds\xad\x05\xdb\xe6\x150\vw\xb8\x99\xdf\xca{\xa3J\x836\xc0\x03\xf8\xd5*y\xcf\\\xb5\x80YX>\xd3\x15\xb3\x18g\x83x\x97~\"\x0e\xb9-\x81\xb6\xce\bYN\xc1x\x10\r¦B\t\xae\x12\x16\xc2ia\xc3,\xc11Οr\x9a\xb1\x9f\xa7\xedֱF\xf7\x10\xdc\x18d\xfb\xad\x01\x02g\x0e\xa7\x00\xec\xe4\t\xaa\x00W!I\xde\x1b\x16\x13R\xc8\xd2\x0f\x05M\x80S\xb0B\x0f\x119\xb4z\x02\x99\xc6|\xa6\x15\x9f\xc9D\xb4\a\xebn0zJ6\xb4\xfe\xcfF\xd5\x03t\xaf\xf8\x05P\xce\xe2\x1b\x16\xf7\xb8~\xec\x0e\x9d\xb4\x8f\n\xfd\x9aļյb\x1c\r\xb1\xaf\x98\xe45\x92f\x198ä-\xd0\x1c\x80\x91\xb6=lu\x1ḟD\xaf3s\x8e0\xa2\xef,\x9d2\xacD\xf8Q\xe5>@\x91I\x1b\xecٴ\xadT[sX%.\x00\xd6)3i\xe0\x848\xec\x8at\x13ف\x9f\xf5y\x1eFߡ\x9d\xe2\xe9,'\x1f\x11JN{\xd0\xeb\x12\xa7\xbd'L\xaf_\x86p\x95WذE\\\xa94\xca\xd7\xf7\xb7\x1f\xff\xb6\xec\r\x03h\xa34\x1a'R\xf8\f_'9tF\xa1/\xea\xffe\xbd9\x00b\x10v\x01\xa7,\x816\xd8d\x18C\x1e1\x05\xf5\b\v\x06\xb5A\x8b2\xe4\r\x1af\x12\xd4\xeaW\xcc\xddl@z\x89\x86\xc8$E\xe5J\xae\xd180\x98\xabR\x8a\xff\xeeh[\xb2=bZ3\x87ց\x0f\xb5\x92հfu\x8b/\x80I>\xa0ܰ-\x18$\x9e\xd0\xca\x0e=\xbf\xc1\x0eq\xfc\xa4\f\x82\x90\x85Z@圶\x8b\xf9\xbc\x14.\xa5\xcc\\5M+\x85\xdb\xce}\xf6\x13\xab\xd6)c\xe7\x1c\xd7Xϭ(3f\xf2J8\xcc]kpδ\xc8\xfcA\xa4O\x9b\xb3\x86\x7feb\x92\xb5=\xb6#\xab\t\x9f\xcftg\xa8\x87r\x1f\b\v,\x92\nG\xdck!Ů\xf7\xff\\>@B\x124\x15\x94\xb2_:\x92K\xd2\x0fISȂb\x00\xed+\x8cj\xa98\x9e8ܝ\xe28\x05\x9b\xb6\x82\xabX\xb0n*\xde(\xb8\xb5R\x8e\xb9Ч\xe4Y\xc0\xb4\xe2'pE\x8e\f\f\x16hP昢\xe0\xb1\xcad\x02Y\xb7f\x18c\x8a\xfc'\xe5C_!\xb0\xe6>\x8b\x9e\xe6=i\xa2\xf4\xdd\x16\x01\x84\x8f\x8dN\x01\x03-0Ԟ\xbb\xbc\x04BZ\x87\x8c\xc7A\n\a\x06\xe3܋\x10\xf3\x0e\x82\xa4o\x9f\xbfH'\xc0(\x06\v\x0e\xff^\xbe\xbb\x9b\xffK\x85s\x00\xcbs\xb4\xbe\xc8vؠt/vu?G+\fr\xaa\xe2q\xd60)\n\xb4n\x16\xa9\xa1\xb1?\xbf\xfaeZ~\x00?(\x03\xf8\xc4\x1a]\xe3\v\x10A滰\x9e\xccF\xd8p\xf0\x1dE\xd8\bWy\xa0Z\xf1x\xc0\x8d?\x82c\x8f\b*\x1e\xa1E\xa8\xc5\xe3\x84\xff\x84\xef\xdaWM{\x98\xbf\x93\xf7\xfcq\r\xdf\x047\xbe\xa6\x9f\xd7\x01\xc6.\x81w\x1dl\x0f'x\x99\x11e\x89\xfb\xf2ld,\x94p(T\x7f\v\xca\xd0Y\xa5\xea\x90\xf0\x84IO!R\"\x1f\xc1\xfb\xf9\xd5/\xd7\xf0M_\x06\aX\t\xc9\xf1\t^\x81\x88w$\xad\xf8\xb73x\xf0v\xb0\x95\x8e=\x11\xa7\xbcR\x16%(YoCi\xbcF\xb0\x8a\xeeVX\xd7Y(\x958l\xd8\x16Tq\x80OR\x11\x99&\x03͌;Z.\xa5\xef\xe1\xdd\xdbw\x8b\x80\x8cL\xa7\xf4Q\x972j!\xa8(b\x92\xc7<\xed\xed\x8e@\xb7\xc1$\x9c\x82\xbcb\xb2\xc4p2\x84\xa2\xa5)\xb8|\xb8}\xfb%=\xaa\x15\x97D\x92\x03\xb7\x86\xf0=e{TY\xc3t\x16V3\xa7\x1a\x91\x0fVS\xd5|\xcbII\x85@s\xa2\xcc|\xdf[\x9c\n\xe1\x89\xfa{\xb7\xe6\xac:ױr\xa2\xb0\xec\xf6M\x8f\x95\x9fG\xe5u\xda\x14\x1eXi\x81\x19\x04\x06\r\xd3d\x11\x8f\xb8\xcdBe\xa3\x99\xa0\xb2\x84*\x8f]\x9f\b\x98\xd65\xd5\x0e\xa1Z\x99\xa0\x18\xeb\xec(\x1ef\xfd\xf9\x0e\tdR\x95\xa9/\xb6DGw\xf3/'\x9c\x0f\x03 \x7f\xae\xa0v]\xc3\\\xc9B\x94\xad\xf1w\xbe\xb1\xa4d[\xd7lU\xe3\x02\x9ciDŽ\x9e!\xc8\aZr\xfc\xfc\x1f:K\x93\x85\x9fhqN\x9f\xaa\xd7\xf8\x1c\x1f\x06eی\xa1d\xf0\xa8\xb4`\x13\xe3\x06\xad\x1by/M\\_\x9f\xe3c\xc1(/\xb9\xc3\xc7爉\xdbo4\xf4xQH7\xe0n\azR\xe9g\xc4\x06\x83\xbf\xb5t\xed\xe9\xe3Φ\x1b\x14\x835t7\x1f\fi\xc5\a#\xfd08\x98\xecuɻH\xc7]\x1b\xff\xf8qF\xdf&<\xeaD\x99\x86\xe4\xe8\xd2S\x0f\x95\xf7\x97vnrE\u05fc^\a\xf9\x12\x9dߌ\xc9\xf8\x8e\xab\xe1\xd11DCq\xa0\xf3.\x14\x19O\xb5^\xba\xe4\xc2N_\xa3\x105\xe4\xfe\xbaF\xb7ɂ\x89\x1a9\xa4ǿ3\xa9\xac\xb0\xa0\x1c\x1d\x9c45<\"\xbc\xc3\x17\xa5\x87\n\xc1\xfa\xfe\xe5\xd7vG\xb3\xb5\xc8}\xfblB\b\xe3\x8c](\xd30\x17Z\xf1\x19\x91\xb8,zM\xfal\x83ֲ\xf2\x94\xd3\xfe\x14V\x85>P\xdc\x02l\xa5Z\xb7k\x04\xf52\xd2\xd76\x1a\xday\xbd\xa8\xc9\x16K\xdfƙ\xab\x92I\x17m]\xfb=\xdd\xe8\xb0\x7f\x18\xf6\xa8V8]\xd7\x1diD\x1d\x03X1{JT\xf7\xb4f\xca\xebv!\xed\xa8\xdb\xc1\x91\xf0}\x87\x9b\x89\xd1\xd1Kmw\xf2&\xb9\xcc\xc4\xdc\x0f\xde\x1b\xce:\x7fdt\x89\xbb'\x90P\xa9:y\xb8r\xac\x06\xd96+4$\x9c\xd5֡\x1d\x04\xfe\xd0D\xd8Ir\xea\xf6\xb7ߟ\x94\x1a(\xc5NIΤo\xf1\xdbP&pauͶ\xbb\xb3\xf8\x9a\x9b\xfck\xba\x15\xbc7\xf2\xe4\xe9\x1a\x0f\xd5\x10\xc7[\x98\x1e\xd3[%\x0f\xdcR\x93\x93\v\xe9\xfe\xfe\xfd\x91\xa2]H\x87\xe5 \x8d\xc4y\x12\xe7\x1b\xe2\xf2\xd7p8R\x03Yɴ\xad\x94\xbb}{\xc24\x96\xbb\x85\xc9E\xf6\xf5\xbc\x0f\x88\xfe\x95!.\x8a\xa60\x01u\x1fp\xce\xf2\xdf\xfe\x1f\x0e\\b\xc5\xcb\x1e\x85\x13\xf9*\xfe\x1d\xc3TVX\xa2f\x86b\x82\x7fú\x19\xbeȾ\x00+|\xa3\x9d\xaa\xddP\xfe\x86\x86\xd9\xd4uNI_\xc0)3~P\x84\x93\t\xa8\x7f\xa0ϙ{&\xcdi4\xe8\x91\xf3\x0e\xed\xf8|\xd3\x1diW\xbb\x97\xcd\x05\xfc\xfe\xc7\xd5\xff\x03\x00\x00\xff\xff\x8b\xcb\x17\x16\x81$\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4Y_s\xdb6\x12\x7f\xf7\xa7\xd8q\x1f\xda΄R\x93\xeb\xdc\xdc\xe8-q\xae7\xbek\x1dO\xe4\xe4\xa5Ӈ\x15\xb1\"Q\x93\x00\n\x80\x92u\xbd~\xf7\x9b\x05H\x8a\xff$YJ\x9b\xe0\xc5\x16\xb0X\xfc\xb0\xff\xb1L\x92\xe4\n\x8d\xfcH\xd6I\xad\x16\x80Fғ'ſ\xdc\xec\xf1\x1fn&\xf5|\xf3\xf2\xeaQ*\xb1\x80\x9b\xcay]\xbe'\xa7+\x9b\xd2[ZK%\xbd\xd4\xea\xaa$\x8f\x02=.\xae\x00P)푧\x1d\xff\x04H\xb5\xf2V\x17\x05\xd9$#5{\xacV\xb4\xaad!\xc8\x06\xe6\xcdћ\xeff/\xbf\x9f}w\x05\xa0\xb0\xa4\x05\x18-6\xba\xa8J\xb2伶\xe4f\x1b*\xc8\xea\x99\xd4W\xceP\xca\xcc3\xab+\xb3\x80\xfdB\xdc\\\x1f\x1cA\xdfk\xf11\xf0y\x1f\xf9\x84\xa5B:\xff\x9f\xc9\xe5\x1f\xa5\xf3\x81\xc4\x14\x95\xc5b\x02GXuReU\x81v\xbc~\x05\xe0Rmh\x01w\f\xc5`J\xe2\n\xa0\xbeg\x80\x96\x00\n\x11$\x87Ž\x95ʓ\xbda\x16\x8d\xc4\x12\x10\xe4R+\x8d\x0f\x92i\xf9\x80^\x83ω\x8f\fRE\xa9\xa4\xca\xc2T\x84\x00^Ê\xa0F\"\x023\x80_\x9dV\xf7\xe8\xf3\x05\xccXp3\xa3\xc5L5?\x81>N\xc4\xe5\xcd\xcb\x18\xcaҜJ\\Ԕڐz}\x7f\xfb\xf1o\xcb\xde4\x80\xb1ڐ\xf5\xb2\x89\xaeqt\x92Gg\x16\xfa\x92\xfd_\xd2[\x03\xe0\x03\xe2.\x10\x9cE\xc8E'\x89s$jL\xd1y\xa4\x03Kƒ#\x15\xf3\nO\xa3\x02\xbd\xfa\x95R?\x1b\xb0^\x92e6\xe0r]\x15!\"m\xc8z\xb0\x94\xeaL\xc9\xff\xb6\xbc\x1d\xfb\"\x1fZ\xa0'烬\xad\xc2\x026XT\xf4\x02P\x89\x01\xe7\x12w`\x89τJu\xf8\x85\rn\x88\xe3'\xb6\x1f\xa9\xd6z\x01\xb9\xf7\xc6-\xe6\xf3L\xfa&\xa5\xa6\xba,+%\xfdn\x1e\xb2\xa3\\U^[7\x17\xb4\xa1b\xeed\x96\xa0Ms\xe9)\xf5\x95\xa59\x1a\x99\x84\x8b\xa8\x90Vg\xa5\xf8\xca\xd6I\xd8\xf5\x8e\x1dyd\x1c!\x11\x9e\xa1\x1eΌ \x1d`\xcd*^q\xaf\x85&\xbe\xbf\xff\xe7\xf2\x01\x1a$QSQ){ґ\\\x1a\xfd\xb04\xa5Zs\x84\xe6}k\xab\xcb\xc0\x93\x940Z*\x1f~\xa4\x85$\xe5\xc1U\xabRz6\x83\xdf*r\x9eU7d{\x13\xca\x0e\x0e\xae\x95a3\x17C\x82[\x057XRq\x83\x8e>\xb3\xaeX+.a%Vf\xe9\xb5Ō~ԑ\xe7\x90\xe8\x94\xd9\xf1x3ŨA\xac:\t5\x9e\b.RBQ\x93N\xb0\xdc\xe6d\xa9\xbbǒ\xd1Nzmw\xcc8\xa6\xe2\xa1I\x1c\xd4N\x90\x83\x16'\xeeƹ$8\x90\xa55YR)5\xe1\xe6X\x994\x01\xbeS-\x8c!\x1e\xd6\a\x1c\t͓\x80_\xdf\xdf6᷑p\r}\x14aO\x8a\x87\xc7ZR!B\xb6:}\xf6\xa4!\xf0\xb8]G\x10!\x06y\r\bFR,\x83\xdb\xf8\x0fR9O(\xeaIv;K\xf5ڋ\x18[\x0e\x82\xe4\xb1\xcf\x13\xac\x12@\x8euR\xc0\xbf\x97\xef\xee\xe6\xff\xd2\xf1\x1e\x80iJ΅r\x80JR\xfeE[\x12\brҒຈf%*\xb9&\xe7g57\xb2\xee\xe7W\xbfL\xcb\x0f\xe0\am\x81\x9e\xb04\x05\xbd\x00\x19eކ\xcf\xc6j\xa4\x8b\x17o9\xc2V\xfa<\x005Z\xd4\x17܆+x|$\xd0\xf5\x15*\x82B>Ҵ\xf4\x01\xaeC\xa1\xb9\x87\xf9;\xbb\xd6\x1f\xd7\xf0Mt\x96k\xfey\x1da\xb4\x89\xb2\xeb}{8>G\x0f\xde\xca,\xa3}E;2\x16\x0e\xec\x1c\x12\xbf\x05m\xf9\xaeJwX\x04Ƭ\xa7\x18\x90H\x8c\xe0\xfd\xfc\xea\x97k\xf8\xa6/\x83\x03GI%\xe8\t^\x81TQ6F\x8bog\xf0\x10\xec`\xa7<>\xf1Ii\xae\x1d)Ъ\xd8\xc5\a\u0086\xc0\xe9\x92`KE\x91ĒD\xc0\x16w\xa0\xd7\a\xceiTĦ\x89`\xd0\xfa\xa3eI3\x1e\u07bd}\xb7\x88\xc8\xd8t\xb2\x10\xdb8s\xad%\x17\x1f\xa8D\x9d\x0f\x83\xdd1\xe8*\x9a\x84א\xe6\xa82\x8a7#XW\x9co.r\xceq=Ќ\xe7\xf9e\xa8\x0f\x9e\x15%\xbeXn}\xa6$B!\xfc\t\x92\xe8>\xf1.\x90\xc4c\xb5\"\xab\xc8S\x10\x86Щc9\xa4d\xbc\x9b\xeb\rٍ\xa4\xed|\xab\xed\xa3TY\xc2F\x9fD\xebr\xf3\xf0~\x9f\x7f\x15\xfe\\z\xf1\xf0\xd2\xff\xd4\xdb\xf7\x1a\x13\x9f_\x04|\xba\x9b_\"\x81\xa6n}~\x8e<(\x87e]I\ry\xb2\xd3ns\x99\xe6\xcd+\xa6\x13\xd5K\x141\xec\xa3\xda}!\xdfa9W\x96\x11풺I\x97\xa0\x12\xfc\xbf\x93\xce\xf3\xfc%\x82\xad\xe4'\x05\x97\x0f\xb7o\xbf\xa4GU\xf2\x92Hr\xa0:\x8f\xe3)٣JJ4I\xa4F\xafK\x99\x0e\xa8\xb96\xbd\x15\xac\xa4\xb5${\xa2\xca|\xdf#n\xaa\xe4\x89*\xb7\xa59\xab\xccu\n\x8d˵\xbf}{\x02Dz%l0\xecuX\x17\xb7\r\xafA\a\xec<<\xc1\xb7\xee\x0eG\xae>\xa8>u\x83L[\x99\x85Tۆ\x8f\xf0\xf4QXb\xb7\xf3\xd9\x1d%\x1a#Uv\x16֦\x91\xb8$\xcf\xcf\xe5\x89\x02\xbd\xdb\x02>V\xc6\x1f\xb5\xbb\xd3.\xf5a\x00\x04\xd0\x12 ߉5\xf4H\xbb$V\x8b\x06%\x97z\\\xcd\xd5%\xf1\x8a\x00\x8d)\xb8\x1e\x8b\x15\xe0\x94\xaf7m\xd1T\xab\xb5\xcc*\x1b\x1eacI\xa9\xaa(pU\xd0\x02\xbc\xadƌ\x8e\xb8O\xb7#{B\xe3\x1f:\xa4\x8d\xbaO\xf4\x84\xa7o\xd5\xeb\x14\x8f/C\xaa*\xc7P\x12x\xd4F\xe2\xc4<\x1b\xfb\xc8\xd1y\xe1\xfa\xfa\x1c\x93\x8a\x9etB\x06u\x03s\xe2\xc1\\;b\xfd|\xe0\x19~\xa4\x06w\x9cΎ\xe7:\xa8\xa5\xdf*~\v\xf5\x11&ӽ\x81\x01\x8d\xd1\xe2j(\xb4nl\x1b,\xee#\xd3p\xa1\xef\xf4\x83\xd5^c\xbd{\x9bq[%tm\xcfi\xac\xc4Nq-\xf7\x98V}\xd3?\xe6\x87\xc1ŭ\x95T\xf3\v\xb1\xd7佤\xb1r3f\x13\x9a\xa2VԎ\"K\n\xfd\x8a\xd8\xf9ޢkN\x9e2\x82.\xbf\xb85\xd47̎Dx\xea\xf1Kt\x8d\xb2 \x01\xed\a\xbc\t6\x0f9\x81\v-\xc1\xaf]˨r$BT\x9e\x00=N\xceM\x03^\xa0\xa7\x84Y\\\x16}&}\xae$\xe70;\xe5t?E\xaa\xd8\xf1\xa9\xb7\x00\xaet\xe5ۖO\xed}\xb5(\xbev\xb5i\x9c\xd7v\xcaѝ\x82r\xcf4Sf\xd8Ɓ\xe3v\bG\xe2\xdb\x1dm'fG\x1fD\xba\x8b7\x8d\tM\xac\xfd\x10\xac\xe3,\x01\xd4\a]b\xff\rH\xc8uј\xbc\xf6\\\aT\xe5\x8a,K'|\x9ai\xc4\xd4\x16,\xf1I\xde\ns\xea-\xd5rh\xa2fdU\xb7\x1dRT\xa1/\xedb\"\x15ҙ\x02w\xedeB\x01\xcb\x16<ݽܛQ\xe3\x9a\x1c(\x0e\xa4\xd9\xe3\r\xc1\xf6\xd3\xd3ty>\xf5!\xab?\xc6_\xa5\x06\xeb\xed7\xb7\xbf\xe6\x84#e\x82\xf3h\xfd'\x05\xc8e\x8fé\xd8\x18Λ\x8e\x8c\xc7CZ\xff\x98\xcf\x19\xcd&\xa57\x9a\f\xc8E\x87w\xdda\xef\xceT\xab\xf6\xf3\xd3\x02~\xff\xe3\xea\xff\x01\x00\x00\xff\xff\xc5p\x17\xe3F\"\x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xdc=]\x93\x1c)r\xef\xfa\x15\x19\xf2\xc3\xda\x11ӣS\xf8\x1e\x1c\xf3&\xcfJ\xd6\xf8\ue909\x19Y\xfbLWewqCA-P\xd3\xea\xb3\xfd\xdf\x1d$P\x1f\xddT\x15\xdd\xf3\xb1\xbb\xe6E1Ր@~g\x92\xa0\xd5j\xf5\x865\xfc;jÕ\xbc\x02\xd6p\xfcaQ\xba\xbf\xcc\xe5ÿ\x99K\xae\xde=\xbe\x7f\xf3\xc0ey\x05\u05ed\xb1\xaa\xbeC\xa3Z]\xe0ϸ\xe1\x92[\xae\xe4\x9b\x1a-+\x99eWo\x00\x98\x94\xca2\xf7ٸ?\x01\n%\xadVB\xa0^mQ^>\xb4k\\\xb7\\\x94\xa8\tx\x9c\xfa\xf1O\x97\xef\xff|\xf9\xa77\x00\x92\xd5x\x05\x1a\x8dU\x1a\xcd\xe5#\n\xd4꒫7\xa6\xc1\xc2\xc1\xdcj\xd56W\xd0\xff\xe0DŽ\xf9\xfcZ\xef\xfcp\xfa\"\xb8\xb1\x7f\x19~\xfd+7\x96~iD\xab\x99\xe8'\xa3\x8f\x86\xcbm+\x98\xee>\xbf\x010\x85j\xf0\n\xbe\xb8i\x1aV`\xf9\x06 ,\x9d\xa6]\x85U?\xbe\xf7 \x8a\nk\xe6\xd7\x03\xa0\x1a\x94\x1fno\xbe\xff\xeb\xfd\xe83@\x89\xa6м\xb1\x84\x80\xffYu\xdf!.\x14\xb8\x01\x06\xdfi\xa3n5\x84x\xb0\x15\xb3\xa0\xb1\xd1hPZ\x03\xb6B`M#xAx\a\xb5\x19@\x8a\xa3\fl\xb4\xaa{hkV<\xb4\rX\x05\f,\xd3[\xb4\xf0\x97v\x8dZ\xa2E\x03\x85h\x8dE}\xd9\x01j\xb4jP[\x1e\xb1\xecۀw\x06_\xe76\xe6\x9aÅ\x1f\x05\xa5c\"\xf4[\b\xf8\xc42\xa0\x0f\xd4\x06l\xc5M\xbfո=`\x12\xd4\xfa\xefX\xd8\xcb\x03\xd0\xf7\xa8\x1d\x180\x95jE\xe9x\xef\x11\xb5CV\xa1\xb6\x92\xff\xa3\x83m\xdc\xc6ݤ\x82Y4\x16\xb8\xb4\xa8%\x13\xf0\xc8D\x8b\x17\xc0dy\x00\xb9f{\xd0\xe8\xe6\x84V\x0e\xe0\xd1\x00s\xb8\x8e\xbf\x11\xf1\xe4F]Aemc\xae\u07bd\xdbr\x1b%\xaaPu\xddJn\xf7\xefH8\xf8\xba\xb5J\x9bw%>\xa2xg\xf8v\xc5tQq\x8b\x85m5\xbec\r_\xd1F$I\xd5e]\xfeSG\xd4Ѵv\xefx\xd4X\xcd\xe5v\xf0\x03\t\xc4\t\xe4q\xa2\xe2\x19σ\xf2[\xec\xa9\xe0>9\xd4\xdd}\xbc\xff6dJn\x02Q\x06\xbc9E\x1f\x87M.7\xa8\xfd8bM\a\x13e\xd9(.-\xfdQ\b\x8e҂i\xd75\xb7\x8e\r~m\xd18~W\x87`\xafI\xeb\xc0\x1a\xa1mJf\xb1<\xecp#\xe1\x9a\xd5(\xae\x99\xc1W\xa6\x95\xa3\x8aY9\"dQk\xa8K\x0f;{\xf4\x0e~\x88\x1aq\x82\xb4A\x8b\xdc7X\x8c$\xcd\r㛨.6J\x8f\x94\x8c\x1b2\xc6QZ\xf8]\xf3Zĩ\xc5\xc3_\x96\xb8̵\x7f\xefF;~s+k%\xff\xb5ER\xa6^\xfc\xf1X_\xe9\x81j\x1f7\xc7F\x87ԝD\xb4k\xf8\xa3\x10m\x89e\xa7\u05cf6\x98\xb3\x8d\x8fGP\xc8\xe81.\x9d\x109\xeb\xe3\xf6\"\xfb_I\x813\x8d \x95M\xc0\xe3\xd2\xc3\x03.\t\x03I\x9aPG\x8bubų[\x06\x90\xad\x10l-\xf0\n\xacn\x8f\xd1\xe8\xc72\xad\xd9~\x02[\xd1\x03x\x12\xb2: A\xd5\b^\x10\xc9;\x85B\xf8\xfa㢊\x1b\xa7(\xe3.o\x95\xe0\xc5~\x01_\x1f\x93\x83\xa2\xb4\x06\xd9\r;\x845V\xec\x91+\x9d\x12\x03\xa5\xa9\xeb\xc0\x9e\xf7jZ9-\x19\x80\x1cڸ\xcc\r'\x91U)\xf5\xb0\xc4\x10\x9f]\x9f\xde:@A\x0ee\xb7\x95@\xed`\xbb\xd7\b\xf8\x03\x8b\xd6&\x96\tP\xb6d\x9a\x94\x86F\x19;M\xf7i\xd5\x05C\xe7(\xf5\xe3\f\xd3\x1c\xed,\xc9\xea\xbe\x05%\x1c\x89\xeap0R\xc8J\xa2\xdbF\xed\x88\xda\xf7ժ\xf5}'\x91\x02kf\xb0\x04%'g&vi\x05\x9a0WI\x9c\xd1롋~\xff\xe4\xf1\x80`k\x14`P`a\x95>Ff\x0eJ}\xcbQ\xac\x13\xa8Lhӱ\x04\xf4\x1b\x98\x01\t\x8e\xd3w\x15/*\xefa8\xf6$8P*4N\x9b\x90˼\x9f\xda$,\x91?L2\xa7=\xfa\xb6 V\x87\xf0R\x1a\xa5o\x19j\xb8oI\xd4\xf6\xba\xf7H\xb7\x84\xefV\xcdn\xfb\xff'b\xa319\x83ig\xe4\x1f\xc8\xfd\xcc\xe6\xe9I\xbe\xa5\b\x0f\xcd%\xdcl\x00\xeb\xc6\xee/\x80\xdb\xf8uI\x12\x98\x10\x839\xfe\xc0\xb49\x9d\xe93I\x93#\x13/D\x98n\x8a? ]\xc8d\xdc\a\x8b\x91M\x93\xbf\x0eG]\x00\xdftH//`ÅE}\x80\xfd\xb3T}\xa4\xccs #\xc7\xea\x01\xe5\tlQ}\xfc\xe1\\\x1c\xd3'\xc12\xf1r8\xd8\xfb\xc61\x82\x18\x9b\xe7\x05\xb8@\xf12\xd7XS\x1c\x0e\xdf\b\x9b\xfd\x17r\xaa?|\xf9\xf98V>l\x19\x9cw\xb4\x91\x05\xa1\xf3\xed\xc3\xc1\x8e\x86\xeb\vQA\xfc\x85|\xa0.\xa8\xf29\x97\v`\xf0\x80{\xef\xba0\t\x8e>,vΘ^#%\x7f\x88\xcf\x1epO`\xd2ٜ\xe3\x96\xcb\r\xbe=`\xc2\xf5O\xb5\x11\x0eݚBX\xec\xf1\xe4>\x10\"(\x86\xcfe\x03߂($r'閩Kb\x8b\xb8?c\x9bY\xac2\x9cc\x98\xfa$\x0e\xf8\xc9xZ:\x89\xa9x\xc8i\x1a$\x99\xc9%\xa8oߙ\xe0e7\x91\x97\x91\x1by\x01_\x94u\xffP\x80f\x88Q~Vh\xbe(K_^\x04\xa3~\xe1/\x89O?\x03\t\x9a\xf4Z\xde!l\x98\xf3\xf36\xcdq[\x87{n\xe0F\xbaxţ$s*J\xef\xfa\xe9\xfcDuk(]'\x95\\\x91\xcdL\xce\x14\xf0\xad\xf4\b\xddO\x9e4L\xf8\xcd\x19\v\xff\x8bO2\vV`\x19#K\xca~2\x8b[^d\xceW\xa3\xde\"4N\x85\xe7qD\xa6b\r\xbb9\x8d}\xf2\xacwlA\xf1\x96ˋY9\x81\xcb\xe8\x15ɸ\xd8u\"\xb39\xdduyGdE\xc9\xc5X\xc4.+K:\xc2b\xe2\xf6\x04\x8d~\x02-N\x15\xcd\xc1ڽ\t\xacY\xe3\xc4\U000bf765#n\xfe_h\x18\xd7\xe6\x12>\xd0I\x95\xc0\xd1o!\x0f6\x00\x931e\xe3\xa6r,\xf0Ȅ\xb3\xbdN\x81J@\xe1-\xb1\xda\x1c\xf9%\x17\xb0\xab\x94\xf1fs\xc3Q\xd0y\xc1\xdb\aܿ\xbdp\xd3/N9\x14\xf2\xb77\xf2\xad\xb7\xe1G\x02\xdb\x19|%\xc5\x1e\xde\xd2oo\x9f\xe2\xcad2[f\xb7\x1f\xab\x87.ö\xaaY\xb3\n\fjU=\xa34d2Y\u07b7\x11\xc7\fs\xe3}R<8\xb9s\xbb\xcdb\xd1F\x19\xfb9\x9d\xb7\x9bX\xcfm\x1c1\xf6L\x139\xaeE\x8f=\xe4\xb1:}뜸\x8dE\x1dry^\aG\xff\xff\x89\x91Q\xeaTd\xb8\xd8.\x19Ǻ\xfc\xaaC\xf0\x027\xf9\x83\x93\x9c%\x9e\xe20:\xbc\x9c\xe8m\x7f\xfc1\xc8':\xc9u\x7f\x0f7\xf2\xdc\x0em\xa1\xea\x9a\x1d\x9e*f-\xf5ڏ\x8c<\x1d\x00y\xea\xebmK\xf2\x9ck\x11{\x1e\xa2\xf3\xc3\x1d\xb7\x15\x97\xc0\xa2\xda@\x1d\x18\x8aA\xa3R9\xe4T\xab\x98\x815\xa2\xecR\xe4\xbf\aS^syC\x13\xc0\xfbg7\xfdУ\xeb%\x9d\xcd\xeb\x8e&\x1d\xe5\xbb\x0f\xded5\xaa\x84]\x85\x1aG\x8cq\x9c\xf7&OQ*;H\x19\x9c\xe0\x106\xaa\xfc\xc9\xc0\x86kc\x87K0К\\Z\x9fH>\xb7\xeeo\xbcF\xd5ڗD\xf0\xc7~\x9a\xd1Yo\xcd~\U0003ab41ժ\xf5\xc6\xdc\xf2\xba;U\r\xe8\xdd1n\xbbc#ʟX\xe5H\xd0\b\xb4\bkܤ\xcf[S\xadP\xd2\xf0\x12u\xac\x12\xf0d\xe3\xca\t\xe6\x86qѦNiR\xed\xd4\bT~\xd4\xfa\xac\x00\xf4\xab\x1f9\xc8\xfbUj7FP\xe6\xde\xe9 \v\x81o\x80[@Y8\x8c\xa3\xf6*\x99\xa6\b\xc8 \xd4\xf0\\=\x97\xa7\xc0]C\xd9\xd6y\bX\x91@r9\x9b\xf2\x1av\xffĸx\t\xb29\xce\xfb\xa4\xf4\x1d\xb2\xf2\x9c\x1c\xc9/\x83\xe1\x80Ҵ\x9a\x0e߽\xee\xd8q\x91\xb7fG9\x10\xac\x95E\x85\xa4\x84\xe4X7x\xf0\\\x1a\x8b,\x97\x17\x9cW\xd4J\xc9\xe56\x8fvىȾyT\xaf\x95\x12ȦO\x01\xfb\xe6p\xfd\n\x9a\xe8\x97~\x9a'j\xa2\x9e\b\xfeؚ\xe8\x90MQ\xa7\xb4\x80Y\xeb\xc2}\x129\x05\xba\x95C\xeb\xf2\x02\x8a\xe8\x94H:\xac\xe29Cd.y\x06mGt\xbd\x91\xdc\x0e\x9dG\a\xe2E\x9dG7A\xe7\x0e\x9c\x93\xe1\xba\x19\x01p\x02\x1a\xe3\x10Z{\xc75'8\x92k\x04V\x96X\xfaܡsEBX\xe2\v\xcf&\x8a\v\x92\xbb;\xdd\x13̢ll\xa3\xa0\x93\xf2\xa0\xfa\x11W\xad|\x90j'W\x14\x8c\x9b\x93uH\xae\xab\xf8\xcc\xd3۳\x95Ѳ~\xc9W\xd3KZh̯\xf9<\x15\xfd\xa7\x17\xd02\xd9|sR\xc2c\x8e\v\x96\xf4\x9a/\x80\x9e\xf8qq\x15s\xf3\xcf\f\x0e\x87\xc2\u05feX\xf9Iei7iP\x03\xa7pW\xa1\xadP\xc7\xd2\xe8\x15\x95\x84\x97\xb3'\x94}\xf0\xd2թ9\xa6\x8a.\xb2/\xbf<\xa8\\\xa3\xe8\xa6\x15\xe2\xc2\xf16kE2\x1c\xb6\x8aD옳\xb2\xea\xb7\xd2\x1eCN\xf5C6\x1e\x87\x95\x0e\xe3\xfa\xbe\xae\n!\x16\xf8\xa98s\xa0qj\xbfT\xd898_\x1f\x973P\xfe/.\xff7/\xfd˨T\xc8Gcn\x95d\x87\xc4\x04\xac\x04\x83\r\xd0\xd8\xd77\x84~\xa1\xd0\xf6\xf7\x85S\x8b\xf5\xd7&H̤\v\x9b\x81\xd6\x04\x9c\x83z\x0f\xb2\x06\xad\xf1\xae@g\aB\xceЍ\xffP\xf8[\b\x11L\x8a_\xbfU\x18\xc57T\xcfs\x03\x7f\x86J\xb5\x89\xaa\xba\x19\x94-TW,oxTh\x11\x0e\x14в\xc7\xf7\x97\xe3_\xac\ne\x17\x94EK\x00\xa2\xa0\xa8\xcf\xccrY\xf2G^\xb6LD\xa9\xedk\xf8=\x03\xf5|\x96\x80\xa64H.<\x03\xc6\xf1#\x86\x83\xaf\x8d?\x969Y\xc5\xcd\xfb\xa2y\xd5\x19g\xd7d\x8ck.&\xac\xe1\xa9\xc7\x17\xcfR\x85\xfa\x9b\xd4Z\x9c^a\x91\x13I,TS\x9cQC\x91Y\xac\xf5\xe4\xf3\x96\x9c*\x89Sb\xee\x17\xab\x88x\xfe:\x88,\xfc,\xd7<\x9c\x82\x9d\x17\xafoxŪ\x86שeȬ`x\xbeR\xc4\xe7\x88;\xa6\xeb\x11\x16\xab\x10\x9e\x14\x97d\xd4\x19\x9cR]\xb0\x88\xb1<\xd6\x7f\xb5\xfa\x81W\xab\x1ax\xddZ\x81Y\x96\x98\xfd\xf1\x94j\x80.v\xf9\x1bk\x1a.\xb7\xc7L\x91\xcb:\xb3l\xb3\xcc2_\x0e\x162\xe2\x99a\x88\xd1Gl\x13ᨿB\x9c\x88\xeeb*\x91K\xab.\xe1\x83\xdc\a\xb8\t8\x83\x90N*{t\xb9\xcb-kDž\x18\xde`\"\xb0\xf3\xa0\xc2=B\xc3j\xbf\xaa)\x0f\xa5\x88\xc7\xe1_T\x89\xb7Jۥ`\xe1\xf6\xb0\x7f\xe2\xb4q\x10@)Q\x82\x8c]\x13\xbb$\x97?\xb8\xfb\xe7m*}0\x18\xddۿ\xa9ҭm\xe9\x1c\xe2\xee\xa0\xfb\xd1}\xda\rj\x94\xfe)\x8a\xff\xbc\xff\xfa\xa5\x83\x9f\xf2A\x83\xa7z\xf0\x04\x82\xf7(ʀ\x9cp|\x15\n~<\xb6\xc8&?\xf3\xd9\x01k\xf8\x7f\xd0\xcbcOH\xcf|\xb8\xbd!\x18\xd1o\xa2\xa7̺J\x83\xeeTo\x8d\u0382t\xa8\x9a\x14\x8b\x9b\xcd\b\xe2\xb8*v\xf8\xd4\x0f\x96\xfeY\xa7h\xc1x\xac\x83r\x82w{\xe3\xd715\xcb'\xe7\xc4\xc9=(ϑ\x15\xd7\xe5\xaaa\xda\xee\x89m\xcc\xc5h\r\xd1b̥W&\x15\xeb\xf1SUI\xf4\xc6\x17\xaa\xe8\xbcnߌOD\x0fqw\xce:\xa6\xefh,\xde\xcex\xc6uL\x1b\xdf\x15a*\xf19Y\x84\xf1li\xab\xa0\x89n\xbf\x9f\x95\x06\xb9\xebF\xcf\xeb9\x17\xd5\xc6\xd4O\x02\x8c\x1bO\xaa\xceH֘*\xf1,\xd0\xd3t\x1d\xbd\x98e\x99m\x9f\xb2I\x0f`\xb4O^T\x03m\xb5è\xcf\xe2\xb6IZiXJ\xb7;\xdb\xeckC\xb8\xb8\x18D\xee\xafsl\x9a\xf9\xe4\xc8ُ\x8dx\xf4L\xa8\x1f\xcaF9\xd5v\x8c\xa93\x0eL\x17]\xbb\x8cB\xdcy\x7f4\xf3\xa9\x8a<\x83q\xc6\xf3\x14\x84\xaf\\\\A\xf2Պ̗)~SD\xcfh5STX\xb6\x02\xcf}\x97\xee~0~\xf9e\xba8[\xc6\xdbt\x0e\xd9\x03\x03\xed|\xe6\xf1\x1bx\x81\x12\x01\xf2\x90\x92S\x0e\x1f\x05\a\xfe\t\xac¿\x96X\x14h̦\x15\xb1\x92\xa7\xd0\xc8,\x96\xb1;7݊O\xaaEi\x1b\xa1X\x89\xfaZ\xc9\rO\x9cX\x8c\xd0\xfa_\xa3\xce\a<[\xd0\xc7V\xf7\xcf\x0f\xce>\xdd\xf6$\xcd\xd50̈́@\xf1\x89\v4?\xab\x9dt\xeb\xca\x10\xc8\xdbԸ\xc1ݥ\xa2\xd5ά\xefA\xb6\xf5\xda9\xb9h\xedt\xb0\xb8Qz\xbe\x8a\xd8\xe3\x9dK\x8b[L\x85\xca;\xcd-\xde7L\x1b\xa4\x15e\xec\xe0\x97\x83!>\xfa\xdc\b\xb6\xf5\xe5b%/\x98\xc5\xce\x00\xd3\fS˧\xf1\x86`\x89=U降$T\xb6PO][\x98\x14\xeb\xa9'0\x13\xa6:\xf9\b\xa6\xb7\xc8\x05k,]\x12!:\x12\x11m\x80A\x0f\xcb\x1e\xbc\x839\x02;\xcdi\xa1\xd47\x14\x95\x19\xcb\xeaD\x94\xb0\xacw\xae\x8f\xc1\xd0ӵ\xba\x1cԦ\r\x1f\x01\xec\x8a\xd0`\xc7LWp\x9c\xf4\xbd{\xd8\x1e\f\xb9\xea\x0e4\x96\x80\x8f(\xc1\x89\"\xe3\x02\xcb9N\xfdF\x89]\xfd\x88\xfa'\xd3\xc1\xa1j9\xc7\xe2\xf7\x96i\xdb-\xfd؏\xd9(]3{\x05%\xb3\xb8r\xa3\xcfs\xdd\xd2Oyj}\xe6\xf1\x1c\xdd\xfe\n\xe2Qī)\xce\xfa\xf9;[5\x1aö1\bݡFآtx\xefr}I\x8f)^{\vƢ+\xbft(d\x85mY\x98\xc0\xbbp\xddif|C\x97\xa2\xd8\xed\xa4\x8aN\xab\x8ap\xc1\xee\x0e\x999|\x92\xf9\b\x17\x9f\x86}C\xd2\xd6\xef؟U0_\x04I\x8f\xf2Z\xdeE\xd6)\x99\xb6\x8af>ɜTJ=d\xb9ٟ\xbb\x8e}:\x89K\xcfJt\xadp\xadZ;\xf0s\x02\xc2\x13ˤ'*\x9fپ\x10\xcc\x0f\xfe\x92\xd1T\x9a4\xcf\xd3\xfb<\x82ԅ\xb7\xca2\x11\x8d\x8c\xe3ˮC5s\xc9\xfe>>\xf0+\xc4\xfe\xe2\x10\xf2\xc1\xcb\xe1=\xec\xaa\x7fn2h\x82\xfe\x8a\xf5TZ5d\xfd\x92@\xba\x97*{\x9fd\xea]\xc0%\xfbGP?Ѣ2p\xfc\xb9\xef=\x85G\xbfL\xef0\xa3LG\x9a@\xc1\x87\xad:\xc98c\xe93^jS1\xb3\xe4\x9e\u07ba>\x9d\xdb10W\x9d\x13z7!\x95黠+\xf8\x82\xbb\xc4W\x8f,:\x8d\"\xa9Jt\xb9\x91\xb7Zm5\x9ac\xa6[ѝ?.\xb7\x9f\x94\xbe\x15\xed\x96˯\xd3\xd5\xd1s\x9do\x99\xb6\xdc1\xad_Ob\xecu\xb4q\x89ߖGO\xff\xc0%\x13\xfc\x1f)]>\xfcqi\x86\x19}\xd7\x04\xe4\x9dc\xa1\"\xe2\x97\x14`\xd0\xd0?\x99\x81\xf9\x89\xf3^\xc2\x17\x95\x14\xe3p`\xcb\xc7@\xb9\x815\x1a\xbb\xc2\xcdFi\xeb\xf3\xf7\xab\x15\xf0Mt\x90\x9c\x86\xa08ѿ\xb8\x0e<\x95x\xef\x8e¢ò\t\xa9DMV\x87BΚ\xed}F\x92\x15\x85\x8b\t\xf0\x9d\xb1,\x15\x9b\x9e\x1d\xbb~?\x80qpM\xd0E\xb1\xfd41\xde\xfcg\xbeIɋ\xff\x1f\x84\xd6\x02\xff\xe5\xe8\xd7W\xbe\xee\xb7cZr\xb9=\v#\xbf\x84\xb1\x89x>\x80}Ɉ>\xae\xfc\xd9b\xfa\xa4Y:\xfaH\f^\x0e\xf0\x1cf\n_\xfe/\x00\x00\xff\xff\xe5\x9d;'\xe7k\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xdc=]s\xdc8r\xef\xfe\x15]\xce\xc3\xdeUi\xe4\xdb\xca=\xa4\xf4\xe6\xc8vV\xb9[[%9\xdeg\f\xd93\xc4\t\x04\xb8\x00\xa8\xf1\\\x92\xff\x9eB\x03\xe0\xc7\fHbF\x1f\xbb\x1b\xbc\xa8\x86$\x1a@\xa3\xbf\xbb\x01\xadV\xab7\xac\xe1\xdfP\x1b\xae\xe4\x15\xb0\x86\xe3w\x8b\xd2\xfd2\x97\x0f\xfff.\xb9z\xf7\xf8\xe3\x9b\a.\xcb+\xb8n\x8dU\xf5\x1d\x1a\xd5\xea\x02?\xe0\x86Kn\xb9\x92oj\xb4\xacd\x96]\xbd\x01`R*\xcb\xdcc\xe3~\x02\x14JZ\xad\x84@\xbdڢ\xbc|h\u05f8n\xb9(Q\x13\xf08\xf4\xe3_.\x7f\xfc\xeb\xe5_\xde\x00HV\xe3\x15h4Vi4\x97\x8f(P\xabK\xaeޘ\x06\v\as\xabU\xdb\\A\xff\xc2\xf7\t\xe3\xf9\xb9\xde\xf9\xee\xf4Dpc\xff6|\xfawn,\xbdiD\xab\x99\xe8\a\xa3\x87\x86\xcbm+\x98\xee\x1e\xbf\x010\x85j\xf0\n>\xbba\x1aV`\xf9\x06 L\x9d\x86]\x85Y?\xfe\xe8A\x14\x15\xd6\xcc\xcf\a@5(\xdf\xdf\xde|\xfb\xd7\xfb\xd1c\x80\x12M\xa1yc\t\x01\xff\xb3\xea\x9eC\x9c(p\x03\f\xbe\xd1B\xddl\b\xf1`+fAc\xa3Ѡ\xb4\x06l\x85\xc0\x9aF\xf0\x82\xf0\x0ej3\x80\x14{\x19\xd8hU\xf7\xd0֬xh\x1b\xb0\n\x18X\xa6\xb7h\xe1o\xed\x1a\xb5D\x8b\x06\n\xd1\x1a\x8b\xfa\xb2\x03\xd4hՠ\xb6n\x8e\x8c\x0eww\x12\xd14En\xd8Z`y\xfb\xed\x0e\x1b\xad\x1e\xb9\x13@\\n\xef\xad\xd2l\x8bׂ\x19s\xbc蜥}Ȃ\x1c\xd8L\xf0\x82\x96{\xf0\x92\x94\xda\xf1z\x00n\xbf\xc1\x8e\xdbJ\xb5\x16\x8cd\x8d5\x95\xb2NdA\xc5\x1e\x1dw*\x19\xb1gp\x04\x14v\\\b𬒀\xabq\xd5\xcd\xd5\xc9\xe1?\xe1#J\xd8U(\xe1\x0e\v\xc1x}\xab\x04/\xf6n\xda\x1fP\xa0\xc5?\x1fO\x8f[\xac\x13(\x9b\xdd\a\x00\xd9\n\xe1\x10v\x05V\xb7\xc7s\xf3}\x99\xd6l\x7f\xf0\x0e\xbf\x17\xa2-\xb1\xecT\xf3Y\xdb\xf5\xf1\b\n\xd9-\x8cK\xb7A\u0380p\b\x95\xfd[\xd2\xc1L\xa3Cf\x02\x1e\x97\x1e\x1epID\x9cd\xab\xdf\x10[ш{\x12\xb2: \ad\xdc\xe9\x04\xc2\xd7\x1f\x17U\xdc8]\x17W\xe9I\x7f\x01_\x1f\x93\x9d\xa2\xc0\r\xe27\xac\x10\xd6\xe8\xf8U\xe9\x94$S\x9a>\x1d\x98d\xbd\xa6UN\xd1\x05 \x87fJ悓Ȫ\x94zX\"\x88\x9f\xdc7\xbd\x82\x87\x82|\x82n)a\xb7\x83\xf9\xb5F\xc0\xefX\xb461M\x80\xb2%\xebBih\x94\xb1\xd3\xfb>\xad}`hߦ^\xce\x10\xcd\xd1ʒ\xa4\xee[УqS\x1d\x0eF:\x95䭆\xdamj\xff\xadV\xad\xffv\x12)\xb0f\x06KPrrd\"\x97V\xa0\tc\x95D\x19\xbd\x1c\xba\xe8\xd7OF+\b\xb6F\x01\x06\x05\x16V\xe9\x94\xf2XF\xa9o9\x82u\x02\x95\ti:\xe6\x80~\x013 \xc1Q\xfa\xae\xe2E\xe5\x8dDG\x9e\x04\aJ崣\xd3yM#\xf6S\x8b\x84\xa5\xed\x0f\x83\xccI\x8f\xbe-\xb0\xd5!\xbc\x94D\xe9[\x86\x18\xee[\x12\xb5\xbd\xec=\x92-\xe1\xb9U\xb3\xcb\xfe\xff\x89بL\xce \xda\x19\xfe\a\xf2 \xb2iz\x92n\xc9IGs\t7\x1b\xc0\xba\xb1\xfb\v\xe06>]\xe2\x04\xe6,\xb7n\x8c?\xf0ޜN\xf4\x99[\x93\xc3\x13/\xb41\xdd\x10\x7f\xc0}!\x95q\x1f4F\xf6\x9e\xfc}\xd8\xeb\x02\xf8\xa6Czy\x01\x1b.,\xea\x03\xec\x9f%\xea\xe3\xce<\a2r\xb4\x1eP\xa8\xc7\x16\xd5\xc7\xef\xce\xc41}\x1c3\x13/\x87\x9d\xbdm\x1c=\x88\xb1z^\x80\v\x14\xf2\xe0\x1ak\n\xa5\xc0W\xc2f\xff\x84\x8c\xea\xf7\x9f?\x1c\x87;\x0e[\x06\xe5\x1d-d\x81\xe9|{\x7f\xb0\xa2\xe1\xfc\x82W\x10ߐ\r\xd49U>lv\x01\f\x1ep\xefM\x17&\xc1\xed\x0f\x8b\x1fg\f\xaf\x91\xe2wDg\x0f\xb8'0\xe9\x80\xdcq˥\x06\xdf\x1e0a\xfa\xa7\xda\b\x87nN!\xb2\xe1\xf1\xe4\x1e\x10\"(\f\x93K\x06\xbe\x05VH\x84\xbf\xd2-S\x96\xc4\x16q\x7f\xc62\xb3He8\xc60zM\x14\xf0\x83\xf1{\xe98\xa6\xe2!,m\x90x&wC}\xfb\xc6\x04/\xbb\x81<\x8f\xdc\xc8\v\xf8\xac\xac\xfbC\x0e\x9a!B\xf9\xa0\xd0|V\x96\x9e\xbc\bF\xfd\xc4_\x12\x9f~\x04b4饼C\xd80l\xebu\x9a\xa3\xb6\x0e\xf7\xdc\xc0\x8dt\xfe\x8aGI\xe6P\x14\xa1\xf7\xc3\xf9\x81\xea\xd6P\xc4U*\xb9\"\x9d\x99\x1c)\xe0[\xe9\x11\xba\x9f\xb7\xb1\xc7\xd82Mĸ\x16-\xf6\x10\xc7\xea\xe4\xad3\xe26\x16u\x88\xe5y\x19\x1c\xed\xff'zF\xa9\xc4\xd6p\xb2]0\x8eu\xf1U\x87\xe0\x05j\U000b9bdc)\x9eb0:\xbc\x9chm\x7f\xfc>\x88':\xceu\xbf\x87\vyn\x83\xb6Pu\xcd\x0e\x13\xc3YS\xbd\xf6=#M\a@~\xf7\xf5\xb6%~\xceՈ=\rQ\nx\xc7m\xc5%\xb0(6P\a\x82bШT\f9\xd5*f`\x8d(\xbb\x10\xf9\xefA\x95\xd7\\\xde\xd0\x00\xf0㳫~\xe8\xd1\xf5\x92\xc6\xe6u\xb7'\xdd\xcew\x0f\xbc\xcajT\t\xbb\n5\x8e\b\xe38\xeeM\x96\xa2Tv\x1028\xc1 lT\xf9\x83\x81\r\xd7\xc6\x0e\xa7`\xa05\xb9{}\xe2\xf6\xb9y\x7f\xe55\xaa־$\x82?\xf6Ì\xd2\xf55\xfb\xce\xeb\xb6\x06V\xab\xd6+s\xcb\xeb.1\x1eлc\xdcvi#\x8a\x9fX嶠\x11h\x11ָI\xa7\xccS\xadP\xd2\xf0\x12u,\xf4\xf0\xdbƕc\xcc\r\xe3\xa2MeiR\xedT\x0fT~\xd4\xfa,\a\xf4\x8b\xef9\x88\xfbUj7FP\xe6\xda)\x91\x85\xc07\xc0-\xa0,\x1c\xc6Q{\x91LC\x04d\x10jx\xae\x9c\xcb\x13\u0ba1l\xeb<\x04\xac\x88!\xb9\x9c\ry\r?\xffĸx\x89ms\x94\xf7I\xe9;d\xe591\x92_\x06\xdd\x01\xa5i5%߽\xec\xd8q\x917g\xb7s X+\x8b\nK_\xb20\x92\r\x1e<\x97\xc6\"˥\x05g\x15\xb5Rr\xb9\xcdۻ\xec@d\xdf<\xaa\xd7J\td\xd3Y\xc0\xbe9\\\xbf\x82$\xfa\xa5\x1f扒\xa8\xdf\x04\x9f\xb6\xa6}\xc8\xdeQ'\xb4\x80Y\xeb\xdc}b9\x05\xba\x95C\xed\xf2\x02\x82\xe8\x14O:\xcc\xe29]d.y\xc6ގ\xf6\xf5Fr;4\x1e\x1d\x88\x175\x1e\xdd\x00\x9d9pN\x84\xebf\x04\xc01h\xf4Ch\xee\x1d՜`H\xae\x11XYb\xe9c\x87\xce\x14\tn\x89\xaf\x1d\x9c(.H\xae\xeetK0kgc\x1b9\x9d\x14\aՏ\xb8j\xe5\x83T;\xb9\"gܜ,CrM\xc5g\x1eޞ-\x8c\x96\xe5K\xbe\x98^\x92Bczͧ\xa9h?\xbd\x80\x94ɦ\x9b\x93\x02\x1esT\xb0$\xd7|\r\xfb\xc4\xcb\xc5Y̍?\xd39$\x85\xaf}\xbd\xf9\x93\xca\xd2nҠ\x06F\xe1\xaeB[\xa1\x8e\xd5\xed+\xaa\xea/g3\x94\xbd\xf3\xd2թ9\xa2\x8a&\xb2\xaf\xa0=\xa8\\#\xef\xa6\x15\xe2\xc2\xd16kE\xd2\x1d\xb6\x8aX옲\xb2\xea\xb7\xd2\x16CN\xf5C6\x1e\x87\x95\x0e\xe3\xfa\xbe\xae\n!\x16\xf8\xa98r\xd8\xe3\xd4z\xa96w\x90_\x1f\x973P\xfc/N\xff7/\xfd˨T\xc8Gcn\x95d\x87\xc4\x04\xac\x04\x81\r\xd0\xd8\xd77\x84\xefB\xad\xf4\xef\v\xa7\x16\xeb/M\xe0\x98I\x136\x03\xad\t8\a\xf5\x1e\xa4\rZ\xe3M\x81N\x0f\x84\x98\xa1\xeb\xff\xbe\xf0\aI\"\x98\x14\xbd~\xad0\xb2o8\x00\xc1\r\xfc\x15*\xd5&\xaa\xeafP\xb6P]\xb1\xbc\xe0Q\xa1EH(\xa0e\x8f?^\x8e\xdfX\x15\xca.(\x8a\x96\x00DNQ\x1f\x99\xe5\xb2䏼l\x99\x88\\\xdb\x1f\xc3\xf0\x04\xd4\xd3Y\x02\x9a\xd2 \xb9\xf0\x04\x18\xfb\x8f\b\x0e\xbe4>-s\xb2\x88\x9b\xb7E\xf3\xaa3ή\xc9\x18\xd7\\Lh\xc3S\xd3\x17\xcfR\x85\xfa\x9b\xd4Z\x9c^a\x91\xe3I,TS\x9cQC\x91Y\xac\xf5\xe4|KN\x95\xc4)>\xf7\x8bUD<\x7f\x1dD\x16~\x96k\x1eN\xc1\u038b\xd77\xbcbU\xc3\xeb\xd42dV0<_)\xe2s\xf8\x1d\xd3\xf5\b\x8bU\bO\xf2K2\xea\fN\xa9.X\xc4X\x1e\xe9\xbfZ\xfd\xc0\xabU\r\xbcn\xad\xc0,I̾<\xa5\x1a\xa0\xf3]~fM\xc3\xe5\xf6\x98(rIg\x96l\x96I\xe6\xf3\xc1DF43t1z\x8fm\xc2\x1d\xf5\xa7\xc0\x13\xde]\f%ri\xd5%\xbc\x97\xfb\x007\x01g\xe0\xd2Ie\x8f\x0ew\xb9i\xd1\x19\xc4\xc1\t&\x02;\x0f*\x1c\x055\xac\xf6\xb3\x9a\xb2\xc0\x93\xfb\xaa\xf4\xc8P>˙\xfbr\x00c\x18\xb1|Mk\xbcn\x85\xe5\x8d@\xa0s\x9ae\xf2\\\x95\xadp\xdf!\xf9\x1f\x8aN\r\xad\xf7\x04\xe9\xcb]Nj\x97\a\x8e\x053\xb0C!\x80\xa5\xa8\xe3h\xf9\x85?p]\xa8\x15\x1d\x93s\xdb\x1b\x89$\x1cӾ\xf0\\\xdc\x1fE\xad\x13p\v&\xe9жI,dRE\xe5H\xd1#[\xd9[\xfc\xf4\xec\xd7\x16\xf5\x1e\xd4#\x95\x15\x04\x8b\xaa\xaf\xdf\x0f\xe2\xc68\xbf/\n\xc0 \x8c\xa7\x02\xfdG\xeeE/\xa0\xe0\xbd\xf4\xfa\xfdp>\xd4\xc7I\xbe\xde}r\xe2\xdcyF\xc91&\xbaK\xd5\xf5Nt[2\xc5s\v\xdd_֙:ݝZ\xb4_\xf2m\xccߨ\x80\xfd\x9c\xc2\xf5\xbc\x14\xcdb\xa1\xfaK9WK\xeeU\xb6E\x99W\x88~Zb\xf3\x05\v\xcf_\xa2\xe0<\x13S9\x05\xe6\xa7\xe1\xe9\x15\n\xca_\xb5\x90\xfc\xb5\nȳ\vdzr\x8bى\xa4\x9c\xd4\xdfr:{\xbe <\xa3\x10<#E\xb54ӌ\x82\xef\xd3\n\xbd3p\x98\xcb\x1a\xafX\xd0\xfd\x8a\x85ܯ]\xc0\xbd@$\v\xafO+\xd4>;K\x11\xd3\xe1\x9fU\x89\xb7J\xdb%g\xe1\xf6\xf0\xfbD\xb6q\xe0@)Q\x82\x8c\x9f&VI&\x7f0\xf7\xcf[T:1\x18\xcd۟U\xe9涔\x87\xb8;\xf8\xfc\xe8<\xed\x065J\x7f\x15\xc5\x7f\xde\x7f\xf9\xdc\xc1O٠\xc1R=\xb8\x02\xc1[\x14e@NH_\x85\x82\x1f\x8f-\xd2\xc9Ϝ;`\r\xff\x0f\xba<\xee\t\xe1\x99\xf7\xb77\x04#\xdaMt\x1b]Wi\xd0e\xf5\xd6\xe84H\x87\xaaI\xb6\xb8ٌ \x8e\xabb\x87\xb75a\xe9o\xe6\x8a\x1a\x8c\xc7:(\xc7x\xb77~\x1eS\xa3|rF\x9c܃\xf2\x14Yq]\xae\x1a\xa6\xed\x9e\xc8\xc6\\\x8c\xe6\x105\xc6\\xeR\xb0\x1e\xdf6\x96Do\xbcd\x8c\xf2u\xfbf\x9c\x11=\xc4\xdd9\xf3\x98>\xa3\xb1x:\xe3\x19\xe71\xad|W\x84\xa9\xc4\xe3d\x11Ƴ\x85\xad\x82$\xba\xfdvV\x18\xe4\xae\xeb=/\xe7\x9cW\x1bC?\t0\xae?\x89:#Yc\xaaĵ@O\x93ut\xe9\x99e\xb6}\xca\"=\x80\xd1:yQ\r\xa4\xd5\x0e\xa3<\x8b\xcb&n\xa5n)\xd9\xeet\xb3\xaf\r\xe1\xe2b\u0e7fN\xda4\xf3ʑ\xb3/\x1b\xf1\xe8\x99\x10?ݵcǘ:#a\xbah\xdae\x14\xe2\xceۣ\x99WU\xe4)\x8c3\xae\xa7 |\xe5\xe2\n\x92\xb7Vd\xdeL\xf1\x9b\"zF\xaa\x99\xa2²\x15x\xeeՂ\xf7\x83\xfe˗\v\xc6\xd12\xae\x17t\xc8\x1e(hg3\x8f\xaf1\f;\x11 \x0fwr\xca\xe0#\xe7\xc0_\x81U\xf8\v/\x8b\x02\x8dٴ\"V\xf2\x14\x1a\x99\xc52~\xceM7\xe3\x93jQ\xdaF(V\xa2\xbeVr\xc3\x13\x19\x8b\x11Z\xffk\xf4\xf1\x01\xcd\x16\xf4\xb0\xd5\xfd\r\x92\xb3W\xb7=Ir5L3!P|\xe2\x02\xcd\a\xb5\x93n^\x19\fy\x9b\xea78\xbbT\xb4ک\xf5=ȶ^;#\x17\xad\x9dv\x167J\xcfW\x11{\xbcsiq\x8b)Wy\xa7\xb9\xc5\xfb\x86i\x834\xa3\x8c\x15\xfcr\xd0\xc5{\x9f\x1b\xc1\xb6\xbe\\\xac\xe4\x05\xb3\xd8)`\x1aaj\xfa\xd4\xdf\x10,\xb1\xa7\xea\x1d5\x11\x84\xcaf\xea\xa9c\v\x93l=u\x8biBU'\xef1\xf5\x1a\xb9`\x8d\xa5C\"\xb4\x8f\xb4\x896\xc0\xa0\xbb\x81\x0f\xae2\x1d\x81\x9d\xa6\xb4P\xea\x1b\x8aʌeu\xc2KX\x96;\xd7\xc7`\xe8\xf6a]\x0ejӆ\x97\x00vEh\xb0c\xa6+8N\xda\xde=l\x0f\x86Lu\a\x1aK\xa0\x9b:\x1d+2.\xb0\x9c\xa3ԯ\x14\xd8Տ\xa8\x7f0\x1d\x1c\xaa\x96s$~o\x99\xb6\xddԏ혍\xd25\xb3WP2\x8b+\xd7\xfb<\xd3-)\x9e\xe8\x80\xd5y7RRO\xcf\x1eE<\x9aⴟ?\xb3U\xa31l\x1b\x9d\xd0\x1dj\x84-J\x87\xf7.֗\xb4\x98ⱷ\xa0,\xba\xf2K\x87BVؖ\x85\x01\xbc\t\xd7e3\xe35\xc8\xc6\u07fc:%\xa2Ӣ\"\x1c\xb0\xbbCf\x0eo\xd5>\xc2ŧ\xe1\xb7!h\xebW\xecs\x15\xcc\x17Aҽʖw\x9eu\x8a\xa7\xad\xa2\x91OR'\x95R\x0fYf\xf6O݇}8\x89KOJt\xacp\xadZ;\xb0s\x02\xc2\x13Ӥ+*\x9fY\xbf\x10\xcc\xf7\xfe\x90\xd1T\x984\xcf\xd2\xfbi\x04\xa9so\x95e\"*\x19G\x97\xdd\a\xd5\xcc!\xfb\xfbxG\xb3\x10\xfb\x8bC\xc8\a\x97\xbf\xf7\xb0\xab\xfe\xba\xc9 \t\xfa#\xd6Sa\xd5\x10\xf5K\x02\xe9n\xaa\xecm\x92\xa9{\x01\x97\xf4\x1fA\xfdD\x93\xca\xc0\xf1O\xfd\xd7Sx\xf4\xd3\xf4\x063ʴ\xa7\t\xe4|ت\xe3\x8c3\xa6>c\xa56\x153K\xe6\xe9\xad\xfb\xa63;\x06\xea\xaa3B\xef&\xb82}\x16t\x05\x9fq\x97x\xea\x91E\xd9(\xe2\xaa\xc4'7\xf2V\xab\xadFsLt+:\xf3\xc7\xe5\xf6\x93ҷ\xa2\xddr\xf9e\xba:z\xee\xe3[\xa6-wD\xeb\xe7\x93\xe8{\x1du\\\xe2\xddr\xef\xe9\x17\\2\xc1\xff\x99\x92\xe5×K#\xccȻ& \xef\x1c\r\x15\x11\xbf$\x00\x83\x84\xfe\xc1\f\xd4O\x1c\xf7\x12>\xab$\x1b\x87\x84-\x1f\x03\xe5\x06\xd6h\xec\n7\x1b\xa5\xad\x8f߯V\xc07\xd1@r\x12\x82\xfcD\x7fi>\xf0T\xe0\xbdK\x85E\x83e\x13B\x89\x9a\xb4\x0e\xb9\x9c5\xdb\xfb\x88$+\n\xe7\x13\xe0;cY\xca7y\x92\x9c&W5\xf0J\x8e\b\xb9\x19~\xdf\xc5\xf8:\xf1A\xe0<\xea\xe8ȷW\xe8b*\x116\xbaQ\x02\x8c\xc3\xde9\xc2\x04\xbc\x18\xbb\x99v\xbb\xf3T\xcd\xd7\x0eʔx\f\xeb\x1b]\x16\x1d\x12\x9e\xe1#\xb7mE\xc5\xe4v\xf2\xd0W\xa5U\xbb\xad\"mN\x19DP\xb6\xe497$\nL\xfc\xff$\xb6\xd5r\x90\xb4\v5\x0fSR\xba\x9b\ued0d\xf2\x04A\xad\xfb\xc3\x1f\xbd\xa8\x9a\xd1\xf9\xd9Q\xc2\t\x88\x8b\xba?\x01\x91\x99\xbd,f\x8f\xa9\x04G\x9bϜg\x9d\xc3P\x12\t\x9d4~6$t\x10\xa7\x900\xb4%z\x8f\xe7w\x83\x91)\x1b\xe5Lt\xcc\x1b1\xb4\xc4yPˋ\x1e\x1aAcs\xe74t\x98\x91\xf3wV\xd8m\x04\xe1\x14ϗ\xc6N\xfb\xbd\xbf_\x8f\xf5\xb1\xb3\xb6>\x9e\xed\xbb~;\x80qpL\xd0y\xb1\xfd0\xd1\xdf\xfc\x13ߤ\xf8\xc5\xff\x13\xa8\xb5\xc0?\x1f\xbd}\xe5\xe3~;\xa6%\x97۳0\xf2K\xe8\x9b\xf0\xe7\x03ؗ\xf4\xe8\xe3̟ͧO\xaa\xa5\xa3\x87D\xe0\xe5\x00\xcfa\xa4\xf0\xe4\xff\x02\x00\x00\xff\xffl\xa8\xb5\x03\xaam\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec=]s\x1c)\x92\xef\xfa\x15\x84\xeea?B\xdd\x1e\xc7\xedÅ\xde|\xb2\xe7\xae\xe3\xfe\x87Y\n\xf5f\xf7\xf6\xe2Q\xc8\xfc\x9a\xdd\xd4ƪ\xf23\x18U\xeb\f\xde\xc3FHa\x85\x92\x17%X\x9es˯/\x18\xe3R*\xcb\xf1\xb3\xc1?\x19˔\xb4Z\x15\x05\xe8\xc5\x03\xc8\xe5c\xbd\x86u-\x8a\x1c4\x01\x0f]\xef~X\xbe\xfd\xcb\xf2\x87\v\xc6$/ᚙl\vy]\x80Y\xee\xa0\x00\xad\x96B]\x98\n2\x04\xfa\xa0U]]\xb3\xf6\a\xd7\xc8w落\xf3\xed\xe9S!\x8c\xfd\x9f\xde\xe7\x8f\xc2X\xfa\xa9*j͋N\x7f\xf4\xd5\b\xf9P\x17\\\xb7\xdf/\x183\x99\xaa\xe0\x9a\xfd\x8c]U<\x83\xfc\x821\x8f?u\xbd`<ω\"\xbc\xb8\xd5BZ\xd07\xaa\xa8\xcb@\x89\x05\xcb\xc1dZT\x96F|g\xb9\xad\rS\x1bf\xb7\xd0\xed\a˯F\xc9[n\xb7\xd7li\xa8\u07b2\xdar\x13~u$r\x00\xfc'\xbbG܌\xd5B>\x8c\xf5\xf6\x8e\xddh%\x19|\xad4\x18D\x99\xe5\xc4@\xf9\xc0\x9e\xb6 \x99ULגP\xf9O\x9e=\xd6\xd5\b\"\x15d\xcb\x01\x9e\x1e\x93\xfe\xc7)\\\xee\xb7\xc0\nn,\xb3\xa2\x04\xc6}\x87\xec\x89\x1b\xc2a\xa34\xb3[a\xa6i\x82@z\xd8:t>\x0e?;\x84rn\xc1\xa3\xd3\x01\x15\x84w\x99i \xb9\xbd\x17%\x18\xcb\xcb>\xccw\x0f\x90\x00\x8cHT\xf1ڐp\xb4\xado\xbb\x9f\x1c\x80\xb5R\x05py\xd1Vڽu\xb2\x97m\xa1\xe4\u05fe\xb2\xaa@\xbe\xbb]}\xf9\xf7\xbb\xdeg֧\xe8\xff-\x9a\xef\xac\xe1\x06\x13\x86q\xf6\x85f\t\xd3~\xda2\xbb\xe5\x96i@1\x00i\xb1F\xa5a\x11H\x9d3\xa5;\xa0*\xd0B\xe5\"\v,\xa2\xc6f\xab\xea\"gk@n-\x9bڕV\x15h+\xc2Y-;\xf0\xa8\x81\x19\xe2\xf1\x93\xd2\xc0\x84ܨk\xb6\xb5\xb62\xd7o\xde<\b\x1b\x94n\xa6ʲ\x96\xc2\xeeߐ\xfe\x14\xeb\xda*m\xde䰃\xe2\x8d\x11\x0f\v\xae\xb3\xad\xb0\x90\xd9Z\xc3\x1b^\x89\x05\rD\x92\xe2]\x96\xf9\xbf\x05~\x9b^\xb7\a3\xd3\x15R\x993\u0603\xba\xd4I\x97\x03\xe5\x86\xd8r\x01?!\xe9>\x7f\xb8\xbb\xefJ\x9e0\x9e)\x1d\x01\x8c\xf1\a\xa9)\xe4\x06\xbc.\xd8hU\x12L\x90y\xa5\x84\xb4\xf4GV\b\x90\x96\x99z]\n\x8bb\xf0[\r\xc6\"\xeb\x86`o\xc80\xa1\xd0\xd6\x15\xce\xdd|Xa%\xd9\r/\xa1\xb8\xe1\x06^\x99W\xc8\x15\xb3@&$q\xabkn\x87\x95\x1dy;?\x04\x9b\x19am\xd0\x15w\x15d\xbd\xa9\x86\xed\xc4FdnB\xa1JnT\xc9@-\xbb2>\xfb\xe9\x17\xd2}ï\x03<\x9c\x82\f\xbd\x82A\xa3d\xb7\xc4\xfc\xd66\xa2\xc89hLi&\x95=\x80y\xa8Z;\x94\xf0P&09\x10vv\xa0RS,\xe9\b\x90ֶ\x0e\xe5+\xcaj\xc2\xfbQT\xab\xb2\x84\\p\v\xc5\xfe$\xf4\xfb \xc6Ȭ\xa8\x1f\xb6vz^lzD\xcfk`\xa2Ӟ&\xe3_C\x8dCk\xfcW\xb2\xecdD\x1dM\xba\xc0j\xd9\xf2pЏ\x84\xa7C\xd20\xb6\xda0\xabQ\xe7z\xec\x9eDQ\xe0LF\x8c+\xc8{\xa8Ż\x13\x1b&l\x18͚\x13\x06\x92-\x9d\x17\xb5l}\x86\xc6\xfe#\x82\x03\xecH\xed\xbb\xfe\xd1S\xe1\x96I\xf8j\xdbZ8\xec\xc8\b6\xbc0\x83!x\x854k\x18Wl]\xdb\xd30\x80\xb2\xb2\xfb+\xd7v\xa3\x8aB=1C\xca\x16\x8d\xe0F<\xd4\xdaM\xf6?\xe6\xb0\xe1ua\xaf\x1d\xce\x7f\x8aI\xeb\xf84\xb3PVh2O\x91\xd3{\xdf\x16\a\x8c\xb3%ob\x8c\xe0&\a?Dy\xf7c\x04\x88r^l\xa5\xd5N\xe4ޜ\x1f\xa8+vTeaɌ\xb8\x93\xbc2[eQ\"Tm\xc7j\xa5\x8c\n\xcb\xcd\xddj\x00\xad3\t\x11]r\x85IN\xadbO\\Xҹ7w+\xf6\x05c\b\b\xad\x99\x9bl\xcc\xd6Z\xa2\x9d\x8b\xf4\xf7\x19x\xbe\xbfW\xbf\x18`yM&:\xb8\xb7Wl\r\x1b\xb4g\x1a\x10\x06\xfe\x04Z\xa3~7\x84\x84\xaa\x0f\\\xa6\x86=\x8e%(\x1b\xde\xe2\v\xc3\xde\xfe\xc0J!k;*uG\x15\x1bQ\x8f[^\xaa\x1d\xe8\xe7\x10\xf7=\xb7\xfc'\x042\xa0)\x02g\x04\xdd\v\f\xd1w\xbd\xa7\x1f\xd7\x11M\xec\xcajӁ*\f\xbb\xbcDmp\xe9B\xce\xcb+\a\xa1\x16\x85]\b\xd9\xed'\xa8&\xec\xe94\x828\xfa:\xa6\x9b{\xf5\xa3q\"\xff,\xfaD`\x8e\u0601J\xe5lG\xf5\xd8F\x14\xc0\xcc\xdeX(\x83\xd6j=\xffN83,\xe4+\x14\x85\ac\x90\xde~P\xe3\x04\x91uQ\xf0u\x01פ\xe4\x8f\xd0l\\ߌ\x11\xed3\x18+\xb2s\x92\xccA\x1c!\x98\xf6?\xf4(C\xa1\x03\x7f\x04\xc6#\xe0==1N)\x8a\x0e\xd1\xfbԺ\x88\"Wi\xc8Љ\xbd\xf6α\x80\x82\x1cr\xa9X\xa1\xe4\x03h\x87Fc\xacPY\x02Jh\xce\xd0\xef\xd4hb\x84d\x9b\x1a]\xd2%C5\x11\x15\x12!\x8d\x05\x1e\x91\xe630\x0f\xbefE\x9dC~S\xd4Ƃ\xbe\xcbT\x05yXe\x1aUͩL\xfcp\x14\xb2\x0f`\n\x91\x012\"s\x95\x16\xb4\xca\x13\x93\xed6\x96\xd9W\xe0\x16\x9d\x90\xd7~\bm\x902\xa9\\\fXlx\xf9\xe7\xcb+\x12\x81~\xef\xfd~\f\xe3\x1a\x1a2\xcdR\xced\xf2\xc7[\b\ve\x84\xba\x93Jj\x06߹\xd6|\x7f\x84\xeb\xcdj\xda\v\xf0=\x06{\xc0y\x19\xaa}#\xde\x0f\xfb\xffW\xe4\xfey\xf9mhՙ\v\x89|.\x84\xb1=6\x1b\xb7\x8c\x85d\x1d\x8b!=\x81\xa4\x83\x89jr\x8a\xab\xff \xc4<\xeb܉M\x96F6\xfd\x04\xf8\xa7\xa2\xe4V\xa9\xc7\x14\xea\xfd7\xd6kװXF;#l\r[\xbe\x13J\x9b\xe1:)|\x85\xac\xb6Q\xcd\xc2-\xcb\xc5f\x03\x1aa\xd1:\x7f\xb3-p\x8cX\xc7\xe3\x17\xd6QY\xd1\n\x83q\xb5LG\x96\x125bC\xa1\b5\n\xd5y8\x18[\x90\x03\x91\x8b\x9d\xc8k^\x90/\xc1e\xe6\xc6\xc7\x1b\xfcbZmB \x0e\xf0\x8fJ\xb5+Ρ\t\x83D&\xf6\x96\xbd\x94\x04t\xf2K\f\x8e\x0e\xab\xc6)\x11\xd6\x12\x8e\xf6\x8d\xcc\xd4u\x01\xc6w\x97\x93\x9f\xdc꤫\x96Yn\x91\xa1\xe0k(\x98\x81\x022\xabt\x9cB)r\xe0J\xaaҍ\x10wD\xcb\xf6ív0\x13`\x19Ÿ[\x91m\x9d\xfb\x8a\x82F\xb0X\xae\xc0в\b\xaf\xaa\"b\xba\xda2)\x1c\xbe\xb3)\xbdі\x04\r2\x84\x1b\xd3%mI\xd4\xcfm\x19%{;7\xfbT\x1f_\xe8\x1f\xc5\xf7_\x89\xe8\xc1\xea\x9c(\xec\x13\x9a\x84цA\xf2|\x88\x92\x1e).\xc0,;\xcbs\u0086\xaf)\f\xed\xf9\x8f\a{)\aD\xf9}\xf1\xee\xb4\t3\x83u\x93s\xeae\x19\xd7t\xf3O\xc272Yw\xdeb\xcd\xe2\xd9\xc7n\xcb+\xda\x16\xf0\fɯ\xd8F\x14\x16ȩ\x9aB\x94\xcd\xe0\xdc9\t\x94j\x81\x19\xed\x12\xdbl\xfb\xa1\xd9cyN\x9c\x1bH\xba\xe5;\xf0)\xa3 3UKZ\x82B=\x80\xdd̀\xe8X\xe3\xac@\xa2\xbd\xeb4\x96u\x99N\x90\x05I\x92\x90\x93\xebU\xdd&?r\x91\xb6^\xc4Nc\xab=\x96<9VN\x9fG!\xb3\xb2\x9b\xc7^\U000af8acK\xc6K\xe4!\xb9\x1d\xa2\x84&\x95ݱ\xbbɷ\xc4\x16d\xb4\xac\xc2YV\x15`\xc1\xe7K\xce\xc0#S҈\x1c\x1a\xd3\xefE@I\xc6ن\x8b\xa2\xd63\xb4\xeal\x92ύ\xa1\xbc69\x7f`\x94\x8eȂH\x94\xb8\xbe=\xc3\v\x9e\xd6\xf8\x95\x9e\xe7Ǧ8\x8c\x1a\xe6\xfb\x8b\x95\x16\xcae\xe1\x9f\xdfe\xf4\xf9\xbe\\\xee\xbf\xfb\x8c\xdf}\xc6\xef>㜎\xbe\xfb\x8c\x13\xe5\xbb\xcf\xf8\xddg<^\xbe\xfb\x8c)\xe5\xbb\xcf8\x13\x91o\xe53\xa6`\xb8\xa05\xce#\x15\x92\xb0JLA\x98B{\xa2/\x9fl\xe3\xcfH\x9c%\x87x5\x0er\xe4\xf4L\xe4\xd8C\xcc\xebh\x8dW\x93T\x8c30\xcc\x1dw|1\xc1a>é\x95\x80\xc0\xf9O\xad\xac\x8eB>\xe3\xa9\x15?\x84\xb4\b\xe3\xa43+\x81H\xf3O-\\\xf9\xe4\x9d\x12x\xd8Jqi\x17\xb11\xc6$)\x01\x8fo\x9ct~\x90\xa9\xf8\x02\xb2\xf4*'af\xc9\xd3(\xeb/\xff|\xf9\xfb`\xd1y\x99\x12e\xc3!m\x9d\x1a\x8f\xe9G\x8c\xe5\xbb)\x89\xfd\xec\xd0\xdf\xcfT8\xab짞di\x88\x1c\x81\xd7\x17\xeb\x01\x95\x7fO\xfa\xc6B\xf9\xa9\xf2\xd6\xf2\fG\xdbW#\xf0\x92\x0e\xb7s\xb3\x97\xd9V+\xa9j\xe3ׄ\x10ֻ\xcc\x1d\xf8\x0f c\xc2>\xaaA\xfe¶\xaa\x8e\x9c\x96\x98 mB\xf6j\x1aAzɬ>1\x02,߽]\xf6\x7f\xb1ʧ\xb6\xb2'a\xb7\x11`t\x11\x04\xcfs\x8c\v:\ai\xbc\x1e\bw\x14\r\x852\x02Li&E\xe1$6@\xe8\xc9+\xfbT\xb9\xd5\xc1\x93\xfd\xa6\xe95\xac\xf4\x04عi\xafM\x96\xe2\xb4\xfb\xfe\x8cd׳\x1eI\xfaf鬧%\xb1\xa6\xaeP&$\xac\xa6\xa7\xa9\xa6\xb0Օ\xf4\xe4\xd4\xe4\b95\x11u\xee\nċ&\x9d\xbeL\xaai2\xcd\xd2\xd2J\xe7R\xecURH_9q\xf4\xf5\xd2Eg$\x89\x9e\xff\xb4\xc99WV\x8e\xa7|&%z&\xad\xbeL㜔\xca97\x813\x89\xaa\xe9S\xe7US4_51\xf3\xf5\xd31'\xc5f\xb2\xc2܄\xcb\xf1\x9b\xfeB\x996\xc6ŷ\x10\xce\xe7\x92I鞛\xfc\xac\x18\xf0\xd3\x00\x16\nKp\x19_\xd1'/\xeb\u008a\xaah/%\x8b\x05\x7f[\xd87\x17\xf6\xfc\xaa蘸\xbf\xae\xea\xd3\xe7F◃\b\x83\x1b\xf6\x04E\xc1xln\x1eP!s\x97afj\x01h\xa7p\x96\xfb\x1b\x89\xfc\r\x9aWn\xbaЉx\xb2velٍ\xcb\xe3\xd7]\x1d5&\xa9z\xec\xc0Kv\xbe?}\xfb\xad\x06\xbdgt\xf9V\xe3'\xb5\a+\xfdD7\x18$\x06\xf5\xe3\xd5\xe1\xb1\xfd\x8b\x83`\xa3U\x0f\xec\x9dt\xd6y\x88\x13\xb5A\xbd\xd3\x06W\xa8T1f\x8a\xf6\x13\x01!U\x03!\xd24\xc5\x11\x9fs\xd2\xf0%B\xads\x04[I\xde\xc8gX\xfdzw\xbb\"XA\x8c\xe8\xe1\xa0&i\xafa\xf9\x1a\xd0t\xb7c?\xa6OV\x9b\x1e\xd4~\xdel\xf7\xe5\x04\xc8\xdd3\x19\xc1}\xf0\xaa9S\xa8\xb5nW\x0e\x97c=\xa1|q\xb9gʿ\x83 t\xbe\xa8\xb8\xb6{\x97`s\xd5\xc3#\x98\xe7\xa9ի\xa3\xd6\xea\xf0\x19\x90n\xe9\x91=\xbc\x00B\xbb\xbb\xfb\xaa\xbf\xa1>\xa4\xe7sp:~\xd2x\xf2\x8c\xf1\v\xe0t\xdc\x13Z\x10\x15#?E\xb3\x02Ͼrh\xfcu\xf1?\xa9\x1d\xbc\x8f\xae \xf6\x9f\x02\x194\x19I\xd7\vP\xe9\xc6\xf3\b\x05\xdb\x1c=\xbao\xfayj/\x9e\x7f\x17P\xf1\xf7U?g\x91\xf0\xae\x0fj\xfcu\f\xba\xce;t\x1a\xf3\xaa\xe8ݡ=\xbb\xfdB\xf1c\xa3J\xfd\xd4\xf7\xf1cX&\f\x9b\xee\x11XB\x1e}0\xe4\\d\xb4J\xf3\a\xf8\xa8\xdcC/)b\xd2o\xd1{\x06\xc8{n!\x87\xd9O\u0098\xa2\xf7c\x1b\x02l\xcf,\x1c\xdc:\x8f؞x\xaf\xbe\xb5\xc5sd\xe4\xfe\xfe\xa3\x1b)\xbd\xaf\xf1\xde?\x95\x81\xfa\xd8\x00\xb2 P\xc0A[\xe3\x7f\xb7\xea\x89.c\x8f\xaf\xf5\x86\xd7,:\x0fj\x01\x1d\x9e\xa0\xb4֓\x86YW\x85\xe29\xe8\x1bz\xd1#aĿ\xf4\x1a\f܁\xfe\xbb \xdenF\xc6\x13z~\xc1\xcc\x11\xf4\xe8\x8a\x02\x8a\x1fE\x01\xc6!\x9eh\x1an\x0f[6\x96\xa2.\xd7\xceS\xdd\xe0\x8fM'G,\xb3\x1b*-\xf4W\xa0\xd1Ot[\x02\xb5\t\x92\x7f\x9c\x18\xacᣐ\x16\x1e`<\x14\x9e\xb0\t\xbb\u07b3 a\xf6\xa4(\xc2/\xe3-;\xcetg\x1e\x93\xf7\x1bWw1X\xdc\x18\x95\t\U000bf7c4\xf5\x97\xf0\xbd\xdc\xcd\xcf\xc7B\xa9#t\xac\r|z\x92\xa0?\a]mV2\xf6\xdcƴ\x9e\xf8\xe5\x00Z\xf4\x99\r\xab\xb0\xef\x11\x18\x03\x00L\x85\x9d\x19\xe3\x1ep\t\x1bB\xc24oR\x1d\xd2sb\xb2\xc5m¸k\xb3\x18\x7fBg\xd1<\xf5s\x91@n\xf7lM\x1f\xf0\xf8Kd\xee}\x9b\x8cW\xb6\xd6A\x0f՚\xee\xc6F எ>\xed-\xb2\xf6\x89\xaaS\x18ܾ\x11ծ\x98O\xbeb9\x02\xa7yM,\xfa4\x91\x8b=\xdd+\x93\v\x84\x7f\x1a\x8fGg\f\xe2|瞜\x9a \xc2Ƕ\xe6\u0600\x9ba\xe0\x90\xfd#V\xaf:\x12\xba*}b\f\xb7X\xa79#\xe9\xe5\x88\x1a\x86+\xd6\xefbL\x18?H\xb7`?\xc3al\xbb`\x1f$\x0e\xe2\x90\x00\xee\xb4\x1c\xe4\xb4\x19@\xdaq\xce\x10wM+:\xaa8\xa2!\xa7\xc5\xf6\xcb\x00\xc6 \x0f\x9a\xde\xeai\xaa\xb8\xb3\x8a\x86\xfdQ\x8c\xf9m\xb4Ǔ\xe1@\xfft\xf0kT\x83\x1f\xd5\xde1\xcd=\xaaF\x0e>\xd2\xfbeyGr\xbc?\xdb\xfdR\xaf\xdbk\xf0\xd9\xdf\xfe~\xf1\xff\x01\x00\x00\xff\xff\xba:\x16j\xf5x\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcV\xcfo\xeb6\f\xbe\xe7\xaf \xb0\xeb\xec\xbcb;\f\xb9\r\xdd\x0eŶ\x87\xa2y\xe8]\x91\x99\x84\xab,y$\x95.\xc3\xfe\xf8A\x92ݦ\xb6\xb2\xf6\xed0\xdd,\x89\x1f?~\xfc!7M\xb32\x03=\"\v\x05\xbf\x013\x10\xfe\xa9\xe8ӗ\xb4O?HKa}\xbaY=\x91\xef6p\x1bEC\xff\x80\x12\"[\xfc\t\xf7\xe4I)\xf8U\x8fj:\xa3f\xb3\x020\xde\a5i[\xd2'\x80\r^98\x87\xdc\x1cзOq\x87\xbbH\xaeC\xce\xe0\x93\xebӧ\xf6\xe6\xfb\xf6\xd3\n\xc0\x9b\x1e7 \xc8\xe9L\x8dFa\xfc#\xa2\xa8\xb4'tȡ\xa5\xb0\x92\x01m\xc2?p\x88\xc3\x06^\x0f\x8a\xfd\xe8\xbb\xf0\xdef\xa8m\x86z(P\xf9ԑ\xe8/\xd7n\xfcJ\xe3\xad\xc1E6\xaeN(_\x90c`\xfd\xfc\xea\xb4\x01\x11.'\xe4\x0f\xd1\x19\xae\x1a\xaf\x00Ć\x017\x90m\ac\xb1[\x01\x8c\x82d\xacf\xd4\xe2tS\xe0\xec\x11{S\x9c\x00\x84\x01\xfd\x8f\xf7w\x8f\xdfm\xdfl\x03t(\x96i\xd0,\xeb\xdf\xcd\xcb>\xd4\xc2\x04\x1200R\x02\r`\xacE\x11\xb0\x91\x19\xbdB\xa1\f\xe4\xf7\x81\xfb\x9cV0\xbb\x10\xf5\x02U\x8f\b\x8fY\xff1\xcc\xf6\xe5p\xe00 +MҔuQq\x17\xbb\xffF<\xad\x14k\xb1\x82.\x95\x1eJ\xf6<\xea\x85\xdd(\x0f\x84=\xe8\x91\x04\x18\aFA_\x8a1m\x1b\x0fa\xf7;Zmg\xd0E\x17I\x99\x8c\xaeK\x15{BV`\xb4\xe1\xe0\xe9\xaf\x17lI\x02%\xa7\xceh\xd6\xce+\xb27\x0eN\xc6E\xfc\x16\x8c\xeffȽ9\x03c\xf2\t\xd1_\xe0e\x03\x99\xf3\xf8-0f\xa97pT\x1dd\xb3^\x1fH\xa7>\xb4\xa1\xef\xa3'=\xafsK\xd1.j`YwxB\xb7\x16:4\x86\xed\x91\x14\xadFƵ\x19\xa8Ɂ\xf8܋m\xdf}\xc3c\xe7\xca\x1b\xb7zN5(\xca\xe4\x0f\x17\a\xb9u\xbe\"=\xa9\x91J1\x15\xa8\x12\xe2k\x16\xd2V\x92\xee\xe1\xe7\xed\x17\x98\x98\x94L\x95\xa4\xbc^]\xe82\xe5'\xa9I~\x8f\\\xec\xf6\x1c\xfa\x8c\x89\xbe\x1b\x02y\xcd\x1f\xd6Q.ܸ\xebIe*픺9\xecm\x9eU\xb0C\x88Cg\x14\xbb\xf9\x85;\x0f\xb7\xa6Gwk\x04\xff\xe7\\\xa5\xacH\x93\x92\xf0\xa1l]N\xe0\xf9\xe5\"\xef\xc5\xc14;\xaf\xa4\xb62%\xb6\x03ڔܤo\xb2\xa6=\xd9\xd2V\xfb\xc0`j&퇘d\x8b\xaf\xe42N\xa4\xc2f6\xa7R\x97\xbfϦ>\x96\xf2\xc9\xd1\b\xce7g\x9c\xeeӝ\xb9\x7fG{\xb4g\xeb\xb0@\x94)\x84\xefSI\v}\xec\x97>\x1b\xf8\x8cϕ\xdd{\x0eiB\xe3|\xd4\\\xad\r(\x8f\u0601\xfc\"\xdcyd\xe5V~\x18\x97#?\a4\x02\x01G\xefSK\a\xbf\x80\xac\xbc\b\x8b;\xa4\xd8W\xd8T\xf9\xdc\xf9}\xc8\x7f\x11&96Z\xda\t\xc7d\x8f~\n\xaf\n\xe0\xf5\\\x97\xb5\x9cs\x1f\x12\xb4\xac\xfc<\xff7\xe34\x97\x88\xb1\xea\xbbɬ\xaa\a\xc9cM\xf1z\x7f\x8d,\xa3sf\xe7p\x03\xcaqi]l\r\xb39ϫf*\xb5/ԣ\xa8\xe9\x87w\nh\xf1*\xa4u\xbf@I\xcd\xf3|D\x7f\xadE\xe0\xd9ȫ\xf3\n\xe4\xee|\xcd\xf4\xf6\xe5os\xd9g\xa5\x9e7\x90f}\xa3T\x11\xf2CJUSZ\xea\xbc\xfa[\xb3Pi{yw\x1a$o\xfae\xfa\xabY\xc6p\x95B\xb5\x02\x16\x9b\x19\xbe\xbb\bO4\xb09L\x01\xff\x13\x00\x00\xff\xff\xd9Ո\xaf\x10\f\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcVM\x8f\xdb6\x10\xbd\xfbW\f\x90kd'h\x0f\x85/E\xb0\xe9!h\xd2,\xe2t\xef\xb48\xb2\xa6K\x91\xeap\xa8\x8d\x8b\xfe\xf8bHi\xd7+\xcb\xd9ݢ\xa8.\x86\xc9ᛏ7\xf3Ȫ\xaaV\xa6\xa7\x1b\xe4H\xc1o\xc1\xf4\x84\xdf\x04\xbd\xfe\x8b\xeb۟\xe2\x9a\xc2fx\xbb\xba%o\xb7p\x95\xa2\x84\xee\vƐ\xb8\xc6\xf7ؐ'\xa1\xe0W\x1d\x8a\xb1F\xccv\x05`\xbc\x0fbt9\xea_\x80:x\xe1\xe0\x1cru@\xbf\xbeM{\xdc'r\x169\x83O\xae\x877\xeb\xb7?\xae߬\x00\xbc\xe9p\vCp\xa9\xc3\xe8M\x1f\xdb .\xd4\x05s=\xa0C\x0ek\n\xab\xd8c\xad.\x0e\x1cR\xbf\x85\x87\x8d\x021\xba/\xa1\xdfd\xb4݈\xf6qD\xcb\x06\x8e\xa2\xfc\xfa\x1d\xa3\x8f\x14%\x1b\xf6.\xb1q\x17#\xcb6\xb1\r,\xbf=x\xaf`\x88\xae\xec\x90?$g\xf8\xd2\xf9\x15@\xacC\x8f[\xc8\xc7{S\xa3]\x01\x8c\xf5\xc9p\xd5T\x9a\xb7\x05\xb1n\xb13\xc5\x0f@\xe8ѿ\xbb\xfep\xf3\xc3\xee\xd12\x80\xc5X3\xf5\x92\xab\xbc\x9c\"P\x04\x03S$p\xd7\"#\xdc\xe4zB\x94\xc0\x18Ǡ\xefA\x01\xa6\xf8\xe3\xfa~\xb1\xe7\xd0#\vMɗ錄NVgq\xfd]=\xda\x03\xd0T\xca)\xb0\xdah\x18AZ\x9cʁv\xcc\x1eB\x03\xd2R\x04ƞ1\xa2/\xad\xa7\xcb\xc6C\xd8\xff\x81\xb5\xacg\xd0;d\x85Q\xae\x92\xb3ڟ\x03\xb2\x00c\x1d\x0e\x9e\xfe\xbaǎ !;uF0\n\x90\x17do\x1c\f\xc6%|\r\xc6\xdb\x19rg\x8e\xc0\xa8>!\xf9\x13\xbc| \xce\xe3\xf8\x14\x18\x81|\x13\xb6Њ\xf4q\xbb\xd9\x1cH\xa6\xa9\xabC\xd7%Or\xdc\xe4\x01\xa2}\x92\xc0qcq@\xb7\x89t\xa8\f\xd7-\t֒\x187\xa6\xa7*'\xe2˔t\xf6\x15\x8fs\x1a\x1f\xb9\x95\xa3\xb6X\x14&\x7f8\xd9\xc8S\xf2\x02zt`J\xd7\x14\xa8\x92\xe2\x03\v\xba\xa4\xa5\xfb\xf2\xcb\xee+L\x91\x14\xa6\n)\x0f\xa6gu\x99\xf8\xd1j\x92o\x90˹\x86C\x971\xd1\xdb>\x90\x97\xfc\xa7v\x84^ \xa6}G\xa2m\xf0g\xc2(J\xdd\x1c\xf6*+\x13\xec\x11Ro\x8d\xa0\x9d\x1b|\xf0pe:tW&\xe2\xff̕\xb2\x12+%\xe1Yl\x9d\xea\xedܸ\x94\xf7tPG\x99\xbc@\xed\xb2\"\xecz\xac\x1f\r\x9e\xa2PC\xa3B4\x81g\x052\x93^,\xe3=\xae\xe7\xb2P@\xb9,\x1a:\xccW\x01\x8c\xb5\xf9\xaa1\xee\xfa\xe2\xd9\xef\x14l!\xef\xab\xecI{\xb8\t\xac\x11\rd\x91\xab)\xcf1\x92\xc4c\u0084Ξu\xeaŚ\xe7T\x18\xadRl\xdcy\xa0\x8f#\xb97\xccw\xa5!_J\xfe\x00\x90;\x8f\xbbQ\xab\xbd\xa0\xb78מ\x1cM\xc8\xed\x1d\xd1\xc2\x1dI[\xe6Ɲ^v\xcfcA\xbf[<.-\xcfb\xffڢZ\x16\x19F\x88X3\x8a\xc6\x11\xd1\xe9\x94\xebЮ\x01>\xa5\x98'\xcf,\"\x82\xaa\a\xd9\xe9\xf4-\x1e\xcf\v\rO\x91;\xbe\x1b\x9e\x0e\xf9L˦O\xef\xdd)\x11\xc6\x06\x19\xfd\xd9\xdd1}\vz\xa0\x0f\x1b\xf6(\x98%\xc1\x86:\xaa\x1a\xd4\xd8K܄\x01y \xbc\xdb\xdc\x05\xbe%\x7f\xa8\x94\x9e\xaa\xb4M\xdc\xe4\xd7\xca\xe6U\xfe\xb9\xe0\xef\xeb\xe7\xf7\x9f\xb7\xf0\xceZ\b\xd2\"+\xc7MrS[\x9eܱ\xaf\xb3\x94\xbf\x86D\xf6\xe7\x7fS\xc4З1{F!wyT\x8e\xfa\\\xc81i\xddv\x85\xc2\xc0\xa0j\xac\x9dэ\xd4\x171Y\xea\xda)\xa6}\b\x0e\xcdy\x9f\xaa\xa6\x13\xa3=\x0f\xa9R\x0f/\x99I\x80o\xd5\x03OUg\xfa\xaaX\x1b\t\x1d\xd53\xebI\x14\x9e\x98\xdf\xeb\xd1L\xb5Dk0\x1d\x9bz\xa9<\x9d\xf2C\xca\x1c\xcen\x96\xef0\xb2\x9cxu\xef\xe0Y\xea/FR|\xb9\xfe\xe7c\xa3\xe5~\xbc\x03\xeaĜ/ۼ9\xcbC_\\\xff\xcd\x1dз&.\f\xf23\xa2\xbe֓\x13\r\x8e\x1a\xac\x8f\xb5\xc3\x02\b\xa1Y\xe8\xbd\x17\x85\xac\x1f\xfa\xd4-5\xe2\xbb\xc1\x903{\x87\v{\xbf{sq\xf7\"\xf9\x8b|\x9e-F}+\xd9-\b\xa7\x82=vٸ\xf2O\x00\x00\x00\xff\xff\xb7\xb0(y\xe0\r\x00\x00"), diff --git a/pkg/apis/velero/v1/restore_types.go b/pkg/apis/velero/v1/restore_types.go index 377a92737c..783988e3a9 100644 --- a/pkg/apis/velero/v1/restore_types.go +++ b/pkg/apis/velero/v1/restore_types.go @@ -129,6 +129,13 @@ type RestoreSpec struct { // +optional // +nullable UploaderConfig *UploaderConfigForRestore `json:"uploaderConfig,omitempty"` + + // DisabledPVReprovisioningStorageClasses is a slice of StorageClasses names. + // PV without snaptshot and having one of these StorageClass will not be + // re-provisionned (even when ReclaimPolicy is Delete). + // +optional + // +nullable + DisabledPVReprovisioningStorageClasses []string `json:"disabledPVReprovisioningStorageClasses,omitempty"` } // UploaderConfigForRestore defines the configuration for the restore. diff --git a/pkg/apis/velero/v1/zz_generated.deepcopy.go b/pkg/apis/velero/v1/zz_generated.deepcopy.go index 03f98b4250..02f5efac46 100644 --- a/pkg/apis/velero/v1/zz_generated.deepcopy.go +++ b/pkg/apis/velero/v1/zz_generated.deepcopy.go @@ -1377,6 +1377,11 @@ func (in *RestoreSpec) DeepCopyInto(out *RestoreSpec) { *out = new(UploaderConfigForRestore) (*in).DeepCopyInto(*out) } + if in.DisabledPVReprovisioningStorageClasses != nil { + in, out := &in.DisabledPVReprovisioningStorageClasses, &out.DisabledPVReprovisioningStorageClasses + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RestoreSpec. diff --git a/pkg/builder/restore_builder.go b/pkg/builder/restore_builder.go index bad4327e99..c3f27070ad 100644 --- a/pkg/builder/restore_builder.go +++ b/pkg/builder/restore_builder.go @@ -171,3 +171,9 @@ func (b *RestoreBuilder) ItemOperationTimeout(timeout time.Duration) *RestoreBui b.object.Spec.ItemOperationTimeout.Duration = timeout return b } + +// DisabledPVReprovisioningStorageClasses appends to the Restore's disabled PV re-rpovisioning StorageClasses. +func (b *RestoreBuilder) DisabledPVReprovisioningStorageClasses(storageClasses ...string) *RestoreBuilder { + b.object.Spec.DisabledPVReprovisioningStorageClasses = append(b.object.Spec.DisabledPVReprovisioningStorageClasses, storageClasses...) + return b +} diff --git a/pkg/cmd/cli/restore/create.go b/pkg/cmd/cli/restore/create.go index 6d4b25f0ab..ef70244c7a 100644 --- a/pkg/cmd/cli/restore/create.go +++ b/pkg/cmd/cli/restore/create.go @@ -78,30 +78,31 @@ func NewCreateCommand(f client.Factory, use string) *cobra.Command { } type CreateOptions struct { - BackupName string - ScheduleName string - RestoreName string - RestoreVolumes flag.OptionalBool - PreserveNodePorts flag.OptionalBool - Labels flag.Map - IncludeNamespaces flag.StringArray - ExcludeNamespaces flag.StringArray - ExistingResourcePolicy string - IncludeResources flag.StringArray - ExcludeResources flag.StringArray - StatusIncludeResources flag.StringArray - StatusExcludeResources flag.StringArray - NamespaceMappings flag.Map - Selector flag.LabelSelector - OrSelector flag.OrLabelSelector - IncludeClusterResources flag.OptionalBool - Wait bool - AllowPartiallyFailed flag.OptionalBool - ItemOperationTimeout time.Duration - ResourceModifierConfigMap string - WriteSparseFiles flag.OptionalBool - ParallelFilesDownload int - client kbclient.WithWatch + BackupName string + ScheduleName string + RestoreName string + RestoreVolumes flag.OptionalBool + PreserveNodePorts flag.OptionalBool + Labels flag.Map + IncludeNamespaces flag.StringArray + ExcludeNamespaces flag.StringArray + ExistingResourcePolicy string + IncludeResources flag.StringArray + ExcludeResources flag.StringArray + StatusIncludeResources flag.StringArray + StatusExcludeResources flag.StringArray + NamespaceMappings flag.Map + Selector flag.LabelSelector + OrSelector flag.OrLabelSelector + IncludeClusterResources flag.OptionalBool + Wait bool + AllowPartiallyFailed flag.OptionalBool + ItemOperationTimeout time.Duration + ResourceModifierConfigMap string + WriteSparseFiles flag.OptionalBool + ParallelFilesDownload int + client kbclient.WithWatch + DisabledPVReprovisioningStorageClasses flag.StringArray } func NewCreateOptions() *CreateOptions { @@ -155,6 +156,8 @@ func (o *CreateOptions) BindFlags(flags *pflag.FlagSet) { f.NoOptDefVal = cmd.TRUE flags.IntVar(&o.ParallelFilesDownload, "parallel-files-download", 0, "The number of restore operations to run in parallel. If set to 0, the default parallelism will be the number of CPUs for the node that node agent pod is running.") + + flags.Var(&o.DisabledPVReprovisioningStorageClasses, "disable-pv-reprovisioning-storageclasses", "PV with no snaptshot that has a StorageClass specified by this flag will not be re-provisionned.") } func (o *CreateOptions) Complete(args []string, f client.Factory) error { @@ -335,6 +338,7 @@ func (o *CreateOptions) Run(c *cobra.Command, f client.Factory) error { WriteSparseFiles: o.WriteSparseFiles.Value, ParallelFilesDownload: o.ParallelFilesDownload, }, + DisabledPVReprovisioningStorageClasses: o.DisabledPVReprovisioningStorageClasses, }, } diff --git a/pkg/cmd/cli/restore/create_test.go b/pkg/cmd/cli/restore/create_test.go index bf771bfe3b..cc28dd2c88 100644 --- a/pkg/cmd/cli/restore/create_test.go +++ b/pkg/cmd/cli/restore/create_test.go @@ -79,6 +79,7 @@ func TestCreateCommand(t *testing.T) { itemOperationTimeout := "10m0s" writeSparseFiles := "true" parallel := 2 + disabledPVReprovisioningStorageClasses := "storageclass1,storageclass2" flags := new(pflag.FlagSet) o := NewCreateOptions() o.BindFlags(flags) @@ -102,6 +103,7 @@ func TestCreateCommand(t *testing.T) { flags.Parse([]string{"--item-operation-timeout", itemOperationTimeout}) flags.Parse([]string{"--write-sparse-files", writeSparseFiles}) flags.Parse([]string{"--parallel-files-download", "2"}) + flags.Parse([]string{"--disable-pv-reprovisioning-storageclasses", disabledPVReprovisioningStorageClasses}) client := velerotest.NewFakeControllerRuntimeClient(t).(kbclient.WithWatch) f.On("Namespace").Return(mock.Anything) @@ -139,6 +141,7 @@ func TestCreateCommand(t *testing.T) { require.Equal(t, itemOperationTimeout, o.ItemOperationTimeout.String()) require.Equal(t, writeSparseFiles, o.WriteSparseFiles.String()) require.Equal(t, parallel, o.ParallelFilesDownload) + require.Equal(t, disabledPVReprovisioningStorageClasses, o.DisabledPVReprovisioningStorageClasses.String()) }) t.Run("create a restore from schedule", func(t *testing.T) { diff --git a/pkg/cmd/util/output/restore_describer.go b/pkg/cmd/util/output/restore_describer.go index 55363b4b63..3726e906c5 100644 --- a/pkg/cmd/util/output/restore_describer.go +++ b/pkg/cmd/util/output/restore_describer.go @@ -149,6 +149,13 @@ func DescribeRestore( d.Printf("\tCluster-scoped:\t%s\n", BoolPointerString(restore.Spec.IncludeClusterResources, "excluded", "included", "auto")) + d.Println() + s = emptyDisplay + if restore.Spec.DisabledPVReprovisioningStorageClasses != nil { + s = strings.Join(restore.Spec.IncludedNamespaces, ", ") + } + d.Printf("Disabled PV Re-provisioning StorageClasses:\t%s\n", s) + d.Println() d.DescribeMap("Namespace mappings", restore.Spec.NamespaceMapping) diff --git a/pkg/restore/restore.go b/pkg/restore/restore.go index 9ae0b0f663..9f77f1a19b 100644 --- a/pkg/restore/restore.go +++ b/pkg/restore/restore.go @@ -1231,7 +1231,19 @@ func (ctx *restoreContext) restoreItem(obj *unstructured.Unstructured, groupReso // When the PV data is skipped from backup, it's BackupVolumeInfo BackupMethod // is not set, and it will fall into the default case. default: - if hasDeleteReclaimPolicy(obj.Object) { + hasDisabledStorageClass, err := hasDisabledPVReprovisioningStorageClass(obj, ctx) + if err != nil { + errs.Add(namespace, err) + return warnings, errs, itemExists + } + + if hasDisabledStorageClass { + obj, err = ctx.handleSkippedPVHasDisabledReprovisioningStorageClass(obj, restoreLogger) + if err != nil { + errs.Add(namespace, err) + return warnings, errs, itemExists + } + } else if hasDeleteReclaimPolicy(obj.Object) { restoreLogger.Infof("Dynamically re-provisioning persistent volume because it doesn't have a snapshot and its reclaim policy is Delete.") ctx.pvsToProvision.Insert(name) @@ -2523,3 +2535,36 @@ func (ctx *restoreContext) handleSkippedPVHasRetainPolicy( obj = resetVolumeBindingInfo(obj) return obj, nil } + +func hasDisabledPVReprovisioningStorageClass(unstructuredPV *unstructured.Unstructured, ctx *restoreContext) (bool, error) { + disabledStorageClasses := ctx.restore.Spec.DisabledPVReprovisioningStorageClasses + + // Converting Unstructured to PV object. + pv := new(v1.PersistentVolume) + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstructuredPV.Object, pv); err != nil { + return false, errors.Wrapf(err, "error converting persistent volume to structured") + } + + // Checking if PV StorageClass is in the DisabledPVReprovisioningStorageClasses list. + for _, disabledStorageClass := range disabledStorageClasses { + if disabledStorageClass == pv.Spec.StorageClassName { + return true, nil + } + } + return false, nil +} + +func (ctx *restoreContext) handleSkippedPVHasDisabledReprovisioningStorageClass( + obj *unstructured.Unstructured, + logger logrus.FieldLogger, +) (*unstructured.Unstructured, error) { + logger.Infof("Restoring persistent volume as-is because it doesn't have a snapshot and it's storage class has re-provisionning disabled.") + + // Check to see if the claimRef.namespace field needs to be remapped, and do so if necessary. + if _, err := remapClaimRefNS(ctx, obj); err != nil { + return nil, err + } + + obj = resetVolumeBindingInfo(obj) + return obj, nil +} diff --git a/pkg/restore/restore_test.go b/pkg/restore/restore_test.go index 8e239e9a70..fb0d522496 100644 --- a/pkg/restore/restore_test.go +++ b/pkg/restore/restore_test.go @@ -196,6 +196,27 @@ func TestRestorePVWithVolumeInfo(t *testing.T) { test.PVs(): {}, }, }, + { + name: "Restore PV with ClaimPolicy as Delete and Disabled Re-provisioning", + restore: defaultRestore().DisabledPVReprovisioningStorageClasses("no-reprovisioning").Result(), + backup: defaultBackup().Result(), + tarball: test.NewTarWriter(t). + AddItems("persistentvolumes", + builder.ForPersistentVolume("pv-1").StorageClass("no-reprovisioning").ReclaimPolicy(corev1api.PersistentVolumeReclaimDelete).Result(), + ).Done(), + apiResources: []*test.APIResource{ + test.PVs(), + }, + volumeInfoMap: map[string]volume.BackupVolumeInfo{ + "pv-1": { + PVName: "pv-1", + Skipped: true, + }, + }, + want: map[*test.APIResource][]string{ + test.PVs(): {"/pv-1"}, + }, + }, { name: "Restore PV with ClaimPolicy as Retain", restore: defaultRestore().Result(), @@ -2462,6 +2483,7 @@ func TestRestorePersistentVolumes(t *testing.T) { wantError bool wantWarning bool csiFeatureVerifierErr string + volumeInfoMap map[string]volume.BackupVolumeInfo }{ { name: "when a PV with a reclaim policy of delete has no snapshot and does not exist in-cluster, it does not get restored, and its PVC gets reset for dynamic provisioning", @@ -3188,6 +3210,172 @@ func TestRestorePersistentVolumes(t *testing.T) { })).Result(), want: []*test.APIResource{}, }, + { + name: "when a PV with a reclaim policy of delete has no snapshot does not exist in-cluster and has a StorageClass that disable re-provisioning, it gets restored, with its claim ref", + restore: defaultRestore().DisabledPVReprovisioningStorageClasses("no-reprovisioning").Result(), + backup: defaultBackup().Result(), + tarball: test.NewTarWriter(t). + AddItems("persistentvolumes", + builder.ForPersistentVolume("pv-1"). + StorageClass("no-reprovisioning"). + ReclaimPolicy(corev1api.PersistentVolumeReclaimDelete). + ClaimRef("ns-1", "pvc-1"). + Result(), + ). + AddItems("persistentvolumeclaims", + builder.ForPersistentVolumeClaim("ns-1", "pvc-1"). + VolumeName("pv-1"). + ObjectMeta( + builder.WithAnnotations("pv.kubernetes.io/bind-completed", "true", "pv.kubernetes.io/bound-by-controller", "true", "foo", "bar"), + ). + Result(), + ). + Done(), + volumeInfoMap: map[string]volume.BackupVolumeInfo{ + "pv-1": { + PVName: "pv-1", + Skipped: true, + }, + }, + apiResources: []*test.APIResource{ + test.PVs(), + test.PVCs(), + }, + want: []*test.APIResource{ + test.PVs( + builder.ForPersistentVolume("pv-1"). + StorageClass("no-reprovisioning"). + ReclaimPolicy(corev1api.PersistentVolumeReclaimDelete). + ObjectMeta( + builder.WithLabels("velero.io/backup-name", "backup-1", "velero.io/restore-name", "restore-1"), + ). + ClaimRef("ns-1", "pvc-1"). + Result(), + ), + test.PVCs( + builder.ForPersistentVolumeClaim("ns-1", "pvc-1"). + VolumeName("pv-1"). + ObjectMeta( + builder.WithLabels("velero.io/backup-name", "backup-1", "velero.io/restore-name", "restore-1"), + builder.WithAnnotations("foo", "bar"), + ). + Result(), + ), + }, + }, + { + name: "when a PV with a reclaim policy of retain has no snapshot does not exist in-cluster and has a StorageClass that disable re-provisioning, it gets restored, with its claim ref", + restore: defaultRestore().DisabledPVReprovisioningStorageClasses("no-reprovisioning").Result(), + backup: defaultBackup().Result(), + tarball: test.NewTarWriter(t). + AddItems("persistentvolumes", + builder.ForPersistentVolume("pv-1"). + StorageClass("no-reprovisioning"). + ReclaimPolicy(corev1api.PersistentVolumeReclaimRetain). + ClaimRef("ns-1", "pvc-1"). + Result(), + ). + AddItems("persistentvolumeclaims", + builder.ForPersistentVolumeClaim("ns-1", "pvc-1"). + VolumeName("pv-1"). + ObjectMeta( + builder.WithAnnotations("pv.kubernetes.io/bind-completed", "true", "pv.kubernetes.io/bound-by-controller", "true", "foo", "bar"), + ). + Result(), + ). + Done(), + volumeInfoMap: map[string]volume.BackupVolumeInfo{ + "pv-1": { + PVName: "pv-1", + Skipped: true, + }, + }, + apiResources: []*test.APIResource{ + test.PVs(), + test.PVCs(), + }, + want: []*test.APIResource{ + test.PVs( + builder.ForPersistentVolume("pv-1"). + StorageClass("no-reprovisioning"). + ReclaimPolicy(corev1api.PersistentVolumeReclaimRetain). + ObjectMeta( + builder.WithLabels("velero.io/backup-name", "backup-1", "velero.io/restore-name", "restore-1"), + ). + ClaimRef("ns-1", "pvc-1"). + Result(), + ), + test.PVCs( + builder.ForPersistentVolumeClaim("ns-1", "pvc-1"). + VolumeName("pv-1"). + ObjectMeta( + builder.WithLabels("velero.io/backup-name", "backup-1", "velero.io/restore-name", "restore-1"), + builder.WithAnnotations("foo", "bar"), + ). + Result(), + ), + }, + }, + { + name: "when a PV with a reclaim policy of delete has a snapshot does not exist in-cluster and has a StorageClass that disable re-provisioning, the snapshot and PV are restored", + restore: defaultRestore().DisabledPVReprovisioningStorageClasses("no-reprovisioning").Result(), + backup: defaultBackup().Result(), + tarball: test.NewTarWriter(t). + AddItems("persistentvolumes", + builder.ForPersistentVolume("pv-1"). + StorageClass("no-reprovisioning"). + ReclaimPolicy(corev1api.PersistentVolumeReclaimDelete). + AWSEBSVolumeID("old-volume"). + Result(), + ). + Done(), + apiResources: []*test.APIResource{ + test.PVs(), + test.PVCs(), + }, + volumeSnapshots: []*volume.Snapshot{ + { + Spec: volume.SnapshotSpec{ + BackupName: "backup-1", + Location: "default", + PersistentVolumeName: "pv-1", + }, + Status: volume.SnapshotStatus{ + Phase: volume.SnapshotPhaseCompleted, + ProviderSnapshotID: "snapshot-1", + }, + }, + }, + volumeSnapshotLocations: []*velerov1api.VolumeSnapshotLocation{ + builder.ForVolumeSnapshotLocation(velerov1api.DefaultNamespace, "default").Provider("provider-1").Result(), + }, + volumeSnapshotterGetter: map[string]vsv1.VolumeSnapshotter{ + "provider-1": &volumeSnapshotter{ + snapshotVolumes: map[string]string{"snapshot-1": "new-volume"}, + }, + }, + volumeInfoMap: map[string]volume.BackupVolumeInfo{ + "pv-1": { + BackupMethod: volume.NativeSnapshot, + PVName: "pv-1", + NativeSnapshotInfo: &volume.NativeSnapshotInfo{ + SnapshotHandle: "testSnapshotHandle", + }, + }, + }, + want: []*test.APIResource{ + test.PVs( + builder.ForPersistentVolume("pv-1"). + StorageClass("no-reprovisioning"). + ReclaimPolicy(corev1api.PersistentVolumeReclaimDelete). + AWSEBSVolumeID("new-volume"). + ObjectMeta( + builder.WithLabels("velero.io/backup-name", "backup-1", "velero.io/restore-name", "restore-1"), + ). + Result(), + ), + }, + }, } for _, tc := range tests { @@ -3231,6 +3419,7 @@ func TestRestorePersistentVolumes(t *testing.T) { BackupReader: tc.tarball, CSIVolumeSnapshots: tc.csiVolumeSnapshots, RestoreVolumeInfoTracker: volume.NewRestoreVolInfoTracker(tc.restore, h.log, test.NewFakeControllerRuntimeClient(t)), + BackupVolumeInfoMap: tc.volumeInfoMap, } warnings, errs := h.restorer.Restore( data,