diff --git a/changelogs/unreleased/10252-Ralthos b/changelogs/unreleased/10252-Ralthos new file mode 100644 index 000000000..8766a8d42 --- /dev/null +++ b/changelogs/unreleased/10252-Ralthos @@ -0,0 +1 @@ +Skip signing a download URL when no artifacts can exist yet, and set a Failed phase with the reason so callers stop waiting diff --git a/config/crd/v1/bases/velero.io_downloadrequests.yaml b/config/crd/v1/bases/velero.io_downloadrequests.yaml index 3234cbb73..771bf8daf 100644 --- a/config/crd/v1/bases/velero.io_downloadrequests.yaml +++ b/config/crd/v1/bases/velero.io_downloadrequests.yaml @@ -105,6 +105,10 @@ spec: format: date-time nullable: true type: string + message: + description: Message explains a Failed phase. It is empty in every + other phase. + type: string phase: description: |- Phase is the current state of the DownloadRequest. Processed means a URL has been @@ -115,6 +119,7 @@ spec: enum: - New - Processed + - Failed type: string type: object type: object diff --git a/config/crd/v1/crds/crds.go b/config/crd/v1/crds/crds.go index ba0734e53..78803dfeb 100644 --- a/config/crd/v1/crds/crds.go +++ b/config/crd/v1/crds/crds.go @@ -33,7 +33,7 @@ var rawCRDs = [][]byte{ []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec}_s#)\x92\xf8{\x7f\n¿\x87\xd9ݐ\xe4\xed\xf8\xdd]\\\xf8\xcd\xe3\xee\xdeQ\xecL\xb7\xb7\xed\xf1<\xa3\xaa\x94Ę\x82\x1a\xa0\xe4\xd6\xee\xedw\xbf \x81\xfaK\xa9\x90,{z\xf7\x9a\x97n\xab !\xff\x90\x99$\t\xcc\xe7\xf37\xb4d\x0f\xa04\x93\xe2\x8aВ\xc1\x17\x03\xc2\xfe\xa5\x17\x8f\xff\xad\x17L^\xee\u07beyd\"\xbf\"7\x956\xb2\xf8\fZV*\x83w\xb0f\x82\x19&ś\x02\fͩ\xa1Wo\b\xa1BHC\xed\xcf\xda\xfeIH&\x85Q\x92sP\xf3\r\x88\xc5c\xb5\x82U\xc5x\x0e\n\x81\x87\xaew\x7f^\xbc\xfd\xaf\xc5\x7f\xbe!D\xd0\x02\xaeȊf\x8fU\xa9\x17;\xe0\xa0\xe4\x82\xc97\xba\x84̂\xdc(Y\x95W\xa4\xf9\xe0\x9a\xf8\xee\xdcP\xbf\xc7\xd6\xf8\x03g\xda\xfc\xb5\xf5\xe3\x8fL\x1b\xfcP\xf2JQ^\xf7\x84\xbf\xe9\xadT\xe6c\x03mNV\xf4\xd1}abSq\xaaB\xfd7\x84\xe8L\x96pE\xb0zI3\xc8\xdf\x10\xe2\xf1\xc1\xe6sB\xf3\x1c)D\xf9\xadb\u0080\xba\x91\xbc*D\r<\a\x9d)V\x1a\xa4\x80\x1b\x1eц\x9aJ\x13]e[B5\xf9\bO\x97Kq\xab\xe4F\x81v\x83$\xe4W-\xc5-5\xdb+\xb2p\xd5\x17\xe5\x96j\xf0_\x1d\x01\xef\xf0\x83\xff\xc9\xec\xedH\xb5QLlb}\xdfKC9\x11U\xb1\x02E䚀RRi\xc2\xe5f\x039\xc9+ێ\x98-4\xc8LJ\xe1\xdau\xc6\xf1\xbe\xfd\x93\x1b\x87%\xc5\x06T\xca@\x9e\xa8\x12LlN\x18Jh\xd9\x19\xcc/\xdd\x1f\xa7\x87\xb3\x05bX\x01\xad\x0e\xc9\x13ՖI\xca \xc3\xe3\x9d\xe3\xf7{V\x806\xb4(\xfb|i5u#ȩ\x01\xdf}\vV\x98V\x8bL\x01Ψ8\xc0\xeb\rā\xb9ϻ\xb7N~\xb3-\x14\xf4\xcaה%\x88\xeb\xdb\xe5\xc3\xff\xbf\xeb\xfcL\xba\xd8\xffϼ\xfe\x9d\x04\xf1d\x9aP\xf2\x80s\x8f(\xaf\n\x88\xd9RC\x14\x94\n4\b\xa3\x91Z\x19-M\xa5\xc02\xf1\xaf\xd5\n\x94\x00\x03\xba\x05/\xe3\x956\xa0PށPC()%\x13\x860\xe1H\xfe\x87\xeb\xdb%\x91\xab_!3\x9aP\x91\x13\xaa\xb5\xcc\x185\x90\x93\x9d\x9dG\xe0\xda\xfeqQC-\x95,A\x19\x16\xa6\xaf+-\r\xd7\xfa\xf5\x10\xae\xb6X\xf2\xb8V$\xb7\xaa\x0e\x1cZ~\x82C\xee)j\xf13[\xa6\x1b\xf4\x91U\xf6g*\xfc\xf0\x17=\xd0w\xa0,\x18\xabm*\x9e[\r\xb9\x03e\t\x98ɍ`\x7f\xafakb$vʩ\x01mPP\x95\xa0\x9c\xec(\xaf`f\x89҃\\\xd0=Q`\xfb$\x95h\xc1\xc3\x06\xba?\x8e\x9f\xa4\x02\xc2\xc4Z^\x91\xad1\xa5\xbe\xba\xbc\xdc0\x13\xf4~&\x8b\xa2\x12\xcc\xec/Q\x85\xb3Ue\xa4җ9\xec\x80_j\xb6\x99S\x95m\x99\x81̲\xf9\x92\x96l\x8e\x88\b\xd4\xfd\x8b\"\xff\x7fA\xd8\x1b\xb4\x8dd\x05\xa4*\xed$\xcd\xfb\x15\x96\x82\xdc\xd0\x02\xf8\r\xd5\xf0ʼ\xb2\\\xd1s˄$n\xb5-~\xbf\xb2#o\xebC0\xdc#\xacu\x8a宄\xac3\xd1l+\xb6f\x99\x9bNk\xa9\x1a\xbd\xe3\x14q\x97B\xf1\xa9o\x8b\xab}o\xc7\xd6\xfb\x12\x1d\x88\xad\x18:\aM\xb6\xf2)h\x1b\x8b\xb0\x159\v\x10rR\x953\xf2\xc4\xccv\x00\x94\x90Rj\xcdV\x1c\xfc\xbc#Ld\xbcʭH~\xa88Ge\xb6\x14\x99\x82ª\v\xdeg5! \xaab8\xd89\xb6\x8e\xfc܂5\xf8:\xc2@[2\xcd\xee\x04-\xf5V\xa2\xa9\x92\x95\x99 \xd0`\x12\xdars\xb7\xecAiQ\xcf\x04\xfbYiȭ6{\xa2\xcc 3o\xee\x96\xe4\x01\xe9\x1aZ\a\xcf\xc7TJ\xd8\xe9\x13\xe9\xeb3\xd0|\x7f/\x7f\xd6\x10\x1c\x81`\x1agd\x05k;E\x14\xd8\xf6\xf6\x13\xfa\"օ2nXC2\x13\xb4\xef9\xaciōW L\x93\xb7\x7f&\x05\x13\x95\x19\xcc\xc1\x83Դ\xd2Q\xc8\x1d\xa8S\x88\xf8\x8e\x1a\xfa\x93mܣ\x1d\x8a\x1cB\xb5\xc4[y:\xae\xf6-\x7f$\x86\xd6r݂\xc84\xb9\xb8 R\x91\v\xe72_\xcc\x1ch\x8f\xb6u\xc6͜\x89v_O\x8c\xf3\xd0\xdbqDp@\x1dc\xf5\xbd\xfc\xa0ݤ:\x89&#\xb0Z$zڂق\"\xa5\xac]\x825\xe3@\xf4^\x1b(\x82\xc3\xe6ͬ\xc7'\xd2\x13*\x17\xce=\bm\xe9\xeb\x11\x19\"/*\xce\xe9\x8a\xc3\x151\xaa\x82\x11ڬ\xa4\xe4@\xc5\x04q>\x836,;\ai\x1c\xa4\ba\x94\xffС\x00z\x15\xf4\x11\b\x8d\x80\xf64\xb3\xee\v\xe7-\xc2v\xa9\x12\x1dS\xa9 \xb3f\xedʛK\x06\x1cM\xb4\x90\x84K\xb1\x01\xe5z\xb7\xda/\b\x98\x02+p9\xb1\x96H\x01\xb7斬+k\xa4\x16\xc4\xce\xf2Q\x19`B\x1b\xa0\x11\xe1|\x06\x7f\xe0\x8b\xd5Ґ\xdf8\xcf\xf4\xce.\xef\xf2\xb0\xdc\x1d\x98\x95\x14>\xbd?\bѻ/\x9ce\xe8%{\x87x\x8e\xcbʘ\x986^\x8c5Q\xb8浬\xf4\xc3nܓ\x83zA\x83\xb1\x8d.\xfet1C\x0ew{\xed\xf6\xa1\tUP\x93%Y\x7fBQ\x9a\xfd\xb063PD\xa8xP\x9f$\xf2\x93*E\xf7#ܬ\x97\xe7g\xe4\xe7\x18\xcc\x1eGE\xa8\xf6\xca<\xed\xf7\xfb\xef\xcc\xd5\xf3\xf0Qc\x98\x8a2a\xf9Ǚ6\x1d\xf6i\xb7\xc0\xb5d\x13\xd2D\xe09\xff\x0er\\\xbb\x1e\xe0\xd6\xefD\xac\xb3\xc8\xfc\x98\x90ײ\xe5\x85\xf7_\x92R[)\x1f\xa7\xa8\xf3\x83\xadӬ\x1aI\x86\xe1P\xb2\x82-\xdd1\xa9<ꍩ\x85/\x90U&:\xeb\xa9!9[\xafAY8\x18\xba\xd3.\x8e0N\x90\xf1\xf5\ri\xa9\x91\xe8\xc7\x1e\x1e\r#-\x9b\x10\xf3\xb1\xa1[?\xa2o%C\xb1\x03\xb5n6\x1a\xe3\x9c\xedX^Q\x8ev\x99\x8a\xcc\xe1C\xebqŴ\xcc\x01&\x0f\xc6\x1c\x95LW\x9cC\x10\x90\xb2L\xea,%\xa5\x00\xeb\xfb\x16vm0\xac:\x8e\xf9\x8aZ_E\x8eaO\x90Y\xaa\xe2\xa0}W9\xba\x91\x8dΘ5L\xc1H\r\xe1t\x05\x9ch\xe0\x90\x19\xa9\xe2\x14\x99\xe2\xb3+)Jp\x84\x90\x11\xcd\xd7]q4\b\x1c\x00Ip)\xb7e\xd9ֹzV\x88\x10\x0e\xc9%X\x87\xcf\x10Z\x960\xe7\x80ڕ\xddE3\xbf\x9d\xb6\xbfp\xfb%\xd8\t\xcd\xd0c\xc1\xb6\xa5\x92\x19\xe8\xe8^vS\x12\xecE$[\xa4\x8d{\x1ds\xa4n\x95\xe4rV\x0e\x87@CIwy-!\x8e\\/\xbc\xff\xd2\n\x88ڹo\xff\x9e\x92\xb1c\xc7E0\u05f7(h?\x8f+i\x887\xaee\x98\r\x1e\x90[|\xa8M\x85\x9a Ֆ\xd7\x02\xf858\n\x05\x13K쀼}\x01\xc7\xc2\xeb\xd0X\xd2I\xac\x9c\xe6\xcaބN\x1a\xee\xd4?\xb8\xa9\\J\xdc*P\xd0a\xde0\xaa\x8e~\xa8\x90\xa6\x15\x908\xc2\xdd,e\xfe\x9d&k\xa6\xb4i\x0fA\x8f\xa4\xa9D\xc1\x1c\xb9\xf0\x12\x98\xbd|\x02q?\xb9\x96\xbdD2\x9f\xbf\xe6\b\x93\x889\xee/\x01ak\xc2\f\x01\x91\xc9J`\x00\xc7\xcec\xec\xc2\x11\xd7iX\x96:I\xd2f?\x19\xcdE\x8b\x959J\n\x13\a#=\xed\xea\x1f(\x1b&\xac\xc5ʑl3c\xd9l\xb1rڜ\b\xa9n\xed\x8cł~aEU\x10ZX\x1e\xa11g\x05t\x99\xde$\xc0\xd9\x16h&\x8c\xb43\xa6\xe4`\xc0'\xb1%\x8e!\x93B\xb3\x1cj\xe3\xea\x05A\nBɚ2^\xa9D\rx\x14y\x8fY\x8axMp\xbe5FZ\xe7s$EB47\xd1W<\xac\x8dK\x95\xee\xf1M\xb9Y\n\x8e\xf7\xb2J\xc5$\xa6\a\x9e\xd9\xd1\xf2\t\x95T\xec\xbfyZ\xa9C\xfd\xe6i\x1d*\xdf<\xad\x89\xf2\xcd\xd3\xfa\xe6i\xa5\xd4\xfc\xe6i}\xf3\xb4\xda\xe5\xff\x84\xa755\xa29\xc6\xd0F>N\x8e\"a\xab\xfa\xd0\x10\x0f\xc0\xf7\xc9\x15>\a\xfcY\xb9\x98\xcb8\xa8H\xe2\xffHZwLi5ƣNδ\xb3&ȼ;\x7f5\xe1J>#\xeb>tz\xbe\xac\xfb\xe5A\x88gʺ\xf7Þ\xf6\xb1Oʹ\x0fD9.;{\xe6\x135\n\xa0!\xac\xee\xb6\xe1cx\x8dI\xc8D\xff\xaf\x9c\x98;\xc8\x1a;\xa3|\xbcx\x16\x7f\xb2\x8cDYz\U000672ef\x8f\xfc\xe7!\xf8(\x89\x87\xb4\xf3\a\xc0#P\xed\n\xb4\x9d\x16\xd6\xcd\xc2\xfb:\xc5\xf8,r\x9b\x9a\x89_\x131\x02\xab+\x92=*~\xad\xba\xc0@\xf1\xa9\xf4\x16\xe9\x19'V\x97\x118IgV\xa9ދl\xab\xa4\x90\x95\xf6Q\t\v\xeb:s'\xfe\x03Ș\xb0Fg\xf8\x7f\x90\xad\xac\"\x99\xe0\a\xc87\x91\x118\x8d|'9\xd0oB\x83\xa1\xbb\xb7\x8b\xee\x17#}\xaa\xe0\xd8\x19\xe7\xa7-\b\xdca\x17\x9b\xf6\x01\x80pa\x83\xbf\xb9\xa0/`\x11@R\x11\xc1\xb8\x93\xbc\xfa\xba\x87\xb6ܑO\xa5\x8b=\x1d\xedw\x1c\x8e\xa9\xa4%\x13\x9e\x9cB\xd8M\x11\x1c\xf1K\x8f\xdd\xed>ˑ\x89\xdf%5\xf0\xf8\x84\xc0\x94\x88\xd8D\xf2\xdf\t)\x7f\x89\xb9\xc5\xcfޞOI\xea;f\xc5\xfcb\t|\xe7O\xdbK\xa2\xcft\x8a\xde1\xd4y\xf1t\xbcWL\xc2{\x9dԻĄ\xbb\xf3eΧ\xc5cO\xca\x1c\x9b\x0e\x1d\x8c'\xcdM\xa6\xcaM\x86\x16\xa6\x10;\x1a\xa5\xc9\x14\xb8c\x12\xdf&\xb9\x936\xcd^-\xb5\xed\xd5\x12\xda^7\x8d\xed\xa0\x14\x1d\xfcxL\xa2Z\xfc\xde\x1e2il\a\xb7\xfa\r*\x9cS\xe2\x92cq\xa3\x93\x8e\xbf\xd6\xe48\x95mRu\xdc\xed\x93փ\x9fz0\xac\xa0\x06W\xf4\x95|\xfa\xa2↕\x1c7~w,\x8f\x06G\xcc\x16\xf6\xf5\x85\x1f\xbfJ<*\xebo\xb0\xf9\xf4\xb9\x9ee\x8b\xdeʄj\xf2\x04\x9c\x13\x1a\xd3\x03\x03\xcc3w\xb5V&\xe7`\xed\xa7\xd5&\xfe\"\x13\x7f\x1f\xd7\xccMO<\r\x8cV\xb8\x88\x85Ĩ\x18\xbf\xf5f\xd4Х\xe8ǁ\xc7\xed\xd6\r\xf8\xdbo\x15\xa8=\xc1{wj\xbf\xac9\xb4\xe6\x15\x89\xb6\vǠڼ\x9a\x1d\x8b\xf7\x0f\x16)\x8d\xea!\xd7\xc2y\t\xfd\xf1`\x1b\xabӚE\x98U\xd4\"v\xe1\x14\t\x13l\xd8\\Ⱥu\xa4ٔC\x9fz\xba\xebe\x97d\xc7/\xca&\xbd\xa0tO\xf5w:\xb5u\xcai\xad\xb4\x84\x85\xc9\xd3Y/\xb5D\x9bZ\xa4%\xfb\xa5i\xa7\xaf\x8e\xdb\xdc|\xc1\xd3V/q\xca*\x91R)\xa7\xaa\x8e\xa3\xd3+\x9c\xa2z\xd5\xd3S\xafuj*\xf9\xb4TRJN\xf2\xaeujJ͉\xc7\x7f\xa6\xf7\xa4\x0f\x9f~J8\xf5\x94\xb0[=\x8d\xe4\t\xe8%\x9cj:\xee4S\x02\xcfR\xa7\xe2+\x9eZz\xc5\xd3J\xaf}JiB\xb2&>\x1fw\x1a\xe9\xe4-\x16\xa9rP\a\xb7\xa9R\xa5\xf0\xa0\xfc\xa5\xacm\xba\x03\xe9\xedτ[\nm\xad\x8e\xbf\x8c\xe6\xc1\xdf\x1c\x8bw\x04\x8fm\xb7ZIky\x1b\x9d\xbd\xb3\xc6\xfd\xe9:\x93\xfe\xe2`\xb7\xbd\xa6\xa1\xa4\n/\xa3^\xed]\xfaM\xd44\xbf\xa7ٶ\a}K5YKUPC.\xea\r\xcbK\a\xdc\xfe}\xb1 䃬s8\xda\xf7\biV\x94|oW(\xe4\xa2\xdd\xe04\t\x88J[\xe8\xedVr\x96E|\xb7\xe8]R\xae\xf2\xe0r\x0f\xbc\xe1*k\xa78\x94\xb6b\xdcuC7\xaf{e\xe7Zr.\x9f\x8e\x8dU\x94\xec/\xf8D\xc03\xa2Y\u05f7K\x84\x11\xc4\x03\xdf\x1c\xa8\x93\xc9jlV`\xcdr\x83\xe7\xd8\xdc_\xae;\x10\xbby\x99\xedێ!w\x17[\a\xb7\xc0\xab\xceLZ\xedr\xbbt\xe3\x18\xeb\xc5\xca\f\x15{\"1\x03\xc8l\x99\xca\xe7%Uf\xef\x12Kf\x9d1\x04[z(\x1a5j=\x86\x97uG\xc9\x1b\xee\xe8\xc6\x1d\xd5}\xd9ݤ\xee\xd3\xee\x94q\x8c\x9f\xb6\x9c\xc4[\xb5\x9c㖾pޱ\\G\x10\x18\x83\xd3z\xd8\xe5\x89\x19\x7f\xd1\xd8yo\x86\x1d[\xf2\x8c=Y\x81O\x11L?Z\xe1^,\xf0O\xdd\xf8\xe9X)\xbc\xd6տf\x80נ>\xe3݊N\xb2\x9a\xbe6\x06\x8a\xd2\xc4|\x8diu\xf8\xfd!\x80\xb5\x9f\xd6{\x80\x89\x86\n1O[\xefEv(\x11\xcek\xa3\x03\xdc<4\x1fc\x04\xb8\xf1\xe77\xceF\x80\x1a\xe0\x18\x01t\x95e\xa0\xf5\xba\xe2|_\x1f\x1f\xf9J\xa8\xf1\x812~>R8h\xa3\x82`\xd1;\bi\x12a\x9f\x9e\x0e\"\x0f3=\x1c\xad:\x8e\x14\x9e\v\xed\x17\xb1N\xa1\xc1\xcd\x10\f\xbe\xc1\xa4\xf2V\x12(m?\xfbU\xb3?f\\\x1ap\xae%.\xb2,4\xc8\t\xec@\x10k\x9d\x1d\x89\xc3\xe3vGB\xf1'r\x9d\x85\xeb>\x836\xf2\xd2\x14\xf1\xd1\x0e\x8d/\x1a}\xa7k\x98\x98ۊ\xef\xb0\f\x890t~]\xb4\xc2=-6\xb7 N\xf3Z\xc7^\xa1\xe9څ\xe7)\xb9\x9b\xbb\xe5\x18\xb8ST\xdc\xf0\x99\x9agN\xe3!\xba\xcfRiCt\x8fRh\x11\x88\xb5\x8c\x9f\x1fw\xf7:\xe0I\x97л\xf7\b\xd1\xe1\xc8\u0099?ʹ?\x98Y\x80\xd6t\x13n\x9f\x7f\xb2K\x8f\r\bp\xe19\xb7y\x12\x01ڜ\xe2\xeb\u07bd\xee\xa6\f\xcdLEyx\t\xd1%$\xb7j}\x87O\x12F\xa0\xe2\x034,<\xfd\x16\xd6dG\x12\xeaK\xc9T\xca\x1a\xee}]\xd1\xd2\x06=a\xe4N\xf3X\x1fp\xb6\xc1\xa7\xa8,\xe76T\xad\xe8\x06\xe6\x99\xe4\x1cP[\x0f\xc7\xf5\x92sݟ\x95\xfc\fTO\xa2\xf6\xa1]\xd7\xef\x00:n\xbb\x8do\xea\xd2\xf3\xf196\xc3T\xef=\xc8\u0380$v|\x94\xa3\xec\xa8\x10}6p8\xd2v\xdd0\xeb\xbcZ\xf6q^\xffj\xe0\xacy\t,2\u0382\xfe*Ռ\x14L\xd8\x7f\xa8\xc8\xdd\x06^h|\xd4\xf8\xb7R>\xdeE\x9c\xd8\xc1\xe0\x7f\xa8+6[\x1dL\xb8a\xe3\x01ו\xac\xfc\xee{\xed\xd0ƷU\xf0%\x813/7\x11\xe6\x01{0@g4\xa2\xfbC\aҤ)p=\x8f\xc0\xba\vO\xd3q\xbe\x9f\xf5!\xf7\x9e\xc1l`\xb7^Z\xf0n@s\x7f\xc2HGaG*\n\xa4\xbe\xa8\xa3\xad\xd0OY\xf5z2\x8f9\x93\x03\x1a\xff\xd0\xd4\x1e\xa3\xa3\x1bf\xcb\xdd\x1bA\xb0\xe3\x04\x9ew\xc1\x8e\xcfjL\b\xff\xad\xadSߵ\xd0Z\xb8\x85,\xb1\xd1(\xdd\xd8\v}\x1fa\xb8]1'\x7f\xab\xa0\x8a\xd0`\x1e\x1e\xb4\xc37a#\x9f\x1d\x911\xa3\x03gc\xa4\xca\xe0m\xe0\xf6\xc7_(3Ll>Hu˫\r\x13\x9fƏ(\x1d\xaa|K\x95aV\xd8\xddxb\x03e\x82r\xf6\xf7\x98^k\x7f\x9c\x06t3\xba\xc0\x9a\x93\x84a\x8c}x\a\xd6\xc7\x1d\x8d\vDUh\xe9\xe9z\x8a\xbf\x12x2\xa5Sk_\xa2\xf1EB\xb7\v\xf2QF\x15\x83O\x87b]\x98\xd6%\x03m\xe6\xb0^Ke\xdcn\xf5|N\xd8:\x04\x1f\xac\xce\xc1\xb8\x99{|\x94\xb0\xd86s\x9dhҘ/\fz+\xb4\xc2x\xf5~A\xf7ng\x8afYe=\xacKm(\x8f88\xcfR\xfc\x18\xe5\xf9\x1e\x1f\xda\xfc\xf9Y;y\xcb6\xa0a\xd0\x11\xfbq$\xc5\xcb?\x9c\xd7\xc7-\x8a ȓb\xc6X\x9fJ\x1eH%\xf0\xa42ַ\xe2\x9chKꓢ\x8fĩ\xd1\xe5xJN\x1a\xca\xf75\x941\xf5\xec\xb1\xc6\x17%\xeb\xd7L}\xf6\x91\xafeٜm\xa9،ި\xb0U\xb2\xdal\x83$\x8f8\xd3$\xaf\x00\x83\xb5\xa8Rtx)\xdaTJ\xb4R\t\x0e\x1cS'A\x18p\xb84{\xc4wW\xddK\xcc\xfe\x01\xf8K\xfff\xcb|\xadd1\xf7\xfdb,u\xe6w\xf2\x15\x93\xd6s1\xdb(Չ\xf3\xda\xfd\xb3\b(\te\t\x82P\xed{N\xb8\xd9\xead3\xf5\x9b5\r\xb7R\xb3\x04o?\xca\xf1\xbf\xb5\x01\x04\x86\x97\xe1\xef.3\xfc\n\x06\xfb\x8c\xe1\xf1\xc9_\x19\x00;*\x8c[N\xd4&\xf2\xc2\x19\xb1\x8b\xa3\x162\xddw\xd0Oڻ\xeb@\x98\x88\xcf\xf8g\xd9c\xa8\xdd\xf9t\rwq\xd9M\xffE\xf5\x19\xd1L\x84\x97\xcc]ꇓ\xfe\xe8N\xa0\xc0\x875\xa5\x8agc\x1e\x0e\xb8t\x11z\xddXˮ\xf6$ޟ\xbc\x14\x7f\xe8\xc1\xe8\x1dB\xc7wT\xeb*a\xf9\xfc\a\x16\xdb\x0f\xc04\xde̢\xf2\xc7\xdf\xfdp\xf9.i\xa9\x17\xa7ȡ\x95\x1f.\xeaƗp\xddwSo9\xd8٦\x01\xba\x8bʣ\xe6\xdc\xee\x8cѴs\x86\xd2\u009b\xfd\xe7\x89%\xed\xce\x18D{\xb1\b\xdayQ~\xa2\xf8\xb0\xf5I\xb3\xf6\x17\xdf6\x12B\xf3`\xcf\x1dDk\xc5\xd0\xc2\xc0_5\x8a\x16\xb5\xb9\x83\x1fQO\xe7-m\xe1{j\xffR\xad\x9a\xe7\x15\xc9?\xfe\xf9\xe6\x7f\x03\x00\x00\xff\xff\xc3!Ko6\x87\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xccZK\x93۸\x11\xbe\xebWt\xed\x1e\xf6\xb2\x94줒J\xe96\x96\x93*W\xc6\xf1\xd4hvr]\bhJ\xb0@\x80\x01@\xc9\xca㿧\x1a\x0f\x89\xe2C\x0f;q\u008b-\x12h\xf4\xf3\xeb\x0f\xc0\x14E1a\xb5|E\xeb\xa4\xd1s`\xb5\xc4/\x1e5\xfdr\xd3\xed\x1f\xdcT\x9a\xd9\xee\xedd+\xb5\x98âq\xdeT\xcf\xe8Lc9\xbe\xc7Rj\xe9\xa5ѓ\n=\x13̳\xf9\x04\x80im<\xa3\u05ce~\x02p\xa3\xbd5J\xa1-֨\xa7\xdbf\x85\xabF*\x816\b\xcfK\xef\xdeL\xdf\xfe~\xfa\xbb\t\x80f\x15\xcea\xc5\xf8\xb6\xa9\x9d7\x96\xadQ\x19\x1eENw\xa8К\xa94\x13W#\xa7\x15\xd6\xd64\xf5\x1cN\x1f\xa2\x84\xb4z\xd4\xfc]\x10\xb6\x8c\xc2\x1e\x93\xb0\xf0]I\xe7\xff<>\xe6Q:\x1f\xc6ժ\xb1L\x8d\xa9\x15\x86\xb8\x8d\xb1\xfe/\xa7\xa5\vX9\x15\xbfH\xbdn\x14\xb3#\xd3'\x00\x8e\x9b\x1a\xe7\x10f\u05cc\xa3\x98\x00$\xd7\x04i\x050!\x82\xb3\x99z\xb2R{\xb4\v\xa3\x9aJ\x1f\xd7\x12踕\xb5\x0fΌ\xb6@2\x06\xb25\xe0<\xf3\x8d\x03\xd7\xf0\r0\a\x0f;&\x15[)\x9c\xfd\xa2Y\xfe\x7f\x90\a\xf0\xd9\x19\xfd\xc4\xfcf\x0e\xd38kZo\x98\xcb_c\x8c\x9eZo\xfc\x81\fp\xdeJ\xbd\x1eR\xe9\x919\xffʔ\x14A\x93\x17Y!H\a~\x83\xa0\x98\xf3\xe0\xe9\x05\xfd\x8a\x1e\x02r\x11B\xf6\x10\xec\x99K\xeb\x00좔\xe0\xa3aMUo\xad3\xb5I\x15x\xedH\x89\xfaӛ\xa4}Kl\xce\xef)\xb7x\x14\xe9<\xab\xea3\xb9\x0fk\x1c\x13v\xe6\x8a\xf7X\xb2F\xf9\xb6\xa9\x14%\xd5\xce\xcbs\xb3j\xe4S\x11g\x9d\xad\xf8\xfe\xec]\\ue\x8cB\x16\xa5\xc4Q\xbb\xb71\v\xf9\x06+6O\x83M\x8d\xfa\xe1\xe9\xc3\xebo\x97g\xafa(\x91:EA\x81c\xad\xd8l\xd0\"\xbc\x86\xfa\x8bqsɴ\xa3L\x00\xb3\xfa\x8cܟ\x82X[S\xa3\xf52\x17K|ZX\xd4z\xdb\xd1\xe9\x9f\xc5\xd97\x002#\xce\x02A\xa0\x841\xafR\xfd\xa0H\x96\x83)\xc1o\xa4\x03\x8b\xb5E\x87:\xc2\x14\xbdf:)8\xed\x88^\xa2%1Tۍ\x12\x84e;\xb4\x1e,r\xb3\xd6\xf2\xefG\xd9\x0e\xbcI\xc9\xec\xd1y\b\x15\xaa\x99\xa2dm\xf0g`Zt$W\xec\x00\x16iMhtK^\x98\xe0\xbaz|\xa4j\x90\xba4s\xd8x_\xbb\xf9l\xb6\x96>#47U\xd5h\xe9\x0f\xb3\x00\xb6r\xd5xc\xddL\xe0\x0e\xd5\xcc\xc9u\xc1,\xdfH\x8f\xdc7\x16g\xac\x96E0DGH\xadď6a\xba;[\xb6W\xd2\xf1\t\x90zGx\b^c\xcaDQ\xd1\xc4S\x14\xe8\x15\xb9\xee\xf9\x8f\xcb\x17Ț\xc4HŠ\x9c\x86\xf6\xfc\x92\xe3Cޔ\xbaD\x1b\xe7\x95\xd6TA&jQ\x1b\xa9}\xf8\xc1\x95D\xed\xc15\xabJzJ\x83\xbf5\xe8<\x85\xae+v\x11\xba\x18\xac\x10\x9a:\x80Dw\xc0\a\r\vV\xa1Z0\x87\xdf9V\x14\x15WP\x10n\x8aV\xbb7w\aG\xf7\xb6>\xe4\x9e:\x12\xdaA4X\xd6\xc8\xcf\xeaN\xa0\x93\x96*\xc33\x8f\xa1\xba:\x0eJP1ޔ\xf33\f\x12\xf40\xceѹ\x8fF`\xf7KG\xe5\x87\xe3\xc03\x1dk\xb4\x95t\xa1\xbdBil\xb7\xf3\xb0#\x92\xb7\x9f\x8cx݀\x03\xa0n\xaa\xbe\"\x05<#\x13\x9f\xb4:\x8c|\xfa\xab\x95\xbe\xbf\xd0H \xe9\x89*.\x0f\x9a?\xa1\x95F\\1\xfe]g\xf8\xd1\x05\x1b\xb3\x872\xe4\xbf\xf6\xea@\xd8\xe5\x0e\x9a\xf7Q;?\x0fO\x1f2\x82\xc7\xdaJ\x85\x99|5\x85\x87TԦ\x847 \xa4#\"\xe1\x82о\xb3t\xa3\x02ј\x83\xb7\xcd]\xe6s\xa3K\xb9\xee\x1b\xdd\xe6Fc\x19sEt\xc7s\x8b\xb0\x12\xa1\x16eGm\xcdN\n\xb4\x05Շ,%O\x9a46v\x90R\xa2\x12=l\x1a\xad\xb2`\x8aEAE\xcdԕ\x18.\x8e\x03\x03\x93fR\xc7\f>\t\bXc\xabԚ\xb5G-\xb0\xdbm\x826&\x00\x9aC\x01{\xe97\x11)\xd5P\xdd\xc1\xc5ڣg\x8b\x87\xa1\xd7\x1d\xdd_6H#c\xe3Ep\xc8-\xfa\x90m\xa8(}(\x95\xa6\x00\x1f\x1b\x17\xb0\xb6\x8b\x13\xf9\t\x84/\xcf\xde\xe2\xa1\xefh\xb8\x16\xdcD\x85FT\x0e$j\x0e?\xfcpݤ^w\xcb\x0fQ\xf7l\xa8\xc5\x12-\xea\x1e\x9b\xc8\xcfK\xe8Q\x944\x94aX\x96Ƚܡ:\x84\x9eD\xe0\xf93\xac\x1a\x0f\xa2\xc1\x105Ʒ{f\x85\x03n\xaa\x9ay\xb9\x92J\xfa\x03H7\"\x9f)e\xf6(Rı\xaa\xfda\n\x1f\xb4\xf3LstG\x1eD\x1e\x8b\xa9\xc0t\x1c\x95\xaa8\x10:f\x8700\x8a\xaf\x8c\xf3\xc0\xd1R:\xaa\x03\xec\xad\xd1\xeb1c\a\xda!\xed\x01\xadF\x8f\xa1#\n\xc3\x1d5C\x8e\xb5w3\xb3C\xbb\x93\xb8\x9f\xed\x8d\xddJ\xbd.H\xc1\"\x81\xcf,\xec\xecf?\x86\x7f\xbe&\vL\x1dq\xe2\x86\xe4]\x86Z?\x10\xbd\xf5\x1b\x8c-b\x19s\xd0X \x02A\xa9]\xa5܍\xc8:TvC\xbc\xbc\xfd\xe4\x90\x0f\xf5\x8f-\xf6[\xc7\x05P\x01\xf8R\x9c|[T\xac.\xe2h\xe6M%\xf9\xa4km\xcc\xfb\xcb\xf8\x937+R\vɉܞ\xe3F\xdeĉ\xb3=̀\x1b\xba\xbb\x9c1\xb4\x1cvS47q\x85+\x1a\x7fj\x8f=m}#t\xa7\xfe\xef\xd0\x13\xeft\xa0\x91\xf8\x01\xb3}?\a\xc0\xe4FkB*o\x80\x1d\xdb\xc0O\xae\xdb\xff\xeeD\xcfU÷8\xe0\xf8\x9e)\xef\xc2\xc0\xec\xe38\x8dti\x1c\x86\xc6tM\r\xb8^\x11\x9c-\xd0ޢ\xcb(\xf2-\x1eH\u0091[0X<\xc0\xaa\xd1BaVu\xbfAM\xdb1Y\x1e\x88\xec\xbf<.\xb3c\x03\x01K[\xa7\xec\xde1 yO\xbb\x00JA1\x87_\x1c\xa6u\x9f\xb1\x04\xa9\x9dG\xd6#\xe9\xf1\x89\xbdq\x0e\xab\xc3\x00\u05fa\xd9A\xcfX~\xbb\x8f\x82\xae\xe4\xa1\xd4 8\xc6\xc4J\xb0\x92\xfa{\xde\x0f-\x1e\x02\xc4\x12\xdf \"}\xe6ґe\xeetth\xd0i\xf1\fdR\xc7\x02a\xd5\xd8\":\x1fR\x01\x8by9H䇃q\xb9.\xe0\x12\xb3\xe89\xfb>v1*\x13\x80\xdd\xc80\xe0z\xb2\xc0E\xa6\x017\xb0\x8d\x9e\x99\xa39\x05w\xb2\x0e\xf8\x0e\xcc\x03\xfe\xfb\xec\x03\xeef \xf0\xddY\bܖ)\x97\xd9\b|\x13#\xb9\xe0\x8bK\\\x05\xae\xf2\x15\xb8\xc8Y`\x94\xb7\xc05\xee\x02w\xf2\x17\bx\x82\xa5\xfcr\x032?\x85\x81\xb9\x93\xd6\xcco\xa8kH\x81\xc0\x06\xfaj<\xa1\x18q\xd0q\xd3\xfb)\x85\xef+\xfa\xee%\xd2\x17չ\x87\xf7e@\xbfB\x8c\x9eҰ\xa3\x17\xf2\xef\x04 \xe7\a c\x04mТ\xdd\xf1\xb4\xfdO\xf1X\x81\x0f\xa0\xf8\x992\xaf\xfd\x19\x17\x8e'\xf2\x99\xff\x10K\xa3Ͱ\xb1\x16]m\xb4\xa0\xb6w\xdb\xe1\xc4I\xe5\xff\xdc\x11\xc5pX\x8bs\xfa\xda\xf9\x96\xa3p\xd3\xf9\\\xb8߸\xfb\x84.\xde\xfa\xb4Ͽ\xccʡݵ\x0e\xe9:6~\x97\xb3\xb9\xc1\xce\xd6:\xb0#\xaa\xa4\xa1\xd1\xe1\xc8\"4\xad\xe9d`F\x9b\x17\xfa\xd0<\xa4\x03m\xf64\xb9%-v=\x13\xe9M8\xb4dZ\xa4\xe3b\xfa4 y/\x95\xa2\x1ef\xb12\xe4,\xd4^Zj\x96,\xb4\xb1\xddo\xa6o\xfewg\x81\x8a9\xbf\xc6Qq\xff\x99\xa6\x00[\x99\xc6\x0f\xf4\xfeV\xc2\x0f\xd6t\xb8e\xbfG\xc7\xf0\xb7\x03\xd7\xe8\t\x8d\xc9\x11፵\xe1\xb2._\"ݱ\xd1\x1cC\xe0\x87Ο8\xb4\xbf\xf5\xff\x00\xe2\x06\xbb\x06\xbbt\xefe촭\xb8&'\xb7\xdf4\xab\xe3\x15\xec\x1c\xfe\xf1\xafɿ\x03\x00\x00\xff\xff%\xff\\)\x99#\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcVK\x8f\xdb6\x10\xbe\xfbW\f\xd0k%wQ\xb4(tk69,\xda\x06\xc6n\x90;M\x8e-f)\x92\x9d\x19z\xeb>\xfe{AR\xf2C\xb67\xc9%\xba\x99\xf3\xe4\xf7\xcd|t\xd34\v\x15\xedG$\xb6\xc1w\xa0\xa2ſ\x04}\xfe\xc5\xed\xf3/\xdcڰ\xdc\xdd-\x9e\xad7\x1d\xdc'\x960<\"\x87D\x1a\xdf\xe2\xc6z+6\xf8ŀ\xa2\x8c\x12\xd5-\x00\x94\xf7AT>\xe6\xfc\x13@\a/\x14\x9cCj\xb6\xe8\xdb\xe7\xb4\xc6u\xb2\xce \x95\xe4S\xe9\xdd\x0f\xed\xdd\xcf\xedO\v\x00\xaf\x06\xec\xc0\xa0C\xc1\xb5\xd2\xcf)\x12\xfe\x99\x90\x85\xdb\x1d:\xa4\xd0ڰ\xe0\x88:\xe7\xdfRH\xb1\x83\xa3\xa1Ə\xb5k\xdfoK\xaa7%\xd5cMU\xacβ\xfcv\xcb\xe3w;zE\x97H\xb9\xeb\r\x15\a\xee\x03\xc9\xfbc\xd1\x06̚\xaa\xc5\xfamr\x8a\xae\x06/\x00X\x87\x88\x1d\x94ب4\x9a\x05\xc0\bH\xc9Հ2\xa6@\xac܊\xac\x17\xa4\xfb\xe0\xd2\xe0\x8f\x95\x905\xd9(\x05\xc2\x0f=\x96\xcbC\u0600\xf4\b\xb5\x1cH\x805\x8e\x1d\x98\x12\a\xf0\x89\x83_)\xe9;h3\x92mu͍\x8c\x0e\x95\x847\xf3c\xd9\xe7\x86Y\xc8\xfa\xed\xad\x16X\x94$\x9e\x9a(um\xf0@'ȟ7P\xfc\xdb\xd8+>\xaf\xfeT\f\xb7*W\x9f\xdd]EZ\xf78\xa8n\xf4\r\x11\xfd\xaf\xab\x87\x8f?>\x9d\x1d\xc3y\xafWH\aˠ\xa6N3p\x155\b\x1e!\x10\f\x81&T\xb9=$\x8d\x14\"\x92؉\xff\xfa\x9d\xac\xd5\xc9鬅\x7f\x9b3\x1b@\xee\xbaF\x81\xc9\xfb\x85\\@\x1c\x87\x02\xcdx\xd1\n\xaee \x8c\x84\x8c\xben\\>V\x1e\xc2\xfa\x13jig\xa9\x9f\x90r\x9a<\xaeə\xbc\x96;$\x01B\x1d\xb6\xde\xfe}\xc8\xcd\xf9\u07b9\xa8SR \xc9c畃\x9dr\t\xbf\a\xe5\xcd,\xf3\xa0\xf6@\x98kB\xf2'\xf9J\x00\xcf\xfb\xf8#\x83h\xfd&tЋD\xee\x96˭\x95Ilt\x18\x86\xe4\xad\xec\x97E7\xec:I ^\x1aܡ[\xb2\xdd6\x8ato\x05\xb5$¥\x8a\xb6)\x17\xf1Ep\xda\xc1|G\xa3<\xf1Yً\xe9\xa9_ч\xaf\xa0'\xabE\x9d\x91\x9a\xaa^\xf1\xc8B>\xca\xd0=\xbe{\xfa\x00S'\x95\xa9J\xca\xd1\xf5\x02\x97\x89\x9f\x8c\xa6\xf5\x1b\xa4\x1a\xb7\xa10\x94\x9c\xe8M\f\xd6K\xf9\xa1\x9dE/\xc0i=X\xe1ib3u\xf3\xb4\xf7E\x90\xb3\x02\xa4h\x94\xa0\x99;b\xa3\x13Q\x19\xbe\x83ΫkA_\x8a\x05\x12\x05\xba8\x9d5\xf5\xae8\x95\xff\x12\xcaz\x06\xe5\xf7c H\xaf\x04^\x90\xf2\x86萲Z\xa1\x01\x93.\xf0\x1ba9}\x93\"\x05\x8d|\xb1\x8a\x00Vp\xb8\xd2\xd3+\xec\xe4\xcf'\xe7\xd4\xdaa\aB\to0\xab\x88\xd4~f+o\xdfg Xe\x9fk\x1c\x1c\xde\xfbϒP\xe0\xf6i\xb8\xac\xd4\xc0{|\xb9r\xfa\xe0W\x14\xb6\x84<\x1f\xf9l\\U\xf4p\xfe\x1e\xbc\x82\xd2ա\xbc8\xe4,\x85\xe6\x04E\x96@j{\x8a+\xa7\xf5A\xe9;\xf8\xe7\xbf\xc5\xff\x01\x00\x00\xff\xffߙ6&\xcb\n\x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcWOs۶\x12\xbf\xebS\xec̻\xbc7\x13\xd2ɼ\xb4\xd3\xd1-Ur\xf0\xc4M=\xb6\x93;\b.I\xc4 \xc0\x02\v\xd9\xea\x9f\xef\xdeY\x80\xa4(\x8a\x92\xe5\x1eʓ\xb4X\xec\xdf\x1f~XdY\xb6\x12\x9d\xfa\x86\xce+k\xd6 :\x85τ\x86\xff\xf9\xfc\xf1'\x9f+{\xb5}\xb7zT\xa6\\\xc3&x\xb2\xed\x1dz\x1b\x9cďX)\xa3HY\xb3j\x91D)H\xacW\x00\xc2\x18K\x82Ş\xff\x02Hk\xc8Y\xad\xd1e5\x9a\xfc1\x14X\x04\xa5Kt\xd1\xf8\xe0z\xfb6\x7f\xf7c\xfe\xc3\n\xc0\x88\x16\xd7P\xda'\xa3\xad(\x1d\xfe\x16ГϷ\xa8\xd1\xd9\\ٕ\xefP\xb2\xed\xda\xd9Эa\xbf\x90\xf6\xf6~S\xcc\x1f{3w\xc9L\\\xd1\xca\xd3\xe7\xa5\xd5\x1b\xd5kt:8\xa1\x8f\x83\x88\x8b\xbe\xb1\x8e\xbe\xec\x1de\xc0\xebiI\x99:h\xe1\x8ev\xae\x00\xbc\xb4\x1d\xae!n\xec\x84\xc4r\x05\xd0g\x1f\re \xca2\xd6S\xe8[\xa7\f\xa1\xdbX\x1dZ\xb3w\x83^:\xd5Q\xac\xd7C\x83@\xbb\x0e\xc1VP)\x8d@vt\x1a\xf5\x01\xbe{kn\x055kȹd9\tW#\xe5\\\x98^#\x95\xfa!\xca\xe1\xf3^Ά\xd7\xe0\xc9)S\x9fr\xce{\xd995\b\xae\xc7D\xfc\x13\xa3Q\x1e\x84\xf7V*AX\u0093\xa2\xe6|Plm)\xa8/{\xf9%Ay\x12\x14\xfc\x10\xd6P\x0fp\x93\xee\x1f\x86\x10\xf5\xf3\xae\x11\xfe\xd0\xfd}\\8\xedybc@\x7f.\x1dF\xe0?\xa8\x16=\x89\xb6;\xb0\xf8\xa1>L\xa4\x14\x94\x04iy\xfb.!H6؊u\xafi;4\x1fn\xaf\xbf\xfd\xff\xfe@\f\x87\x89\xff\x99\x8dr\x98C:6b\xc8\x7f\x8a\x11\x10\x06\x84#U\tIP9\xdbB!\xe4c\xe8\xc0\x16\xdfQ\x12x\xb2N\xd4\xf8\x06|\x90\r\b\xb6\x92\x14&\xbe\xb4\xadc\xb7\xf3Q\xd69ۡ#5\x9c\x8d\xf4M(f\"=\x97\x05\x7f\x9cx\xda\x05%s\r\xfa\xd8\xd4\xfe\xcc`\xd9\xd7*5[yp\xd89\xf4h\x12\xfb\xb0X\x98>\x9b|f\xfa\x1e\x1d\x9b\xe1\xa3\x1ct\xc9\x14\xb5EG\xe0P\xdaڨ\xdfG۞+\xc6N\xb5\xa0XL>\x95Fh\xd8\n\x1d\xf0\r\x88\xf1\xc4\f_+v\xe00V0\x98\x89\xbd\xb8\xc1\xcf\xe3\xf8\xc5:\x04e*\xbb\x86\x86\xa8\xf3뫫Z\xd1@\xbcҶm0\x8avW\x91CU\x11\xc8:\x7fU\xe2\x16\xf5\x95Wu&\x9cl\x14\xa1\xa4\xe0\xf0Jt*\x8b\x89\x98H\xbey[\xfeg8\x96\xfe\xc0\xed\x11\x9a\xd3\x17\xf9\xf2\x15\xeda\xbaH\xe8J\xa6R\x8a\xfb.\xb0\x88Kw\xf7\xe9\xfeaJ\x10\xca\x0f\x10\x1bU\x8f\xea2\U00107ae9L\x85.\xed\x8b0e\x9bh\xca\xce*C\xf1\x8f\xd4\n\r\x81\x0fE\xab\xc8\x0fX\xe7\xd6\xcd\xcdn\xe2\xe5\x04\x05B\xe8\xf8\xf8\x95s\x85k\x03\x1bѢ\xde\b\x8f\xffr\xaf\xb8+>\xe3&\\ԭ\xe9\x95;WN\xe5\x9d,\f\x17\xe6\x89\xd6\xce(\xe3\xbeCɍ\xe5\xda\xf2NU)\x99\x8eTe\x1d\x88#V=,\xd42\x03\xc4\xe0\"\xa3ϥ\xb3Xz\xdaW\x1e\x9e\x1aqHX\xffżΙs|\x1fH\xe2\xa3\xff\xcd\x1bu.\x06X\x04\xfab$\x03\xbe\xe9\xccE{\xec\x9a?4\xa1]v\x90\xc1\xcf1\xe6\x1b[\x9f]\xdfXC|.\xce*}\xe3\xe9\x00\xef\x8d\xe8|c_н&l\x7f\xedХ\xc1\xec\xac\xea0ߍ\xc3\xd0\x19ŠO\xfa\xbdC\xbeA\xf0t\xa6\xbd\xc2EV.\x88\xa9\u05fc(\xd1\xcd\xfd\xf5kJxB\xfd\x15M\xba6\x95}!Ž\xe2\xa2\xde\t\x1a\x18\xbe8C\xbc\x8ci\x9e\xa6\x06LO\xe7\xb7ϡ@g\x90\xd0\xef\x99z2\xb3Ϳ\xa7F\xc9\xe6Ĭ\xb7|$Ά\xcf<\xa2\x1c.\x1c\xca\f&\xc3\xeaT<\x19\x17\xe7N\x8e\xd8\uf503\xacg\xa4\x8b\x184\x8e\x83\xaf\xe0\xd04\x87\xf6\xa5\x96\xc1\xb9xE\x8dө\x98o\xb8\x94D\a\xe6\xf9zw\xf3\x02\x93\x1e]\xd80\x99\x0e\xbf\xde\xddć\x99P&\x85\xd89̼\xaay\xac\xe25&\xd8H|\x89\x8e\xe3\x90\aב\x97{\xadD\xc1\x95z\xc6\xe3\xfe\xf0\x13\xabBR-\xf2\x84\x04\xf8\xdc)\x87\x1e\x04\xc1'\xfe\x19\xcf\xe6\x1b\xf0\x16\x14\r#\x18\xdf\xc9\x1eKμ\xedH\xef\xe2F\xbe\xac\xa5\x90\xcd\x12\xaa\xce \nG'/\x94h\x1fM\xbapФ9c>C\x8f\t\x98\x12\xa40\v\xf9\x16\b%j\xe4\xb7N\xb1K7\xe7\xce\x13\xb6\xc7qWֵ\x82\xd2\xf8\x9fq\x89\x8e4L\xd0Z\x14\x1a\xd7@.\x9cB\xf9b\xe2\xf1\x19\xf3O`q\xcb\x1b\x97\xd0:2\xc4\x1c\xaep\xeb\xacD\xcf-kQ\x18\x1e\x03\x197\x8d\xf0P .\x95\xa8Ǎ2d\xa70\x8c\xb0*-\xfa\xd8m\xb65\x05^?)\xe2\xb3\xe2\x89N\x99\xf9\xebdɏ\x9dN?-G\x81\x15\xefw\xa8w<^[s\xf0\xcc=\x06\xdb\xf2$\x92\xc1\x17|Z\x90\x8e\xb9_\x8e\xb9E\xba<\x12z\x1e\xe7\xcb\t\x9e\xfb\xf6M%\xa1\x18_+k\xf8\xe3\xaf\xd5\xdf\x01\x00\x00\xff\xff\x95\xc8\xe1W\x9b\x12\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcW\xddo\xdb8\x12\x7f\xf7_1\xc0\xbd\xdc\x01\x95\xd2\xe2z\x87\x83\xdfzn\x17\b\x9av\x83$\xed;-\x8d%6\x14\xa9\xe5\f\x9dx?\xfe\xf7Ő\x92,˲\xe3\xec\xc3\xea\xc9\x1e\xce\xf7Ǐ\xc3,\xcb\x16\xaa\xd5\xdfѓvv\t\xaa\xd5\xf8\xcch\xe5\x1f\xe5\x8f\xff\xa3\\\xbb\xab\xed\xbbţ\xb6\xe5\x12V\x81\xd85wH.\xf8\x02?\xe2F[\xcd\xda\xd9E\x83\xacJ\xc5j\xb9\x00P\xd6:VB&\xf9\vP8\xcb\xde\x19\x83>\xab\xd0\xe6\x8fa\x8d\xeb\xa0M\x89>*\xefMo\xdf\xe6\xef\xfe\x9b\xffg\x01`U\x83K(ݓ5N\x95\x1e\x7f\tHL\xf9\x16\rz\x97k\xb7\xa0\x16\v\xd1]y\x17\xda%\xec\x0f\x92lg7\xf9\xfc\xb1Ss\x97\xd4\xc4\x13\xa3\x89?ϝ\xde莣5\xc1+s\xecD<\xa4\xday\xfe\xba7\x94\x81\x9c\xa7#m\xab`\x94?\x92\\\x00P\xe1Z\\B\x14lU\x81\xe5\x02\xa0\x8b>*\xca@\x95ȩ2\xb7^[F\xbfr&4vo\x06\xa9\xf0\xba嘯\x87\x1a\x81w-\x82\xdb\xc0F\x1b\x04v\x83\xd1\xc8\x0f\xf0\x83\x9c\xbdU\\/!\x97\x94\xe5\xac|\x85\x9cKb:\x8e\x94\xea\x87H\x87\xcf{\xba(^\x02\xb1\u05f6:e\\d\xc58\xd7\b\xbe\xeb\x89\xf8'z\xa3\t\x14\x91+\xb4b,\xe1Is}\xde)\xd16\xe7\xd4\xd7=\xfd\x12\xa7\x88\x15\a\xea\xdd\xea\xf3\x01~T\xfdC\x17\"\x7f\xde֊\x0e\xcd\xdfǃӖG:\xfa\xee\xcf\v\x8f\xb1\xf1\x1ft\x83Īi\x0f4~\xa8\x0e\x03)\x15'B:\u07beK\x1dT\xd4بe\xc7\xe9Z\xb4\x1fn\xaf\xbf\xff\xfb\xfe\x80\f\x87\x81\xff\x9e\rt\x98\xb6t,D\x1f\xff\xb8G@YP\x9e\xf5F\x15\f\x1b\xef\x1aX\xab\xe21\xb4\xe0\xd6?\xb0` v^U\xf8\x06(\x145(ђ\x18F\xb6\x8c\xabb\xb5\xf3\x81\xd6zעg\xdd\xcfF\xfaF\x103\xa2\x9e\x8bB>\t\xb4\xa1\x997\x90\xc1\xff\xa3\xcf7\xae:{\xber\x96e.\xce2}\x97\xed\x00\xef\xadj\xa9v/\xf0^36?\xb7\xe8\xd3bv\x96\xb5\xdf\xef\x86e\xe8\fc0'\xedޡ\xdc x:Ҏ\xe1\"-\x17\xf8\xd4q^\x14\xe8\xea\xfe\xfa5)<\xc1\xfe\x8a\"]ۍ{!\xc4=\xe3,\xdf\t\x18迸C\xbc\xdcӲM\xf5==\xde\xdf>\x875z\x8b\x8c\xb4G\xea\xd1\xce6\xfd\x9ej]\xd4'v\xbd\xf9\x918\xeb\xbe\xe0\x88\xf683\x94\x19\x8c\x96\xd51y\xb4.N\x8d\x1c\xa1\xdf)\x03Y\x87H\x17!h\\\a_\x81\xa1i\x0f\xedR]\x04\xef\xe3\x155l\xa7j*p)\x88\xf6\xc8\xf3\xed\xee\xe6\x05$=\xba\xb0a\xb4\x1d~\xbb\xbb\x89\x0f3\xa5mr\xb1\xf5\x98\x91\xaed\xad\x923\x01\xd8\b|\t\x8e\xe3\x92\a\xd7\x11\x97;\xae\x04\xc1\x1b\xfd\x8c\xc7\xf5\x91'\xd6\x06Y7(\x1b\x12\xe0s\xab=\x12(\x86O\xf23\xce\xe6\x1b \a\x9a\xfb\x15L\xeed\xc2R\"oZ6\xbb((\x97u\xa1\x8az\xae\xab\xcet\x14\x0eF^H\xd1ޛt\xe1\xa0M{\xc6t\x87\x1e\x02\xb0%\x14\xca\xceĻF(Ѡ\xbcuֻts\ue2319\xf6{\xe3|\xa38\xad\xff\x99\xa4\xe8\x88\xc3\x06c\xd4\xda\xe0\x12؇S]>\x1bx\x83D\xaa\x9a\x01\x82\x83\xa8\xbf$.\x89\xca\xc4\xfa+\xf8Ii#ɗgP_glZ\x96\xed\vp\x8b~7\x13\xb3\xe3\x1a}'\xf3\x1a/\xa3\xc4_i\xde[\x11\x9c\x9b\xa9\x01ǦC\x05\xb7\xde\x15H\xd2X\r\xaa\x18\xaatw\xad\bֈs\x85\xec\xba[[v\xe3a\x89I)\x1dR\xecI\xd15\x1e\x8fn\x9f\xc5g-{\xa7\xb6\xd37Ԝ\x1d7z\x96=Վ\x06eV\xf2-sP\x86\x02\xcb8cF\x1e\xb6\xda\x18\xf0(\xd3@\xa3\xb0\xa4%œow73V\xc5\xfd)m+~F\xc5Ѿ\x18\x18\\\xa3A\x9f{\x86H\xaf\x95\xcf\a\x1c\x132E\xb0\x88\xa4S\x19\x91\x8b\xe02\x90\xc3\xd8\x13\xc2Io\b'Ң,ǯ\xee\xefR\xea\x93\xd4\x1cy\xcfj\xf6$>\xf4\xad\x05V\xdc\xe7\x89\xe7\xcf\xce^\b\b\n\xf7L\xf8\xf8\xef\xc8@\xb4\xc0\x12\a\xb9\x17\bi\x1d2\x1e\a)\xe4\x19\x8cs7!\xae\x1fe\x12B\v!\xe6h\xa4\x13`d^\x82ÿV\xffy\xbb\xf8\xa7\nr\x00+)\x11\xf7\x95\xbd\xaf\xaen\xdaꞣ\x15\x069\xd5\xea8\xaf\x99\x14k\xb4n\x1e\xa9\xa1\xb1?\xbe\xfc)\x8f\x1f\xc0w\xca\x00~dT#߀\b\x98\xb7\xa9K2\x1ba\x83\xe0-E\xd8\v\xb7\xf5\x8cjţ\x80{/\x82c\x8f䷃\b\rB%\x1e3\xde2|\xd7>w\xef\xd8\xfc\x95|\xe5o\xd7\xf0U\bU\xd7\xf4\xe7u`\xa3MR\xfb\xee\xb4c'\xf8T#6\x1b쪼\x89\xb1PRE\xe9\xc8\xd7\xe4u\xc4\x1a\xa4\xea\x91\xf0\x84IO\xd1\xe9\xf1\t{?\xbe\xfc\xe9\x1a\xbe\x1abp\xe4(!9~\x84\x97\x14k<6Z\xf1\xaf\xe7\xf0\xe0\xed\xe0 \x1d\xfbH'\x95[eQ\x82\x92\xd5!\x94;;\x04\xabj\x84=V\xd5,\x94\x03\x1c\xf6\xec\x00j}䜤\"2MF^ĝ,\t\"\x0e\xa7/\xcd4GN\xdf\xd3\xee\x8bϙ\x9ft{?[\xbe\xf9D$|q\xf8\tH\xf4\v\xed\v\x90xl\n4\x12\x1dz0\xb8*-\xe1P\xa2vvAAe'p\xbf\xd8+\xf3(\xe4fF\xc68\vZ\xb7\v\xdf\xf5\\|\xe1\xff\xb9Tpߔ\xfcT\xe9=\x91\xcf\a\x01\x9dn\x17\x97 \x90j\xb9\xa7Ǯ\xa38\xacR\xc0\x1fѤ;\xbfߊr\x9b*\xfb\x9e\xb7\xad\x19\x0f\xee\x98\xc9\xc3g\xba;\x84\xb3O\xee\xca\xc3,\xb6\xecgLr\xfa\xbf\x15\xd6\xd1\xf8%\xc06ⓜ\xcb\xfb\xbb7\x9f\xf3F5\xe2\x12Or\xa4b\r\xdf\xc7Y\xc7լfz\x16V3\xa7jQ\x8eVS\xc5v\xc7IIk\x81\xe6L\xfa\xf7n\xb08\x95#\x99گ]\xf3\xac\xfcӱM&\xe1\xeb\xbfY\x9cJ\vO\xe2u\xde\x14\x1e\xd8\xc6\x023\b\fj\xe6K\x82G<\xccBơ\x99\xa0t\x812\x82\xb6\r\fL\xeb\x8abz\xc8\"2\x14c\xfe\x1b\xe1a\xd6\xcbw\f\x90\xac*S\x0fr\x85\xce\t\xf9\x19\xc1y?b\xe4\xf7\x05\xaa\xedЖJ\xae\xc5&\xf6\xb6\xa7Hɦ\xaaXQ\xe1\x12\x9ci\x8eU\xd8'\x81|\xa0%\xa7\xe5\x7f\xdf[\x9a,\xfcL;9/ՠ\xc9<\x15\x06eSOY\x99\xc1\xa3҂e\xc6\rZ7\xb9\xbd4q}\xfd\x9c;\x16\x8c\xf2\x92J>4=r=\x88h\xe81\x81O}\b\xa7\xba*/\xab\xf4g\xf8\x06\x83\xbf4T\x8e\f\xf9\x9e\xe5\x9bc\xa35\xbd\xb7\x844\xa4\x15\x1f\x8d\f\xdd\xe0h2\xc8\xf7\xa4\x8e\xa1\x7f\xbexF\xcf0<\xa9FLS\xe7#>\xb4R\xda}iא\n;퐷\xcf:\x97h\xfc\u0558\x88\xef\xf4\x9b\xd8up\xa2ƶ\xf4\x1f\xfa\xbaP\xdc\x15\bڠf\xd9\x1e \xf8w\x1a\xeb\x1b\xd6_\xda@LXh,r\xdf/\x9d\x9c=\xa1\x90^\x159s8\xa3\xfd\x97\xf9\x8b|\x1b2\xbc\xf0\xf6\xdf\xc5.\xeaIN\xc9L!d\t5\xff`\x97\x9e\x96s\x88u\xe4Z\xbc\x025\xe4\xbe\n\xa5\"y\xcdD\x85\x1c\xd2/\x1a\x9eI\xa5\xc05\xa58\xc1ǥ>Nj\x92\x1d\xad\xffNk2\x03\xc24\xe1\xf9#\x959~X>\xa3ɻ\xd1rت*\xeaK6u\x81\x86.\xa6\x7f\xde\x06\x89{\xaa\xfb\xcb-\x93\x9b\xac\x93Kϳ\b\x15\xb3\xeeX\a0\xf7>>\x96\xac\xff\x9e\xdd}5Z\xcb6\xe7\xdc\xf9\x0faU\xe8\xdc\xc5-\xc0\nո\xfc\xfd\xfd\xd2F\x17\xf4\xcc^q\xae)6\xf4~\xccm\x93\xb3\xf3-Q\xdaӏ\x1b\xdd\x0fyve\xa5\x0f,\xfe\xe9#\xbdx\x04SȰ\xday\xb7g9\x8b\xe1O\xc5.\xb1\xe2Հ\u0099\xb8\x1f\x7f\xb9\x96\x8b\xae+\xf2\x02\xe4\x80\xfc3\xfe\xed\xf8\xf7:7m\x90a.6\xc8C<\xcau\x15\x94\xf4u\x842\xd3\xdfT\xc0\xd9@>\x14\xe8ό\xe1Ys\x9a\fz\xcey\x8fv|\xc1\xee\x8f4E\xfb\xe3\x8e%\xfc\xfa\xdb\xd5\xff\x03\x00\x00\xff\xff]\x94\x176\x9e*\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4Z͒\x1b\xb7\x11\xbe\xefSt\xad\x0f\xb6\xab4d\xa4$\xae\x14o\xd2*Nmbo\xb6DI\x17\x97\x0f\xe0\xa09\x03s\x06\x80\x01\f\xb9\xb4\xe3wO5\x80\x19\xce\x0fH.\xa9\x925\x17i\xf1\xd3\xf8\xf0u\xa3\xbb\xd1`\x96e7L\x8b\x8fh\xacPr\x01L\v|r(\xe9/;\xdb\xfc\xc3΄\x9ao_\xdel\x84\xe4\v\xb8k\xacS\xf5;\xb4\xaa19\xbeŵ\x90\xc2\t%ojt\x8c3\xc7\x167\x00LJ\xe5\x185[\xfa\x13 W\xd2\x19UUh\xb2\x02\xe5lӬpՈ\x8a\xa3\xf1\xc2ۥ\xb7\x7f\x99\xbd\xfcn\xf6\xf7\x1b\x00\xc9j\\\x80V|\xab\xaa\xa6F\x83\xd6)\x83v\xb6\xc5\n\x8d\x9a\tuc5\xe6$\xbc0\xaa\xd1\v8t\x84\xc9q\xe1\x00\xfaQ\xf1\x8f^λ \xc7wUº\xff$\xbb\x7f\x10\xd6\xf9!\xbaj\f\xab\x128|\xaf-\x95q\x0f\x87\xb52\xd0[\x13z\x84,\x9a\x8a\x99\xe9\xcc\x1b\x00\x9b+\x8d\v\xf0\x135ˑ\xdf\x00D\x06\xbc\xa0\f\x18\xe7\x9eSV=\x1a!\x1d\x9a;\x12!\xbbe8\xda\xdc\b\xed\xd3%\xb3\x18{\x03\xf9K\xdf\x11\x9bܞ0[g\x84,R(ދ\x1a\x817\xc6+\x9d\xf6\x9f#\xb8R\xd8)\xbc\x1d\xb3\x04\xd18\xbf\xf14\x18\xdfO\"\xadc\xb5\x1e\xa3\xeaM\r\xb08s\x98\x02u\xa7j]\xa1C\x0e\xab\xbd\xc3v+kej\xe6\x16 \xa4\xfb\xeeo\xc7\xf9\x88\x84\xcd\xfcԷJ\x0e\xc9yC\xad\xd0k\x0eHH[\x05\x9a$Cʱ\xeaS\x808\x12\xf0\xa67? \tr\xfb\xedg\xa1\x90\xe9\x81Z\x83+\x11ް|\xd3hX:eX\x81\xf0\x83ʃ\nw%\x1a\xf4#Va\x04\x9dm\x10\xa4;e\x92\xaaӘ\xcf\xc2\xd8(\xac\x955\xd2\xdfp\xa1\xcfb_\xb9A\x96\xb4\xaf\xd6I\xcd\xfc\b\xa1d\xda\xc8^\x17\xf8,\x03\xeb\x13)\x15\xc7\x1ek\x13\\\u00826*GkO\x18>\t\x19 y84\x9c\xa5\xa8D?\xa6\x05\xd4\xe8J1\x8e\x06\x9c\x82\x92I^aС3L\xdau\xb4\x8c\xa9\n\xdbi\xef\xf7z\b\xe5C+\xaf\xd73\xc1\x14\x86n_\x067\x98\x97X\xb3E\x1c\xab4\xca\u05cf\xf7\x1f\xff\xba\x1c4\x03Ѣ\xd18\xd1\xfa\xd1\xf0\xf5BR\xaf\x15\x86{\xfe_6\xe8\x03\xa0\x05\xc2,\xe0\x14\x9b\xd0z.\xa2\x7fE\x1e1\x05\x8e\x84\x05\x83ڠE\x19\xa2\x1553\tj\xf5\v\xe6n6\x12\xbdDCb\xc8\xed7\x15\xa7\x90\xb6E\xe3\xc0`\xae\n)~\xebd[\"\x9c\x16\xad\x98C\xeb\xfcA4\x92U\xb0eU\x83/\x80I>\x92\\\xb3=\x18\xa45\xa1\x91=y~\x82\x1d\xe3\xf8\xd1[\x93\\\xab\x05\x94\xcei\xbb\x98\xcf\v\xe1\xda@\x9d\xab\xban\xa4p\xfb\xb9\x8f\xb9b\xd58e\xec\x9c\xe3\x16\xab\xb9\x15E\xc6L^\n\x87\xb9k\fΙ\x16\x99߈\xf4\xc1zV\xf3\xafL\f\xedv\xb0\xecD\xd1\xe1\xf3\xe1\xf5\x02\xf5P\xbc\xa5\x93\xc0\xa2\xa8\xb0Ń\x16\xa8\x89\xa8{\xf7\xcf\xe5{h\x91\x04M\x05\xa5\x1c\x86Nxi\xf5Cl\n\xb9&çyk\xa3j/\x13%\xd7JH\xe7\xff\xc8+\x81ҁmV\xb5pd\x06\xbf6h\x1d\xa9n,\xf6\xce'3\xb0\xa2\x03E~\x80\x8f\a\xdcK\xb8c5Vw\xcc⟬+Ҋ\xcdH\t\xcf\xd2V?E\x1b\x0f\x0e\xf4\xf6:\xda\xfc\xea\x88j\xc7\xfem\xa91'\xcd\x12\xb94U\xacE\x8c$ke\x80M\xc6\x0f\x99J\xbb\x00\xfa\x92\x11e<\xe8\x9c\xd9\xd1\xf7&%\xa8E,{\x8e<\xc6;\x1b\x03U5\fT\xfdo\x12#\rje\x85Sf\x7f\x88\x94c\x938\xaa\x1d\xfar&s\xac\xae\xd9ޝ\x9f\tBr\xe2\x1d;\x93&g\x14\xa4z\xa0J\x16\x8a\x0e\xd9D\x1dp\xefh\x1cٹE\x97ެ<\x1aل\x84C\x8e\t\xfd\\r\xbc\xed\x95R\x15\xb21\x9bZ\xf13\x9b~T\xd1q\x18\\\xa3A\x1f\xff\x83\x9b\xd5\xca;cDŽl\xddGH\xb9\xc1\xa9\xc4>V\xe4n\x8e\xa9\xe6\xb8\x1d\u0089\x90\x94\x04\xfc\xfa\xf1\xbe\r;\xadeE\xe8\x93\xc8\xd2\xe7'i\x16\xf4\xad\x05V\xdc\a\xea\xf3k'-\x84\xbe\xfbu\x00\xe1}\xafS\xc0@\v\xccq\x10\xf7@H\xeb\x90\xf1\xd8H\xee\xc6`\xec{\x11|\xeaQ\x90\x10\xaeE1>\x92J\x80\x91\x8f\x17\x1c\xfe\xbd\xfc\xef\xc3\xfc_*\xec\x03XN\x99\x90\xbf\xab`\x8dҽ\xe8\xee+\x1c\xad0\xc8\xe9\xf6\x81\xb3\x9aI\xb1F\xebfQ\x1a\x1a\xfbӫ\x9f\xd3\xfc\x01|\xaf\f\xe0\x13\xa3\xa4\xff\x05\x88\xc0y\x176Z\xab\x116l\xbc\x93\b;\xe1J\x0fT+\x1e7\xb8\xf3[plC'&l\xa1A\xa8\xc4\x06\xd3\xec\x03\xdc\xfa\xe4\xe9\x00\xf3wr)\x7f\xdc\xc27\xc1I\xdcҟ\xb7\x01F\x97 \xf4\xbd\xce\x01\x8e+\x99\x03gDQ\xe0!ў\x18\v\x054\n\x05߂2\xb4W\xa9z\"\xbc`\xd2Sp\xc4\xc8'\xf0~z\xf5\xf3-|3\xe4\xe0\xc8RBr|\x82Wt\xc6=7Z\xf1og\xf0\xde\xdb\xc1^:\xf6D+奲(A\xc9j\x1f\xf2\xcd-\x82U5\xc2\x0e\xab*\v\xa9\x18\x87\x1dۃZ\x1fY\xa7U\x11\x99&\x03͌;\x99\x8eE\x1eN\x1f\x9ai~\xd2~\xcf;/>_y\xd6\xe9\xfdb\xb1\xfe\x99L\xf8\xc4\xfc\x13\x98\xe8_u\xae`bӬ\xd0Ht\xe8\xc9\xe0*\xb7\xc4C\x8e\xdaٹڢ\xd9\n\xdc\xcdw\xcal\x84,22\xc6,h\xdd\xce}1g\xfe\x95\xff\xe7ڍ\xfb:˧\xee\xde\v\xf9r\x14\xd0\xeav~\r\x03m\x1e\xfd\xfc\xd8u\x94\x87e\xcc\xec\xc62\xe9\xcc\xefJ\x91\x97\xed\xad\xaa\xe7mkƃ;fr\xff\x85\xce\x0e\xf1\xdc\x18B\xb4\xcfb)2c\x92\xd3\xff\xad\xb0\x8eگ!\xb6\x11\x9f\xe4\\>ܿ\xfd\x92'\xaa\x11\xd7x\x92#\xb7\x85\xf0=e\aTY\xcdt\x16F3\xa7j\x91\x8fFS\xae|\xcfIIk\x81\xe6L\xf6\xf7n0\xb8\xcd\xda\x13Yw7梴\xdbJ\xa6m\xa9\xdc\xfd\xdb38\x96\xdd\xc0\x16\xc3A\x871\xe9leё8\x99k>\x03\xcfR\xfc\x96p[ID4\xb4\xc5T\xa9B\xe4\xac\x02\xeb\xdbd,VF\x98\xad\xec)\xa0T=r\f\xb7_U\xec\xe1\xf5\xbe\xe0ḧ\x1dB\x1e\x8enQ+#\n!Yu\xf0\xd8\xfe\xea(Y\xcd\xfc_\t[\xad\x99\xd6B\x16\x17q\xdbַ\x96蜐E\"\xd1\xef\x97\xdfO]\aN\x9e\x93\xf3.\xe0\xc3\b\b0\x83\xc0hO\xa4\xaa\r\uecd0uj&(e\xa4\xac0\xa6\xd6+\x04\xa6uEy]\xc8$S\xbe\xa9\xad\xd6\xe5J\xaeE\x11+\xa7S\xa6dSUlU\xe1\x02\x9ci\x8e]ڒǽ_(<\xa3\xf1\x0f\xbd\xa1\xad\xbaϔ*ӻ\x1a\x140\xa7\x9bA\xd9\xd4S(\x19l\x94\x16,\xd1N\x87s☨\xe3\xf6\xf6\x12\x93\n'\xff\f\a\xe1Μ*8D\xc7\x11\xaf!\xf1\x8a\x1d\xdcG:\x9a_\xeaP\f\xfe\xdaНj\x880K\xd7VFc\xb4\xe27c\xd2\xfa\xbex\xd4y\xf0\xa4\xe3\x8e\xe1\xa1\x1f\xf5\x06\n\x9eU\x96\xf2\x85\xf2K\nS\xe19,\xf2\x1e\xd2\x00\xd7>\x92\xd1\x05\xe3\xea\xd2\x14\xdda\xb5C\u07bd!\\S\xb7y=\x16\xe2\vʆ\xc7C\"j\xec\x8a\x1c\xd1N̡\xec\x12B\x8c6\xa8Y\xd2\"\xc0?\nX_\x18\xfd\xda\x06i\xc2Bc\x91{\xdf:Y\xfchL\xe0\xccaF\xf3\xafs \xe9bWx\x9e\xeb\xbf\xc2\\U\xf9\x9a\x8a\x99r\xc8:\xda\xfc\xfbP\xfb0\x98\xa2\xec \xaf#,\x88C\xee\xafܠ$\xac\x99\xa8\x90C\xf7,}1\xf3\t\xd0\xd3d\xecs\x92_\xa3\xb5\xac8\xe7\xb4~\f\xa3B\xe5-N\x01\xb6R\x8d;b\x95_\xdbx\xb4.\x8a\xc9R\xf1sH\x1e\x14\xf70\xe4\xf1'\xb7)\x9a\x84Z\xfa\xcfp\x17a\xf4E\xcdsEJ\x1a\x93r5\x1d\xe4Ӿ\x06Nİ\a\xdc%Z\xdb\x13\x9c\xe8z\x8cn!\xd15\xf9=@\xbf3T\x92S9Mۗ\x94\xd9=\xb6'\xfa\xbe\xf7\xc7\xe5\"\xb6#\xbek\x1cBW\x87.U\xd5\xfa\x00\xffH.\x9bz\x85\x86T\xb1Je\xc4\xc0$\xefk.UL\xe8$\xb4a8\x88\x8a\xf5\xb0X@\xf7\xa7\xdc)\xe0\xc2\xea\x8a\xed\xbb\xcd\xf8\x1b\x1c\x1d\xe9\xf4s\xc2\xe1\\\xb5\xbe\x8a\"ϑ\xbc\xedt\xa5\xba\xfb\xd1B\xfa~z:Ӈ3پ\xef\xef~\x8c\xf0yV8\x91w\x0e\x7f\x1cr\x8d\x81,\a\x12\xce\x05\x8b\xf8c\x95\xcb}\xfcp\x99?ӽ'ٛ4z\xe4\xbc';>y\xf5[\x9aU\xf7\x1e\xbc\x80\xdf\xff\xb8\xf9\x7f\x00\x00\x00\xff\xffϡa\xa5-&\x00\x00"), []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec=]\x93\xdc(\x92\xef\xfe\x15\x84\xefa\xee\"\xba\xca7q\x1fq\xd1o\u07b6}\xee\u06ddv\x87\xdbg?SRV\x89i\x04\x1a@]\xae\xdd\xdb\xff~A\x02\x12R!\x89\xaa\xfe\x98\x99\x8d\xd1KG\xab \x81\xfc\xce$A\xab\xd5\xea\x15m\xd8WP\x9aIqIh\xc3\xe0\xbb\x01a\xff\xd3\xeb\xfb\xff\xd2k&\xdf<\xfc\xf8꞉\xf2\x92\\\xb5\xda\xc8\xfa3h٪\x02\xde\xc1\x96\tf\x98\x14\xafj0\xb4\xa4\x86^\xbe\"\x84\n!\r\xb5\xaf\xb5\xfd\x97\x90B\n\xa3$\xe7\xa0V;\x10\xeb\xfbv\x03\x9b\x96\xf1\x12\x14\x02\x0fC?\xfc\xeb\xfa\xc7\xff\\\xff\xc7+B\x04\xad\xe1\x92(\xd0F*\xd0\xeb\a\xe0\xa0\xe4\x9a\xc9W\xba\x81\xc2\xc2\xdc)\xd96\x97\xa4\xff\xc1\xf5\xf1㹹~v\xdd\xf1\rg\xda\xfc9~\xfb\x17\xa6\r\xfe\xd2\xf0VQ\xde\x0f\x86/u%\x95\xb9\xe9\x01\xae\x88\xf2\xcd5\x13\xbb\x96S\xd5uxE\x88.d\x03\x97\x04\xdb7\xb4\x80\xf2\x15!~Q\xd8\x7fEhY\"\x9a(\xbfUL\x18PW\x92\xb7\xb5蠗\xa0\v\xc5\x1a\x83h\xf8R\x01.\x86\xc8-1\x15\x90\r-\xeeۆ\x98\x8a\xe90(a\x9al\x95\xac\xb1;!?k)n\xa9\xa9.\xc9\xda\"h\xedz\xd8\xf9\xf8\x06\x0e\x9f\x7f\xc2\xd7\xfe\x959\xd89k\xa3\x98إf\xe1\xf1D\xb4\xa1\xa6\xd5D\xb7EE\xa8&7\xb0\x7fs-n\x95\xdc)\xd0:1>6_7\x15\xd5\xc3\xc1\xef\xf0\x87\xcc\xc1\xbfHC9\x11m\xbd\x01e\xd1\x00JI\xa5\t\x97\xbb\x1d\x94\xa4lm?č\x8ah\x9c\x9a\x87\xeb8\x98\xc8\xfb\xf8\x95\x9b\x88%\xc9\x0eT\xceL\xf6T\t&v\xe7\xcc%t\x1d\xcc\xe6\xdb\xf0ej>\x11\xa4 e\xebB\x01\n\xd8\x17V\x836\xb4n\x06@\xdf\xee`\x00\xaf\xa4ƽp??\xfc\xe8X\xb9\xa8\xa0\xa6\x97\xbe\xa5l@\xbc\xbd\xbd\xfe\xfaow\x83\xd7d\x88\x8e\xff[u\xefI\xc7\"L\x13J\xbe\xa2(Z$\xa0j \xa6\xa2\x86(h\x14h\x10F#\x86h\xd3pV\xe0ĉ\xdcF\x90B/\xc7\xd5=\xb4\xc0\xfa\x92Pb\xa8ځ!\x7fn7\xa0\x04\x18Ф\xe0\xad6\xa0\xd6\x1d\xa0F\xc9\x06\x94aAl\xdd\x13i\xb7\xe8\xed\xdc\xc2\xeccq\xe1z\x91Ҫ9pK\xf0r\r\xa5G\x9f\x13R\x94L\xbf\u0530\xd9)H\xab\x97\xdd\xe0\xa6n\xa0\xa2\x0fL\xaa\x94\x18H\x85M#{ޫii\xb5\xa4\a2\xb6q\x99\vN\"\xab\x92\xf2~\x89!>\xda6\xbdu \x05\x86<\xddR<\xb5\xbd\xed\xde\x00\x81\xefP\xb4&1M\x12\x9cC\xa9H#\xb5\x99\xa6\xfb\xb4\xea\"\xb1s\x94\xfaq\x86i\x8eV\x96du\xf7x%\x1c\x88jq0P\xc8R\x80]Fm\x89ڷU\xb2um'\x91B6TCI\xa4\x98\x1c\x19٥\xe5\xa0\xfdX%rF\xaf\x87.\xfa\xf5\xa3\xc7C8\xdd\x00'\x1a8\x14F\xaacd\xe6\xa0\xd4=9\x8au\x02\x95\tm:\x94\x80~\x013 \x89\xe5\xf4}Ŋ\xcay\x18\x96=\x11\x0e)%h\xabM\xd0e>L-\x92,\x91\xdf\x0f2\xa7=\xfagA\xac\xc6\xf0R\x1a\xa5\x7f2\xd4p\xff$Q\xdb\xeb\xde#\xdd\xe2\xdf\x1b9\xbb\xec\x7fL\xc4\x06cr\x06\xd3\xce\xc8?A\xf73\x9b\xa7'\xf9\x16#<\xd0kr\xbd%P7\xe6pA\x98\to\x97$\x81r\x1e\x8d\xf1;\xa6\xcd\xe9L\x9fI\x9a\x1c\x99x&\xc2tC\xfc\x0e\xe9\x82&\xe3\xce[\x8cl\x9a\xfc%\xeeuAضCzyA\xb6\x8c\x1bP#쟥\xea\x03e\x9e\x02\x199V\x8f`\x9e\xc0\x14\xd5\xfb\xef\xd6\xc5\xd1}\x9a6\x13/\xe3\xce\xce7\x0e\x11\xc4\xd0y\xd6;~\xbe\xaf\xee\xbb|\xc1ʚ\x9c\x95\x87`d\x9d\x81\x03\xaf\xbb\xcb\xe5\xf5\xac\xac\xccf\xb4\n\x9c\xb0\xd8t\"9:\xdd4\a)\x8f@\aZqtq\x16\xa9\x1b\xef^\xe6[\x94\x13x\xe1T\xd5\x10\xcdݙ\xe0\x9a6V-\xfc\xcdZZ\x94\xa6\xbf\x93\x862\xa5\xd7\xe4-\xee\xd8r\x18\xfc\xe6\xf3p\x11\x98\x8c!\x1b;\x94\xe5\x9f\aʭ\xed\xb7\n\\\x10\xe0\xce\x13\x90\xdb#\xbf\xe8\x82\xec+\xa9\x9d\xd9\xde2\xe0\xb8_\xf1\xfa\x1e\x0e\xaf/\xec\xf0\x8bC\xc6J\xe6\xf5\xb5x\xed|\x88#\x85\xd19\x1cR\xf0\x03y\x8d\xbf\xbd~\x8c+\x95ɩ\x99\xcd\x06,Z\xd3&\x8fCE2Y\xdf?\x03\x8e\x89s\xf3}R\xde;\xd9s\xab\xcdb\xd1Fj\xf31\x9d7\x9c\x98\xcfm\xe81\xf4\x8c\x139\xb6ň\xc1\xe7\xd1:}o\x9dȭ\x01\xe5s\x89\xce\x06\x84\xf8㑑YjW&\x9el\x97\f\xa4]~\xd7\"x\x81\x9b\xdc\xc6M\xce\x14OqX-^N\xf4\xf6\xdf\x7f\x8f\xf2\x99Vr\xed\xff\xf1B\x9eڡ.d]\xd3\xf1\xaef\xd6T\xaf\\\xcf\xc0\xd3\x1e\x90\xa3\xbeڵ(Ϲ\x16\xb9\xe7!ܿ\xdc3S1AhP\x1b\xa0\x83\xebѡ\xeb9\x9dݫ\x8e&\x1d\xe5\xbb\x17\xced5\xb2$\xfb\n\x14\f\x18\xe38\uf39e\xaa\x90&JY\x9c\xe0\x906\xb2\xfcA\x93-S\xda\xc4SФչ\xb4>\x91|v\xde_X\r\xb25ω\xe0\xf7\xfd0\x83\xbd\xe6\x9a~gu[\x13Z\xcb\xd6\x19s\xc3\xeanWףwO\x99鶭0\x7fc\xa4%A\xc3\xc1\x00\xd9\xc06\xbdߛz\n)4+\xa1+\x1drdc\xd2\n\xe6\x962ަv\x89Rϩ\x11\xb0\xc0\xea\xa73P\xfc\xc9\xf5\x8c\xf2\x8e\x95\xdc\x0f\x11\x94\xb9v\xdcH\x03¶\x84\x19\x02\xa2\xb0\x18\a\xe5T2\x0eᑁ\xa8a\xb9z.O\x81\xdb\aD[\xe7!`\x85\x02\xc9\xc4l\xca-n\xfe\x812\xfe\x1cd\xb3\x9c\xf7A\xaa\xcf@\xcbsr4ߢ\xee\x04\x84n\x15n\xfe;ݱg}\xeedq=\nb\xa8&{\xe0\x9c\xd0\x14w\x1c-\xbfp'\x93\v\xb9\xc2#\x81\x96\xbc\x81I\xfcy\xe6\v'\xc5x\f\f\xa9W'\xe0\x16T\xe0\xe9f\x9dXȤ9\xccѢG~\xb9\x8b.\xf0\xdd/-\xa8\x03\x91\x0fX\xc2ཷ\xfe\xac\x82W7\xdaƘA\x01ze<\xb5\xa9p\x14\xca\xf4\n\x8a\xbc\x15Η\x18\xcf\a\xfbX\xcdׇjV\x9d\xdb(,9\xc6Dw!\xbbމnKn\x7fnQ\xff\xf3\x06n\xa7\x87n\x8b\xbeR\xbe?\xfb+\x15\xeb\x9fS\xa4\x9f\xb7\x1d\xb4X\x94\xff\\\x81\xdcR(\x97\xed\xbd\xe6\x15ݟ\xb6\x89\xfa\x8cE\xf6\xcfQ\\\x9f\x89\xa9\x9cb\xfa\xd3\xf0\xf4\x02\xc5\xf3/Z4\xffR\xc5\xf2\xd9E\xf2Y\xfb\x98ٛV\xb9یgV}/\xef\xba\xcf\x17\xbdg\x14\xbbg\xec\xa4-/\xf2\x8c\xe5e\x14\xb3\x9fVĞA\xb3\\Q|\xc1b\xf5\x17,R\x7f\xe9\xe2\xf4\x05\xceZ\xf8\xf9\xb4\"\xf4\xb3w`\xc2V\xff\x8d,\xe1V*\xb3\x14\x9c\u070e\xdb'vR\xa3\x80M\xf2\x92\x88\xd04\xb1J\f1|xqޢқ\x9e\xc1\x9d\xfeI\x96vnK{,\x9fG͏\xce*oA\x81p\xd7|\xfc\xcfݧ\x9b\x0e~\xca\xe7\xf5\x9e\xf1\xe8z\t\xe7\xc1\x94\x1e9~k\xce\x1739l\xa1\x0f\xf0\xc4\xfb\"\xb4a\xff\x8d\xf7\x0e>\"\x1d\xf4\xf6\xf6\x1aa\x04?\r/2\xec\xaa(\xba\x1d\xcb\rX\x8bաjR,\xae\xb7\x03\x88Ê\xdf\xf8\x1a%(ݕY\xc1b\xb2P\xe3e\x05\xef\xf6\xda\xcdcj\x94\x0f\xd6i\x14\a\"\x1dGVL\x95\xab\x86*s@\xb6\xd1\x17\x839\x0433\x97ΙT\xac\xc7׀%\xd1\x1bn\xff½\xc8C3\xdc\xed\x1d\xe3\xee\x9cyL\x9f?YfX6Jk|sq\xfc`\xbc\xe4j\x11\x19\xbf\x88\xb2\xb7/S\xa6\x93y\xc5\xd6ٗk9\xf4L\xa8\x1fܑ\xb0\xaa\xed\x18Sg\x14\xe8,\x86\xdb\x19\a?\xe6\x13\v\x99W3\xe5\x19\x8c3\xaecB|\xe5\xe2\x8a$oiʼ\x89\xe9WE\xf4\x8cV\xd3E\x05e\xcb\xe1\xdc{X\xef\xa2\xfe\xcb7\xb1\x86\xd12\xeeb\xb5Ȏ\f\xb4\xf5\xb0\x86w\xbezJx\xc81%\xa7\x82pLظ+\x1f\vw;pQ\x80\xd6ۖ\x87\xcaQ\xbc\xc0\x1b\xcaМ\xe9n\xc6'\xd5>\xea{ּs5\x94\xe3\xb0\xfb,\x1cO\x83\v\x97\xf8G\xd6\x01\xf7\x14\xd4\x03\xa8U\x81\x1ea\xab\xa0\f\x15\x9d3^$\xa9\x03H\xa6\xe3H~\xe0\xaa'\xfa\x7f\xab@ W:'*\x94\x8e\xc6\xd0,:\x1a(\t<\x80 lK\xa2yI\x11M8\x05\xfe#\xc5\r8\xd8n\xa10nC\x97\xa2\xc3\x1c\xa4\xf6\b#\xac\x97\xfb\x84g\xf5\b\x83\xd76\\\xd2\x12\x94s\xb4\x17\b\xf9\xbf\x83\xc6#M\x14\x10\xd0_\xa2<{\x01\xed\xa3\xecQC\x15\xe5\x1c\xf8\a\xc6A\xbf\x93{a畡foS\xfd\xa2\x13\xd0E\xab\xac\xb3v\b\xb7\xf0k0f:-\xbb\x95j\xfe,\xd2\xf1\x15\xfb\xc3g\xaf\x98\x81\xbb\x86*\r8\xa3\x8c\x15|\x1buqy\xde-\xa7;Wt^\xb2\x82\x1a\xe8\x04\aG\x98\x9a>\xf6\xd7\b\x8b\x1f\xb0\x06XNl/e\xab\xea\xa9Ï\x93\xcaz\xea\"\xef\x84\x03\x96\xbc\xca\xdb\xf9Y\x05m\f\x1e5E:\"\x11M\xf8\x9c\x84\xdc\x1e\xdd\xe6=\x00;\xcdi\xfe\xc0P\xfc\xed\x83s4\xdd\xd51\x18\xbc\x80_\x95Q\x85{|\x95qW\xcaN\xf6Twǖ\x92\x11U\x0fہA\xb5fA\a\xcddE\x912\x0e\xe5\x1c\xa7~\xe9\xb4\xd5\x0f\xba\x83\x835\xf7\x96\xc5\xef\fU\xa6\x9b\xfa\xb1w\xea\"s\xf7釕\xed}\x9e~J_H\x8e_\xd08\xeb^m\xf7\x1d\x0f\x14\x8f\"\x1cp\xb5>\x8d;\xf9]\x83\xd6t\x17ҽ{P@v ,\u07bb]\xbc\xa4\x1f\x1c\x0e\xcf{\x17`\x90\ue845i)\x0f_\x10\xa1\xf8E\x13_\xa7\x14\xbe\x04\x80\xf9\xe2ݤ\xe1M\xab\n\x7fL\xff3P=\xfe\xb0\xc4\x11.>\xc4m\xfdv\xac[\xb1\xabB\xa0\xee(\x05~Z\xc005\xfe\x94\xc8`J\x12G>\xc9I\xa8\xa4\xbc\xcf\n\x9e>v\r\xfb\x8d\x1b&\x1c+\xe1\xe5\x04\x1bٚ\xc8{\xf5\bOL\x13/\xda~b\xfb\x820ߺ\xa3\xcaS\xbb\x98y\xfe\xfb\xc7\x01\xa4.i1\xfa\xd4\v\xed\x1aT3W\xf5܅\xcf\x14p~\xb8\x18C\x1e}\xff\xa4\x87]\xf5\x97f{M\xd0_\xd421P\xd8_K\x02\xe9\xee\xdb\xee=ͩۍ\x97\xec\x1fB\xfd\x80\x93\xca\xc0\xf1Ǿ\xf5\x14\x1e\xdd4]\x18\x04\"\x9d? \x18R\x9a\xaa\x93\x8c3\xa6>\x13{\xe0爖6\xe3l\x9b\xce\xed\x88\xccU\x17Z|\x9e\x90\xca\xf4\x8d\x12+r\x03\xfb\xc4[\x87,\xac3A\xa9J49\xfa\xc0R\xfc\xe37ʬ\xfb\xf3A\xaa[\xde\xee\x98\xf84}\xc6j\xae\xf1-U\x86Y\xa6u\xf3I\xf4\xbd\n6.\xf1\xdbr\xef\xe9\x1f\x98\xa0\x9c\xfd5\xa5\xcb\xe3\x1f\x97F\x98\xd1w\x8dG\xde9\x16* ~I\x01z\r\xfd\x83\x8e\xccO\x18wMndR\x8c})\x16\x1b\x02e\x9al@\x9b\x15l\xb7R\x19\xb7S\xbeZ\xd9\xf0\xc5;HVC`\xf4\xef\xbe\x1bCX*\xba\xea\x8a\\\x82ò\xf5\tb\x85V\a\x13\t5=\xb8<3-\n\x1b\x13\xc0\x1bmh*\xe2|\x94\x9e\xc6\x04\x84\x97\x95\x1c\x15r\x1d\xb7\xef2\xb7\x9d\xfa@p\x0euxq\x8c3\xe8|\xaazdp/\x15\xd1\x16{\xe7(\x13\xe2\xd4\xd8\xf5t2%\xcf\xd4|\xe9\xa0L\xa9G\xbf\xbe\xc1'/|)\x93od\xc9VTT\xec&\x8f\x8eWJ\xb6\xbb*\xf0\xe6\x94CD\xca\x16\xf3!\r\xaa\x02\x1d>\xd1eZ%\xa2\xf2\x18_\xcd8\xa5\xa5\xbb\xe9N\xfb(\x8fPԪ?Bګ\xaa\x19\x9b\x9f\x9d\xfb\x9d\x80\xb8h\xfb\x13\x10\xa9>\x88b\xf6\xb0\xeb\xf1\xce\xe3I\xaee\x12\t\x9d6~2$t\x10\xa7\x90\x10\xfb\x12}\xc4\xf3\x9b\xc1Ȕ\x8fr&:\xe6\x9d\x18\\\xe2<\xa8\xe5E\xc7N\xd0\xd0\xdd9\r\x1dz\x10\xfc\x9d\x95\xe8\x1b@8%\xf2ű\xd3q\xefo7b}輭\xf7gǮ_G0F\x97\r\xd8(\xb6\x1f&ě\xff̶)yq\xdfA\xdcp\xf8\x97\xa3__\xf8Ҁ\xf0Q\xcas0\x12\xbe]\x99\x88\xe7=\xd8\xe7\x8c\xe8\xbb/q>UL\x9f4KG/\x91\xc1\xcb\b\xcf~\xa4\xf8M\xbb\xe9\xbf\xd9D\xfe\xf6\xf7W\xff\x1f\x00\x00\xff\xff\x95Pn\x17dw\x00\x00"), diff --git a/pkg/apis/velero/v1/download_request_types.go b/pkg/apis/velero/v1/download_request_types.go index 0f98d898b..1eb9d5474 100644 --- a/pkg/apis/velero/v1/download_request_types.go +++ b/pkg/apis/velero/v1/download_request_types.go @@ -56,7 +56,7 @@ type DownloadTarget struct { } // DownloadRequestPhase represents the lifecycle phase of a DownloadRequest. -// +kubebuilder:validation:Enum=New;Processed +// +kubebuilder:validation:Enum=New;Processed;Failed type DownloadRequestPhase string const ( @@ -68,6 +68,12 @@ const ( // into Status.DownloadURL. The controller signs the key by convention and does not // check that the object is present, so this phase does not imply the file exists. DownloadRequestPhaseProcessed DownloadRequestPhase = "Processed" + + // DownloadRequestPhaseFailed means the controller will not sign a URL for this request + // and no retry will change that. Status.Message carries the reason. A caller waiting on + // Status.DownloadURL should stop when it sees this phase rather than poll until its own + // timeout, which would report a storage problem that is not the cause. + DownloadRequestPhaseFailed DownloadRequestPhase = "Failed" ) // DownloadRequestStatus is the current status of a DownloadRequest. @@ -89,6 +95,10 @@ type DownloadRequestStatus struct { // +optional // +nullable Expiration *metav1.Time `json:"expiration,omitempty"` + + // Message explains a Failed phase. It is empty in every other phase. + // +optional + Message string `json:"message,omitempty"` } // TODO(2.0) After converting all resources to use the runtime-controller client, diff --git a/pkg/cmd/util/downloadrequest/downloadrequest.go b/pkg/cmd/util/downloadrequest/downloadrequest.go index 209b6c37c..2c90a2894 100644 --- a/pkg/cmd/util/downloadrequest/downloadrequest.go +++ b/pkg/cmd/util/downloadrequest/downloadrequest.go @@ -42,6 +42,11 @@ var ErrNotFound = errors.New("file not found") var ErrDownloadRequestDownloadURLTimeout = errors.New("download request download url timeout, check velero server logs for errors. backup storage location may not be available") var unzipLimit int64 = 1024 * 1024 * 1024 // 1GB limit +// ErrDownloadRequestFailed is returned when the server refused the request and gave no +// reason. The controller sets a message in every path that fails today, so this is a +// fallback rather than the usual case. +var ErrDownloadRequestFailed = errors.New("download request failed, check velero server logs for errors") + func Stream( ctx context.Context, kbClient kbclient.Client, @@ -115,6 +120,16 @@ func getDownloadURL( if updated.Status.DownloadURL != "" { return updated.Status.DownloadURL, nil } + + // Failed is terminal. Waiting for a URL that will never be signed would end in + // ErrDownloadRequestDownloadURLTimeout, which blames the storage location for + // something the status already explains. + if updated.Status.Phase == veleroV1api.DownloadRequestPhaseFailed { + if updated.Status.Message != "" { + return "", errors.New(updated.Status.Message) + } + return "", ErrDownloadRequestFailed + } } } } diff --git a/pkg/controller/download_request_controller.go b/pkg/controller/download_request_controller.go index 02d385bec..a2a865251 100644 --- a/pkg/controller/download_request_controller.go +++ b/pkg/controller/download_request_controller.go @@ -18,6 +18,7 @@ package controller import ( "context" + "fmt" "time" "github.com/cockroachdb/errors" @@ -132,11 +133,13 @@ func (r *downloadRequestReconciler) Reconcile(ctx context.Context, req ctrl.Requ // Update the expiration. downloadRequest.Status.Expiration = &metav1.Time{Time: r.clock.Now().Add(persistence.DownloadURLTTL)} - if downloadRequest.Spec.Target.Kind == velerov1api.DownloadTargetKindRestoreLog || + isRestoreTarget := downloadRequest.Spec.Target.Kind == velerov1api.DownloadTargetKindRestoreLog || downloadRequest.Spec.Target.Kind == velerov1api.DownloadTargetKindRestoreResults || downloadRequest.Spec.Target.Kind == velerov1api.DownloadTargetKindRestoreResourceList || downloadRequest.Spec.Target.Kind == velerov1api.DownloadTargetKindRestoreItemOperations || - downloadRequest.Spec.Target.Kind == velerov1api.DownloadTargetKindRestoreVolumeInfo { + downloadRequest.Spec.Target.Kind == velerov1api.DownloadTargetKindRestoreVolumeInfo + + if isRestoreTarget { restore := &velerov1api.Restore{} if err := r.client.Get(ctx, kbclient.ObjectKey{ Namespace: downloadRequest.Namespace, @@ -149,6 +152,16 @@ func (r *downloadRequestReconciler) Reconcile(ctx context.Context, req ctrl.Requ log.Warnf("fail to get restore for DownloadRequest %s. Retry later.", err.Error()) return ctrl.Result{}, errors.WithStack(err) } + + if restorePhaseHasNoArtifacts(restore.Status.Phase) { + msg := fmt.Sprintf("restore %q is in phase %q and has not written any artifacts", + restore.Name, restore.Status.Phase) + log.Infof("%s, not signing a URL", msg) + downloadRequest.Status.Phase = velerov1api.DownloadRequestPhaseFailed + downloadRequest.Status.Message = msg + return ctrl.Result{}, nil + } + backupName = restore.Spec.BackupName } @@ -165,6 +178,15 @@ func (r *downloadRequestReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, errors.WithStack(err) } + if !isRestoreTarget && backupPhaseHasNoArtifacts(backup.Status.Phase) { + msg := fmt.Sprintf("backup %q is in phase %q and has not written any artifacts", + backup.Name, backup.Status.Phase) + log.Infof("%s, not signing a URL", msg) + downloadRequest.Status.Phase = velerov1api.DownloadRequestPhaseFailed + downloadRequest.Status.Message = msg + return ctrl.Result{}, nil + } + location := &velerov1api.BackupStorageLocation{} if err := r.client.Get(ctx, kbclient.ObjectKey{ Namespace: backup.Namespace, @@ -236,3 +258,32 @@ func (r *downloadRequestReconciler) SetupWithManager(mgr ctrl.Manager) error { WatchesRawSource(downloadRequestSource). Complete(r) } + +// backupPhaseHasNoArtifacts reports whether a backup in this phase is known to have +// written nothing to object storage yet, so no DownloadTargetKind can exist for it. +// +// Only pre-execution phases are listed. InProgress and everything after it may have a +// partial log or other artifacts, and Deleting may still have all of them, so those are +// left alone: signing there preserves the behavior callers have today. +func backupPhaseHasNoArtifacts(phase velerov1api.BackupPhase) bool { + switch phase { + case velerov1api.BackupPhaseNew, + velerov1api.BackupPhaseQueued, + velerov1api.BackupPhaseReadyToStart, + velerov1api.BackupPhaseFailedValidation: + return true + default: + return false + } +} + +// restorePhaseHasNoArtifacts is the same test for a restore. +func restorePhaseHasNoArtifacts(phase velerov1api.RestorePhase) bool { + switch phase { + case velerov1api.RestorePhaseNew, + velerov1api.RestorePhaseFailedValidation: + return true + default: + return false + } +} diff --git a/pkg/controller/download_request_phase_test.go b/pkg/controller/download_request_phase_test.go new file mode 100644 index 000000000..f37cb908d --- /dev/null +++ b/pkg/controller/download_request_phase_test.go @@ -0,0 +1,277 @@ +/* +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 controller + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/runtime" + testclocks "k8s.io/utils/clock/testing" + ctrl "sigs.k8s.io/controller-runtime" + kbclient "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + v1crds "github.com/vmware-tanzu/velero/config/crd/v1/crds" + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "github.com/vmware-tanzu/velero/pkg/builder" + persistencemocks "github.com/vmware-tanzu/velero/pkg/persistence/mocks" + "github.com/vmware-tanzu/velero/pkg/plugin/clientmgmt" + pluginmocks "github.com/vmware-tanzu/velero/pkg/plugin/mocks" + velerotest "github.com/vmware-tanzu/velero/pkg/test" +) + +// Expectations are declared once and reused by both the behavior tests and the coverage +// tests below, so a phase can only be tested by being classified here first. +var backupPhaseExpectations = map[velerov1api.BackupPhase]bool{ + // Pre-execution: nothing has been written for any target kind. + velerov1api.BackupPhaseNew: true, + velerov1api.BackupPhaseQueued: true, + velerov1api.BackupPhaseReadyToStart: true, + velerov1api.BackupPhaseFailedValidation: true, + + // From here on there may be a partial log or other artifacts, and Deleting may + // still have all of them, so these keep the behavior callers have today. + velerov1api.BackupPhaseInProgress: false, + velerov1api.BackupPhaseWaitingForPluginOperations: false, + velerov1api.BackupPhaseWaitingForPluginOperationsPartiallyFailed: false, + velerov1api.BackupPhaseFinalizing: false, + velerov1api.BackupPhaseFinalizingPartiallyFailed: false, + velerov1api.BackupPhaseCompleted: false, + velerov1api.BackupPhasePartiallyFailed: false, + velerov1api.BackupPhaseFailed: false, + velerov1api.BackupPhaseDeleting: false, +} + +var restorePhaseExpectations = map[velerov1api.RestorePhase]bool{ + velerov1api.RestorePhaseNew: true, + velerov1api.RestorePhaseFailedValidation: true, + + velerov1api.RestorePhaseInProgress: false, + velerov1api.RestorePhaseWaitingForPluginOperations: false, + velerov1api.RestorePhaseWaitingForPluginOperationsPartiallyFailed: false, + velerov1api.RestorePhaseFinalizing: false, + velerov1api.RestorePhaseFinalizingPartiallyFailed: false, + velerov1api.RestorePhaseCompleted: false, + velerov1api.RestorePhasePartiallyFailed: false, + velerov1api.RestorePhaseFailed: false, +} + +func TestBackupPhaseHasNoArtifacts(t *testing.T) { + for phase, want := range backupPhaseExpectations { + t.Run(string(phase), func(t *testing.T) { + assert.Equal(t, want, backupPhaseHasNoArtifacts(phase)) + }) + } + + // A backup that has not been reconciled yet has an empty phase. It is left alone + // deliberately: the state is transient and the caller can retry. + assert.False(t, backupPhaseHasNoArtifacts(velerov1api.BackupPhase(""))) +} + +func TestRestorePhaseHasNoArtifacts(t *testing.T) { + for phase, want := range restorePhaseExpectations { + t.Run(string(phase), func(t *testing.T) { + assert.Equal(t, want, restorePhaseHasNoArtifacts(phase)) + }) + } + + assert.False(t, restorePhaseHasNoArtifacts(velerov1api.RestorePhase(""))) +} + +// The two tests below read the phase enum out of the generated CRDs, which come from the +// same kubebuilder markers as the Go constants. Adding a phase to the API without +// classifying it here fails, which a hand-written list of phases cannot do. +func TestBackupPhaseExpectationsCoverTheCRD(t *testing.T) { + phases := statusPhaseEnum(t, "backups.velero.io") + require.NotEmpty(t, phases, "no status.phase enum found in the Backup CRD") + + for _, phase := range phases { + _, ok := backupPhaseExpectations[velerov1api.BackupPhase(phase)] + assert.True(t, ok, "BackupPhase %q is served by the CRD but not classified by backupPhaseHasNoArtifacts", phase) + } + assert.Len(t, backupPhaseExpectations, len(phases), "backupPhaseExpectations and the CRD enum have drifted apart") +} + +func TestRestorePhaseExpectationsCoverTheCRD(t *testing.T) { + phases := statusPhaseEnum(t, "restores.velero.io") + require.NotEmpty(t, phases, "no status.phase enum found in the Restore CRD") + + for _, phase := range phases { + _, ok := restorePhaseExpectations[velerov1api.RestorePhase(phase)] + assert.True(t, ok, "RestorePhase %q is served by the CRD but not classified by restorePhaseHasNoArtifacts", phase) + } + assert.Len(t, restorePhaseExpectations, len(phases), "restorePhaseExpectations and the CRD enum have drifted apart") +} + +// statusPhaseEnum returns the allowed values of status.phase for a generated CRD. +func statusPhaseEnum(t *testing.T, crdName string) []string { + t.Helper() + + for _, crd := range v1crds.CRDs { + if crd.Name != crdName { + continue + } + for _, version := range crd.Spec.Versions { + if version.Schema == nil || version.Schema.OpenAPIV3Schema == nil { + continue + } + status, ok := version.Schema.OpenAPIV3Schema.Properties["status"] + if !ok { + continue + } + phase, ok := status.Properties["phase"] + if !ok { + continue + } + + values := make([]string, 0, len(phase.Enum)) + for _, raw := range phase.Enum { + var value string + require.NoError(t, json.Unmarshal(raw.Raw, &value)) + values = append(values, value) + } + return values + } + } + + t.Fatalf("CRD %q not found", crdName) + return nil +} + +// The guard is only useful if a caller can tell why it fired. These reconcile a real +// request against a fake client and assert on what a client would actually observe. +func TestGuardSetsFailedPhaseWithReason(t *testing.T) { + tests := []struct { + name string + targetKind velerov1api.DownloadTargetKind + backupPhase velerov1api.BackupPhase + wantPhase velerov1api.DownloadRequestPhase + wantMessage string + }{ + { + name: "backup that never ran fails with the phase named", + targetKind: velerov1api.DownloadTargetKindBackupLog, + backupPhase: velerov1api.BackupPhaseFailedValidation, + wantPhase: velerov1api.DownloadRequestPhaseFailed, + wantMessage: `backup "a-backup" is in phase "FailedValidation" and has not written any artifacts`, + }, + { + name: "backup that ran is untouched by the guard", + targetKind: velerov1api.DownloadTargetKindBackupLog, + backupPhase: velerov1api.BackupPhaseCompleted, + wantPhase: velerov1api.DownloadRequestPhaseProcessed, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + harness := newDownloadRequestHarness(t, tc.targetKind, tc.backupPhase) + got := harness.reconcile(t) + + assert.Equal(t, tc.wantPhase, got.Status.Phase) + assert.Equal(t, tc.wantMessage, got.Status.Message, + "the message is the only thing telling a caller why no URL arrived") + + if tc.wantPhase == velerov1api.DownloadRequestPhaseFailed { + assert.Empty(t, got.Status.DownloadURL, + "a failed request must not carry a URL that would 404") + } + }) + } +} + +// A message is set only on failure. An empty message alongside Failed would put the CLI +// back on its generic storage-location error, which is the thing this replaces. +func TestFailedPhaseAlwaysCarriesAMessage(t *testing.T) { + harness := newDownloadRequestHarness(t, + velerov1api.DownloadTargetKindBackupLog, velerov1api.BackupPhaseNew) + + got := harness.reconcile(t) + + require.Equal(t, velerov1api.DownloadRequestPhaseFailed, got.Status.Phase) + assert.NotEmpty(t, got.Status.Message) +} + +// downloadRequestHarness builds the smallest cluster a DownloadRequest reconcile needs: +// the request, its backup, and a storage location whose store returns a URL. +type downloadRequestHarness struct { + client kbclient.Client + reqName string + r *downloadRequestReconciler +} + +func newDownloadRequestHarness( + t *testing.T, + kind velerov1api.DownloadTargetKind, + backupPhase velerov1api.BackupPhase, +) *downloadRequestHarness { + t.Helper() + + s := runtime.NewScheme() + require.NoError(t, velerov1api.AddToScheme(s)) + + backup := builder.ForBackup(velerov1api.DefaultNamespace, "a-backup"). + StorageLocation("a-location").Phase(backupPhase).Result() + location := builder.ForBackupStorageLocation(velerov1api.DefaultNamespace, "a-location").Result() + request := builder.ForDownloadRequest(velerov1api.DefaultNamespace, "a-request"). + Target(kind, "a-backup").Result() + + c := fake.NewClientBuilder().WithScheme(s). + WithObjects(request, backup, location).Build() + + store := &persistencemocks.BackupStore{} + store.On("GetDownloadURL", request.Spec.Target).Return("a-url", nil) + + pluginManager := &pluginmocks.Manager{} + pluginManager.On("CleanupClients").Return(nil) + + r := NewDownloadRequestReconciler( + c, + testclocks.NewFakeClock(time.Now()), + func(logrus.FieldLogger) clientmgmt.Manager { return pluginManager }, + NewFakeObjectBackupStoreGetter(map[string]*persistencemocks.BackupStore{"a-location": store}), + velerotest.NewLogger(), + nil, + nil, + ) + + return &downloadRequestHarness{client: c, reqName: request.Name, r: r} +} + +func (h *downloadRequestHarness) reconcile(t *testing.T) *velerov1api.DownloadRequest { + t.Helper() + + _, err := h.r.Reconcile(context.Background(), ctrl.Request{ + NamespacedName: kbclient.ObjectKey{ + Namespace: velerov1api.DefaultNamespace, + Name: h.reqName, + }, + }) + require.NoError(t, err) + + got := &velerov1api.DownloadRequest{} + require.NoError(t, h.client.Get(context.Background(), kbclient.ObjectKey{ + Namespace: velerov1api.DefaultNamespace, Name: h.reqName, + }, got)) + return got +}