Repository: akuity/kargo

Issue:
Status Check Functions in conditionals
# Proposed Feature

This is a follow up to https://github.com/akuity/kargo/issues/3125.

We added conditionals, but would now like the ability to run steps based on status conditions (e.g. always, or upon failure).

GitHub Actions solves this by re-using their `if` clause with [Status Check Functions](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#status-check-functions).

Examples:

```
if: ${{ success() }}
if: ${{ always() }}
if: ${{ cancelled() }}
if: ${{ failure() }}
```

At first I felt reusing the `if` clause for this purpose seemed a bit too magical and preferred this to be in a separate field. From docs:

> A default status check of success() is applied unless you include one of these functions

However, after thinking about this more, having it in the `if` clause has advantages over introducing it into another field because it can be mixed with other checks. e.g.:

```
if: ${{ failure() && steps.demo.conclusion == 'failure' }}
```

So I am in favor of GitHub's approach to this.

# Motivation

This would be useful in things like notification steps

# Suggested Implementation

Introduce status check functions understood in the `if` clause.


Hints from issue comments:
@jessesuen: Alternative/related proposals:
* https://github.com/akuity/kargo/issues/2972
* https://github.com/akuity/kargo/issues/3228@krancour: I would happily close #3228 in favor of this approach.@sbyrne-teck: Hey all - is the proposal here to solve rollback scenarios with this too? 
Case I'm thinking about is - 
1. Promote to Stage A (git clone, commit, push; argo-update)
2. Run Verification Steps(metrics check, qa test run)
3. A Test Fails causing failed verification
4. Run a step to redo step one with the previous freight as input - effectively a rollback@jessesuen: > is the proposal here to solve rollback scenarios with this too?
 
No, https://github.com/akuity/kargo/issues/2972 would be the issue to follow, which could automatically trigger a roll back in the case of verification failure.

Solution patch:
diff --git a/api/v1alpha1/generated.pb.go b/api/v1alpha1/generated.pb.go
index 9ef0660d..7e91ce5f 100644
--- a/api/v1alpha1/generated.pb.go
+++ b/api/v1alpha1/generated.pb.go
@@ -2134,280 +2134,282 @@ func init() {
 }
 
 var fileDescriptor_e26b7f7bbc391025 = []byte{
-	// 4355 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x7c, 0x4d, 0x6c, 0x1c, 0x47,
-	0x76, 0xbf, 0x7a, 0x86, 0x33, 0x24, 0xdf, 0x90, 0x14, 0x59, 0xa2, 0x6c, 0x2e, 0xf7, 0x6f, 0x51,
-	0xff, 0xb6, 0x63, 0xd8, 0xb1, 0x3d, 0x8c, 0x68, 0xcb, 0x96, 0x25, 0xaf, 0x02, 0xce, 0x50, 0x1f,
-	0xf4, 0x6a, 0x2d, 0xa6, 0x46, 0x96, 0xd7, 0xb2, 0x0d, 0xa5, 0x38, 0x53, 0x9c, 0xe9, 0xe5, 0x4c,
-	0xf7, 0xb8, 0xaa, 0x87, 0x16, 0x93, 0x20, 0x71, 0x3e, 0x11, 0x20, 0x41, 0x62, 0x20, 0x1b, 0x78,
-	0x0f, 0x09, 0x12, 0x24, 0xa7, 0x60, 0x81, 0x5c, 0x73, 0xc8, 0xc1, 0x87, 0x5c, 0xbc, 0xc9, 0x26,
-	0x30, 0x36, 0x87, 0x38, 0xc0, 0x82, 0x59, 0x73, 0x81, 0x9c, 0x73, 0xc9, 0x45, 0x40, 0x80, 0xa0,
-	0x3e, 0xba, 0xbb, 0xba, 0xa7, 0x47, 0x9c, 0x1e, 0x7e, 0x44, 0xd8, 0x1b, 0x59, 0xaf, 0xea, 0xf7,
-	0xaa, 0x5e, 0xd5, 0x7b, 0xf5, 0x3e, 0xaa, 0x07, 0x5e, 0x69, 0x3a, 0x7e, 0xab, 0xb7, 0x59, 0xae,
-	0x7b, 0x9d, 0x65, 0xb2, 0xdd, 0x73, 0xfc, 0xdd, 0xe5, 0x6d, 0xc2, 0x9a, 0xde, 0x32, 0xe9, 0x3a,
-	0xcb, 0x3b, 0x17, 0x48, 0xbb, 0xdb, 0x22, 0x17, 0x96, 0x9b, 0xd4, 0xa5, 0x8c, 0xf8, 0xb4, 0x51,
-	0xee, 0x32, 0xcf, 0xf7, 0xd0, 0x33, 0xd1, 0xa8, 0xb2, 0x1a, 0x55, 0x96, 0xa3, 0xca, 0xa4, 0xeb,
-	0x94, 0x83, 0x51, 0x8b, 0x2f, 0x19, 0xd8, 0x4d, 0xaf, 0xe9, 0x2d, 0xcb, 0xc1, 0x9b, 0xbd, 0x2d,
-	0xf9, 0x9f, 0xfc, 0x47, 0xfe, 0xa5, 0x40, 0x17, 0x6f, 0x6e, 0x5f, 0xe2, 0x65, 0x47, 0x72, 0xa6,
-	0x0f, 0x7c, 0xea, 0x72, 0xc7, 0x73, 0xf9, 0x4b, 0xa4, 0xeb, 0x70, 0xca, 0x76, 0x28, 0x5b, 0xee,
-	0x6e, 0x37, 0x05, 0x8d, 0xc7, 0x3b, 0x2c, 0xef, 0xf4, 0x4d, 0x6f, 0xf1, 0x95, 0x08, 0xa9, 0x43,
-	0xea, 0x2d, 0xc7, 0xa5, 0x6c, 0x37, 0x1a, 0xde, 0xa1, 0x3e, 0x49, 0x1b, 0xb5, 0x3c, 0x68, 0x14,
-	0xeb, 0xb9, 0xbe, 0xd3, 0xa1, 0x7d, 0x03, 0x5e, 0x3d, 0x68, 0x00, 0xaf, 0xb7, 0x68, 0x87, 0x24,
-	0xc7, 0xd9, 0xef, 0xc3, 0x99, 0x55, 0x97, 0xb4, 0x77, 0xb9, 0xc3, 0x71, 0xcf, 0x5d, 0x65, 0xcd,
-	0x5e, 0x87, 0xba, 0x3e, 0x3a, 0x0f, 0x63, 0x2e, 0xe9, 0xd0, 0x05, 0xeb, 0xbc, 0xf5, 0xdc, 0x64,
-	0x65, 0xea, 0xf3, 0xbd, 0xa5, 0x53, 0xfb, 0x7b, 0x4b, 0x63, 0x6f, 0x91, 0x0e, 0xc5, 0x92, 0x82,
-	0x9e, 0x86, 0xc2, 0x0e, 0x69, 0xf7, 0xe8, 0x42, 0x4e, 0x76, 0x99, 0xd6, 0x5d, 0x0a, 0x77, 0x45,
-	0x23, 0x56, 0x34, 0xfb, 0xb7, 0xf3, 0x31, 0xf8, 0x6f, 0x51, 0x9f, 0x34, 0x88, 0x4f, 0x50, 0x07,
-	0x8a, 0x6d, 0xb2, 0x49, 0xdb, 0x7c, 0xc1, 0x3a, 0x9f, 0x7f, 0xae, 0xb4, 0x72, 0xad, 0x3c, 0xcc,
-	0x26, 0x96, 0x53, 0xa0, 0xca, 0xb7, 0x24, 0xce, 0x35, 0xd7, 0x67, 0xbb, 0x95, 0x19, 0x3d, 0x89,
-	0xa2, 0x6a, 0xc4, 0x9a, 0x09, 0xfa, 0x4d, 0x0b, 0x4a, 0xc4, 0x75, 0x3d, 0x9f, 0xf8, 0x62, 0x9b,
-	0x16, 0x72, 0x92, 0xe9, 0x9b, 0xa3, 0x33, 0x5d, 0x8d, 0xc0, 0x14, 0xe7, 0x33, 0x9a, 0x73, 0xc9,
-	0xa0, 0x60, 0x93, 0xe7, 0xe2, 0xeb, 0x50, 0x32, 0xa6, 0x8a, 0x66, 0x21, 0xbf, 0x4d, 0x77, 0x95,
-	0x7c, 0xb1, 0xf8, 0x13, 0xcd, 0xc7, 0x04, 0xaa, 0x25, 0x78, 0x39, 0x77, 0xc9, 0x5a, 0xbc, 0x0a,
-	0xb3, 0x49, 0x86, 0x59, 0xc6, 0xdb, 0x7f, 0x64, 0xc1, 0xbc, 0xb1, 0x0a, 0x4c, 0xb7, 0x28, 0xa3,
-	0x6e, 0x9d, 0xa2, 0x65, 0x98, 0x14, 0x7b, 0xc9, 0xbb, 0xa4, 0x1e, 0x6c, 0xf5, 0x9c, 0x5e, 0xc8,
-	0xe4, 0x5b, 0x01, 0x01, 0x47, 0x7d, 0xc2, 0x63, 0x91, 0x7b, 0xd4, 0xb1, 0xe8, 0xb6, 0x08, 0xa7,
-	0x0b, 0xf9, 0xf8, 0xb1, 0xd8, 0x10, 0x8d, 0x58, 0xd1, 0xec, 0xfb, 0xf0, 0xb5, 0x60, 0x3e, 0x77,
-	0x68, 0xa7, 0xdb, 0x26, 0x3e, 0x8d, 0x26, 0x75, 0xf0, 0xd1, 0x3b, 0x0f, 0x63, 0xdb, 0x8e, 0xdb,
-	0x48, 0xce, 0xe2, 0x9b, 0x8e, 0xdb, 0xc0, 0x92, 0x62, 0x6f, 0xc3, 0xf4, 0x6a, 0xb7, 0xcb, 0xbc,
-	0x1d, 0xda, 0xa8, 0xf9, 0xa4, 0x49, 0xd1, 0x3d, 0x00, 0xa2, 0x1b, 0x56, 0x7d, 0x09, 0x5d, 0x5a,
-	0xf9, 0xf9, 0xb2, 0xd2, 0x99, 0xb2, 0xa9, 0x33, 0xe5, 0xee, 0x76, 0x53, 0x34, 0xf0, 0xb2, 0x50,
-	0xcd, 0xf2, 0xce, 0x85, 0xf2, 0x1d, 0xa7, 0x43, 0x2b, 0x33, 0xfb, 0x7b, 0x4b, 0xb0, 0x1a, 0x22,
-	0x60, 0x03, 0xcd, 0xfe, 0x2d, 0x0b, 0xce, 0xae, 0xb2, 0xa6, 0x57, 0x5d, 0x5b, 0xed, 0x76, 0x6f,
-	0x52, 0xd2, 0xf6, 0x5b, 0x35, 0x9f, 0xf8, 0x3d, 0x8e, 0xae, 0x42, 0x91, 0xcb, 0xbf, 0xf4, 0x62,
-	0x9e, 0x0d, 0xce, 0xa7, 0xa2, 0x3f, 0xdc, 0x5b, 0x9a, 0x4f, 0x19, 0x48, 0xb1, 0x1e, 0x85, 0x9e,
-	0x87, 0xf1, 0x0e, 0xe5, 0x9c, 0x34, 0x03, 0x89, 0x9f, 0xd6, 0x00, 0xe3, 0xdf, 0x52, 0xcd, 0x38,
-	0xa0, 0xdb, 0xff, 0x98, 0x83, 0xd3, 0x21, 0x96, 0x66, 0x7f, 0x0c, 0xdb, 0xdb, 0x83, 0xa9, 0x96,
-	0xb1, 0x42, 0xb9, 0xcb, 0xa5, 0x95, 0x2b, 0x43, 0x6a, 0x52, 0x9a, 0x90, 0x2a, 0xf3, 0x9a, 0xcd,
-	0x94, 0xd9, 0x8a, 0x63, 0x6c, 0x50, 0x07, 0x80, 0xef, 0xba, 0x75, 0xcd, 0x74, 0x4c, 0x32, 0x7d,
-	0x3d, 0x23, 0xd3, 0x5a, 0x08, 0x50, 0x41, 0x9a, 0x25, 0x44, 0x6d, 0xd8, 0x60, 0x60, 0xff, 0xad,
-	0x05, 0x67, 0x52, 0xc6, 0xa1, 0x37, 0x12, 0xfb, 0xf9, 0x4c, 0xdf, 0x7e, 0xa2, 0xbe, 0x61, 0xd1,
-	0x6e, 0xbe, 0x08, 0x13, 0x8c, 0xee, 0x38, 0xe2, 0xa6, 0xd0, 0x12, 0x9e, 0xd5, 0xe3, 0x27, 0xb0,
-	0x6e, 0xc7, 0x61, 0x0f, 0xf4, 0x02, 0x4c, 0x06, 0x7f, 0x0b, 0x31, 0xe7, 0x85, 0x32, 0x89, 0x8d,
-	0x0b, 0xba, 0x72, 0x1c, 0xd1, 0xed, 0xdf, 0x80, 0x42, 0xb5, 0x45, 0x98, 0x2f, 0x4e, 0x0c, 0xa3,
-	0x5d, 0xef, 0x6d, 0x7c, 0x4b, 0x4f, 0x31, 0x3c, 0x31, 0x58, 0x35, 0xe3, 0x80, 0x3e, 0xc4, 0x66,
-	0x3f, 0x0f, 0xe3, 0x3b, 0x94, 0xc9, 0xf9, 0xe6, 0xe3, 0x60, 0x77, 0x55, 0x33, 0x0e, 0xe8, 0xf6,
-	0xbf, 0x5a, 0x30, 0x2f, 0x67, 0xb0, 0xe6, 0xf0, 0xba, 0xb7, 0x43, 0xd9, 0x2e, 0xa6, 0xbc, 0xd7,
-	0x3e, 0xe2, 0x09, 0xad, 0xc1, 0x2c, 0xa7, 0x9d, 0x1d, 0xca, 0xaa, 0x9e, 0xcb, 0x7d, 0x46, 0x1c,
-	0xd7, 0xd7, 0x33, 0x5b, 0xd0, 0xbd, 0x67, 0x6b, 0x09, 0x3a, 0xee, 0x1b, 0x81, 0x9e, 0x83, 0x09,
-	0x3d, 0x6d, 0x71, 0x94, 0x84, 0x60, 0xa7, 0xc4, 0x1e, 0xe8, 0x35, 0x71, 0x1c, 0x52, 0xed, 0xff,
-	0xb4, 0x60, 0x4e, 0xae, 0xaa, 0xd6, 0xdb, 0xe4, 0x75, 0xe6, 0x74, 0x85, 0x01, 0x7e, 0x1c, 0x97,
-	0x74, 0x15, 0x66, 0x1a, 0x81, 0xe0, 0x6f, 0x39, 0x1d, 0xc7, 0x97, 0x3a, 0x52, 0xa8, 0x3c, 0xa1,
-	0x31, 0x66, 0xd6, 0x62, 0x54, 0x9c, 0xe8, 0xad, 0xb6, 0xaf, 0xdd, 0xe3, 0x3e, 0x65, 0x1b, 0xcc,
-	0xeb, 0x78, 0x62, 0x9d, 0x77, 0x08, 0xdf, 0x46, 0xbf, 0x0c, 0x13, 0x1d, 0x7d, 0xe9, 0x69, 0xab,
-	0xf9, 0x0b, 0xc3, 0x59, 0xcd, 0xdb, 0x9b, 0xdf, 0xa1, 0x75, 0x5f, 0x5c, 0x98, 0x91, 0xb6, 0x45,
-	0x6d, 0x38, 0x44, 0x45, 0xef, 0xc2, 0x18, 0xef, 0xd2, 0xba, 0x14, 0x51, 0x69, 0xe5, 0xb5, 0xe1,
-	0x94, 0x3a, 0x36, 0xc9, 0x5a, 0x97, 0xd6, 0x23, 0xd9, 0x8a, 0xff, 0xb0, 0x84, 0xb4, 0xff, 0xdd,
-	0x82, 0x85, 0xb4, 0x55, 0xdd, 0x72, 0xb8, 0x8f, 0xde, 0xef, 0x5b, 0x59, 0x79, 0xb8, 0x95, 0x89,
-	0xd1, 0x72, 0x5d, 0xa1, 0xf6, 0x06, 0x2d, 0xc6, 0xaa, 0xee, 0x43, 0xc1, 0xf1, 0x69, 0x27, 0x70,
-	0x35, 0x2e, 0x0f, 0xb7, 0xac, 0xb4, 0xc9, 0x46, 0x57, 0xe8, 0xba, 0x00, 0xc4, 0x0a, 0xd7, 0x7e,
-	0x0f, 0xa6, 0xaa, 0x3d, 0xc6, 0xa8, 0xeb, 0xab, 0x0b, 0xee, 0x9b, 0x50, 0xe0, 0x8e, 0xab, 0xed,
-	0x7c, 0xb6, 0xbb, 0x6d, 0x52, 0x80, 0xd7, 0xc4, 0x60, 0xac, 0x30, 0xec, 0x3f, 0xcb, 0xc3, 0x99,
-	0xe0, 0xc4, 0xd0, 0xc6, 0x2a, 0xf3, 0x9d, 0x2d, 0x52, 0xf7, 0x39, 0x6a, 0xc0, 0x54, 0x23, 0x6a,
-	0xf6, 0xb5, 0x21, 0xce, 0xc2, 0x2b, 0x34, 0xf6, 0x06, 0xbc, 0x8f, 0x63, 0xa8, 0xe8, 0x1d, 0xc8,
-	0x37, 0x1d, 0x5f, 0x7b, 0x86, 0x97, 0x86, 0x93, 0xdc, 0x0d, 0x27, 0x69, 0x79, 0x2a, 0x25, 0xcd,
-	0x2a, 0x7f, 0xc3, 0xf1, 0xb1, 0x40, 0x44, 0x9b, 0x50, 0x74, 0x3a, 0xa4, 0x49, 0x33, 0xee, 0xca,
-	0xba, 0x18, 0x93, 0x44, 0x0f, 0x5d, 0x4d, 0x49, 0xe5, 0x58, 0x23, 0x0b, 0x1e, 0x75, 0x61, 0x31,
-	0x94, 0xcd, 0x1e, 0x7e, 0xe7, 0x53, 0x6c, 0x67, 0xc4, 0x43, 0x52, 0x39, 0xd6, 0xc8, 0xf6, 0x97,
-	0x39, 0x98, 0x8d, 0xe4, 0x57, 0xf5, 0x3a, 0x1d, 0xc7, 0x47, 0x8b, 0x90, 0x73, 0x1a, 0xda, 0x20,
-	0x81, 0x1e, 0x98, 0x5b, 0x5f, 0xc3, 0x39, 0xa7, 0x81, 0x9e, 0x85, 0xe2, 0x26, 0x23, 0x6e, 0xbd,
-	0xa5, 0x0d, 0x51, 0x08, 0x5c, 0x91, 0xad, 0x58, 0x53, 0xd1, 0x53, 0x90, 0xf7, 0x49, 0x53, 0xdb,
-	0x9f, 0x50, 0x7e, 0x77, 0x48, 0x13, 0x8b, 0x76, 0x61, 0xf8, 0x78, 0x4f, 0xea, 0xb0, 0xdc, 0x79,
-	0xc3, 0xf0, 0xd5, 0x54, 0x33, 0x0e, 0xe8, 0x82, 0x23, 0xe9, 0xf9, 0x2d, 0x8f, 0x2d, 0x14, 0xe2,
-	0x1c, 0x57, 0x65, 0x2b, 0xd6, 0x54, 0xe1, 0xa2, 0xd4, 0xe5, 0xfc, 0x7d, 0xca, 0x16, 0x8a, 0x71,
-	0x17, 0xa5, 0x1a, 0x10, 0x70, 0xd4, 0x07, 0x7d, 0x00, 0xa5, 0x3a, 0xa3, 0xc4, 0xf7, 0xd8, 0x1a,
-	0xf1, 0xe9, 0xc2, 0x78, 0xe6, 0x13, 0x78, 0x5a, 0x78, 0xe9, 0xd5, 0x08, 0x02, 0x9b, 0x78, 0xf6,
-	0xdf, 0xe5, 0x61, 0x21, 0x12, 0xad, 0xdc, 0xdb, 0xc8, 0x33, 0xd5, 0xe2, 0xb1, 0x06, 0x88, 0xe7,
-	0x59, 0x28, 0x36, 0x9c, 0x26, 0xe5, 0x7e, 0x52, 0xca, 0x6b, 0xb2, 0x15, 0x6b, 0x2a, 0xfa, 0xbd,
-	0x44, 0x34, 0x52, 0x90, 0x07, 0xe5, 0xf6, 0x70, 0x07, 0x65, 0xd0, 0xe4, 0x46, 0x08, 0x49, 0xd0,
-	0x0a, 0x40, 0xd3, 0xf1, 0xf5, 0xa5, 0xa5, 0x77, 0x3d, 0x34, 0xd6, 0x37, 0x42, 0x0a, 0x36, 0x7a,
-	0xa1, 0x77, 0x60, 0x52, 0xca, 0x6b, 0x44, 0xfd, 0x97, 0x2e, 0x4c, 0x35, 0x00, 0xc0, 0x11, 0xd6,
-	0xa1, 0x83, 0x9c, 0xf7, 0x00, 0x5d, 0x7b, 0xd0, 0x65, 0x94, 0x8b, 0xab, 0xfb, 0x2e, 0x61, 0x0e,
-	0xd9, 0x6c, 0xd3, 0xa3, 0x8a, 0x63, 0xbf, 0x18, 0x83, 0xf1, 0xeb, 0x8c, 0x3a, 0xcd, 0x96, 0x7f,
-	0x02, 0x57, 0xe2, 0xd3, 0x50, 0x20, 0x6d, 0x87, 0x70, 0x79, 0xba, 0x8d, 0x29, 0xad, 0x8a, 0x46,
-	0xac, 0x68, 0xe8, 0x3d, 0x28, 0x7a, 0xcc, 0x69, 0x3a, 0xee, 0xc2, 0xa4, 0x9c, 0xc4, 0xcb, 0xc3,
-	0x9d, 0x1f, 0xbd, 0x8a, 0xdb, 0x72, 0x68, 0x74, 0x44, 0xd5, 0xff, 0x58, 0x43, 0xa2, 0x7b, 0x30,
-	0xae, 0x54, 0x2e, 0x30, 0x63, 0xcb, 0x43, 0x9b, 0x61, 0xa5, 0xb5, 0x91, 0x69, 0x50, 0xff, 0x73,
-	0x1c, 0x00, 0xa2, 0x5a, 0x68, 0x85, 0xc7, 0x24, 0xf4, 0x0b, 0x19, 0xac, 0xf0, 0x40, 0xb3, 0x5b,
-	0x0b, 0xcd, 0x6e, 0x21, 0x0b, 0xa8, 0x34, 0xac, 0x83, 0xec, 0xac, 0x10, 0xb1, 0x76, 0xf7, 0x8b,
-	0x23, 0x88, 0x58, 0xc7, 0x1a, 0x33, 0xf1, 0x18, 0x21, 0x88, 0x06, 0xec, 0xef, 0xe6, 0x61, 0x4e,
-	0xf7, 0xac, 0x7a, 0xed, 0x36, 0xad, 0x4b, 0xdf, 0x52, 0x59, 0xf1, 0x7c, 0xaa, 0x15, 0x77, 0x02,
-	0x9f, 0x42, 0xdd, 0x8c, 0x95, 0x4c, 0xb3, 0x89, 0x78, 0x94, 0xa5, 0x1f, 0xa1, 0x6c, 0x44, 0xb8,
-	0x4b, 0xba, 0x97, 0xf6, 0x2e, 0xd0, 0xef, 0x5a, 0x70, 0x66, 0x87, 0x32, 0x67, 0xcb, 0xa9, 0x4b,
-	0x7d, 0xbc, 0xe9, 0x70, 0xdf, 0x63, 0xbb, 0xfa, 0xde, 0x7c, 0x75, 0x38, 0xce, 0x77, 0x0d, 0x80,
-	0x75, 0x77, 0xcb, 0xab, 0x7c, 0x5d, 0x73, 0x3b, 0x73, 0xb7, 0x1f, 0x1a, 0xa7, 0xf1, 0x5b, 0xec,
-	0x02, 0x44, 0xb3, 0x4d, 0x31, 0x07, 0xb7, 0x4c, 0xe5, 0x1d, 0x7a, 0x62, 0xc1, 0x62, 0x03, 0xdb,
-	0x69, 0x9a, 0x91, 0xcf, 0x2c, 0x28, 0x69, 0xfa, 0x09, 0xb8, 0x89, 0x38, 0xee, 0x26, 0xbe, 0x94,
-	0x69, 0xfe, 0x03, 0x3c, 0x43, 0x06, 0xd3, 0x31, 0x25, 0x47, 0x17, 0x75, 0xba, 0x44, 0xd9, 0xc0,
-	0xff, 0x6f, 0xa6, 0x4b, 0x1e, 0xee, 0x2d, 0xcd, 0xc5, 0x3a, 0x47, 0x39, 0x94, 0x83, 0x63, 0x97,
-	0xcb, 0x13, 0xdf, 0xfb, 0xcb, 0xa5, 0x53, 0x1f, 0xff, 0xf8, 0xfc, 0x29, 0xfb, 0xd3, 0x3c, 0xcc,
-	0x26, 0xa5, 0x3a, 0x84, 0xed, 0x8d, 0x6c, 0xd8, 0xc4, 0xb1, 0xda, 0xb0, 0xdc, 0xf1, 0xd9, 0xb0,
-	0xfc, 0x71, 0xd8, 0xb0, 0xb1, 0x23, 0xb3, 0x61, 0xf6, 0xbf, 0x58, 0x30, 0x13, 0xee, 0xcc, 0x87,
-	0x3d, 0xe1, 0x7f, 0x44, 0x52, 0xb7, 0x8e, 0x5e, 0xea, 0xf7, 0x61, 0x9c, 0x7b, 0x3d, 0x56, 0x97,
-	0x4e, 0xb6, 0x40, 0x7f, 0x25, 0x9b, 0xd1, 0x54, 0x63, 0x0d, 0xcf, 0x52, 0x35, 0xe0, 0x00, 0xd5,
-	0xfe, 0x2c, 0x17, 0x2e, 0x48, 0xd3, 0x94, 0xe3, 0xc5, 0x84, 0x5b, 0x2a, 0x16, 0x34, 0x61, 0x3a,
-	0x5e, 0xa2, 0x15, 0x6b, 0x2a, 0xb2, 0xa5, 0x3d, 0x0f, 0xfc, 0xff, 0xc9, 0x0a, 0x68, 0xb3, 0x2c,
-	0x37, 0x41, 0x51, 0x50, 0x17, 0x66, 0x19, 0xfd, 0xb0, 0xe7, 0x30, 0xda, 0xa8, 0x79, 0x64, 0x5b,
-	0x38, 0x2d, 0x3a, 0xc9, 0x35, 0xa4, 0xde, 0xaf, 0xf5, 0x98, 0x34, 0x61, 0x95, 0x79, 0x11, 0xbb,
-	0xe3, 0x04, 0x16, 0xee, 0x43, 0x47, 0x1e, 0xcc, 0x93, 0x1d, 0xe2, 0xb4, 0xc9, 0xa6, 0xd3, 0x76,
-	0xfc, 0xdd, 0x9a, 0xcf, 0x88, 0x4f, 0x9b, 0xbb, 0xda, 0xc5, 0xbe, 0xa2, 0xd7, 0x32, 0xbf, 0x9a,
-	0xd2, 0xe7, 0xe1, 0xde, 0xd2, 0xd7, 0xb5, 0x2c, 0xd2, 0xc8, 0x38, 0x15, 0xd8, 0xfe, 0x8f, 0x42,
-	0x68, 0x21, 0x74, 0x5e, 0xeb, 0x57, 0xa1, 0x54, 0x57, 0xc1, 0x64, 0x7b, 0x77, 0xdd, 0xd5, 0x67,
-	0x7a, 0x6d, 0x84, 0xdb, 0xae, 0x5c, 0x8d, 0x60, 0x12, 0x5e, 0xa8, 0x41, 0xc1, 0x26, 0x37, 0xf4,
-	0x11, 0x80, 0x32, 0xfd, 0xb4, 0xb1, 0xee, 0xea, 0xbb, 0xad, 0x3a, 0x0a, 0xef, 0xbb, 0x21, 0x8a,
-	0x62, 0x1d, 0x3a, 0x59, 0x11, 0x01, 0x1b, 0xac, 0xc4, 0xaa, 0x83, 0x2c, 0xee, 0x75, 0x8f, 0x69,
-	0x23, 0x31, 0xd2, 0xaa, 0x57, 0x23, 0x98, 0xa4, 0xef, 0x1d, 0x51, 0xb0, 0xc9, 0x6d, 0x91, 0xc1,
-	0x6c, 0x52, 0x56, 0x29, 0xf7, 0xdb, 0xcd, 0xf8, 0xfd, 0xb6, 0x32, 0xa4, 0x45, 0x30, 0x12, 0x03,
-	0x66, 0x1d, 0x81, 0xc1, 0xe9, 0x84, 0x8c, 0x52, 0x58, 0xae, 0xc7, 0x59, 0xbe, 0x9c, 0xe5, 0xae,
-	0xd7, 0xd9, 0x76, 0x93, 0x27, 0x87, 0xd9, 0xa4, 0x74, 0x8e, 0x8c, 0x69, 0x2c, 0xc5, 0x6f, 0x5e,
-	0xe2, 0x7f, 0x9e, 0x83, 0xc9, 0xd0, 0x8c, 0x67, 0xc9, 0xd7, 0x29, 0xf7, 0x2b, 0x77, 0x40, 0x10,
-	0x9d, 0x1f, 0x26, 0x88, 0x1e, 0x1b, 0x1c, 0x44, 0x07, 0x39, 0xfd, 0xe2, 0xa3, 0x73, 0xfa, 0x46,
-	0x10, 0x3d, 0x3e, 0x7c, 0x10, 0x3d, 0x71, 0x70, 0x10, 0x6d, 0xff, 0x95, 0x05, 0xa8, 0x3f, 0x63,
-	0x92, 0x45, 0x50, 0x24, 0x79, 0xb9, 0xbe, 0x9a, 0x35, 0x7c, 0x3d, 0xe8, 0x8e, 0xb5, 0x3f, 0x2b,
-	0xc0, 0xe9, 0x1b, 0xce, 0xc8, 0xa9, 0x57, 0x1f, 0x9e, 0x54, 0x48, 0x35, 0xaa, 0x1d, 0xdf, 0xd0,
-	0xb2, 0xaa, 0xfd, 0xbd, 0xac, 0x87, 0x3e, 0x59, 0x4d, 0xef, 0xf6, 0x70, 0x30, 0x09, 0x0f, 0x82,
-	0x1e, 0xfa, 0x90, 0x5c, 0x81, 0x69, 0xee, 0x33, 0xa7, 0xee, 0xab, 0xe4, 0x2e, 0x5f, 0x28, 0xc9,
-	0x9b, 0xeb, 0xac, 0xee, 0x3e, 0x5d, 0x33, 0x89, 0x38, 0xde, 0x37, 0x35, 0x67, 0x3c, 0x96, 0x39,
-	0x67, 0xbc, 0x0c, 0x93, 0xa4, 0xdd, 0xf6, 0x3e, 0xba, 0x43, 0x9a, 0x5c, 0x67, 0x69, 0xc2, 0x53,
-	0xb3, 0x1a, 0x10, 0x70, 0xd4, 0x07, 0x95, 0x01, 0x9c, 0xa6, 0xeb, 0x31, 0x2a, 0x47, 0x14, 0xe5,
-	0x15, 0x2a, 0xeb, 0x62, 0xeb, 0x61, 0x2b, 0x36, 0x7a, 0xa0, 0x1a, 0x9c, 0x75, 0x5c, 0x4e, 0xeb,
-	0x3d, 0x46, 0x6b, 0xdb, 0x4e, 0xf7, 0xce, 0xad, 0x9a, 0xb4, 0x12, 0xbb, 0xf2, 0x34, 0x4f, 0x54,
-	0x9e, 0xd2, 0xcc, 0xce, 0xae, 0xa7, 0x75, 0xc2, 0xe9, 0x63, 0xd1, 0x2b, 0x30, 0xe5, 0xb8, 0xf5,
-	0x76, 0xaf, 0x41, 0x37, 0x88, 0xdf, 0xe2, 0x0b, 0x13, 0x72, 0x1a, 0xb3, 0xfb, 0x7b, 0x4b, 0x53,
-	0xeb, 0x46, 0x3b, 0x8e, 0xf5, 0x12, 0xa3, 0xe8, 0x03, 0x63, 0xd4, 0x64, 0x34, 0xea, 0xda, 0x03,
-	0x73, 0x94, 0xd9, 0x2b, 0x25, 0xab, 0x0e, 0x99, 0xb2, 0xea, 0xdf, 0xcf, 0x41, 0x51, 0x15, 0xb5,
-	0xd0, 0xc5, 0x44, 0xe5, 0xe8, 0xa9, 0xbe, 0xca, 0x51, 0x29, 0xad, 0x00, 0x68, 0x43, 0xd1, 0xe1,
-	0xbc, 0x17, 0xf7, 0x58, 0xd6, 0x65, 0x0b, 0xd6, 0x14, 0x99, 0x71, 0xf4, 0xdc, 0x2d, 0xa7, 0xa9,
-	0xd3, 0x31, 0x57, 0x0d, 0x3f, 0x25, 0x7a, 0x9a, 0x70, 0x3f, 0x7c, 0xbb, 0x10, 0xb9, 0x2c, 0xb1,
-	0x0e, 0xc2, 0x77, 0x79, 0xb3, 0x76, 0xfb, 0x2d, 0xc5, 0xa3, 0x2a, 0x11, 0xb1, 0x46, 0x16, 0x3c,
-	0xbc, 0x9e, 0xdf, 0xed, 0xf9, 0xf2, 0xa0, 0x1c, 0x11, 0x8f, 0xdb, 0x12, 0x11, 0x6b, 0x64, 0xfb,
-	0x53, 0x0b, 0x4e, 0x2b, 0x19, 0x54, 0x5b, 0xb4, 0xbe, 0x5d, 0xf3, 0x69, 0x57, 0x84, 0x10, 0x3d,
-	0x4e, 0x79, 0x32, 0x84, 0x78, 0x9b, 0x53, 0x8e, 0x25, 0xc5, 0x58, 0x7d, 0xee, 0xb8, 0x56, 0x6f,
-	0x5f, 0x02, 0x63, 0x73, 0x64, 0x55, 0x56, 0x15, 0x27, 0xd5, 0x15, 0x96, 0x8f, 0x8c, 0x90, 0xea,
-	0xb5, 0x8b, 0x03, 0xba, 0xbd, 0x9f, 0x83, 0x82, 0xf4, 0xf2, 0xb3, 0x58, 0xae, 0x78, 0x5a, 0x2e,
-	0x37, 0x54, 0x5a, 0xee, 0x80, 0xcc, 0x6d, 0x94, 0x9a, 0x1c, 0x7b, 0x64, 0x6a, 0x92, 0xa7, 0x65,
-	0x26, 0xdf, 0xc8, 0x10, 0xdc, 0x8c, 0xf2, 0x32, 0xe2, 0xb0, 0x99, 0xbf, 0x9f, 0x5a, 0x30, 0x9f,
-	0x96, 0xa3, 0xcf, 0x22, 0xf3, 0x17, 0x61, 0xa2, 0xdb, 0x26, 0xfe, 0x96, 0xc7, 0x3a, 0xc9, 0xda,
-	0xec, 0x86, 0x6e, 0xc7, 0x61, 0x0f, 0xc4, 0x00, 0x58, 0x10, 0xe6, 0x06, 0x21, 0xe0, 0xd5, 0xc3,
-	0xe5, 0x6f, 0xa3, 0x1d, 0x0e, 0x9b, 0x38, 0x36, 0xb8, 0xd8, 0x7f, 0x50, 0x80, 0x39, 0x39, 0x64,
-	0xd4, 0x0b, 0x71, 0x94, 0x63, 0xd5, 0x85, 0x27, 0x64, 0x70, 0xda, 0x7f, 0x87, 0xaa, 0x93, 0x76,
-	0x49, 0x8f, 0x7f, 0x62, 0x3d, 0xb5, 0xd7, 0xc3, 0x81, 0x14, 0x3c, 0x00, 0xb7, 0xff, 0x62, 0x84,
-	0x9f, 0xbd, 0x8b, 0xd1, 0x3c, 0x6c, 0xe3, 0x07, 0x1e, 0xb6, 0x81, 0xd7, 0xe8, 0xc4, 0x21, 0xae,
-	0xd1, 0xfe, 0xab, 0x6d, 0x32, 0xd3, 0xd5, 0xf6, 0x17, 0x39, 0x18, 0xdf, 0x60, 0x9e, 0xac, 0xf5,
-	0x1c, 0x7f, 0x42, 0xfc, 0xed, 0x11, 0x6b, 0xc4, 0x02, 0x4a, 0xd9, 0x72, 0x59, 0x23, 0x9e, 0x88,
-	0xd7, 0x87, 0x8d, 0xfc, 0x6e, 0x3e, 0x4b, 0xd8, 0xa1, 0x81, 0x0f, 0xc8, 0xef, 0xfe, 0xd0, 0x82,
-	0xe9, 0xd8, 0x14, 0x1e, 0xe3, 0x5a, 0x7a, 0x42, 0x4e, 0x69, 0xb5, 0xf4, 0x7f, 0xb2, 0x60, 0x2e,
-	0xd6, 0xf3, 0x04, 0xb2, 0xa3, 0xdf, 0x8e, 0x67, 0x47, 0x5f, 0x1e, 0x61, 0x3d, 0x03, 0x72, 0xa4,
-	0x7f, 0x92, 0x5c, 0x8d, 0x58, 0x29, 0xfa, 0x75, 0x98, 0xeb, 0x06, 0xa5, 0xf7, 0x0d, 0xaf, 0xed,
-	0xd4, 0x1d, 0x1a, 0x24, 0xdb, 0x2f, 0x66, 0x7c, 0x97, 0x20, 0x87, 0xef, 0x56, 0xbe, 0xa6, 0xb9,
-	0xcf, 0x6d, 0x24, 0x71, 0x71, 0x3f, 0x2b, 0x99, 0x7b, 0xd6, 0xb3, 0x7a, 0x6c, 0x73, 0xcf, 0x7a,
-	0x7e, 0x03, 0xe4, 0xfa, 0x23, 0x0b, 0xa6, 0x0c, 0xf5, 0xe0, 0xa8, 0x05, 0xf0, 0x11, 0x61, 0xb4,
-	0xe5, 0x85, 0x6e, 0xdc, 0xd0, 0x19, 0xc1, 0x77, 0x82, 0x71, 0x12, 0x29, 0x3a, 0xf9, 0x61, 0x3b,
-	0xc7, 0x06, 0x36, 0xfa, 0xb6, 0x91, 0xdc, 0x53, 0xba, 0x35, 0x14, 0x17, 0x99, 0x3b, 0x50, 0x1c,
-	0x4c, 0x4d, 0x36, 0x52, 0x82, 0xf6, 0x0f, 0x22, 0x4d, 0xd6, 0xf9, 0xb2, 0x3a, 0x40, 0xdd, 0x73,
-	0x1b, 0x8e, 0x1f, 0x3e, 0xce, 0x2a, 0xad, 0x2c, 0x0f, 0xb7, 0x35, 0xd5, 0x60, 0x5c, 0xb4, 0xa0,
-	0xb0, 0x89, 0x63, 0x03, 0x16, 0xd5, 0xa0, 0x20, 0x4c, 0x49, 0xf0, 0xdc, 0x6d, 0x25, 0xb3, 0x71,
-	0xe2, 0xfa, 0x65, 0x87, 0xf8, 0x13, 0x2b, 0x2c, 0xfb, 0xaf, 0x73, 0x30, 0x19, 0x9e, 0xc5, 0x13,
-	0xb7, 0xdc, 0x2f, 0x67, 0xd4, 0xa2, 0x41, 0xd6, 0x08, 0x7d, 0x90, 0xb0, 0xdc, 0x59, 0xd5, 0xf3,
-	0x00, 0xdb, 0xfd, 0x0f, 0x6a, 0xc7, 0x55, 0xdf, 0x13, 0x50, 0xc5, 0x3b, 0x71, 0x55, 0x5c, 0xce,
-	0xb8, 0x9a, 0x01, 0xca, 0xf8, 0x71, 0x0e, 0x4e, 0x27, 0x0c, 0x12, 0x7a, 0x5a, 0x1e, 0xaa, 0x66,
-	0x50, 0x94, 0x09, 0x07, 0xea, 0x14, 0x9a, 0xa4, 0xa1, 0x1d, 0xe1, 0x83, 0x85, 0xde, 0x99, 0xc7,
-	0xb4, 0x90, 0xbf, 0x31, 0x92, 0x0d, 0x0c, 0x40, 0x2a, 0x73, 0xca, 0x7d, 0x33, 0x70, 0x71, 0x9c,
-	0x0d, 0xda, 0x80, 0x79, 0xd2, 0xf3, 0xbd, 0x10, 0xe0, 0x9a, 0x4b, 0x36, 0xdb, 0x54, 0xe5, 0xe3,
-	0x26, 0x2a, 0xff, 0x2f, 0xcc, 0x84, 0xa7, 0xf4, 0xc1, 0xa9, 0x23, 0xed, 0xbf, 0xb1, 0xe0, 0xc9,
-	0x01, 0xf3, 0x19, 0xa2, 0x3c, 0xd5, 0x86, 0x69, 0xf9, 0x80, 0x3c, 0x94, 0x43, 0x70, 0x8a, 0x87,
-	0xdb, 0x79, 0x73, 0xa8, 0x5a, 0x7d, 0xac, 0x09, 0xc7, 0xc1, 0xed, 0x1f, 0xe6, 0x00, 0x85, 0x73,
-	0xcd, 0x52, 0x45, 0xfb, 0x00, 0xc6, 0xb7, 0x54, 0x3a, 0xfa, 0x70, 0x65, 0xd0, 0x4a, 0xc9, 0xac,
-	0x04, 0x07, 0x98, 0xe8, 0xdd, 0xa3, 0xd1, 0x35, 0xe8, 0xd7, 0x33, 0x74, 0x0f, 0x60, 0xcb, 0x71,
-	0x1d, 0xde, 0x1a, 0xf1, 0x35, 0x89, 0x74, 0xb2, 0xaf, 0x87, 0x08, 0xd8, 0x40, 0xb3, 0xff, 0x34,
-	0x67, 0xe8, 0xb0, 0xbc, 0xde, 0x87, 0x3a, 0xfb, 0xcf, 0xc7, 0x85, 0x39, 0xd9, 0x5f, 0x22, 0x0f,
-	0x05, 0x73, 0x0f, 0xc6, 0x76, 0x08, 0x0b, 0xaa, 0x75, 0x43, 0x3e, 0x54, 0xeb, 0x7f, 0xa3, 0x12,
-	0xed, 0xe9, 0x5d, 0xc2, 0x38, 0x96, 0x98, 0xc2, 0xf5, 0xe1, 0x3e, 0xed, 0x06, 0x97, 0x4b, 0x66,
-	0xc3, 0xe9, 0xd3, 0xae, 0xb9, 0x40, 0xda, 0x95, 0x37, 0x00, 0xed, 0x72, 0xfb, 0xbb, 0xe3, 0x86,
-	0x55, 0xd0, 0xf7, 0xd9, 0x9b, 0x80, 0xda, 0x84, 0xfb, 0x37, 0x89, 0xdb, 0x10, 0xba, 0x44, 0xb7,
-	0x18, 0xe5, 0x2d, 0x1d, 0x39, 0x2d, 0x6a, 0x14, 0x74, 0xab, 0xaf, 0x07, 0x4e, 0x19, 0x85, 0x2e,
-	0x06, 0x1f, 0x00, 0x28, 0x29, 0x2f, 0xc5, 0x3e, 0x00, 0x78, 0xb8, 0xb7, 0x34, 0x13, 0xe9, 0xa3,
-	0xf1, 0x49, 0x40, 0x86, 0xa7, 0xee, 0xe6, 0x79, 0x2f, 0x1c, 0xc3, 0x79, 0xff, 0x35, 0x98, 0xdb,
-	0x4a, 0xbe, 0x99, 0xd0, 0xef, 0xcc, 0x5e, 0x1b, 0xf1, 0xc9, 0x45, 0xe5, 0xec, 0x7e, 0x54, 0x68,
-	0x8f, 0x9a, 0x71, 0x3f, 0x23, 0xe4, 0x05, 0x0f, 0xec, 0x65, 0x12, 0x4c, 0xe5, 0x37, 0x87, 0xd6,
-	0xb9, 0x44, 0xfa, 0x2c, 0xf9, 0xb4, 0x5e, 0x41, 0xe2, 0x18, 0x83, 0x84, 0x0e, 0x16, 0x8f, 0x52,
-	0x07, 0xd1, 0xc5, 0xb0, 0xae, 0x28, 0xa6, 0x23, 0x43, 0xcc, 0x7c, 0x5f, 0x45, 0x50, 0x90, 0xb0,
-	0xd9, 0x0f, 0x7d, 0x62, 0xc1, 0x59, 0x71, 0x58, 0xaf, 0x3d, 0xa0, 0xf5, 0x9e, 0x90, 0x4a, 0xf0,
-	0xdd, 0xcd, 0x42, 0x49, 0x4a, 0xe3, 0xca, 0xb0, 0xae, 0x5d, 0x0a, 0x44, 0x14, 0x2f, 0xa7, 0x92,
-	0x71, 0x3a, 0x63, 0x74, 0x5f, 0x39, 0x63, 0x54, 0xa6, 0x23, 0x0e, 0x9f, 0x65, 0x0c, 0x1d, 0x33,
-	0x65, 0x77, 0x7c, 0x6a, 0xff, 0x24, 0x6f, 0x9a, 0xab, 0xe1, 0x72, 0x9f, 0xf7, 0x60, 0xcc, 0x27,
-	0x7c, 0x5b, 0x6b, 0xc1, 0x1b, 0x23, 0x3c, 0x9d, 0x8e, 0x74, 0x41, 0xc6, 0xc6, 0xb2, 0x49, 0x62,
-	0xa2, 0x45, 0xc8, 0x11, 0x9e, 0xac, 0x84, 0xad, 0x72, 0x9c, 0x23, 0x5c, 0x56, 0xc9, 0xb6, 0x74,
-	0xe6, 0x22, 0xaa, 0x92, 0x6d, 0xe1, 0x9c, 0xb3, 0x85, 0xde, 0x85, 0x02, 0xa3, 0x3e, 0xdb, 0xd5,
-	0xd6, 0xfc, 0xd2, 0x08, 0x86, 0x0b, 0x8b, 0xf1, 0x4a, 0x44, 0xf2, 0x4f, 0xac, 0x10, 0x43, 0x7b,
-	0x5b, 0x3c, 0x06, 0x7b, 0x1b, 0xa5, 0x91, 0xf3, 0xc7, 0x96, 0x46, 0xfe, 0xbe, 0x65, 0x5c, 0xf0,
-	0xe1, 0x42, 0xd1, 0xdb, 0x30, 0xee, 0x3b, 0x1d, 0xea, 0xf5, 0xfc, 0x6c, 0x9e, 0x65, 0xf8, 0xd0,
-	0x40, 0x9a, 0xb1, 0x3b, 0x0a, 0x02, 0x07, 0x58, 0xe8, 0x2a, 0xcc, 0x50, 0xc6, 0x3c, 0x76, 0xa7,
-	0x25, 0xcc, 0xb2, 0xd7, 0x56, 0x6e, 0xd4, 0x74, 0x94, 0xe1, 0xb9, 0x16, 0xa3, 0xe2, 0x44, 0xef,
-	0x20, 0x7f, 0xf1, 0xb3, 0xf2, 0x2d, 0x80, 0xce, 0x5f, 0x9c, 0xe8, 0x47, 0x00, 0x23, 0xe7, 0x2f,
-	0x0e, 0x7c, 0xfd, 0xff, 0x3e, 0x3c, 0x91, 0xae, 0xc7, 0x47, 0xf2, 0xf5, 0xdc, 0x0f, 0x92, 0xb2,
-	0x92, 0xee, 0x53, 0xa0, 0x7e, 0xd6, 0x71, 0xba, 0x3b, 0xb9, 0xa3, 0x76, 0x77, 0x98, 0xb9, 0x14,
-	0xfd, 0xad, 0x21, 0xfa, 0x40, 0x9f, 0x33, 0x2b, 0xcb, 0xd7, 0x6b, 0x7d, 0x30, 0x03, 0xcf, 0xda,
-	0x3f, 0x5b, 0x70, 0x36, 0xb5, 0x77, 0x28, 0xc3, 0xdc, 0x71, 0xca, 0xd0, 0x3a, 0x6a, 0x19, 0x7e,
-	0x2f, 0x07, 0xb3, 0x98, 0x76, 0xbd, 0x58, 0xe5, 0x61, 0x23, 0xf8, 0x4a, 0x23, 0x43, 0x4c, 0x90,
-	0x28, 0xe7, 0x57, 0xc6, 0x63, 0x9f, 0x67, 0x08, 0x75, 0xe9, 0x04, 0x0e, 0xe0, 0xd0, 0xea, 0xdf,
-	0x57, 0x13, 0x51, 0x37, 0x87, 0xaa, 0xae, 0x28, 0x40, 0x81, 0x2c, 0x9f, 0xc3, 0x69, 0xe3, 0xfe,
-	0x5a, 0x86, 0x87, 0x75, 0xfd, 0xc8, 0xb2, 0x19, 0x2b, 0x40, 0xfb, 0xd3, 0x1c, 0xa8, 0xf8, 0xe1,
-	0x04, 0xac, 0xe3, 0x2f, 0xc5, 0xac, 0xe3, 0x72, 0x96, 0xfc, 0xd6, 0xa0, 0x3c, 0x4a, 0x32, 0xb6,
-	0xbb, 0x90, 0x31, 0x69, 0xf6, 0x88, 0x1c, 0xca, 0xdf, 0x5b, 0x30, 0x29, 0xfb, 0x9d, 0x80, 0xa1,
-	0xdd, 0x88, 0x1b, 0xda, 0x17, 0x32, 0xac, 0x62, 0x80, 0x81, 0xfd, 0xaf, 0xbc, 0x9e, 0x7d, 0x18,
-	0x39, 0xb6, 0x08, 0x6b, 0xe8, 0x90, 0x28, 0xd2, 0x12, 0xd1, 0x88, 0x15, 0x2d, 0xd4, 0xed, 0xf1,
-	0x63, 0xd0, 0xed, 0x5f, 0x51, 0xaf, 0x12, 0x29, 0xf7, 0x69, 0xe3, 0x7a, 0x18, 0xfb, 0xe4, 0x33,
-	0x3f, 0xaf, 0xd4, 0x4f, 0x40, 0xa3, 0x72, 0x18, 0x4e, 0xa0, 0xe2, 0x3e, 0x3e, 0x22, 0x1e, 0xea,
-	0x26, 0x8d, 0x99, 0x8e, 0x13, 0x5e, 0x1b, 0xd1, 0x72, 0xaa, 0x78, 0xa8, 0xaf, 0x19, 0xf7, 0x33,
-	0x42, 0x2d, 0x98, 0x32, 0x1f, 0x86, 0xeb, 0x73, 0xba, 0x92, 0xfd, 0x05, 0xba, 0x7a, 0xed, 0x61,
-	0xb6, 0xe0, 0x18, 0xb2, 0xfd, 0x87, 0x16, 0x40, 0x94, 0x0d, 0x16, 0x7b, 0x5e, 0xf7, 0x7a, 0xae,
-	0x4a, 0x03, 0xe4, 0xa3, 0x3d, 0xaf, 0x8a, 0x46, 0xac, 0x68, 0x42, 0x7f, 0x54, 0x30, 0xa5, 0x0f,
-	0xf5, 0x85, 0x2c, 0x71, 0x5a, 0x22, 0xeb, 0xac, 0x1a, 0xb1, 0x06, 0xb4, 0x3f, 0x2e, 0x42, 0xc9,
-	0xd0, 0xb3, 0x44, 0xce, 0x79, 0xfa, 0x78, 0x72, 0xce, 0xe9, 0x89, 0x80, 0xd2, 0x48, 0x89, 0x00,
-	0x0e, 0x33, 0x3a, 0xbc, 0x0d, 0xbe, 0x1e, 0x50, 0x89, 0x92, 0x91, 0x83, 0x68, 0x24, 0xbc, 0xd6,
-	0xeb, 0x31, 0x48, 0x9c, 0x60, 0x21, 0xbc, 0x5e, 0xdd, 0x52, 0xeb, 0x75, 0x3a, 0x84, 0xed, 0x2e,
-	0x4c, 0xc9, 0xc9, 0x87, 0x5e, 0xef, 0xf5, 0x18, 0x15, 0x27, 0x7a, 0xa3, 0x8d, 0x70, 0x43, 0xd5,
-	0x8b, 0xf4, 0x17, 0xb3, 0x6c, 0xa8, 0xf2, 0xfa, 0xe3, 0xfb, 0x28, 0x44, 0xea, 0x6d, 0xca, 0xa0,
-	0xa1, 0x71, 0x43, 0xfd, 0xf6, 0x86, 0x38, 0xc6, 0x45, 0x79, 0xa8, 0x42, 0x91, 0xde, 0xee, 0xeb,
-	0x81, 0x53, 0x46, 0x09, 0x33, 0xa0, 0xe3, 0xe4, 0x50, 0x77, 0x74, 0x66, 0x22, 0x6b, 0x9c, 0x15,
-	0x05, 0x7e, 0xf2, 0x99, 0x72, 0x35, 0x81, 0x8a, 0xfb, 0xf8, 0xa0, 0x0f, 0x61, 0x5a, 0x6c, 0x72,
-	0xc4, 0x18, 0x0e, 0xc9, 0x58, 0x67, 0x44, 0x0d, 0x48, 0x1c, 0xe7, 0x60, 0xff, 0x71, 0x1e, 0xd2,
-	0xa3, 0xf4, 0xe8, 0x0b, 0x29, 0xeb, 0x11, 0x5f, 0x48, 0xbd, 0x03, 0x93, 0xdc, 0x27, 0x4c, 0x7d,
-	0xaa, 0x96, 0x1b, 0xed, 0x53, 0xb5, 0x5a, 0x00, 0x80, 0x23, 0xac, 0x44, 0xca, 0x24, 0x7f, 0xa4,
-	0x29, 0x93, 0x15, 0x00, 0x19, 0x88, 0x49, 0x33, 0x23, 0xef, 0x9b, 0xe9, 0x48, 0x6b, 0xaf, 0x85,
-	0x14, 0x6c, 0xf4, 0x42, 0xdf, 0x08, 0x6f, 0x71, 0xf5, 0x5a, 0xe1, 0xe7, 0xfa, 0x1e, 0x97, 0x9d,
-	0x89, 0xb9, 0x79, 0x89, 0x2c, 0xec, 0xf0, 0x2f, 0x52, 0xed, 0xff, 0xc9, 0x41, 0xcc, 0x84, 0xa2,
-	0xdf, 0xb7, 0x60, 0x8e, 0x24, 0x7e, 0xca, 0x23, 0xf0, 0x40, 0x7f, 0x31, 0xdb, 0xef, 0xab, 0xf4,
-	0xfd, 0x12, 0x48, 0x54, 0x3d, 0x4d, 0x76, 0xe1, 0xb8, 0x9f, 0x29, 0xfa, 0x1d, 0x0b, 0xce, 0x90,
-	0xfe, 0xdf, 0x6a, 0xd1, 0x3b, 0xff, 0xfa, 0xc8, 0x3f, 0xf6, 0x52, 0x79, 0x72, 0x7f, 0x6f, 0x29,
-	0xed, 0x57, 0x6c, 0x70, 0x1a, 0x3b, 0xf4, 0x1e, 0x8c, 0x11, 0xd6, 0x0c, 0x12, 0xb7, 0xd9, 0xd9,
-	0x06, 0x3f, 0xc1, 0x13, 0xf9, 0x01, 0xab, 0xac, 0xc9, 0xb1, 0x04, 0xb5, 0x7f, 0x9c, 0x87, 0xd9,
-	0xe4, 0x67, 0x55, 0xfa, 0xd1, 0xf2, 0x58, 0xea, 0xa3, 0x65, 0xa1, 0x28, 0xb2, 0x74, 0x91, 0xfc,
-	0x94, 0x50, 0x56, 0x20, 0x14, 0x2d, 0x54, 0x14, 0xf9, 0xb1, 0x43, 0xe1, 0x10, 0x8a, 0x22, 0xbf,
-	0x70, 0x88, 0xb0, 0xd0, 0xa5, 0x78, 0x2e, 0xd8, 0x4e, 0xe6, 0x82, 0xe7, 0xcc, 0xb5, 0x8c, 0x9a,
-	0x0e, 0xee, 0x40, 0xc9, 0xd8, 0x07, 0xad, 0x8e, 0x97, 0x33, 0xcb, 0x3d, 0x3a, 0x76, 0xa7, 0xd5,
-	0x6b, 0xb5, 0x88, 0x62, 0xe2, 0x47, 0xca, 0x2f, 0xa5, 0x75, 0xa8, 0x7c, 0xa9, 0x14, 0x97, 0x81,
-	0x66, 0xff, 0x9b, 0x05, 0xd3, 0xb1, 0x97, 0xf4, 0x82, 0x5b, 0xf0, 0xc5, 0xc2, 0xe8, 0xbf, 0x5b,
-	0x73, 0x37, 0x44, 0xc0, 0x06, 0x1a, 0xfa, 0x0e, 0x94, 0xda, 0x9e, 0xdb, 0xa4, 0xdc, 0xaf, 0x79,
-	0x64, 0x5b, 0xeb, 0x49, 0xd6, 0xe4, 0xd3, 0xc2, 0xfe, 0xde, 0xd2, 0xfc, 0x2d, 0x05, 0x53, 0xf5,
-	0x3a, 0xdd, 0x36, 0xf5, 0xd5, 0xb7, 0x2d, 0xd8, 0x04, 0x97, 0x75, 0xe7, 0xb0, 0x70, 0xff, 0xb8,
-	0xd6, 0x9d, 0xa3, 0x17, 0x07, 0x47, 0x5c, 0x77, 0x8e, 0x3d, 0x65, 0x38, 0xa0, 0xee, 0x1c, 0xf6,
-	0x7d, 0x6c, 0xeb, 0xce, 0xe1, 0x0c, 0x07, 0xc4, 0x4e, 0xff, 0x9d, 0x33, 0x56, 0x11, 0x8f, 0x9f,
-	0x72, 0x8f, 0x88, 0x9f, 0xde, 0x87, 0x09, 0xc7, 0xf5, 0x29, 0xdb, 0x21, 0x6d, 0x9d, 0x3c, 0xce,
-	0x7a, 0x16, 0xc3, 0xa5, 0xae, 0x6b, 0x1c, 0x1c, 0x22, 0xa2, 0x36, 0x9c, 0x0d, 0x8a, 0x2d, 0x8c,
-	0x92, 0xa8, 0x1c, 0xac, 0x1f, 0x32, 0xbe, 0x1a, 0x54, 0x05, 0xae, 0xa7, 0x75, 0x7a, 0x38, 0x88,
-	0x80, 0xd3, 0x41, 0x11, 0x87, 0x69, 0x6e, 0x24, 0x0e, 0x82, 0x1b, 0x71, 0xc8, 0x42, 0x55, 0x32,
-	0xd7, 0x62, 0xbc, 0x7e, 0x34, 0x41, 0x71, 0x9c, 0x87, 0xfd, 0x89, 0x05, 0x33, 0xf1, 0x47, 0x33,
-	0xff, 0xe7, 0x41, 0xcc, 0x8f, 0xf2, 0x70, 0x3a, 0x71, 0xf8, 0x13, 0x81, 0xcc, 0xe4, 0x49, 0x06,
-	0x32, 0xc5, 0x91, 0x02, 0x99, 0x74, 0x0f, 0x7e, 0x6c, 0x24, 0x0f, 0xfe, 0x8a, 0xf2, 0xa2, 0xf5,
-	0x61, 0x5a, 0x5f, 0xd3, 0x9f, 0xeb, 0x84, 0x1b, 0x7c, 0xcb, 0x24, 0xe2, 0x78, 0x5f, 0xe9, 0xe1,
-	0x34, 0xfa, 0x7f, 0x96, 0x45, 0x87, 0x00, 0xaf, 0x67, 0x7d, 0x80, 0x1c, 0x02, 0x28, 0x0f, 0x27,
-	0x85, 0x80, 0xd3, 0xd8, 0x55, 0xde, 0xfc, 0xfc, 0xab, 0x73, 0xa7, 0xbe, 0xf8, 0xea, 0xdc, 0xa9,
-	0x2f, 0xbf, 0x3a, 0x77, 0xea, 0xe3, 0xfd, 0x73, 0xd6, 0xe7, 0xfb, 0xe7, 0xac, 0x2f, 0xf6, 0xcf,
-	0x59, 0x5f, 0xee, 0x9f, 0xb3, 0x7e, 0xb2, 0x7f, 0xce, 0xfa, 0xe4, 0xa7, 0xe7, 0x4e, 0xdd, 0x7b,
-	0x66, 0x98, 0x1f, 0x73, 0xfc, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc8, 0xee, 0x9b, 0xbb, 0xf3,
-	0x51, 0x00, 0x00,
+	// 4387 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5c, 0x4d, 0x6c, 0x1c, 0x47,
+	0x76, 0x56, 0xcf, 0x70, 0x86, 0xe4, 0x1b, 0xfe, 0x96, 0x28, 0x8b, 0xcb, 0x8d, 0x45, 0xa5, 0xed,
+	0x18, 0x76, 0x6c, 0x0f, 0x23, 0xda, 0xb2, 0x65, 0xc9, 0xab, 0x80, 0x33, 0xd4, 0x0f, 0xbd, 0x5a,
+	0x8b, 0xa9, 0x91, 0xe5, 0xb5, 0x6c, 0x43, 0x29, 0xce, 0x14, 0x67, 0x7a, 0x39, 0xd3, 0x3d, 0xee,
+	0xaa, 0xa1, 0xc5, 0x24, 0x48, 0x9c, 0x5f, 0x04, 0x48, 0x10, 0x18, 0xc8, 0x06, 0xde, 0x43, 0x82,
+	0x04, 0xd9, 0x53, 0xb0, 0x40, 0xae, 0x39, 0xe4, 0xe0, 0x43, 0x2e, 0xde, 0x64, 0x13, 0x18, 0xce,
+	0x21, 0x0e, 0xb0, 0x60, 0x62, 0x2e, 0x90, 0x73, 0x2e, 0xb9, 0x08, 0x08, 0x10, 0xd4, 0x4f, 0x77,
+	0x57, 0xf7, 0xf4, 0x88, 0xd3, 0x23, 0x52, 0x11, 0x7c, 0x9b, 0xa9, 0x57, 0xf5, 0xbd, 0xaa, 0x57,
+	0xf5, 0x5e, 0xbd, 0xf7, 0xaa, 0xaa, 0xe1, 0xe5, 0xa6, 0xc3, 0x5b, 0xbd, 0xad, 0x72, 0xdd, 0xeb,
+	0xac, 0x90, 0x9d, 0x9e, 0xc3, 0xf7, 0x56, 0x76, 0x88, 0xdf, 0xf4, 0x56, 0x48, 0xd7, 0x59, 0xd9,
+	0x3d, 0x47, 0xda, 0xdd, 0x16, 0x39, 0xb7, 0xd2, 0xa4, 0x2e, 0xf5, 0x09, 0xa7, 0x8d, 0x72, 0xd7,
+	0xf7, 0xb8, 0x87, 0x9e, 0x8e, 0x5a, 0x95, 0x55, 0xab, 0xb2, 0x6c, 0x55, 0x26, 0x5d, 0xa7, 0x1c,
+	0xb4, 0x5a, 0x7a, 0xd1, 0xc0, 0x6e, 0x7a, 0x4d, 0x6f, 0x45, 0x36, 0xde, 0xea, 0x6d, 0xcb, 0x7f,
+	0xf2, 0x8f, 0xfc, 0xa5, 0x40, 0x97, 0xae, 0xef, 0x5c, 0x60, 0x65, 0x47, 0x72, 0xa6, 0xf7, 0x38,
+	0x75, 0x99, 0xe3, 0xb9, 0xec, 0x45, 0xd2, 0x75, 0x18, 0xf5, 0x77, 0xa9, 0xbf, 0xd2, 0xdd, 0x69,
+	0x0a, 0x1a, 0x8b, 0x57, 0x58, 0xd9, 0xed, 0xeb, 0xde, 0xd2, 0xcb, 0x11, 0x52, 0x87, 0xd4, 0x5b,
+	0x8e, 0x4b, 0xfd, 0xbd, 0xa8, 0x79, 0x87, 0x72, 0x92, 0xd6, 0x6a, 0x65, 0x50, 0x2b, 0xbf, 0xe7,
+	0x72, 0xa7, 0x43, 0xfb, 0x1a, 0xbc, 0x72, 0x58, 0x03, 0x56, 0x6f, 0xd1, 0x0e, 0x49, 0xb6, 0xb3,
+	0xdf, 0x83, 0x93, 0x6b, 0x2e, 0x69, 0xef, 0x31, 0x87, 0xe1, 0x9e, 0xbb, 0xe6, 0x37, 0x7b, 0x1d,
+	0xea, 0x72, 0x74, 0x16, 0xc6, 0x5c, 0xd2, 0xa1, 0x8b, 0xd6, 0x59, 0xeb, 0xd9, 0xc9, 0xca, 0xd4,
+	0x67, 0xfb, 0xcb, 0x27, 0x0e, 0xf6, 0x97, 0xc7, 0xde, 0x24, 0x1d, 0x8a, 0x25, 0x05, 0x3d, 0x05,
+	0x85, 0x5d, 0xd2, 0xee, 0xd1, 0xc5, 0x9c, 0xac, 0x32, 0xad, 0xab, 0x14, 0x6e, 0x8b, 0x42, 0xac,
+	0x68, 0xf6, 0xef, 0xe6, 0x63, 0xf0, 0xdf, 0xa1, 0x9c, 0x34, 0x08, 0x27, 0xa8, 0x03, 0xc5, 0x36,
+	0xd9, 0xa2, 0x6d, 0xb6, 0x68, 0x9d, 0xcd, 0x3f, 0x5b, 0x5a, 0xbd, 0x52, 0x1e, 0x66, 0x12, 0xcb,
+	0x29, 0x50, 0xe5, 0x1b, 0x12, 0xe7, 0x8a, 0xcb, 0xfd, 0xbd, 0xca, 0x8c, 0xee, 0x44, 0x51, 0x15,
+	0x62, 0xcd, 0x04, 0xfd, 0xb6, 0x05, 0x25, 0xe2, 0xba, 0x1e, 0x27, 0x5c, 0x4c, 0xd3, 0x62, 0x4e,
+	0x32, 0x7d, 0x63, 0x74, 0xa6, 0x6b, 0x11, 0x98, 0xe2, 0x7c, 0x52, 0x73, 0x2e, 0x19, 0x14, 0x6c,
+	0xf2, 0x5c, 0x7a, 0x0d, 0x4a, 0x46, 0x57, 0xd1, 0x1c, 0xe4, 0x77, 0xe8, 0x9e, 0x92, 0x2f, 0x16,
+	0x3f, 0xd1, 0x42, 0x4c, 0xa0, 0x5a, 0x82, 0x17, 0x73, 0x17, 0xac, 0xa5, 0xcb, 0x30, 0x97, 0x64,
+	0x98, 0xa5, 0xbd, 0xfd, 0x27, 0x16, 0x2c, 0x18, 0xa3, 0xc0, 0x74, 0x9b, 0xfa, 0xd4, 0xad, 0x53,
+	0xb4, 0x02, 0x93, 0x62, 0x2e, 0x59, 0x97, 0xd4, 0x83, 0xa9, 0x9e, 0xd7, 0x03, 0x99, 0x7c, 0x33,
+	0x20, 0xe0, 0xa8, 0x4e, 0xb8, 0x2c, 0x72, 0x0f, 0x5a, 0x16, 0xdd, 0x16, 0x61, 0x74, 0x31, 0x1f,
+	0x5f, 0x16, 0x9b, 0xa2, 0x10, 0x2b, 0x9a, 0x7d, 0x17, 0xbe, 0x11, 0xf4, 0xe7, 0x16, 0xed, 0x74,
+	0xdb, 0x84, 0xd3, 0xa8, 0x53, 0x87, 0x2f, 0xbd, 0xb3, 0x30, 0xb6, 0xe3, 0xb8, 0x8d, 0x64, 0x2f,
+	0xbe, 0xed, 0xb8, 0x0d, 0x2c, 0x29, 0xf6, 0x0e, 0x4c, 0xaf, 0x75, 0xbb, 0xbe, 0xb7, 0x4b, 0x1b,
+	0x35, 0x4e, 0x9a, 0x14, 0xdd, 0x01, 0x20, 0xba, 0x60, 0x8d, 0x4b, 0xe8, 0xd2, 0xea, 0x2f, 0x96,
+	0x95, 0xce, 0x94, 0x4d, 0x9d, 0x29, 0x77, 0x77, 0x9a, 0xa2, 0x80, 0x95, 0x85, 0x6a, 0x96, 0x77,
+	0xcf, 0x95, 0x6f, 0x39, 0x1d, 0x5a, 0x99, 0x39, 0xd8, 0x5f, 0x86, 0xb5, 0x10, 0x01, 0x1b, 0x68,
+	0xf6, 0xef, 0x58, 0x70, 0x6a, 0xcd, 0x6f, 0x7a, 0xd5, 0xf5, 0xb5, 0x6e, 0xf7, 0x3a, 0x25, 0x6d,
+	0xde, 0xaa, 0x71, 0xc2, 0x7b, 0x0c, 0x5d, 0x86, 0x22, 0x93, 0xbf, 0xf4, 0x60, 0x9e, 0x09, 0xd6,
+	0xa7, 0xa2, 0xdf, 0xdf, 0x5f, 0x5e, 0x48, 0x69, 0x48, 0xb1, 0x6e, 0x85, 0x9e, 0x83, 0xf1, 0x0e,
+	0x65, 0x8c, 0x34, 0x03, 0x89, 0xcf, 0x6a, 0x80, 0xf1, 0xef, 0xa8, 0x62, 0x1c, 0xd0, 0xed, 0x7f,
+	0xcc, 0xc1, 0x6c, 0x88, 0xa5, 0xd9, 0x1f, 0xc3, 0xf4, 0xf6, 0x60, 0xaa, 0x65, 0x8c, 0x50, 0xce,
+	0x72, 0x69, 0xf5, 0xd2, 0x90, 0x9a, 0x94, 0x26, 0xa4, 0xca, 0x82, 0x66, 0x33, 0x65, 0x96, 0xe2,
+	0x18, 0x1b, 0xd4, 0x01, 0x60, 0x7b, 0x6e, 0x5d, 0x33, 0x1d, 0x93, 0x4c, 0x5f, 0xcb, 0xc8, 0xb4,
+	0x16, 0x02, 0x54, 0x90, 0x66, 0x09, 0x51, 0x19, 0x36, 0x18, 0xd8, 0x7f, 0x6b, 0xc1, 0xc9, 0x94,
+	0x76, 0xe8, 0xf5, 0xc4, 0x7c, 0x3e, 0xdd, 0x37, 0x9f, 0xa8, 0xaf, 0x59, 0x34, 0x9b, 0x2f, 0xc0,
+	0x84, 0x4f, 0x77, 0x1d, 0xb1, 0x53, 0x68, 0x09, 0xcf, 0xe9, 0xf6, 0x13, 0x58, 0x97, 0xe3, 0xb0,
+	0x06, 0x7a, 0x1e, 0x26, 0x83, 0xdf, 0x42, 0xcc, 0x79, 0xa1, 0x4c, 0x62, 0xe2, 0x82, 0xaa, 0x0c,
+	0x47, 0x74, 0xfb, 0xb7, 0xa0, 0x50, 0x6d, 0x11, 0x9f, 0x8b, 0x15, 0xe3, 0xd3, 0xae, 0xf7, 0x16,
+	0xbe, 0xa1, 0xbb, 0x18, 0xae, 0x18, 0xac, 0x8a, 0x71, 0x40, 0x1f, 0x62, 0xb2, 0x9f, 0x83, 0xf1,
+	0x5d, 0xea, 0xcb, 0xfe, 0xe6, 0xe3, 0x60, 0xb7, 0x55, 0x31, 0x0e, 0xe8, 0xf6, 0xbf, 0x5a, 0xb0,
+	0x20, 0x7b, 0xb0, 0xee, 0xb0, 0xba, 0xb7, 0x4b, 0xfd, 0x3d, 0x4c, 0x59, 0xaf, 0x7d, 0xc4, 0x1d,
+	0x5a, 0x87, 0x39, 0x46, 0x3b, 0xbb, 0xd4, 0xaf, 0x7a, 0x2e, 0xe3, 0x3e, 0x71, 0x5c, 0xae, 0x7b,
+	0xb6, 0xa8, 0x6b, 0xcf, 0xd5, 0x12, 0x74, 0xdc, 0xd7, 0x02, 0x3d, 0x0b, 0x13, 0xba, 0xdb, 0x62,
+	0x29, 0x09, 0xc1, 0x4e, 0x89, 0x39, 0xd0, 0x63, 0x62, 0x38, 0xa4, 0xda, 0xff, 0x65, 0xc1, 0xbc,
+	0x1c, 0x55, 0xad, 0xb7, 0xc5, 0xea, 0xbe, 0xd3, 0x15, 0x06, 0xf8, 0x71, 0x1c, 0xd2, 0x65, 0x98,
+	0x69, 0x04, 0x82, 0xbf, 0xe1, 0x74, 0x1c, 0x2e, 0x75, 0xa4, 0x50, 0x79, 0x42, 0x63, 0xcc, 0xac,
+	0xc7, 0xa8, 0x38, 0x51, 0x5b, 0x4d, 0x5f, 0xbb, 0xc7, 0x38, 0xf5, 0x37, 0x7d, 0xaf, 0xe3, 0x89,
+	0x71, 0xde, 0x22, 0x6c, 0x07, 0xfd, 0x2a, 0x4c, 0x74, 0xf4, 0xa6, 0xa7, 0xad, 0xe6, 0x2f, 0x0d,
+	0x67, 0x35, 0x6f, 0x6e, 0x7d, 0x8f, 0xd6, 0xb9, 0xd8, 0x30, 0x23, 0x6d, 0x8b, 0xca, 0x70, 0x88,
+	0x8a, 0xde, 0x81, 0x31, 0xd6, 0xa5, 0x75, 0x29, 0xa2, 0xd2, 0xea, 0xab, 0xc3, 0x29, 0x75, 0xac,
+	0x93, 0xb5, 0x2e, 0xad, 0x47, 0xb2, 0x15, 0xff, 0xb0, 0x84, 0xb4, 0xff, 0xdd, 0x82, 0xc5, 0xb4,
+	0x51, 0xdd, 0x70, 0x18, 0x47, 0xef, 0xf5, 0x8d, 0xac, 0x3c, 0xdc, 0xc8, 0x44, 0x6b, 0x39, 0xae,
+	0x50, 0x7b, 0x83, 0x12, 0x63, 0x54, 0x77, 0xa1, 0xe0, 0x70, 0xda, 0x09, 0x5c, 0x8d, 0x8b, 0xc3,
+	0x0d, 0x2b, 0xad, 0xb3, 0xd1, 0x16, 0xba, 0x21, 0x00, 0xb1, 0xc2, 0xb5, 0xdf, 0x85, 0xa9, 0x6a,
+	0xcf, 0xf7, 0xa9, 0xcb, 0xd5, 0x06, 0xf7, 0x6d, 0x28, 0x30, 0xc7, 0xd5, 0x76, 0x3e, 0xdb, 0xde,
+	0x36, 0x29, 0xc0, 0x6b, 0xa2, 0x31, 0x56, 0x18, 0xf6, 0x9f, 0xe7, 0xe1, 0x64, 0xb0, 0x62, 0x68,
+	0x63, 0xcd, 0xe7, 0xce, 0x36, 0xa9, 0x73, 0x86, 0x1a, 0x30, 0xd5, 0x88, 0x8a, 0xb9, 0x36, 0xc4,
+	0x59, 0x78, 0x85, 0xc6, 0xde, 0x80, 0xe7, 0x38, 0x86, 0x8a, 0xde, 0x86, 0x7c, 0xd3, 0xe1, 0xda,
+	0x33, 0xbc, 0x30, 0x9c, 0xe4, 0xae, 0x39, 0x49, 0xcb, 0x53, 0x29, 0x69, 0x56, 0xf9, 0x6b, 0x0e,
+	0xc7, 0x02, 0x11, 0x6d, 0x41, 0xd1, 0xe9, 0x90, 0x26, 0xcd, 0x38, 0x2b, 0x1b, 0xa2, 0x4d, 0x12,
+	0x3d, 0x74, 0x35, 0x25, 0x95, 0x61, 0x8d, 0x2c, 0x78, 0xd4, 0x85, 0xc5, 0x50, 0x36, 0x7b, 0xf8,
+	0x99, 0x4f, 0xb1, 0x9d, 0x11, 0x0f, 0x49, 0x65, 0x58, 0x23, 0xdb, 0x5f, 0xe6, 0x60, 0x2e, 0x92,
+	0x5f, 0xd5, 0xeb, 0x74, 0x1c, 0x8e, 0x96, 0x20, 0xe7, 0x34, 0xb4, 0x41, 0x02, 0xdd, 0x30, 0xb7,
+	0xb1, 0x8e, 0x73, 0x4e, 0x03, 0x3d, 0x03, 0xc5, 0x2d, 0x9f, 0xb8, 0xf5, 0x96, 0x36, 0x44, 0x21,
+	0x70, 0x45, 0x96, 0x62, 0x4d, 0x45, 0x4f, 0x42, 0x9e, 0x93, 0xa6, 0xb6, 0x3f, 0xa1, 0xfc, 0x6e,
+	0x91, 0x26, 0x16, 0xe5, 0xc2, 0xf0, 0xb1, 0x9e, 0xd4, 0x61, 0x39, 0xf3, 0x86, 0xe1, 0xab, 0xa9,
+	0x62, 0x1c, 0xd0, 0x05, 0x47, 0xd2, 0xe3, 0x2d, 0xcf, 0x5f, 0x2c, 0xc4, 0x39, 0xae, 0xc9, 0x52,
+	0xac, 0xa9, 0xc2, 0x45, 0xa9, 0xcb, 0xfe, 0x73, 0xea, 0x2f, 0x16, 0xe3, 0x2e, 0x4a, 0x35, 0x20,
+	0xe0, 0xa8, 0x0e, 0x7a, 0x1f, 0x4a, 0x75, 0x9f, 0x12, 0xee, 0xf9, 0xeb, 0x84, 0xd3, 0xc5, 0xf1,
+	0xcc, 0x2b, 0x70, 0x56, 0x78, 0xe9, 0xd5, 0x08, 0x02, 0x9b, 0x78, 0xf6, 0xdf, 0xe5, 0x61, 0x31,
+	0x12, 0xad, 0x9c, 0xdb, 0xc8, 0x33, 0xd5, 0xe2, 0xb1, 0x06, 0x88, 0xe7, 0x19, 0x28, 0x36, 0x9c,
+	0x26, 0x65, 0x3c, 0x29, 0xe5, 0x75, 0x59, 0x8a, 0x35, 0x15, 0xfd, 0x41, 0x22, 0x1a, 0x29, 0xc8,
+	0x85, 0x72, 0x73, 0xb8, 0x85, 0x32, 0xa8, 0x73, 0x23, 0x84, 0x24, 0x68, 0x15, 0xa0, 0xe9, 0x70,
+	0xbd, 0x69, 0xe9, 0x59, 0x0f, 0x8d, 0xf5, 0xb5, 0x90, 0x82, 0x8d, 0x5a, 0xe8, 0x6d, 0x98, 0x94,
+	0xf2, 0x1a, 0x51, 0xff, 0xa5, 0x0b, 0x53, 0x0d, 0x00, 0x70, 0x84, 0xf5, 0xd0, 0x41, 0xce, 0xbb,
+	0x80, 0xae, 0xdc, 0xeb, 0xfa, 0x94, 0x89, 0xad, 0xfb, 0x36, 0xf1, 0x1d, 0xb2, 0xd5, 0xa6, 0x47,
+	0x15, 0xc7, 0x7e, 0x3e, 0x06, 0xe3, 0x57, 0x7d, 0xea, 0x34, 0x5b, 0xfc, 0x11, 0x6c, 0x89, 0x4f,
+	0x41, 0x81, 0xb4, 0x1d, 0xc2, 0xe4, 0xea, 0x36, 0xba, 0xb4, 0x26, 0x0a, 0xb1, 0xa2, 0xa1, 0x77,
+	0xa1, 0xe8, 0xf9, 0x4e, 0xd3, 0x71, 0x17, 0x27, 0x65, 0x27, 0x5e, 0x1a, 0x6e, 0xfd, 0xe8, 0x51,
+	0xdc, 0x94, 0x4d, 0xa3, 0x25, 0xaa, 0xfe, 0x63, 0x0d, 0x89, 0xee, 0xc0, 0xb8, 0x52, 0xb9, 0xc0,
+	0x8c, 0xad, 0x0c, 0x6d, 0x86, 0x95, 0xd6, 0x46, 0xa6, 0x41, 0xfd, 0x67, 0x38, 0x00, 0x44, 0xb5,
+	0xd0, 0x0a, 0x8f, 0x49, 0xe8, 0xe7, 0x33, 0x58, 0xe1, 0x81, 0x66, 0xb7, 0x16, 0x9a, 0xdd, 0x42,
+	0x16, 0x50, 0x69, 0x58, 0x07, 0xd9, 0x59, 0x21, 0x62, 0xed, 0xee, 0x17, 0x47, 0x10, 0xb1, 0x8e,
+	0x35, 0x66, 0xe2, 0x31, 0x42, 0x10, 0x0d, 0xd8, 0xdf, 0xcf, 0xc3, 0xbc, 0xae, 0x59, 0xf5, 0xda,
+	0x6d, 0x5a, 0x97, 0xbe, 0xa5, 0xb2, 0xe2, 0xf9, 0x54, 0x2b, 0xee, 0x04, 0x3e, 0x85, 0xda, 0x19,
+	0x2b, 0x99, 0x7a, 0x13, 0xf1, 0x28, 0x4b, 0x3f, 0x42, 0xd9, 0x88, 0x70, 0x96, 0x74, 0x2d, 0xed,
+	0x5d, 0xa0, 0xdf, 0xb7, 0xe0, 0xe4, 0x2e, 0xf5, 0x9d, 0x6d, 0xa7, 0x2e, 0xf5, 0xf1, 0xba, 0xc3,
+	0xb8, 0xe7, 0xef, 0xe9, 0x7d, 0xf3, 0x95, 0xe1, 0x38, 0xdf, 0x36, 0x00, 0x36, 0xdc, 0x6d, 0xaf,
+	0xf2, 0x4d, 0xcd, 0xed, 0xe4, 0xed, 0x7e, 0x68, 0x9c, 0xc6, 0x6f, 0xa9, 0x0b, 0x10, 0xf5, 0x36,
+	0xc5, 0x1c, 0xdc, 0x30, 0x95, 0x77, 0xe8, 0x8e, 0x05, 0x83, 0x0d, 0x6c, 0xa7, 0x69, 0x46, 0x3e,
+	0xb5, 0xa0, 0xa4, 0xe9, 0x8f, 0xc0, 0x4d, 0xc4, 0x71, 0x37, 0xf1, 0xc5, 0x4c, 0xfd, 0x1f, 0xe0,
+	0x19, 0xfa, 0x30, 0x1d, 0x53, 0x72, 0x74, 0x5e, 0xa7, 0x4b, 0x94, 0x0d, 0xfc, 0x79, 0x33, 0x5d,
+	0x72, 0x7f, 0x7f, 0x79, 0x3e, 0x56, 0x39, 0xca, 0xa1, 0x1c, 0x1e, 0xbb, 0x5c, 0x9c, 0xf8, 0xc1,
+	0x5f, 0x2d, 0x9f, 0xf8, 0xe8, 0xa7, 0x67, 0x4f, 0xd8, 0x9f, 0xe4, 0x61, 0x2e, 0x29, 0xd5, 0x21,
+	0x6c, 0x6f, 0x64, 0xc3, 0x26, 0x8e, 0xd5, 0x86, 0xe5, 0x8e, 0xcf, 0x86, 0xe5, 0x8f, 0xc3, 0x86,
+	0x8d, 0x1d, 0x99, 0x0d, 0xb3, 0xff, 0xc5, 0x82, 0x99, 0x70, 0x66, 0x3e, 0xe8, 0x09, 0xff, 0x23,
+	0x92, 0xba, 0x75, 0xf4, 0x52, 0xbf, 0x0b, 0xe3, 0xcc, 0xeb, 0xf9, 0x75, 0xe9, 0x64, 0x0b, 0xf4,
+	0x97, 0xb3, 0x19, 0x4d, 0xd5, 0xd6, 0xf0, 0x2c, 0x55, 0x01, 0x0e, 0x50, 0xed, 0x4f, 0x73, 0xe1,
+	0x80, 0x34, 0x4d, 0x39, 0x5e, 0xbe, 0x70, 0x4b, 0xc5, 0x80, 0x26, 0x4c, 0xc7, 0x4b, 0x94, 0x62,
+	0x4d, 0x45, 0xb6, 0xb4, 0xe7, 0x81, 0xff, 0x3f, 0x59, 0x01, 0x6d, 0x96, 0xe5, 0x24, 0x28, 0x0a,
+	0xea, 0xc2, 0x9c, 0x4f, 0x3f, 0xe8, 0x39, 0x3e, 0x6d, 0xd4, 0x3c, 0xb2, 0x23, 0x9c, 0x16, 0x9d,
+	0xe4, 0x1a, 0x52, 0xef, 0xd7, 0x7b, 0xbe, 0x34, 0x61, 0x95, 0x05, 0x11, 0xbb, 0xe3, 0x04, 0x16,
+	0xee, 0x43, 0x47, 0x1e, 0x2c, 0x90, 0x5d, 0xe2, 0xb4, 0xc9, 0x96, 0xd3, 0x76, 0xf8, 0x5e, 0x8d,
+	0xfb, 0x84, 0xd3, 0xe6, 0x9e, 0x76, 0xb1, 0x2f, 0xe9, 0xb1, 0x2c, 0xac, 0xa5, 0xd4, 0xb9, 0xbf,
+	0xbf, 0xfc, 0x4d, 0x2d, 0x8b, 0x34, 0x32, 0x4e, 0x05, 0xb6, 0xff, 0xa3, 0x10, 0x5a, 0x08, 0x9d,
+	0xd7, 0xfa, 0x75, 0x28, 0xd5, 0x55, 0x30, 0xd9, 0xde, 0xdb, 0x70, 0xf5, 0x9a, 0x5e, 0x1f, 0x61,
+	0xb7, 0x2b, 0x57, 0x23, 0x98, 0x84, 0x17, 0x6a, 0x50, 0xb0, 0xc9, 0x0d, 0x7d, 0x08, 0xa0, 0x4c,
+	0x3f, 0x6d, 0x6c, 0xb8, 0x7a, 0x6f, 0xab, 0x8e, 0xc2, 0xfb, 0x76, 0x88, 0xa2, 0x58, 0x87, 0x4e,
+	0x56, 0x44, 0xc0, 0x06, 0x2b, 0x31, 0xea, 0x20, 0x8b, 0x7b, 0xd5, 0xf3, 0xb5, 0x91, 0x18, 0x69,
+	0xd4, 0x6b, 0x11, 0x4c, 0xd2, 0xf7, 0x8e, 0x28, 0xd8, 0xe4, 0xb6, 0xe4, 0xc3, 0x5c, 0x52, 0x56,
+	0x29, 0xfb, 0xdb, 0xf5, 0xf8, 0xfe, 0xb6, 0x3a, 0xa4, 0x45, 0x30, 0x12, 0x03, 0xe6, 0x39, 0x82,
+	0x0f, 0xb3, 0x09, 0x19, 0xa5, 0xb0, 0xdc, 0x88, 0xb3, 0x7c, 0x29, 0xcb, 0x5e, 0xaf, 0xb3, 0xed,
+	0x26, 0x4f, 0x06, 0x73, 0x49, 0xe9, 0x1c, 0x19, 0xd3, 0x58, 0x8a, 0xdf, 0xdc, 0xc4, 0xff, 0x22,
+	0x07, 0x93, 0xa1, 0x19, 0xcf, 0x92, 0xaf, 0x53, 0xee, 0x57, 0xee, 0x90, 0x20, 0x3a, 0x3f, 0x4c,
+	0x10, 0x3d, 0x36, 0x38, 0x88, 0x0e, 0x72, 0xfa, 0xc5, 0x07, 0xe7, 0xf4, 0x8d, 0x20, 0x7a, 0x7c,
+	0xf8, 0x20, 0x7a, 0xe2, 0xf0, 0x20, 0xda, 0xfe, 0x6b, 0x0b, 0x50, 0x7f, 0xc6, 0x24, 0x8b, 0xa0,
+	0x48, 0x72, 0x73, 0x7d, 0x25, 0x6b, 0xf8, 0x7a, 0xd8, 0x1e, 0x6b, 0x7f, 0x5a, 0x80, 0xd9, 0x6b,
+	0xce, 0xc8, 0xa9, 0x57, 0x0e, 0xa7, 0x15, 0x52, 0x8d, 0x6a, 0xc7, 0x37, 0xb4, 0xac, 0x6a, 0x7e,
+	0x2f, 0xea, 0xa6, 0xa7, 0xab, 0xe9, 0xd5, 0xee, 0x0f, 0x26, 0xe1, 0x41, 0xd0, 0x43, 0x2f, 0x92,
+	0x4b, 0x30, 0xcd, 0xb8, 0xef, 0xd4, 0xb9, 0x4a, 0xee, 0xb2, 0xc5, 0x92, 0xdc, 0xb9, 0x4e, 0xe9,
+	0xea, 0xd3, 0x35, 0x93, 0x88, 0xe3, 0x75, 0x53, 0x73, 0xc6, 0x63, 0x99, 0x73, 0xc6, 0x2b, 0x30,
+	0x49, 0xda, 0x6d, 0xef, 0xc3, 0x5b, 0xa4, 0xc9, 0x74, 0x96, 0x26, 0x5c, 0x35, 0x6b, 0x01, 0x01,
+	0x47, 0x75, 0x50, 0x19, 0xc0, 0x69, 0xba, 0x9e, 0x4f, 0x65, 0x8b, 0xa2, 0xdc, 0x42, 0xe5, 0xb9,
+	0xd8, 0x46, 0x58, 0x8a, 0x8d, 0x1a, 0xa8, 0x06, 0xa7, 0x1c, 0x97, 0xd1, 0x7a, 0xcf, 0xa7, 0xb5,
+	0x1d, 0xa7, 0x7b, 0xeb, 0x46, 0x4d, 0x5a, 0x89, 0x3d, 0xb9, 0x9a, 0x27, 0x2a, 0x4f, 0x6a, 0x66,
+	0xa7, 0x36, 0xd2, 0x2a, 0xe1, 0xf4, 0xb6, 0xe8, 0x65, 0x98, 0x72, 0xdc, 0x7a, 0xbb, 0xd7, 0xa0,
+	0x9b, 0x84, 0xb7, 0xd8, 0xe2, 0x84, 0xec, 0xc6, 0xdc, 0xc1, 0xfe, 0xf2, 0xd4, 0x86, 0x51, 0x8e,
+	0x63, 0xb5, 0x44, 0x2b, 0x7a, 0xcf, 0x68, 0x35, 0x19, 0xb5, 0xba, 0x72, 0xcf, 0x6c, 0x65, 0xd6,
+	0x4a, 0xc9, 0xaa, 0x43, 0xa6, 0xac, 0xfa, 0x8f, 0x72, 0x50, 0x54, 0x87, 0x5a, 0xe8, 0x7c, 0xe2,
+	0xe4, 0xe8, 0xc9, 0xbe, 0x93, 0xa3, 0x52, 0xda, 0x01, 0xa0, 0x0d, 0x45, 0x87, 0xb1, 0x5e, 0xdc,
+	0x63, 0xd9, 0x90, 0x25, 0x58, 0x53, 0x64, 0xc6, 0xd1, 0x73, 0xb7, 0x9d, 0xa6, 0x4e, 0xc7, 0x5c,
+	0x36, 0xfc, 0x94, 0xe8, 0x6a, 0xc2, 0xdd, 0xf0, 0xee, 0x42, 0xe4, 0xb2, 0xc4, 0x2a, 0x08, 0xdf,
+	0xe5, 0x8d, 0xda, 0xcd, 0x37, 0x15, 0x8f, 0xaa, 0x44, 0xc4, 0x1a, 0x59, 0xf0, 0xf0, 0x7a, 0xbc,
+	0xdb, 0xe3, 0x72, 0xa1, 0x1c, 0x11, 0x8f, 0x9b, 0x12, 0x11, 0x6b, 0x64, 0xfb, 0x13, 0x0b, 0x66,
+	0x95, 0x0c, 0xaa, 0x2d, 0x5a, 0xdf, 0xa9, 0x71, 0xda, 0x15, 0x21, 0x44, 0x8f, 0x51, 0x96, 0x0c,
+	0x21, 0xde, 0x62, 0x94, 0x61, 0x49, 0x31, 0x46, 0x9f, 0x3b, 0xae, 0xd1, 0xdb, 0x17, 0xc0, 0x98,
+	0x1c, 0x79, 0x2a, 0xab, 0x0e, 0x27, 0xd5, 0x16, 0x96, 0x8f, 0x8c, 0x90, 0xaa, 0xb5, 0x87, 0x03,
+	0xba, 0x7d, 0x90, 0x83, 0x82, 0xf4, 0xf2, 0xb3, 0x58, 0xae, 0x78, 0x5a, 0x2e, 0x37, 0x54, 0x5a,
+	0xee, 0x90, 0xcc, 0x6d, 0x94, 0x9a, 0x1c, 0x7b, 0x60, 0x6a, 0x92, 0xa5, 0x65, 0x26, 0x5f, 0xcf,
+	0x10, 0xdc, 0x8c, 0x72, 0x33, 0xe2, 0x61, 0x33, 0x7f, 0x3f, 0xb3, 0x60, 0x21, 0x2d, 0x47, 0x9f,
+	0x45, 0xe6, 0x2f, 0xc0, 0x44, 0xb7, 0x4d, 0xf8, 0xb6, 0xe7, 0x77, 0x92, 0x67, 0xb3, 0x9b, 0xba,
+	0x1c, 0x87, 0x35, 0x90, 0x0f, 0xe0, 0x07, 0x61, 0x6e, 0x10, 0x02, 0x5e, 0x7e, 0xb8, 0xfc, 0x6d,
+	0x34, 0xc3, 0x61, 0x11, 0xc3, 0x06, 0x17, 0xfb, 0x8f, 0x0a, 0x30, 0x2f, 0x9b, 0x8c, 0xba, 0x21,
+	0x8e, 0xb2, 0xac, 0xba, 0xf0, 0x84, 0x0c, 0x4e, 0xfb, 0xf7, 0x50, 0xb5, 0xd2, 0x2e, 0xe8, 0xf6,
+	0x4f, 0x6c, 0xa4, 0xd6, 0xba, 0x3f, 0x90, 0x82, 0x07, 0xe0, 0xf6, 0x6f, 0x8c, 0xf0, 0xf5, 0xdb,
+	0x18, 0xcd, 0xc5, 0x36, 0x7e, 0xe8, 0x62, 0x1b, 0xb8, 0x8d, 0x4e, 0x3c, 0xc4, 0x36, 0xda, 0xbf,
+	0xb5, 0x4d, 0x66, 0xda, 0xda, 0xfe, 0x32, 0x07, 0xe3, 0x9b, 0xbe, 0x27, 0xcf, 0x7a, 0x8e, 0x3f,
+	0x21, 0xfe, 0xd6, 0x88, 0x67, 0xc4, 0x02, 0x4a, 0xd9, 0x72, 0x79, 0x46, 0x3c, 0x11, 0x3f, 0x1f,
+	0x36, 0xf2, 0xbb, 0xf9, 0x2c, 0x61, 0x87, 0x06, 0x3e, 0x24, 0xbf, 0xfb, 0x13, 0x0b, 0xa6, 0x63,
+	0x5d, 0x78, 0x8c, 0xcf, 0xd2, 0x13, 0x72, 0x4a, 0x3b, 0x4b, 0xff, 0x27, 0x0b, 0xe6, 0x63, 0x35,
+	0x1f, 0x41, 0x76, 0xf4, 0xbb, 0xf1, 0xec, 0xe8, 0x4b, 0x23, 0x8c, 0x67, 0x40, 0x8e, 0xf4, 0x4f,
+	0x93, 0xa3, 0x11, 0x23, 0x45, 0xbf, 0x09, 0xf3, 0xdd, 0xe0, 0xe8, 0x7d, 0xd3, 0x6b, 0x3b, 0x75,
+	0x87, 0x06, 0xc9, 0xf6, 0xf3, 0x19, 0xef, 0x25, 0xc8, 0xe6, 0x7b, 0x95, 0x6f, 0x68, 0xee, 0xf3,
+	0x9b, 0x49, 0x5c, 0xdc, 0xcf, 0x4a, 0xe6, 0x9e, 0x75, 0xaf, 0x1e, 0xdb, 0xdc, 0xb3, 0xee, 0xdf,
+	0x00, 0xb9, 0x7e, 0x61, 0xc1, 0x94, 0xa1, 0x1e, 0x0c, 0xb5, 0x00, 0x3e, 0x24, 0x3e, 0x6d, 0x79,
+	0xa1, 0x1b, 0x37, 0x74, 0x46, 0xf0, 0xed, 0xa0, 0x9d, 0x44, 0x8a, 0x56, 0x7e, 0x58, 0xce, 0xb0,
+	0x81, 0x8d, 0xbe, 0x6b, 0x24, 0xf7, 0x94, 0x6e, 0x0d, 0xc5, 0x45, 0xe6, 0x0e, 0x14, 0x07, 0x53,
+	0x93, 0x8d, 0x94, 0xa0, 0xfd, 0xe3, 0x48, 0x93, 0x75, 0xbe, 0xac, 0x0e, 0x50, 0xf7, 0xdc, 0x86,
+	0xc3, 0xc3, 0xcb, 0x59, 0xa5, 0xd5, 0x95, 0xe1, 0xa6, 0xa6, 0x1a, 0xb4, 0x8b, 0x06, 0x14, 0x16,
+	0x31, 0x6c, 0xc0, 0xa2, 0x1a, 0x14, 0x84, 0x29, 0x09, 0xae, 0xbb, 0xad, 0x66, 0x36, 0x4e, 0x4c,
+	0xdf, 0xec, 0x10, 0x3f, 0xb1, 0xc2, 0xb2, 0x7f, 0x98, 0x83, 0xc9, 0x70, 0x2d, 0x3e, 0x72, 0xcb,
+	0xfd, 0x52, 0x46, 0x2d, 0x1a, 0x64, 0x8d, 0xd0, 0xfb, 0x09, 0xcb, 0x9d, 0x55, 0x3d, 0x0f, 0xb1,
+	0xdd, 0xff, 0xa0, 0x66, 0x5c, 0xd5, 0x7d, 0x04, 0xaa, 0x78, 0x2b, 0xae, 0x8a, 0x2b, 0x19, 0x47,
+	0x33, 0x40, 0x19, 0x3f, 0xca, 0xc1, 0x6c, 0xc2, 0x20, 0xa1, 0xa7, 0xe4, 0xa2, 0x6a, 0x06, 0x87,
+	0x32, 0x61, 0x43, 0x9d, 0x42, 0x93, 0x34, 0xb4, 0x2b, 0x7c, 0xb0, 0xd0, 0x3b, 0xf3, 0x7c, 0x2d,
+	0xe4, 0x6f, 0x8d, 0x64, 0x03, 0x03, 0x90, 0xca, 0xbc, 0x72, 0xdf, 0x0c, 0x5c, 0x1c, 0x67, 0x83,
+	0x36, 0x61, 0x81, 0xf4, 0xb8, 0x17, 0x02, 0x5c, 0x71, 0xc9, 0x56, 0x9b, 0xaa, 0x7c, 0xdc, 0x44,
+	0xe5, 0xe7, 0xc2, 0x4c, 0x78, 0x4a, 0x1d, 0x9c, 0xda, 0xd2, 0xfe, 0x1b, 0x0b, 0x4e, 0x0f, 0xe8,
+	0xcf, 0x10, 0xc7, 0x53, 0x6d, 0x98, 0x96, 0x17, 0xc8, 0x43, 0x39, 0x04, 0xab, 0x78, 0xb8, 0x99,
+	0x37, 0x9b, 0xaa, 0xd1, 0xc7, 0x8a, 0x70, 0x1c, 0xdc, 0xfe, 0x49, 0x0e, 0x50, 0xd8, 0xd7, 0x2c,
+	0xa7, 0x68, 0xef, 0xc3, 0xf8, 0xb6, 0x4a, 0x47, 0x3f, 0xdc, 0x31, 0x68, 0xa5, 0x64, 0x9e, 0x04,
+	0x07, 0x98, 0xe8, 0x9d, 0xa3, 0xd1, 0x35, 0xe8, 0xd7, 0x33, 0x74, 0x07, 0x60, 0xdb, 0x71, 0x1d,
+	0xd6, 0x1a, 0xf1, 0x36, 0x89, 0x74, 0xb2, 0xaf, 0x86, 0x08, 0xd8, 0x40, 0xb3, 0xff, 0x2c, 0x67,
+	0xe8, 0xb0, 0xdc, 0xde, 0x87, 0x5a, 0xfb, 0xcf, 0xc5, 0x85, 0x39, 0xd9, 0x7f, 0x44, 0x1e, 0x0a,
+	0xe6, 0x0e, 0x8c, 0xed, 0x12, 0x3f, 0x38, 0xad, 0x1b, 0xf2, 0xa2, 0x5a, 0xff, 0x1d, 0x95, 0x68,
+	0x4e, 0x6f, 0x13, 0x9f, 0x61, 0x89, 0x29, 0x5c, 0x1f, 0xc6, 0x69, 0x37, 0xd8, 0x5c, 0x32, 0x1b,
+	0x4e, 0x4e, 0xbb, 0xe6, 0x00, 0x69, 0x57, 0xee, 0x00, 0xb4, 0xcb, 0xec, 0xef, 0x8f, 0x1b, 0x56,
+	0x41, 0xef, 0x67, 0x6f, 0x00, 0x6a, 0x13, 0xc6, 0xaf, 0x13, 0xb7, 0x21, 0x74, 0x89, 0x6e, 0xfb,
+	0x94, 0xb5, 0x74, 0xe4, 0xb4, 0xa4, 0x51, 0xd0, 0x8d, 0xbe, 0x1a, 0x38, 0xa5, 0x15, 0x3a, 0x1f,
+	0x3c, 0x00, 0x50, 0x52, 0x5e, 0x8e, 0x3d, 0x00, 0xb8, 0xbf, 0xbf, 0x3c, 0x13, 0xe9, 0xa3, 0xf1,
+	0x24, 0x20, 0xc3, 0x55, 0x77, 0x73, 0xbd, 0x17, 0x8e, 0x61, 0xbd, 0xff, 0x06, 0xcc, 0x6f, 0x27,
+	0xef, 0x4c, 0xe8, 0x7b, 0x66, 0xaf, 0x8e, 0x78, 0xe5, 0xa2, 0x72, 0xea, 0x20, 0x3a, 0x68, 0x8f,
+	0x8a, 0x71, 0x3f, 0x23, 0xe4, 0x05, 0x17, 0xec, 0x65, 0x12, 0x4c, 0xe5, 0x37, 0x87, 0xd6, 0xb9,
+	0x44, 0xfa, 0x2c, 0x79, 0xb5, 0x5e, 0x41, 0xe2, 0x18, 0x83, 0x84, 0x0e, 0x16, 0x8f, 0x52, 0x07,
+	0xd1, 0xf9, 0xf0, 0x5c, 0x51, 0x74, 0x47, 0x86, 0x98, 0xf9, 0xbe, 0x13, 0x41, 0x41, 0xc2, 0x66,
+	0x3d, 0xf4, 0xb1, 0x05, 0xa7, 0xc4, 0x62, 0xbd, 0x72, 0x8f, 0xd6, 0x7b, 0x42, 0x2a, 0xc1, 0xbb,
+	0x9b, 0xc5, 0x92, 0x94, 0xc6, 0xa5, 0x61, 0x5d, 0xbb, 0x14, 0x88, 0x28, 0x5e, 0x4e, 0x25, 0xe3,
+	0x74, 0xc6, 0xe8, 0xae, 0x72, 0xc6, 0xa8, 0x4c, 0x47, 0x3c, 0x7c, 0x96, 0x31, 0x74, 0xcc, 0x94,
+	0xdd, 0xe1, 0xd4, 0xfe, 0xe1, 0x98, 0x69, 0xae, 0x86, 0xcb, 0x7d, 0xde, 0x81, 0x31, 0x4e, 0xd8,
+	0x8e, 0xd6, 0x82, 0xd7, 0x47, 0xb8, 0x3a, 0x1d, 0xe9, 0x82, 0x8c, 0x8d, 0x65, 0x91, 0xc4, 0x44,
+	0x4b, 0x90, 0x23, 0x2c, 0x79, 0x12, 0xb6, 0xc6, 0x70, 0x8e, 0x30, 0x79, 0x4a, 0xb6, 0xad, 0x33,
+	0x17, 0xd1, 0x29, 0xd9, 0x36, 0xce, 0x39, 0xdb, 0x68, 0x0d, 0x66, 0xeb, 0x9e, 0xcb, 0x1d, 0xb7,
+	0x47, 0x6f, 0xba, 0x57, 0x7c, 0xdf, 0xf3, 0x75, 0x9e, 0xe2, 0xb4, 0xae, 0x38, 0x5b, 0x8d, 0x93,
+	0x71, 0xb2, 0x3e, 0x7a, 0x07, 0x0a, 0x3e, 0xe5, 0xfe, 0x9e, 0xde, 0x10, 0x2e, 0x8c, 0x60, 0xfb,
+	0xb0, 0x68, 0xaf, 0xa4, 0x2c, 0x7f, 0x62, 0x85, 0x18, 0x9a, 0xec, 0xe2, 0x31, 0x98, 0xec, 0x28,
+	0x13, 0x9d, 0x3f, 0xb6, 0x4c, 0xf4, 0x8f, 0x2c, 0xc3, 0x47, 0x08, 0x07, 0x8a, 0xde, 0x82, 0x71,
+	0xee, 0x74, 0xa8, 0xd7, 0xe3, 0xd9, 0x9c, 0xd3, 0xf0, 0xae, 0x82, 0xb4, 0x84, 0xb7, 0x14, 0x04,
+	0x0e, 0xb0, 0xd0, 0x65, 0x98, 0xa1, 0x62, 0x46, 0x6e, 0xb5, 0x84, 0x65, 0xf7, 0xda, 0xca, 0x13,
+	0x9b, 0x8e, 0x92, 0x44, 0x57, 0x62, 0x54, 0x9c, 0xa8, 0x1d, 0xa4, 0x40, 0xbe, 0x2e, 0xcf, 0x09,
+	0x74, 0x0a, 0xe4, 0x91, 0xbe, 0x23, 0x18, 0x39, 0x05, 0x72, 0xe8, 0x03, 0x82, 0xf7, 0xe0, 0x89,
+	0x74, 0x53, 0x70, 0x24, 0x0f, 0xf0, 0x7e, 0x9c, 0x94, 0x95, 0xf4, 0xc0, 0x02, 0xf5, 0xb3, 0x8e,
+	0xd3, 0x63, 0xca, 0x1d, 0xb5, 0xc7, 0xe4, 0x9b, 0x43, 0xd1, 0xcf, 0x15, 0xd1, 0xfb, 0x7a, 0x9d,
+	0x59, 0x59, 0x1e, 0xc0, 0xf5, 0xc1, 0x0c, 0x5c, 0x6b, 0xff, 0x6c, 0xc1, 0xa9, 0xd4, 0xda, 0xa1,
+	0x0c, 0x73, 0xc7, 0x29, 0x43, 0xeb, 0xa8, 0x65, 0xf8, 0x83, 0x1c, 0xcc, 0x61, 0xda, 0xf5, 0x62,
+	0x87, 0x17, 0x9b, 0xc1, 0x43, 0x8f, 0x0c, 0x61, 0x45, 0xe2, 0x46, 0x40, 0x65, 0x3c, 0xf6, 0xc2,
+	0x43, 0xa8, 0x4b, 0x27, 0xf0, 0x21, 0x87, 0x56, 0xff, 0xbe, 0x63, 0x15, 0xb5, 0x73, 0xa8, 0x03,
+	0x1a, 0x05, 0x28, 0x90, 0xe5, 0x8d, 0x3a, 0x6d, 0xdc, 0x5f, 0xcd, 0x70, 0x37, 0xaf, 0x1f, 0x59,
+	0x16, 0x63, 0x05, 0x68, 0x7f, 0x92, 0x03, 0x15, 0x82, 0x3c, 0x02, 0xeb, 0xf8, 0x2b, 0x31, 0xeb,
+	0xb8, 0x92, 0x25, 0x45, 0x36, 0x28, 0x15, 0x93, 0x0c, 0x0f, 0xcf, 0x65, 0xcc, 0xbb, 0x3d, 0x20,
+	0x0d, 0xf3, 0xf7, 0x16, 0x4c, 0xca, 0x7a, 0x8f, 0xc0, 0xd0, 0x6e, 0xc6, 0x0d, 0xed, 0xf3, 0x19,
+	0x46, 0x31, 0xc0, 0xc0, 0xfe, 0x77, 0x5e, 0xf7, 0x3e, 0x0c, 0x3e, 0x5b, 0xc4, 0x6f, 0xe8, 0xa8,
+	0x2a, 0xd2, 0x12, 0x51, 0x88, 0x15, 0x2d, 0xd4, 0xed, 0xf1, 0x63, 0xd0, 0xed, 0x5f, 0x53, 0x17,
+	0x1b, 0x29, 0xe3, 0xb4, 0x71, 0x35, 0x0c, 0x9f, 0xf2, 0x99, 0x6f, 0x68, 0xea, 0x5b, 0xa4, 0xd1,
+	0x89, 0x1a, 0x4e, 0xa0, 0xe2, 0x3e, 0x3e, 0x22, 0xa4, 0xea, 0x26, 0x8d, 0x99, 0x0e, 0x35, 0x5e,
+	0x1d, 0xd1, 0x72, 0xaa, 0x90, 0xaa, 0xaf, 0x18, 0xf7, 0x33, 0x42, 0x2d, 0x98, 0x32, 0xef, 0x96,
+	0xeb, 0x75, 0xba, 0x9a, 0xfd, 0x12, 0xbb, 0xba, 0x30, 0x62, 0x96, 0xe0, 0x18, 0xb2, 0xfd, 0xc7,
+	0x16, 0x40, 0x94, 0x50, 0x16, 0x73, 0x5e, 0xf7, 0x7a, 0xae, 0xca, 0x24, 0xe4, 0xa3, 0x39, 0xaf,
+	0x8a, 0x42, 0xac, 0x68, 0x42, 0x7f, 0x54, 0x3c, 0xa6, 0x17, 0xf5, 0xb9, 0x2c, 0xa1, 0x5e, 0x22,
+	0x71, 0xad, 0x0a, 0xb1, 0x06, 0xb4, 0x3f, 0x2a, 0x42, 0xc9, 0xd0, 0xb3, 0x44, 0xda, 0x7a, 0xfa,
+	0x78, 0xd2, 0xd6, 0xe9, 0xb9, 0x84, 0xd2, 0x48, 0xb9, 0x04, 0x06, 0x33, 0x3a, 0x42, 0x0e, 0x1e,
+	0x20, 0xa8, 0x5c, 0xcb, 0xc8, 0x71, 0x38, 0x12, 0x5e, 0xeb, 0xd5, 0x18, 0x24, 0x4e, 0xb0, 0x10,
+	0x5e, 0xaf, 0x2e, 0xa9, 0xf5, 0x3a, 0x1d, 0xe2, 0xef, 0x2d, 0x4e, 0xc9, 0xce, 0x87, 0x5e, 0xef,
+	0xd5, 0x18, 0x15, 0x27, 0x6a, 0xa3, 0xcd, 0x70, 0x42, 0xd5, 0xa5, 0xf6, 0x17, 0xb2, 0x4c, 0xa8,
+	0xf2, 0xfa, 0xe3, 0xf3, 0x28, 0x44, 0xea, 0x6d, 0xc9, 0xa0, 0xa1, 0x71, 0x4d, 0x7d, 0xbe, 0x43,
+	0x2c, 0xe3, 0xa2, 0x5c, 0x54, 0xa1, 0x48, 0x6f, 0xf6, 0xd5, 0xc0, 0x29, 0xad, 0x84, 0x19, 0xd0,
+	0xa1, 0x76, 0xa8, 0x3b, 0x3a, 0xb9, 0x91, 0x35, 0xce, 0x8a, 0x62, 0x47, 0x79, 0xd3, 0xb9, 0x9a,
+	0x40, 0xc5, 0x7d, 0x7c, 0xd0, 0x07, 0x30, 0x2d, 0x26, 0x39, 0x62, 0x0c, 0x0f, 0xc9, 0x58, 0x27,
+	0x55, 0x0d, 0x48, 0x1c, 0xe7, 0x60, 0x7f, 0x91, 0x87, 0xf4, 0x40, 0x3f, 0x7a, 0x64, 0x65, 0x3d,
+	0xe0, 0x91, 0xd5, 0xdb, 0x30, 0xc9, 0x38, 0xf1, 0xd5, 0x6b, 0xb7, 0xdc, 0x68, 0xaf, 0xdd, 0x6a,
+	0x01, 0x00, 0x8e, 0xb0, 0x12, 0x59, 0x97, 0xfc, 0x91, 0x66, 0x5d, 0x56, 0x01, 0x64, 0x20, 0x26,
+	0xcd, 0x8c, 0xdc, 0x6f, 0xa6, 0x23, 0xad, 0xbd, 0x12, 0x52, 0xb0, 0x51, 0x0b, 0x7d, 0x2b, 0xdc,
+	0xc5, 0xd5, 0x85, 0x87, 0x5f, 0xe8, 0xbb, 0x9f, 0x76, 0x32, 0xe6, 0xe6, 0x25, 0x12, 0xb9, 0x19,
+	0x2e, 0xb5, 0xa6, 0x24, 0x08, 0xc6, 0xb3, 0x25, 0x08, 0xec, 0xff, 0xcd, 0x41, 0xcc, 0x0a, 0xa3,
+	0x3f, 0xb4, 0x60, 0x9e, 0x24, 0x3e, 0x28, 0x12, 0x38, 0xb1, 0xbf, 0x9c, 0xed, 0x2b, 0x2f, 0x7d,
+	0xdf, 0x23, 0x89, 0xce, 0x70, 0x93, 0x55, 0x18, 0xee, 0x67, 0x8a, 0x7e, 0xcf, 0x82, 0x93, 0xa4,
+	0xff, 0x8b, 0x31, 0x7a, 0xf1, 0xbc, 0x36, 0xf2, 0x27, 0x67, 0x2a, 0xa7, 0x0f, 0xf6, 0x97, 0xd3,
+	0xbe, 0xa5, 0x83, 0xd3, 0xd8, 0xa1, 0x77, 0x61, 0x8c, 0xf8, 0xcd, 0x20, 0x7d, 0x9c, 0x9d, 0x6d,
+	0xf0, 0x21, 0xa0, 0xc8, 0x95, 0x58, 0xf3, 0x9b, 0x0c, 0x4b, 0x50, 0xfb, 0xa7, 0x79, 0x98, 0x4b,
+	0x3e, 0xee, 0xd2, 0x57, 0xa7, 0xc7, 0x52, 0xaf, 0x4e, 0x0b, 0x5d, 0x93, 0x07, 0x28, 0xc9, 0x07,
+	0x8d, 0xf2, 0x1c, 0x44, 0xd1, 0x42, 0x5d, 0x93, 0x4f, 0x2e, 0x0a, 0x0f, 0xa1, 0x6b, 0xf2, 0x9d,
+	0x45, 0x84, 0x85, 0x2e, 0xc4, 0x33, 0xd2, 0x76, 0x32, 0x23, 0x3d, 0x6f, 0x8e, 0x65, 0xd4, 0xa4,
+	0x74, 0x07, 0x4a, 0xc6, 0x3c, 0x68, 0x8d, 0xbe, 0x98, 0x59, 0xee, 0xd1, 0xb2, 0x9b, 0x55, 0x77,
+	0xe6, 0x22, 0x8a, 0x89, 0x1f, 0xd9, 0x0f, 0x29, 0xad, 0x87, 0xca, 0xda, 0x4a, 0x71, 0x19, 0x68,
+	0xf6, 0xbf, 0x59, 0x30, 0x1d, 0xbb, 0xcf, 0x2f, 0xb8, 0x05, 0xef, 0x26, 0x46, 0xff, 0x7a, 0xce,
+	0xed, 0x10, 0x01, 0x1b, 0x68, 0xe8, 0x7b, 0x50, 0x6a, 0x7b, 0x6e, 0x93, 0x32, 0x5e, 0xf3, 0xc8,
+	0x8e, 0xd6, 0x93, 0xac, 0xf9, 0xab, 0xc5, 0x83, 0xfd, 0xe5, 0x85, 0x1b, 0x0a, 0xa6, 0xea, 0x75,
+	0xba, 0x6d, 0xca, 0xd5, 0x0b, 0x1b, 0x6c, 0x82, 0xcb, 0xd3, 0xef, 0xf0, 0xfa, 0xc0, 0xe3, 0x7a,
+	0xfa, 0x1d, 0xdd, 0x7b, 0x38, 0xe2, 0xd3, 0xef, 0xd8, 0x85, 0x8a, 0x43, 0x4e, 0xbf, 0xc3, 0xba,
+	0x8f, 0xed, 0xe9, 0x77, 0xd8, 0xc3, 0x01, 0xe1, 0xd7, 0xff, 0xe4, 0x8c, 0x51, 0xc4, 0x43, 0xb0,
+	0xdc, 0x03, 0x42, 0xb0, 0xf7, 0x60, 0xc2, 0x71, 0x39, 0xf5, 0x77, 0x49, 0x5b, 0xe7, 0x9f, 0xb3,
+	0xae, 0xc5, 0x70, 0xa8, 0x1b, 0x1a, 0x07, 0x87, 0x88, 0xa8, 0x0d, 0xa7, 0x82, 0x23, 0x1f, 0x9f,
+	0x92, 0xe8, 0x50, 0x5a, 0x5f, 0xa7, 0x7c, 0x25, 0x38, 0x9b, 0xb8, 0x9a, 0x56, 0xe9, 0xfe, 0x20,
+	0x02, 0x4e, 0x07, 0x45, 0x0c, 0xa6, 0x99, 0x91, 0x7b, 0x08, 0x76, 0xc4, 0x21, 0x8f, 0xcb, 0x92,
+	0xe9, 0x1a, 0xe3, 0x0e, 0xa6, 0x09, 0x8a, 0xe3, 0x3c, 0xec, 0x8f, 0x2d, 0x98, 0x89, 0x5f, 0xdd,
+	0xf9, 0x7f, 0x8f, 0x83, 0xbe, 0xc8, 0xc3, 0x6c, 0x62, 0xf1, 0x27, 0x62, 0xa1, 0xc9, 0x47, 0x19,
+	0x0b, 0x15, 0x47, 0x8a, 0x85, 0xd2, 0x83, 0x80, 0xb1, 0x91, 0x82, 0x80, 0x4b, 0xca, 0x11, 0xd7,
+	0x8b, 0x69, 0x63, 0x5d, 0x3f, 0x1a, 0x0a, 0x27, 0xf8, 0x86, 0x49, 0xc4, 0xf1, 0xba, 0xd2, 0xc3,
+	0x69, 0xf4, 0x7f, 0x1c, 0x46, 0x47, 0x11, 0xaf, 0x65, 0xbd, 0x06, 0x1d, 0x02, 0x28, 0x0f, 0x27,
+	0x85, 0x80, 0xd3, 0xd8, 0x55, 0xde, 0xf8, 0xec, 0xab, 0x33, 0x27, 0x3e, 0xff, 0xea, 0xcc, 0x89,
+	0x2f, 0xbf, 0x3a, 0x73, 0xe2, 0xa3, 0x83, 0x33, 0xd6, 0x67, 0x07, 0x67, 0xac, 0xcf, 0x0f, 0xce,
+	0x58, 0x5f, 0x1e, 0x9c, 0xb1, 0xfe, 0xf3, 0xe0, 0x8c, 0xf5, 0xf1, 0xcf, 0xce, 0x9c, 0xb8, 0xf3,
+	0xf4, 0x30, 0x9f, 0x94, 0xfc, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xa2, 0x3f, 0x08, 0x11, 0x79,
+	0x52, 0x00, 0x00,
 }
 
 func (m *AnalysisRunArgument) Marshal() (dAtA []byte, err error) {
@@ -5074,6 +5076,14 @@ func (m *PromotionStep) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	_ = i
 	var l int
 	_ = l
+	i--
+	if m.ContinueOnError {
+		dAtA[i] = 1
+	} else {
+		dAtA[i] = 0
+	}
+	i--
+	dAtA[i] = 0x40
 	i -= len(m.If)
 	copy(dAtA[i:], m.If)
 	i = encodeVarintGenerated(dAtA, i, uint64(len(m.If)))
@@ -5833,6 +5843,14 @@ func (m *StepExecutionMetadata) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	_ = i
 	var l int
 	_ = l
+	i--
+	if m.ContinueOnError {
+		dAtA[i] = 1
+	} else {
+		dAtA[i] = 0
+	}
+	i--
+	dAtA[i] = 0x38
 	i -= len(m.Message)
 	copy(dAtA[i:], m.Message)
 	i = encodeVarintGenerated(dAtA, i, uint64(len(m.Message)))
@@ -7343,6 +7361,7 @@ func (m *PromotionStep) Size() (n int) {
 	}
 	l = len(m.If)
 	n += 1 + l + sovGenerated(uint64(l))
+	n += 2
 	return n
 }
 
@@ -7611,6 +7630,7 @@ func (m *StepExecutionMetadata) Size() (n int) {
 	n += 1 + l + sovGenerated(uint64(l))
 	l = len(m.Message)
 	n += 1 + l + sovGenerated(uint64(l))
+	n += 2
 	return n
 }
 
@@ -8590,6 +8610,7 @@ func (this *PromotionStep) String() string {
 		`Task:` + strings.Replace(this.Task.String(), "PromotionTaskReference", "PromotionTaskReference", 1) + `,`,
 		`Vars:` + repeatedStringForVars + `,`,
 		`If:` + fmt.Sprintf("%v", this.If) + `,`,
+		`ContinueOnError:` + fmt.Sprintf("%v", this.ContinueOnError) + `,`,
 		`}`,
 	}, "")
 	return s
@@ -8808,6 +8829,7 @@ func (this *StepExecutionMetadata) String() string {
 		`ErrorCount:` + fmt.Sprintf("%v", this.ErrorCount) + `,`,
 		`Status:` + fmt.Sprintf("%v", this.Status) + `,`,
 		`Message:` + fmt.Sprintf("%v", this.Message) + `,`,
+		`ContinueOnError:` + fmt.Sprintf("%v", this.ContinueOnError) + `,`,
 		`}`,
 	}, "")
 	return s
@@ -17816,6 +17838,26 @@ func (m *PromotionStep) Unmarshal(dAtA []byte) error {
 			}
 			m.If = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
+		case 8:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ContinueOnError", wireType)
+			}
+			var v int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowGenerated
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				v |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.ContinueOnError = bool(v != 0)
 		default:
 			iNdEx = preIndex
 			skippy, err := skipGenerated(dAtA[iNdEx:])
@@ -19881,6 +19923,26 @@ func (m *StepExecutionMetadata) Unmarshal(dAtA []byte) error {
 			}
 			m.Message = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
+		case 7:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ContinueOnError", wireType)
+			}
+			var v int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowGenerated
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				v |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.ContinueOnError = bool(v != 0)
 		default:
 			iNdEx = preIndex
 			skippy, err := skipGenerated(dAtA[iNdEx:])
diff --git a/api/v1alpha1/generated.proto b/api/v1alpha1/generated.proto
index c60663c8..62760ccc 100644
--- a/api/v1alpha1/generated.proto
+++ b/api/v1alpha1/generated.proto
@@ -1105,6 +1105,12 @@ message PromotionStep {
   // considered to have failed.
   optional string if = 7;
 
+  // ContinueOnError is a boolean value that, if set to true, will cause the
+  // Promotion to continue executing the next step even if this step fails. It
+  // also will not permit this failure to impact the overall status of the
+  // Promotion.
+  optional bool continueOnError = 8;
+
   // Retry is the retry policy for this step.
   optional PromotionStepRetry retry = 4;
 
@@ -1385,6 +1391,12 @@ message StepExecutionMetadata {
 
   // Message is a display message about the step, including any errors.
   optional string message = 6;
+
+  // ContinueOnError is a boolean value that, if set to true, will cause the
+  // Promotion to continue executing the next step even if this step fails. It
+  // also will not permit this failure to impact the overall status of the
+  // Promotion.
+  optional bool continueOnError = 7;
 }
 
 // Verification describes how to verify that a Promotion has been successful
diff --git a/api/v1alpha1/promotion_types.go b/api/v1alpha1/promotion_types.go
index 8bcf2b14..eb9c5105 100644
--- a/api/v1alpha1/promotion_types.go
+++ b/api/v1alpha1/promotion_types.go
@@ -37,6 +37,16 @@ const (
 	PromotionPhaseAborted PromotionPhase = "Aborted"
 )
 
+// IsTerminal returns true if the PromotionPhase is a terminal one.
+func (p *PromotionPhase) IsTerminal() bool {
+	switch *p {
+	case PromotionPhaseSucceeded, PromotionPhaseFailed, PromotionPhaseErrored, PromotionPhaseAborted:
+		return true
+	default:
+		return false
+	}
+}
+
 type PromotionStepStatus string
 
 const (
@@ -64,13 +74,38 @@ const (
 	PromotionStepStatusSkipped PromotionStepStatus = "Skipped"
 )
 
-// IsTerminal returns true if the PromotionPhase is a terminal one.
-func (p *PromotionPhase) IsTerminal() bool {
-	switch *p {
-	case PromotionPhaseSucceeded, PromotionPhaseFailed, PromotionPhaseErrored, PromotionPhaseAborted:
-		return true
+// severityByStatus defines relative severity levels for each
+// PromotionStepStatus.
+var severityByStatus = map[PromotionStepStatus]int{
+	PromotionStepStatusSucceeded: 0,
+	PromotionStepStatusSkipped:   1,
+	PromotionStepStatusRunning:   2,
+	PromotionStepStatusAborted:   3,
+	PromotionStepStatusFailed:    4,
+	PromotionStepStatusErrored:   5,
+}
+
+// Compare compares the severity of the current PromotionStepStatus with
+// another. It returns -1 if the current status is less severe than the other, 0
+// if the two statuses are equally severe, or 1 if the current status is more
+// severe than the other.
+func (s PromotionStepStatus) Compare(other PromotionStepStatus) int {
+	// Get the severity levels of the current and other statuses
+	thisSeverity, lhsOK := severityByStatus[s]
+	otherSeverity, rhsOK := severityByStatus[other]
+
+	if !lhsOK || !rhsOK {
+		panic(fmt.Sprintf("unknown PromotionStepStatus: %s or %s", s, other))
+	}
+
+	// Compare the severity levels
+	switch {
+	case thisSeverity < otherSeverity:
+		return -1
+	case thisSeverity > otherSeverity:
+		return 1
 	default:
-		return false
+		return 0
 	}
 }
 
@@ -226,6 +261,11 @@ type PromotionStep struct {
 	// If the expression does not evaluate to a boolean value, the step will be
 	// considered to have failed.
 	If string `json:"if,omitempty" protobuf:"bytes,7,opt,name=if"`
+	// ContinueOnError is a boolean value that, if set to true, will cause the
+	// Promotion to continue executing the next step even if this step fails. It
+	// also will not permit this failure to impact the overall status of the
+	// Promotion.
+	ContinueOnError bool `json:"continueOnError,omitempty" protobuf:"varint,8,opt,name=continueOnError"`
 	// Retry is the retry policy for this step.
 	Retry *PromotionStepRetry `json:"retry,omitempty" protobuf:"bytes,4,opt,name=retry"`
 	// Vars is a list of variables that can be referenced by expressions in
@@ -349,6 +389,22 @@ type PromotionList struct {
 // StepExecutionMetadataList is a list of StepExecutionMetadata.
 type StepExecutionMetadataList []StepExecutionMetadata
 
+// HasFailures returns true if any of the StepExecutionMetadata in the list
+// have a status of PromotionStepStatusErrored or PromotionStepStatusFailed.
+func (s StepExecutionMetadataList) HasFailures() bool {
+	for _, stepExecMeta := range s {
+		if stepExecMeta.ContinueOnError {
+			continue
+		}
+		switch stepExecMeta.Status {
+		case PromotionStepStatusErrored, PromotionStepStatusFailed:
+			return true
+		}
+		// Other statuses have no effect on the failure check.
+	}
+	return false
+}
+
 // StepExecutionMetadata tracks metadata pertaining to the execution of
 // a promotion step.
 type StepExecutionMetadata struct {
@@ -366,4 +422,9 @@ type StepExecutionMetadata struct {
 	Status PromotionStepStatus `json:"status,omitempty" protobuf:"bytes,5,opt,name=status"`
 	// Message is a display message about the step, including any errors.
 	Message string `json:"message,omitempty" protobuf:"bytes,6,opt,name=message"`
+	// ContinueOnError is a boolean value that, if set to true, will cause the
+	// Promotion to continue executing the next step even if this step fails. It
+	// also will not permit this failure to impact the overall status of the
+	// Promotion.
+	ContinueOnError bool `json:"continueOnError,omitempty" protobuf:"varint,7,opt,name=continueOnError"`
 }
diff --git a/charts/kargo/resources/crds/kargo.akuity.io_clusterpromotiontasks.yaml b/charts/kargo/resources/crds/kargo.akuity.io_clusterpromotiontasks.yaml
index afbd4ed9..d037c8f8 100644
--- a/charts/kargo/resources/crds/kargo.akuity.io_clusterpromotiontasks.yaml
+++ b/charts/kargo/resources/crds/kargo.akuity.io_clusterpromotiontasks.yaml
@@ -66,6 +66,13 @@ spec:
                         expressions in defining values at any level of this block.
                         See https://docs.kargo.io/user-guide/reference-docs/expressions for details.
                       x-kubernetes-preserve-unknown-fields: true
+                    continueOnError:
+                      description: |-
+                        ContinueOnError is a boolean value that, if set to true, will cause the
+                        Promotion to continue executing the next step even if this step fails. It
+                        also will not permit this failure to impact the overall status of the
+                        Promotion.
+                      type: boolean
                     if:
                       description: |-
                         If is an optional expression that, if present, must evaluate to a boolean
diff --git a/charts/kargo/resources/crds/kargo.akuity.io_promotions.yaml b/charts/kargo/resources/crds/kargo.akuity.io_promotions.yaml
index cd732b09..2d7e089b 100644
--- a/charts/kargo/resources/crds/kargo.akuity.io_promotions.yaml
+++ b/charts/kargo/resources/crds/kargo.akuity.io_promotions.yaml
@@ -98,6 +98,13 @@ spec:
                         expressions in defining values at any level of this block.
                         See https://docs.kargo.io/user-guide/reference-docs/expressions for details.
                       x-kubernetes-preserve-unknown-fields: true
+                    continueOnError:
+                      description: |-
+                        ContinueOnError is a boolean value that, if set to true, will cause the
+                        Promotion to continue executing the next step even if this step fails. It
+                        also will not permit this failure to impact the overall status of the
+                        Promotion.
+                      type: boolean
                     if:
                       description: |-
                         If is an optional expression that, if present, must evaluate to a boolean
@@ -655,6 +662,13 @@ spec:
                     alias:
                       description: Alias is the alias of the step.
                       type: string
+                    continueOnError:
+                      description: |-
+                        ContinueOnError is a boolean value that, if set to true, will cause the
+                        Promotion to continue executing the next step even if this step fails. It
+                        also will not permit this failure to impact the overall status of the
+                        Promotion.
+                      type: boolean
                     errorCount:
                       description: ErrorCount tracks consecutive failed attempts to
                         execute the step.
diff --git a/charts/kargo/resources/crds/kargo.akuity.io_promotiontasks.yaml b/charts/kargo/resources/crds/kargo.akuity.io_promotiontasks.yaml
index cb7d0da8..440067eb 100644
--- a/charts/kargo/resources/crds/kargo.akuity.io_promotiontasks.yaml
+++ b/charts/kargo/resources/crds/kargo.akuity.io_promotiontasks.yaml
@@ -66,6 +66,13 @@ spec:
                         expressions in defining values at any level of this block.
                         See https://docs.kargo.io/user-guide/reference-docs/expressions for details.
                       x-kubernetes-preserve-unknown-fields: true
+                    continueOnError:
+                      description: |-
+                        ContinueOnError is a boolean value that, if set to true, will cause the
+                        Promotion to continue executing the next step even if this step fails. It
+                        also will not permit this failure to impact the overall status of the
+                        Promotion.
+                      type: boolean
                     if:
                       description: |-
                         If is an optional expression that, if present, must evaluate to a boolean
diff --git a/charts/kargo/resources/crds/kargo.akuity.io_stages.yaml b/charts/kargo/resources/crds/kargo.akuity.io_stages.yaml
index d35aff2f..e51e5e56 100644
--- a/charts/kargo/resources/crds/kargo.akuity.io_stages.yaml
+++ b/charts/kargo/resources/crds/kargo.akuity.io_stages.yaml
@@ -91,6 +91,13 @@ spec:
                                 expressions in defining values at any level of this block.
                                 See https://docs.kargo.io/user-guide/reference-docs/expressions for details.
                               x-kubernetes-preserve-unknown-fields: true
+                            continueOnError:
+                              description: |-
+                                ContinueOnError is a boolean value that, if set to true, will cause the
+                                Promotion to continue executing the next step even if this step fails. It
+                                also will not permit this failure to impact the overall status of the
+                                Promotion.
+                              type: boolean
                             if:
                               description: |-
                                 If is an optional expression that, if present, must evaluate to a boolean
@@ -1052,6 +1059,13 @@ spec:
                             alias:
                               description: Alias is the alias of the step.
                               type: string
+                            continueOnError:
+                              description: |-
+                                ContinueOnError is a boolean value that, if set to true, will cause the
+                                Promotion to continue executing the next step even if this step fails. It
+                                also will not permit this failure to impact the overall status of the
+                                Promotion.
+                              type: boolean
                             errorCount:
                               description: ErrorCount tracks consecutive failed attempts
                                 to execute the step.
@@ -1901,6 +1915,13 @@ spec:
                             alias:
                               description: Alias is the alias of the step.
                               type: string
+                            continueOnError:
+                              description: |-
+                                ContinueOnError is a boolean value that, if set to true, will cause the
+                                Promotion to continue executing the next step even if this step fails. It
+                                also will not permit this failure to impact the overall status of the
+                                Promotion.
+                              type: boolean
                             errorCount:
                               description: ErrorCount tracks consecutive failed attempts
                                 to execute the step.
diff --git a/go.sum b/go.sum
index be79e426..1402d548 100644
--- a/go.sum
+++ b/go.sum
@@ -9,8 +9,6 @@ code.gitea.io/sdk/gitea v0.21.0 h1:69n6oz6kEVHRo1+APQQyizkhrZrLsTLXey9142pfkD4=
 code.gitea.io/sdk/gitea v0.21.0/go.mod h1:tnBjVhuKJCn8ibdyyhvUyxrR1Ca2KHEoTWoukNhXQPA=
 connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw=
 connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8=
-connectrpc.com/grpchealth v1.3.0 h1:FA3OIwAvuMokQIXQrY5LbIy8IenftksTP/lG4PbYN+E=
-connectrpc.com/grpchealth v1.3.0/go.mod h1:3vpqmX25/ir0gVgW6RdnCPPZRcR6HvqtXX5RNPmDXHM=
 connectrpc.com/grpchealth v1.4.0 h1:MJC96JLelARPgZTiRF9KRfY/2N9OcoQvF2EWX07v2IE=
 connectrpc.com/grpchealth v1.4.0/go.mod h1:WhW6m1EzTmq3Ky1FE8EfkIpSDc6TfUx2M2KqZO3ts/Q=
 dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
@@ -533,8 +531,6 @@ github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-gitlab.com/gitlab-org/api/client-go v0.127.0 h1:8xnxcNKGF2gDazEoMs+hOZfOspSSw8D0vAoWhQk9U+U=
-gitlab.com/gitlab-org/api/client-go v0.127.0/go.mod h1:bYC6fPORKSmtuPRyD9Z2rtbAjE7UeNatu2VWHRf4/LE=
 gitlab.com/gitlab-org/api/client-go v0.128.0 h1:Wvy1UIuluKemubao2k8EOqrl3gbgJ1PVifMIQmg2Da4=
 gitlab.com/gitlab-org/api/client-go v0.128.0/go.mod h1:bYC6fPORKSmtuPRyD9Z2rtbAjE7UeNatu2VWHRf4/LE=
 go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
@@ -700,17 +696,13 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
 gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
-google.golang.org/api v0.229.0 h1:p98ymMtqeJ5i3lIBMj5MpR9kzIIgzpHHh8vQ+vgAzx8=
-google.golang.org/api v0.229.0/go.mod h1:wyDfmq5g1wYJWn29O22FDWN48P7Xcz0xz+LBpptYvB0=
 google.golang.org/api v0.230.0 h1:2u1hni3E+UXAXrONrrkfWpi/V6cyKVAbfGVeGtC3OxM=
 google.golang.org/api v0.230.0/go.mod h1:aqvtoMk7YkiXx+6U12arQFExiRV9D/ekvMCwCd/TksQ=
 google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
-google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24=
-google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw=
+google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
+google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e h1:ztQaXfzEXTmCBvbtWYRhJxW+0iJcz2qXfd38/e9l7bA=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
-google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI=
-google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
 google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
 google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
 google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
diff --git a/internal/controller/promotions/promotions.go b/internal/controller/promotions/promotions.go
index c16c6778..05fd83c8 100644
--- a/internal/controller/promotions/promotions.go
+++ b/internal/controller/promotions/promotions.go
@@ -469,12 +469,13 @@ func (r *reconciler) promote(
 	steps := make([]promotion.Step, len(workingPromo.Spec.Steps))
 	for i, step := range workingPromo.Spec.Steps {
 		steps[i] = promotion.Step{
-			Kind:   step.Uses,
-			Alias:  step.As,
-			If:     step.If,
-			Retry:  step.Retry,
-			Vars:   step.Vars,
-			Config: step.Config.Raw,
+			Kind:            step.Uses,
+			Alias:           step.As,
+			If:              step.If,
+			ContinueOnError: step.ContinueOnError,
+			Retry:           step.Retry,
+			Vars:            step.Vars,
+			Config:          step.Config.Raw,
 		}
 	}
 
diff --git a/internal/expressions/function/functions.go b/internal/expressions/function/functions.go
index 28293776..25c015fa 100644
--- a/internal/expressions/function/functions.go
+++ b/internal/expressions/function/functions.go
@@ -46,6 +46,17 @@ func DataOperations(ctx context.Context, c client.Client, project string) []expr
 	}
 }
 
+// StatusOperations returns a slice of expr.Option containing functions for
+// assessing the status of all preceding steps.
+func StatusOperations(stepExecMetas kargoapi.StepExecutionMetadataList) []expr.Option {
+	return []expr.Option{
+		Always(),
+		Failure(stepExecMetas),
+		Success(stepExecMetas),
+		Status(stepExecMetas),
+	}
+}
+
 // Warehouse returns an expr.Option that provides a `warehouse()` function
 // for use in expressions.
 //
@@ -140,6 +151,53 @@ func Secret(ctx context.Context, c client.Client, project string) expr.Option {
 	)
 }
 
+// Always returns an expr.Option that provides an `always()` function
+// for use in expressions.
+//
+// The `always()` function unconditionally returns true.
+func Always() expr.Option {
+	return expr.Function(
+		"always",
+		func(...any) (any, error) {
+			return true, nil
+		},
+		new(func() bool),
+	)
+}
+
+// Failure returns an expr.Option that provides a `failure()` function
+// for use in expressions.
+//
+// The `failure()` function checks the status of all preceding steps and
+// returns true if any of them have failed or errored and false otherwise.
+func Failure(stepExecMetas kargoapi.StepExecutionMetadataList) expr.Option {
+	return expr.Function("failure", hasFailure(stepExecMetas), new(func() bool))
+}
+
+// Success returns an expr.Option that provides a `success()` function
+// for use in expressions.
+//
+// The `success()` function checks the status of all preceding steps and
+// returns true if none of them have failed or errored and false otherwise.
+func Success(stepExecMetas kargoapi.StepExecutionMetadataList) expr.Option {
+	return expr.Function(
+		"success",
+		func(a ...any) (any, error) {
+			failed, err := hasFailure(stepExecMetas)(a...)
+			return !failed.(bool), err // nolint: forcetypeassert
+		},
+		new(func() bool),
+	)
+}
+
+func Status(stepExecMetas kargoapi.StepExecutionMetadataList) expr.Option {
+	return expr.Function(
+		"status",
+		getStatus(stepExecMetas),
+		new(func(alias string) kargoapi.PromotionStepStatus),
+	)
+}
+
 // warehouse creates a FreightOrigin of kind Warehouse with the specified name.
 //
 // It returns an error if the argument count is incorrect or if the name is not
@@ -373,3 +431,36 @@ func getSecret(ctx context.Context, c client.Client, project string) exprFn {
 		return data, nil
 	}
 }
+
+func hasFailure(stepExecMetas kargoapi.StepExecutionMetadataList) exprFn {
+	return func(a ...any) (any, error) {
+		if len(a) != 0 {
+			return nil, fmt.Errorf("expected 0 arguments, got %d", len(a))
+		}
+		return stepExecMetas.HasFailures(), nil
+	}
+}
+
+func getStatus(stepExecMetas kargoapi.StepExecutionMetadataList) exprFn {
+	return func(a ...any) (any, error) {
+		if len(a) != 1 {
+			return nil, fmt.Errorf("expected 1 argument, got %d", len(a))
+		}
+
+		alias, ok := a[0].(string)
+		if !ok {
+			return nil, fmt.Errorf("argument must be string, got %T", a[0])
+		}
+
+		if alias == "" {
+			return nil, fmt.Errorf("argument must not be empty")
+		}
+
+		for _, stepExecMeta := range stepExecMetas {
+			if stepExecMeta.Alias == alias {
+				return stepExecMeta.Status, nil
+			}
+		}
+		return "", nil
+	}
+}
diff --git a/internal/promotion/promotion.go b/internal/promotion/promotion.go
index 7acd8922..9dd71aa6 100644
--- a/internal/promotion/promotion.go
+++ b/internal/promotion/promotion.go
@@ -77,6 +77,11 @@ type Step struct {
 	// If the expression does not evaluate to a boolean value, the step will
 	// fail.
 	If string
+	// ContinueOnError is a boolean value that, if set to true, will cause the
+	// Promotion to continue executing the next step even if this step fails. It
+	// also will not permit this failure to impact the overall status of the
+	// Promotion.
+	ContinueOnError bool
 	// Retry is the retry configuration for the Step.
 	Retry *kargoapi.PromotionStepRetry
 	// Vars is a list of variables definitions that can be used by the
@@ -107,6 +112,18 @@ func StepEnvWithSecrets(secrets map[string]map[string]string) StepEnvOption {
 	}
 }
 
+// StepEnvWithStepMetas returns a StepEnvOption that adds StepExecutionMetadata
+// indexed by alias to the environment of the Step.
+func StepEnvWithStepMetas(promoCtx Context) StepEnvOption {
+	metas := make(map[string]any, len(promoCtx.StepExecutionMetadata))
+	for _, stepMeta := range promoCtx.StepExecutionMetadata {
+		metas[stepMeta.Alias] = stepMeta
+	}
+	return func(env map[string]any) {
+		env["stepMetas"] = metas
+	}
+}
+
 // StepEnvWithOutputs returns a StepEnvOption that adds the provided outputs to
 // the environment of the Step.
 func StepEnvWithOutputs(outputs promotion.State) StepEnvOption {
@@ -192,8 +209,11 @@ func (s *Step) Skip(
 	promoCtx Context,
 	state promotion.State,
 ) (bool, error) {
+	// If no "if" condition is provided, then this step is automatically skipped
+	// if any of the previous steps have errored or failed and is not skipped
+	// otherwise.
 	if s.If == "" {
-		return false, nil
+		return promoCtx.StepExecutionMetadata.HasFailures(), nil
 	}
 
 	vars, err := s.GetVars(ctx, cl, promoCtx, state)
@@ -203,6 +223,7 @@ func (s *Step) Skip(
 
 	env := s.BuildEnv(
 		promoCtx,
+		StepEnvWithStepMetas(promoCtx),
 		StepEnvWithOutputs(state),
 		StepEnvWithTaskOutputs(s.Alias, state),
 		StepEnvWithVars(vars),
@@ -212,14 +233,17 @@ func (s *Step) Skip(
 		s.If,
 		env,
 		append(
-			exprfn.FreightOperations(
-				ctx,
-				cl,
-				promoCtx.Project,
-				promoCtx.FreightRequests,
-				promoCtx.Freight.References(),
+			append(
+				exprfn.FreightOperations(
+					ctx,
+					cl,
+					promoCtx.Project,
+					promoCtx.FreightRequests,
+					promoCtx.Freight.References(),
+				),
+				exprfn.DataOperations(ctx, cl, promoCtx.Project)...,
 			),
-			exprfn.DataOperations(ctx, cl, promoCtx.Project)...,
+			exprfn.StatusOperations(promoCtx.StepExecutionMetadata)...,
 		)...,
 	)
 	if err != nil {
@@ -253,6 +277,7 @@ func (s *Step) GetConfig(
 
 	env := s.BuildEnv(
 		promoCtx,
+		StepEnvWithStepMetas(promoCtx),
 		StepEnvWithOutputs(state),
 		StepEnvWithTaskOutputs(s.Alias, state),
 		StepEnvWithVars(vars),
@@ -317,6 +342,7 @@ func (s *Step) GetVars(
 			v.Value,
 			s.BuildEnv(
 				promoCtx,
+				StepEnvWithStepMetas(promoCtx),
 				StepEnvWithOutputs(state),
 				StepEnvWithTaskOutputs(s.Alias, state),
 				StepEnvWithVars(vars),
diff --git a/internal/promotion/simple_engine.go b/internal/promotion/simple_engine.go
index 217474e0..3c8834de 100644
--- a/internal/promotion/simple_engine.go
+++ b/internal/promotion/simple_engine.go
@@ -2,6 +2,7 @@ package promotion
 
 import (
 	"context"
+	"errors"
 	"fmt"
 	"os"
 	"regexp"
@@ -62,21 +63,31 @@ func (e *simpleEngine) Promote(
 		return Result{Status: kargoapi.PromotionPhaseErrored}, err
 	}
 
-	result, err := e.executeSteps(ctx, promoCtx, steps, workDir)
-	if err != nil {
-		return result, fmt.Errorf("step execution failed: %w", err)
+	result := e.executeSteps(ctx, promoCtx, steps, workDir)
+	if result.Status == kargoapi.PromotionPhaseErrored {
+		err = errors.New(result.Message)
 	}
 
-	return result, nil
+	return result, err
 }
 
 // executeSteps executes a list of Steps in sequence.
 func (e *simpleEngine) executeSteps(
 	ctx context.Context,
-	promoCtx Context,
+	pCtx Context,
 	steps []Step,
 	workDir string,
-) (Result, error) {
+) Result {
+	// Important: Make a shallow copy of the PromotionContext with a deep copy of
+	// the StepExecutionMetadata. We'll be modifying StepExecutionMetadata
+	// in-place throughout this method, but we don't want to modify the original
+	// StepExecutionMetadata that we were passed in the PromotionContext. If we
+	// did, the status patch operation that will eventually be performed wouldn't
+	// see any difference between the original and the modified
+	// StepExecutionMetadata.
+	promoCtx := pCtx
+	promoCtx.StepExecutionMetadata = promoCtx.StepExecutionMetadata.DeepCopy()
+
 	// Initialize the state which will be passed to each step.
 	// This is the state that will be updated by each step,
 	// and returned as the final state after all steps have
@@ -87,71 +98,69 @@ func (e *simpleEngine) executeSteps(
 	}
 
 	var (
-		healthChecks  []health.Criteria
-		err           error
-		stepExecMetas = promoCtx.StepExecutionMetadata.DeepCopy()
+		healthChecks []health.Criteria
+		err          error
 	)
 
 	// Execute each step in sequence, starting from the step index specified in
 	// the Context if provided.
+stepLoop:
 	for i := promoCtx.StartFromStep; i < int64(len(steps)); i++ {
+		step := steps[i]
+
+		// If we don't have metadata for this step yet, create it.
+		if int64(len(promoCtx.StepExecutionMetadata)) == i {
+			promoCtx.StepExecutionMetadata = append(
+				promoCtx.StepExecutionMetadata,
+				kargoapi.StepExecutionMetadata{
+					Alias:           step.Alias,
+					ContinueOnError: step.ContinueOnError,
+				},
+			)
+		}
+		stepExecMeta := &promoCtx.StepExecutionMetadata[i]
+
 		select {
 		case <-ctx.Done():
-			return Result{
-				Status:                kargoapi.PromotionPhaseErrored,
-				CurrentStep:           i,
-				StepExecutionMetadata: stepExecMetas,
-				State:                 state,
-				HealthChecks:          healthChecks,
-			}, ctx.Err()
+			stepExecMeta.Status = kargoapi.PromotionStepStatusErrored
+			stepExecMeta.Message = ctx.Err().Error()
+			if stepExecMeta.StartedAt != nil {
+				stepExecMeta.FinishedAt = ptr.To(metav1.Now())
+			}
+			break stepLoop
 		default:
 		}
 
-		step := steps[i]
-
 		// Prepare the step for execution by setting the alias.
 		if step.Alias, err = e.stepAlias(step.Alias, i); err != nil {
-			return Result{
-				Status:                kargoapi.PromotionPhaseErrored,
-				CurrentStep:           i,
-				StepExecutionMetadata: stepExecMetas,
-				State:                 state,
-				HealthChecks:          healthChecks,
-			}, fmt.Errorf("error getting step alias for step %d: %w", i, err)
-		}
-
-		// Get the StepRunner for the step.
-		runner := e.registry.getStepRunner(step.Kind)
-		if runner == nil {
-			return Result{
-				Status:                kargoapi.PromotionPhaseErrored,
-				CurrentStep:           i,
-				StepExecutionMetadata: stepExecMetas,
-				State:                 state,
-				HealthChecks:          healthChecks,
-			}, fmt.Errorf("no promotion step runner found for kind %d", i)
-		}
-
-		// If we don't have metadata for this step yet, create it.
-		if int64(len(stepExecMetas)) == i {
-			stepExecMetas = append(stepExecMetas, kargoapi.StepExecutionMetadata{
-				Alias: step.Alias,
-			})
+			stepExecMeta.Status = kargoapi.PromotionStepStatusErrored
+			stepExecMeta.Message = fmt.Sprintf("error getting step alias: %s", err)
+			// Continue, because despite this failure, some steps' "if" conditions may
+			// still allow them to run.
+			continue
 		}
-		stepExecMeta := &stepExecMetas[i]
+		stepExecMeta.Alias = step.Alias
 
 		// Check if the step should be skipped.
 		var skip bool
 		if skip, err = step.Skip(ctx, e.kargoClient, promoCtx, state); err != nil {
-			return Result{
-				Status:                kargoapi.PromotionPhaseErrored,
-				CurrentStep:           i,
-				StepExecutionMetadata: stepExecMetas,
-				State:                 state,
-				HealthChecks:          healthChecks,
-			}, fmt.Errorf("error checking if step %d should be skipped: %w", i, err)
+			stepExecMeta.Status = kargoapi.PromotionStepStatusErrored
+			stepExecMeta.Message = fmt.Sprintf("error checking if step %d should be skipped: %s", i, err)
+			// Continue, because despite this failure, some steps' "if" conditions may
+			// still allow them to run.
+			continue
 		} else if skip {
 			stepExecMeta.Status = kargoapi.PromotionStepStatusSkipped
+			continue // Move on to the next step
+		}
+
+		// Get the StepRunner for the step.
+		runner := e.registry.getStepRunner(step.Kind)
+		if runner == nil {
+			stepExecMeta.Status = kargoapi.PromotionStepStatusErrored
+			stepExecMeta.Message = fmt.Sprintf("no promotion step runner found for kind %q", step.Kind)
+			// Continue, because despite this failure, some steps' "if" conditions may
+			// still allow them to run.
 			continue
 		}
 
@@ -186,13 +195,11 @@ func (e *simpleEngine) executeSteps(
 		default:
 			// Deal with statuses that no step should have returned.
 			stepExecMeta.FinishedAt = ptr.To(metav1.Now())
-			return Result{
-				Status:                kargoapi.PromotionPhaseErrored,
-				CurrentStep:           i,
-				StepExecutionMetadata: stepExecMetas,
-				State:                 state,
-				HealthChecks:          healthChecks,
-			}, fmt.Errorf("step %d returned an invalid status", i)
+			stepExecMeta.Status = kargoapi.PromotionStepStatusErrored
+			stepExecMeta.Message = fmt.Sprintf("step %d returned an invalid status: %s", i, result.Status)
+			// Continue, because despite this failure, some steps' "if" conditions may
+			// still allow them to run.
+			continue
 		}
 
 		// Reconcile status and err...
@@ -231,13 +238,11 @@ func (e *simpleEngine) executeSteps(
 		case promotion.IsTerminal(err):
 			// This is an unrecoverable error.
 			stepExecMeta.FinishedAt = ptr.To(metav1.Now())
-			return Result{
-				Status:                kargoapi.PromotionPhaseErrored,
-				CurrentStep:           i,
-				StepExecutionMetadata: stepExecMetas,
-				State:                 state,
-				HealthChecks:          healthChecks,
-			}, fmt.Errorf("an unrecoverable error occurred: %w", err)
+			stepExecMeta.Status = kargoapi.PromotionStepStatusErrored
+			stepExecMeta.Message = fmt.Sprintf("an unrecoverable error occurred: %s", err)
+			// Continue, because despite this failure, some steps' "if" conditions may
+			// still allow them to run.
+			continue
 		case err != nil:
 			// If we get to here, the error is POTENTIALLY recoverable.
 			stepExecMeta.ErrorCount++
@@ -246,16 +251,14 @@ func (e *simpleEngine) executeSteps(
 			if stepExecMeta.ErrorCount >= errorThreshold {
 				// The error threshold has been met.
 				stepExecMeta.FinishedAt = ptr.To(metav1.Now())
-				return Result{
-						Status:                kargoapi.PromotionPhaseErrored,
-						CurrentStep:           i,
-						StepExecutionMetadata: stepExecMetas,
-						State:                 state,
-						HealthChecks:          healthChecks,
-					}, fmt.Errorf(
-						"step %d met error threshold of %d: %s", i,
-						errorThreshold, stepExecMeta.Message,
-					)
+				stepExecMeta.Status = kargoapi.PromotionStepStatusErrored
+				stepExecMeta.Message = fmt.Sprintf(
+					"step %d met error threshold of %d: %s", i,
+					errorThreshold, stepExecMeta.Message,
+				)
+				// Continue, because despite this failure, some steps' "if" conditions
+				// may still allow them to run.
+				continue
 			}
 		}
 
@@ -268,13 +271,11 @@ func (e *simpleEngine) executeSteps(
 		if timeout != nil && *timeout > 0 && metav1.Now().Sub(stepExecMeta.StartedAt.Time) > *timeout {
 			// Timeout has elapsed.
 			stepExecMeta.FinishedAt = ptr.To(metav1.Now())
-			return Result{
-				Status:                kargoapi.PromotionPhaseErrored,
-				CurrentStep:           i,
-				StepExecutionMetadata: stepExecMetas,
-				State:                 state,
-				HealthChecks:          healthChecks,
-			}, fmt.Errorf("step %d timeout of %s has elapsed", i, timeout.String())
+			stepExecMeta.Status = kargoapi.PromotionStepStatusErrored
+			stepExecMeta.Message = fmt.Sprintf("step %d timed out after %s", i, timeout.String())
+			// Continue, because despite this failure, some steps' "if" conditions may
+			// still allow them to run.
+			continue
 		}
 
 		if err != nil {
@@ -285,10 +286,10 @@ func (e *simpleEngine) executeSteps(
 			return Result{
 				Status:                kargoapi.PromotionPhaseRunning,
 				CurrentStep:           i,
-				StepExecutionMetadata: stepExecMetas,
+				StepExecutionMetadata: promoCtx.StepExecutionMetadata,
 				State:                 state,
 				HealthChecks:          healthChecks,
-			}, nil
+			}
 		}
 
 		// If we get to here, the step is still Running (waiting for some external
@@ -297,20 +298,57 @@ func (e *simpleEngine) executeSteps(
 		return Result{
 			Status:                kargoapi.PromotionPhaseRunning,
 			CurrentStep:           i,
-			StepExecutionMetadata: stepExecMetas,
+			StepExecutionMetadata: promoCtx.StepExecutionMetadata,
 			State:                 state,
 			HealthChecks:          healthChecks,
-		}, nil
+		}
 	}
 
+	status, msg := determinePromoPhase(steps, promoCtx.StepExecutionMetadata)
+
 	// All steps have succeeded, return the final state.
 	return Result{
-		Status:                kargoapi.PromotionPhaseSucceeded,
+		Status:                status,
+		Message:               msg,
 		CurrentStep:           int64(len(steps)) - 1,
-		StepExecutionMetadata: stepExecMetas,
+		StepExecutionMetadata: promoCtx.StepExecutionMetadata,
 		State:                 state,
 		HealthChecks:          healthChecks,
-	}, nil
+	}
+}
+
+// determinePromoPhase determines the final PromotionPhase as a function of the
+// step configuration and step execution metadata.
+func determinePromoPhase(
+	steps []Step,
+	stepExecMetas kargoapi.StepExecutionMetadataList,
+) (kargoapi.PromotionPhase, string) {
+	worstStepStatus := kargoapi.PromotionStepStatusSucceeded
+	var worstMsg string
+	for i, stepExecMeta := range stepExecMetas {
+		if steps[i].ContinueOnError {
+			// If continueOnError is set, we don't don't permit this step's outcome
+			// to affect the overall PromotionPhase.
+			continue
+		}
+		if stepExecMeta.Status.Compare(worstStepStatus) > 0 {
+			worstStepStatus = stepExecMeta.Status
+			worstMsg = stepExecMeta.Message
+		}
+	}
+	switch worstStepStatus {
+	case kargoapi.PromotionStepStatusSucceeded, kargoapi.PromotionStepStatusSkipped:
+		return kargoapi.PromotionPhaseSucceeded, worstMsg
+	case kargoapi.PromotionStepStatusAborted:
+		return kargoapi.PromotionPhaseAborted, worstMsg
+	case kargoapi.PromotionStepStatusFailed:
+		return kargoapi.PromotionPhaseFailed, worstMsg
+	case kargoapi.PromotionStepStatusErrored:
+		return kargoapi.PromotionPhaseErrored, worstMsg
+	default:
+		// This really shouldn't ever happen. We'll treat it as an error.
+		return kargoapi.PromotionPhaseErrored, worstMsg
+	}
 }
 
 // executeStep executes a single Step.
@@ -331,7 +369,7 @@ func (e *simpleEngine) executeStep(
 
 	result, err := runner.Run(ctx, stepCtx)
 	if err != nil {
-		err = fmt.Errorf("failed to run step %q: %w", step.Kind, err)
+		err = fmt.Errorf("error running step %q: %w", step.Kind, err)
 	}
 	return result, err
 }
diff --git a/ui/src/features/stage/create-stage.tsx b/ui/src/features/stage/create-stage.tsx
index 577aaeb0..312ae5d9 100644
--- a/ui/src/features/stage/create-stage.tsx
+++ b/ui/src/features/stage/create-stage.tsx
@@ -120,6 +120,7 @@ export const CreateStage = ({
           uses: step?.identifier,
           as: step?.as || '',
           if: '',
+          continueOnError: step.continueOnError || false,
           config: step?.state as JSON, // step.state is type 'object' and it is safe to fake JSON type because it doesn't matter for stageFormToYAML function
           vars: []
         }))
@@ -171,6 +172,7 @@ export const CreateStage = ({
                   uses: step?.identifier,
                   as: step?.as || '',
                   if: '',
+                  continueOnError: step?.continueOnError || false,
                   config: step?.state as JSON, // step.state is type 'object' and it is safe to fake JSON type because it doesn't matter for stageFormToYAML function
                   vars: []
                 }))
diff --git a/ui/src/features/stage/promotion-steps-wizard/promotion-step-form.tsx b/ui/src/features/stage/promotion-steps-wizard/promotion-step-form.tsx
index 4b0fc6d1..6458b8a8 100644
--- a/ui/src/features/stage/promotion-steps-wizard/promotion-step-form.tsx
+++ b/ui/src/features/stage/promotion-steps-wizard/promotion-step-form.tsx
@@ -1,4 +1,4 @@
-import { Form, Input } from 'antd';
+import { Checkbox, Form, Input } from 'antd';
 
 import { RunnerForm } from './runner-form';
 import { RunnerWithConfiguration } from './types';
@@ -18,6 +18,19 @@ export const PromotionStepForm = (props: {
             }
           />
         </Form.Item>
+        <Form.Item extra='When enabled, any failure in this step will not immediately halt execution of the promotion process, nor will it prevent the promotion process, overall, from succeeding.'>
+          <Checkbox
+            checked={props.selectedRunner?.continueOnError || false}
+            onChange={(e) =>
+              props.patchSelectedRunner({
+                ...props.selectedRunner,
+                continueOnError: e.target.checked
+              })
+            }
+          >
+            Continue On Error
+          </Checkbox>
+        </Form.Item>
       </Form>
       <RunnerForm
         runner={props.selectedRunner}
diff --git a/ui/src/features/stage/promotion-steps-wizard/types.ts b/ui/src/features/stage/promotion-steps-wizard/types.ts
index 545f2b28..e87a5707 100644
--- a/ui/src/features/stage/promotion-steps-wizard/types.ts
+++ b/ui/src/features/stage/promotion-steps-wizard/types.ts
@@ -3,4 +3,5 @@ import { Runner } from '@ui/features/promotion-directives/registry/types';
 export type RunnerWithConfiguration /* configuration that users do in wizard */ = Runner & {
   state?: object; // object that we don't care about. this mostly handled by rsjf
   as?: string; // added this so that state does not loose actual value - not a concern now but when we have "edit" stage wizard
+  continueOnError?: boolean;
 };
diff --git a/ui/src/features/stage/promotion-steps-wizard/use-promotion-wizard-steps-state.ts b/ui/src/features/stage/promotion-steps-wizard/use-promotion-wizard-steps-state.ts
index dad69e88..ff3d9bc6 100644
--- a/ui/src/features/stage/promotion-steps-wizard/use-promotion-wizard-steps-state.ts
+++ b/ui/src/features/stage/promotion-steps-wizard/use-promotion-wizard-steps-state.ts
@@ -48,7 +48,8 @@ const APIPromotionStepsToLocalStateEquivalent = (
     runnerWithConfig.push({
       ...runnerMeta,
       state: step.config,
-      as: step.as
+      as: step.as,
+      continueOnError: step.continueOnError
     });
   }
 
@@ -79,6 +80,7 @@ const stateToYAML = (state: RunnerWithConfiguration[]): string => {
       // @ts-expect-error this will be object but its hard to convey in types after migration of connectrpc to v2
       config: step.state,
       as: step.as || '',
+      continueOnError: step.continueOnError || false,
       vars: []
     });
   }
diff --git a/ui/src/gen/api/v1alpha1/generated_pb.ts b/ui/src/gen/api/v1alpha1/generated_pb.ts
index 34765ba2..b1ec83c2 100644
--- a/ui/src/gen/api/v1alpha1/generated_pb.ts
+++ b/ui/src/gen/api/v1alpha1/generated_pb.ts
@@ -18,7 +18,7 @@ import type { Message } from "@bufbuild/protobuf";
  * Describes the file api/v1alpha1/generated.proto.
  */
 export const file_api_v1alpha1_generated: GenFile = /*@__PURE__*/
-  fileDesc("ChxhcGkvdjFhbHBoYTEvZ2VuZXJhdGVkLnByb3RvEiRnaXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEiMgoTQW5hbHlzaXNSdW5Bcmd1bWVudBIMCgRuYW1lGAEgASgJEg0KBXZhbHVlGAIgASgJIrACChNBbmFseXNpc1J1bk1ldGFkYXRhElUKBmxhYmVscxgBIAMoCzJFLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BbmFseXNpc1J1bk1ldGFkYXRhLkxhYmVsc0VudHJ5El8KC2Fubm90YXRpb25zGAIgAygLMkouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkFuYWx5c2lzUnVuTWV0YWRhdGEuQW5ub3RhdGlvbnNFbnRyeRotCgtMYWJlbHNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBGjIKEEFubm90YXRpb25zRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJGChRBbmFseXNpc1J1blJlZmVyZW5jZRIRCgluYW1lc3BhY2UYASABKAkSDAoEbmFtZRgCIAEoCRINCgVwaGFzZRgDIAEoCSI3ChlBbmFseXNpc1RlbXBsYXRlUmVmZXJlbmNlEgwKBG5hbWUYASABKAkSDAoEa2luZBgCIAEoCSJPCg1BcHByb3ZlZFN0YWdlEj4KCmFwcHJvdmVkQXQYASABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZSI4ChVBcmdvQ0RBcHBIZWFsdGhTdGF0dXMSDgoGc3RhdHVzGAEgASgJEg8KB21lc3NhZ2UYAiABKAki1AEKD0FyZ29DREFwcFN0YXR1cxIRCgluYW1lc3BhY2UYASABKAkSDAoEbmFtZRgCIAEoCRJRCgxoZWFsdGhTdGF0dXMYAyABKAsyOy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXJnb0NEQXBwSGVhbHRoU3RhdHVzEk0KCnN5bmNTdGF0dXMYBCABKAsyOS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXJnb0NEQXBwU3luY1N0YXR1cyJKChNBcmdvQ0RBcHBTeW5jU3RhdHVzEg4KBnN0YXR1cxgBIAEoCRIQCghyZXZpc2lvbhgCIAEoCRIRCglyZXZpc2lvbnMYAyADKAkiNwoFQ2hhcnQSDwoHcmVwb1VSTBgBIAEoCRIMCgRuYW1lGAIgASgJEg8KB3ZlcnNpb24YAyABKAkiYQoUQ2hhcnREaXNjb3ZlcnlSZXN1bHQSDwoHcmVwb1VSTBgBIAEoCRIMCgRuYW1lGAIgASgJEhgKEHNlbXZlckNvbnN0cmFpbnQYAyABKAkSEAoIdmVyc2lvbnMYBCADKAkiZAoRQ2hhcnRTdWJzY3JpcHRpb24SDwoHcmVwb1VSTBgBIAEoCRIMCgRuYW1lGAIgASgJEhgKEHNlbXZlckNvbnN0cmFpbnQYAyABKAkSFgoOZGlzY292ZXJ5TGltaXQYBCABKAUioQEKFENsdXN0ZXJQcm9tb3Rpb25UYXNrEkIKCG1ldGFkYXRhGAEgASgLMjAuazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLk9iamVjdE1ldGESRQoEc3BlYxgCIAEoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25UYXNrU3BlYyKnAQoYQ2x1c3RlclByb21vdGlvblRhc2tMaXN0EkAKCG1ldGFkYXRhGAEgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkxpc3RNZXRhEkkKBWl0ZW1zGAIgAygLMjouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkNsdXN0ZXJQcm9tb3Rpb25UYXNrIkkKDEN1cnJlbnRTdGFnZRI5CgVzaW5jZRgBIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lIrYCChNEaXNjb3ZlcmVkQXJ0aWZhY3RzEkAKDGRpc2NvdmVyZWRBdBgEIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lEkUKA2dpdBgBIAMoCzI4LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5HaXREaXNjb3ZlcnlSZXN1bHQSSgoGaW1hZ2VzGAIgAygLMjouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkltYWdlRGlzY292ZXJ5UmVzdWx0EkoKBmNoYXJ0cxgDIAMoCzI6LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DaGFydERpc2NvdmVyeVJlc3VsdCKwAQoQRGlzY292ZXJlZENvbW1pdBIKCgJpZBgBIAEoCRIOCgZicmFuY2gYAiABKAkSCwoDdGFnGAMgASgJEg8KB3N1YmplY3QYBCABKAkSDgoGYXV0aG9yGAUgASgJEhEKCWNvbW1pdHRlchgGIAEoCRI/CgtjcmVhdG9yRGF0ZRgHIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lIqQCChhEaXNjb3ZlcmVkSW1hZ2VSZWZlcmVuY2USCwoDdGFnGAEgASgJEg4KBmRpZ2VzdBgCIAEoCRJkCgthbm5vdGF0aW9ucxgFIAMoCzJPLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5EaXNjb3ZlcmVkSW1hZ2VSZWZlcmVuY2UuQW5ub3RhdGlvbnNFbnRyeRISCgpnaXRSZXBvVVJMGAMgASgJEj0KCWNyZWF0ZWRBdBgEIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lGjIKEEFubm90YXRpb25zRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASIxChJFeHByZXNzaW9uVmFyaWFibGUSDAoEbmFtZRgBIAEoCRINCgV2YWx1ZRgCIAEoCSKiAwoHRnJlaWdodBJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEg0KBWFsaWFzGAcgASgJEkMKBm9yaWdpbhgJIAEoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0T3JpZ2luEkAKB2NvbW1pdHMYAyADKAsyLy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuR2l0Q29tbWl0EjsKBmltYWdlcxgEIAMoCzIrLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5JbWFnZRI7CgZjaGFydHMYBSADKAsyKy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQ2hhcnQSQwoGc3RhdHVzGAYgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRTdGF0dXMirQIKEUZyZWlnaHRDb2xsZWN0aW9uEgoKAmlkGAMgASgJElEKBWl0ZW1zGAEgAygLMkIuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRDb2xsZWN0aW9uLkl0ZW1zRW50cnkSUwoTdmVyaWZpY2F0aW9uSGlzdG9yeRgCIAMoCzI2LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5WZXJpZmljYXRpb25JbmZvGmQKCkl0ZW1zRW50cnkSCwoDa2V5GAEgASgJEkUKBXZhbHVlGAIgASgLMjYuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRSZWZlcmVuY2U6AjgBIo0BCgtGcmVpZ2h0TGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRI8CgVpdGVtcxgCIAMoCzItLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0IisKDUZyZWlnaHRPcmlnaW4SDAoEa2luZBgBIAEoCRIMCgRuYW1lGAIgASgJIqECChBGcmVpZ2h0UmVmZXJlbmNlEgwKBG5hbWUYASABKAkSQwoGb3JpZ2luGAggASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRPcmlnaW4SQAoHY29tbWl0cxgCIAMoCzIvLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5HaXRDb21taXQSOwoGaW1hZ2VzGAMgAygLMisuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkltYWdlEjsKBmNoYXJ0cxgEIAMoCzIrLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DaGFydCKcAQoORnJlaWdodFJlcXVlc3QSQwoGb3JpZ2luGAEgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRPcmlnaW4SRQoHc291cmNlcxgCIAEoCzI0LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0U291cmNlcyKYAQoORnJlaWdodFNvdXJjZXMSDgoGZGlyZWN0GAEgASgIEg4KBnN0YWdlcxgCIAMoCRJIChByZXF1aXJlZFNvYWtUaW1lGAMgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkR1cmF0aW9uEhwKFGF2YWlsYWJpbGl0eVN0cmF0ZWd5GAQgASgJItcECg1GcmVpZ2h0U3RhdHVzElkKC2N1cnJlbnRseUluGAMgAygLMkQuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRTdGF0dXMuQ3VycmVudGx5SW5FbnRyeRJXCgp2ZXJpZmllZEluGAEgAygLMkMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRTdGF0dXMuVmVyaWZpZWRJbkVudHJ5ElkKC2FwcHJvdmVkRm9yGAIgAygLMkQuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRTdGF0dXMuQXBwcm92ZWRGb3JFbnRyeRpmChBDdXJyZW50bHlJbkVudHJ5EgsKA2tleRgBIAEoCRJBCgV2YWx1ZRgCIAEoCzIyLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DdXJyZW50U3RhZ2U6AjgBGmYKD1ZlcmlmaWVkSW5FbnRyeRILCgNrZXkYASABKAkSQgoFdmFsdWUYAiABKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuVmVyaWZpZWRTdGFnZToCOAEaZwoQQXBwcm92ZWRGb3JFbnRyeRILCgNrZXkYASABKAkSQgoFdmFsdWUYAiABKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXBwcm92ZWRTdGFnZToCOAEieQoJR2l0Q29tbWl0Eg8KB3JlcG9VUkwYASABKAkSCgoCaWQYAiABKAkSDgoGYnJhbmNoGAMgASgJEgsKA3RhZxgEIAEoCRIPCgdtZXNzYWdlGAYgASgJEg4KBmF1dGhvchgHIAEoCRIRCgljb21taXR0ZXIYCCABKAkibgoSR2l0RGlzY292ZXJ5UmVzdWx0Eg8KB3JlcG9VUkwYASABKAkSRwoHY29tbWl0cxgCIAMoCzI2LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5EaXNjb3ZlcmVkQ29tbWl0Io4CCg9HaXRTdWJzY3JpcHRpb24SDwoHcmVwb1VSTBgBIAEoCRIfChdjb21taXRTZWxlY3Rpb25TdHJhdGVneRgCIAEoCRIOCgZicmFuY2gYAyABKAkSFQoNc3RyaWN0U2VtdmVycxgLIAEoCBIYChBzZW12ZXJDb25zdHJhaW50GAQgASgJEhEKCWFsbG93VGFncxgFIAEoCRISCgppZ25vcmVUYWdzGAYgAygJEh0KFWluc2VjdXJlU2tpcFRMU1ZlcmlmeRgHIAEoCBIUCgxpbmNsdWRlUGF0aHMYCCADKAkSFAoMZXhjbHVkZVBhdGhzGAkgAygJEhYKDmRpc2NvdmVyeUxpbWl0GAogASgFIsgBCgZIZWFsdGgSDgoGc3RhdHVzGAEgASgJEg4KBmlzc3VlcxgCIAMoCRJOCgZjb25maWcYBCABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OEk4KBm91dHB1dBgFIAEoCzI+Lms4cy5pby5hcGlleHRlbnNpb25zX2FwaXNlcnZlci5wa2cuYXBpcy5hcGlleHRlbnNpb25zLnYxLkpTT04ibwoPSGVhbHRoQ2hlY2tTdGVwEgwKBHVzZXMYASABKAkSTgoGY29uZmlnGAIgASgLMj4uazhzLmlvLmFwaWV4dGVuc2lvbnNfYXBpc2VydmVyLnBrZy5hcGlzLmFwaWV4dGVuc2lvbnMudjEuSlNPTiIeCgtIZWFsdGhTdGF0cxIPCgdoZWFsdGh5GAEgASgDItABCgVJbWFnZRIPCgdyZXBvVVJMGAEgASgJEhIKCmdpdFJlcG9VUkwYAiABKAkSCwoDdGFnGAMgASgJEg4KBmRpZ2VzdBgEIAEoCRJRCgthbm5vdGF0aW9ucxgFIAMoCzI8LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5JbWFnZS5Bbm5vdGF0aW9uc0VudHJ5GjIKEEFubm90YXRpb25zRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASKNAQoUSW1hZ2VEaXNjb3ZlcnlSZXN1bHQSDwoHcmVwb1VSTBgBIAEoCRIQCghwbGF0Zm9ybRgCIAEoCRJSCgpyZWZlcmVuY2VzGAMgAygLMj4uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkRpc2NvdmVyZWRJbWFnZVJlZmVyZW5jZSL5AQoRSW1hZ2VTdWJzY3JpcHRpb24SDwoHcmVwb1VSTBgBIAEoCRISCgpnaXRSZXBvVVJMGAIgASgJEh4KFmltYWdlU2VsZWN0aW9uU3RyYXRlZ3kYAyABKAkSFQoNc3RyaWN0U2VtdmVycxgKIAEoCBIYChBzZW12ZXJDb25zdHJhaW50GAQgASgJEhEKCWFsbG93VGFncxgFIAEoCRISCgppZ25vcmVUYWdzGAYgAygJEhAKCHBsYXRmb3JtGAcgASgJEh0KFWluc2VjdXJlU2tpcFRMU1ZlcmlmeRgIIAEoCBIWCg5kaXNjb3ZlcnlMaW1pdBgJIAEoBSLZAQoHUHJvamVjdBJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEkUKBHNwZWMYAiABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvamVjdENvbmZpZ1NwZWMSQwoGc3RhdHVzGAMgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb2plY3RTdGF0dXMimgEKDVByb2plY3RDb25maWcSQgoIbWV0YWRhdGEYASABKAsyMC5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuT2JqZWN0TWV0YRJFCgRzcGVjGAIgASgLMjcuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb2plY3RDb25maWdTcGVjIpkBChFQcm9qZWN0Q29uZmlnTGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRJCCgVpdGVtcxgCIAMoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9qZWN0Q29uZmlnImUKEVByb2plY3RDb25maWdTcGVjElAKEXByb21vdGlvblBvbGljaWVzGAEgAygLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblBvbGljeSKNAQoLUHJvamVjdExpc3QSQAoIbWV0YWRhdGEYASABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuTGlzdE1ldGESPAoFaXRlbXMYAiADKAsyLS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvamVjdCKaAQoMUHJvamVjdFN0YXRzEkgKCndhcmVob3VzZXMYASABKAsyNC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuV2FyZWhvdXNlU3RhdHMSQAoGc3RhZ2VzGAIgASgLMjAuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlN0YWdlU3RhdHMilwEKDVByb2plY3RTdGF0dXMSQwoKY29uZGl0aW9ucxgDIAMoCzIvLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5Db25kaXRpb24SQQoFc3RhdHMYBCABKAsyMi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvamVjdFN0YXRzItkBCglQcm9tb3Rpb24SQgoIbWV0YWRhdGEYASABKAsyMC5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuT2JqZWN0TWV0YRJBCgRzcGVjGAIgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblNwZWMSRQoGc3RhdHVzGAMgASgLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0YXR1cyKRAQoNUHJvbW90aW9uTGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRI+CgVpdGVtcxgCIAMoCzIvLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb24ilAEKD1Byb21vdGlvblBvbGljeRINCgVzdGFnZRgBIAEoCRJUCg1zdGFnZVNlbGVjdG9yGAMgASgLMj0uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblBvbGljeVNlbGVjdG9yEhwKFGF1dG9Qcm9tb3Rpb25FbmFibGVkGAIgASgIInMKF1Byb21vdGlvblBvbGljeVNlbGVjdG9yEgwKBG5hbWUYASABKAkSSgoNbGFiZWxTZWxlY3RvchgCIAEoCzIzLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MYWJlbFNlbGVjdG9yIvIBChJQcm9tb3Rpb25SZWZlcmVuY2USDAoEbmFtZRgBIAEoCRJHCgdmcmVpZ2h0GAIgASgLMjYuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRSZWZlcmVuY2USRQoGc3RhdHVzGAMgASgLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0YXR1cxI+CgpmaW5pc2hlZEF0GAQgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUiuwEKDVByb21vdGlvblNwZWMSDQoFc3RhZ2UYASABKAkSDwoHZnJlaWdodBgCIAEoCRJGCgR2YXJzGAQgAygLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkV4cHJlc3Npb25WYXJpYWJsZRJCCgVzdGVwcxgDIAMoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25TdGVwIrcECg9Qcm9tb3Rpb25TdGF0dXMSGgoSbGFzdEhhbmRsZWRSZWZyZXNoGAQgASgJEg0KBXBoYXNlGAEgASgJEg8KB21lc3NhZ2UYAiABKAkSRwoHZnJlaWdodBgFIAEoCzI2LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0UmVmZXJlbmNlElIKEWZyZWlnaHRDb2xsZWN0aW9uGAcgASgLMjcuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRDb2xsZWN0aW9uEksKDGhlYWx0aENoZWNrcxgIIAMoCzI1LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5IZWFsdGhDaGVja1N0ZXASPgoKZmluaXNoZWRBdBgGIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lEhMKC2N1cnJlbnRTdGVwGAkgASgDEloKFXN0ZXBFeGVjdXRpb25NZXRhZGF0YRgLIAMoCzI7LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5TdGVwRXhlY3V0aW9uTWV0YWRhdGESTQoFc3RhdGUYCiABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OIuICCg1Qcm9tb3Rpb25TdGVwEgwKBHVzZXMYASABKAkSSgoEdGFzaxgFIAEoCzI8LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25UYXNrUmVmZXJlbmNlEgoKAmFzGAIgASgJEgoKAmlmGAcgASgJEkcKBXJldHJ5GAQgASgLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0ZXBSZXRyeRJGCgR2YXJzGAYgAygLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkV4cHJlc3Npb25WYXJpYWJsZRJOCgZjb25maWcYAyABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OIm0KElByb21vdGlvblN0ZXBSZXRyeRI/Cgd0aW1lb3V0GAEgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkR1cmF0aW9uEhYKDmVycm9yVGhyZXNob2xkGAIgASgNIpoBCg1Qcm9tb3Rpb25UYXNrEkIKCG1ldGFkYXRhGAEgASgLMjAuazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLk9iamVjdE1ldGESRQoEc3BlYxgCIAEoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25UYXNrU3BlYyKZAQoRUHJvbW90aW9uVGFza0xpc3QSQAoIbWV0YWRhdGEYASABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuTGlzdE1ldGESQgoFaXRlbXMYAiADKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uVGFzayI0ChZQcm9tb3Rpb25UYXNrUmVmZXJlbmNlEgwKBG5hbWUYASABKAkSDAoEa2luZBgCIAEoCSKfAQoRUHJvbW90aW9uVGFza1NwZWMSRgoEdmFycxgBIAMoCzI4LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5FeHByZXNzaW9uVmFyaWFibGUSQgoFc3RlcHMYAiADKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uU3RlcCJeChFQcm9tb3Rpb25UZW1wbGF0ZRJJCgRzcGVjGAEgASgLMjsuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblRlbXBsYXRlU3BlYyKjAQoVUHJvbW90aW9uVGVtcGxhdGVTcGVjEkYKBHZhcnMYAiADKAsyOC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRXhwcmVzc2lvblZhcmlhYmxlEkIKBXN0ZXBzGAEgAygLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0ZXAi5gEKEFJlcG9TdWJzY3JpcHRpb24SQgoDZ2l0GAEgASgLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkdpdFN1YnNjcmlwdGlvbhJGCgVpbWFnZRgCIAEoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5JbWFnZVN1YnNjcmlwdGlvbhJGCgVjaGFydBgDIAEoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DaGFydFN1YnNjcmlwdGlvbiLNAQoFU3RhZ2USQgoIbWV0YWRhdGEYASABKAsyMC5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuT2JqZWN0TWV0YRI9CgRzcGVjGAIgASgLMi8uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlN0YWdlU3BlYxJBCgZzdGF0dXMYAyABKAsyMS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuU3RhZ2VTdGF0dXMiiQEKCVN0YWdlTGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRI6CgVpdGVtcxgCIAMoCzIrLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5TdGFnZSLQAgoJU3RhZ2VTcGVjEg0KBXNoYXJkGAQgASgJEkYKBHZhcnMYByADKAsyOC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRXhwcmVzc2lvblZhcmlhYmxlEk4KEHJlcXVlc3RlZEZyZWlnaHQYBSADKAsyNC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRnJlaWdodFJlcXVlc3QSUgoRcHJvbW90aW9uVGVtcGxhdGUYBiABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uVGVtcGxhdGUSSAoMdmVyaWZpY2F0aW9uGAMgASgLMjIuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlZlcmlmaWNhdGlvbiJeCgpTdGFnZVN0YXRzEg0KBWNvdW50GAIgASgDEkEKBmhlYWx0aBgBIAEoCzIxLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5IZWFsdGhTdGF0cyLWAwoLU3RhZ2VTdGF0dXMSQwoKY29uZGl0aW9ucxgNIAMoCzIvLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5Db25kaXRpb24SGgoSbGFzdEhhbmRsZWRSZWZyZXNoGAsgASgJEk8KDmZyZWlnaHRIaXN0b3J5GAQgAygLMjcuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRDb2xsZWN0aW9uEhYKDmZyZWlnaHRTdW1tYXJ5GAwgASgJEjwKBmhlYWx0aBgIIAEoCzIsLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5IZWFsdGgSGgoSb2JzZXJ2ZWRHZW5lcmF0aW9uGAYgASgDElIKEGN1cnJlbnRQcm9tb3Rpb24YByABKAsyOC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uUmVmZXJlbmNlEk8KDWxhc3RQcm9tb3Rpb24YCiABKAsyOC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uUmVmZXJlbmNlItoBChVTdGVwRXhlY3V0aW9uTWV0YWRhdGESDQoFYWxpYXMYASABKAkSPQoJc3RhcnRlZEF0GAIgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUSPgoKZmluaXNoZWRBdBgDIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lEhIKCmVycm9yQ291bnQYBCABKA0SDgoGc3RhdHVzGAUgASgJEg8KB21lc3NhZ2UYBiABKAkiiwIKDFZlcmlmaWNhdGlvbhJaChFhbmFseXNpc1RlbXBsYXRlcxgBIAMoCzI/LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BbmFseXNpc1RlbXBsYXRlUmVmZXJlbmNlElYKE2FuYWx5c2lzUnVuTWV0YWRhdGEYAiABKAsyOS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQW5hbHlzaXNSdW5NZXRhZGF0YRJHCgRhcmdzGAMgAygLMjkuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkFuYWx5c2lzUnVuQXJndW1lbnQinQIKEFZlcmlmaWNhdGlvbkluZm8SCgoCaWQYBCABKAkSDQoFYWN0b3IYByABKAkSPQoJc3RhcnRUaW1lGAUgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUSDQoFcGhhc2UYASABKAkSDwoHbWVzc2FnZRgCIAEoCRJPCgthbmFseXNpc1J1bhgDIAEoCzI6LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BbmFseXNpc1J1blJlZmVyZW5jZRI+CgpmaW5pc2hUaW1lGAYgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUilAEKDVZlcmlmaWVkU3RhZ2USPgoKdmVyaWZpZWRBdBgBIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lEkMKC2xvbmdlc3RTb2FrGAIgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkR1cmF0aW9uItkBCglXYXJlaG91c2USQgoIbWV0YWRhdGEYASABKAsyMC5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuT2JqZWN0TWV0YRJBCgRzcGVjGAIgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLldhcmVob3VzZVNwZWMSRQoGc3RhdHVzGAMgASgLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLldhcmVob3VzZVN0YXR1cyKRAQoNV2FyZWhvdXNlTGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRI+CgVpdGVtcxgCIAMoCzIvLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5XYXJlaG91c2UizgEKDVdhcmVob3VzZVNwZWMSDQoFc2hhcmQYAiABKAkSQAoIaW50ZXJ2YWwYBCABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuRHVyYXRpb24SHQoVZnJlaWdodENyZWF0aW9uUG9saWN5GAMgASgJEk0KDXN1YnNjcmlwdGlvbnMYASADKAsyNi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUmVwb1N1YnNjcmlwdGlvbiJiCg5XYXJlaG91c2VTdGF0cxINCgVjb3VudBgCIAEoAxJBCgZoZWFsdGgYASABKAsyMS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuSGVhbHRoU3RhdHMi/QEKD1dhcmVob3VzZVN0YXR1cxJDCgpjb25kaXRpb25zGAkgAygLMi8uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkNvbmRpdGlvbhIaChJsYXN0SGFuZGxlZFJlZnJlc2gYBiABKAkSGgoSb2JzZXJ2ZWRHZW5lcmF0aW9uGAQgASgDEhUKDWxhc3RGcmVpZ2h0SUQYCCABKAkSVgoTZGlzY292ZXJlZEFydGlmYWN0cxgHIAEoCzI5LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5EaXNjb3ZlcmVkQXJ0aWZhY3RzQpcCCihjb20uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExQg5HZW5lcmF0ZWRQcm90b1ABWiRnaXRodWIuY29tL2FrdWl0eS9rYXJnby9hcGkvdjFhbHBoYTGiAgVHQ0FLQaoCJEdpdGh1Yi5Db20uQWt1aXR5LkthcmdvLkFwaS5WMWFscGhhMcoCJEdpdGh1YlxDb21cQWt1aXR5XEthcmdvXEFwaVxWMWFscGhhMeICMEdpdGh1YlxDb21cQWt1aXR5XEthcmdvXEFwaVxWMWFscGhhMVxHUEJNZXRhZGF0YeoCKUdpdGh1Yjo6Q29tOjpBa3VpdHk6OkthcmdvOjpBcGk6OlYxYWxwaGEx", [file_k8s_io_apiextensions_apiserver_pkg_apis_apiextensions_v1_generated, file_k8s_io_apimachinery_pkg_apis_meta_v1_generated, file_k8s_io_apimachinery_pkg_runtime_generated, file_k8s_io_apimachinery_pkg_runtime_schema_generated]);
+  fileDesc("ChxhcGkvdjFhbHBoYTEvZ2VuZXJhdGVkLnByb3RvEiRnaXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEiMgoTQW5hbHlzaXNSdW5Bcmd1bWVudBIMCgRuYW1lGAEgASgJEg0KBXZhbHVlGAIgASgJIrACChNBbmFseXNpc1J1bk1ldGFkYXRhElUKBmxhYmVscxgBIAMoCzJFLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BbmFseXNpc1J1bk1ldGFkYXRhLkxhYmVsc0VudHJ5El8KC2Fubm90YXRpb25zGAIgAygLMkouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkFuYWx5c2lzUnVuTWV0YWRhdGEuQW5ub3RhdGlvbnNFbnRyeRotCgtMYWJlbHNFbnRyeRILCgNrZXkYASABKAkSDQoFdmFsdWUYAiABKAk6AjgBGjIKEEFubm90YXRpb25zRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASJGChRBbmFseXNpc1J1blJlZmVyZW5jZRIRCgluYW1lc3BhY2UYASABKAkSDAoEbmFtZRgCIAEoCRINCgVwaGFzZRgDIAEoCSI3ChlBbmFseXNpc1RlbXBsYXRlUmVmZXJlbmNlEgwKBG5hbWUYASABKAkSDAoEa2luZBgCIAEoCSJPCg1BcHByb3ZlZFN0YWdlEj4KCmFwcHJvdmVkQXQYASABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZSI4ChVBcmdvQ0RBcHBIZWFsdGhTdGF0dXMSDgoGc3RhdHVzGAEgASgJEg8KB21lc3NhZ2UYAiABKAki1AEKD0FyZ29DREFwcFN0YXR1cxIRCgluYW1lc3BhY2UYASABKAkSDAoEbmFtZRgCIAEoCRJRCgxoZWFsdGhTdGF0dXMYAyABKAsyOy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXJnb0NEQXBwSGVhbHRoU3RhdHVzEk0KCnN5bmNTdGF0dXMYBCABKAsyOS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXJnb0NEQXBwU3luY1N0YXR1cyJKChNBcmdvQ0RBcHBTeW5jU3RhdHVzEg4KBnN0YXR1cxgBIAEoCRIQCghyZXZpc2lvbhgCIAEoCRIRCglyZXZpc2lvbnMYAyADKAkiNwoFQ2hhcnQSDwoHcmVwb1VSTBgBIAEoCRIMCgRuYW1lGAIgASgJEg8KB3ZlcnNpb24YAyABKAkiYQoUQ2hhcnREaXNjb3ZlcnlSZXN1bHQSDwoHcmVwb1VSTBgBIAEoCRIMCgRuYW1lGAIgASgJEhgKEHNlbXZlckNvbnN0cmFpbnQYAyABKAkSEAoIdmVyc2lvbnMYBCADKAkiZAoRQ2hhcnRTdWJzY3JpcHRpb24SDwoHcmVwb1VSTBgBIAEoCRIMCgRuYW1lGAIgASgJEhgKEHNlbXZlckNvbnN0cmFpbnQYAyABKAkSFgoOZGlzY292ZXJ5TGltaXQYBCABKAUioQEKFENsdXN0ZXJQcm9tb3Rpb25UYXNrEkIKCG1ldGFkYXRhGAEgASgLMjAuazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLk9iamVjdE1ldGESRQoEc3BlYxgCIAEoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25UYXNrU3BlYyKnAQoYQ2x1c3RlclByb21vdGlvblRhc2tMaXN0EkAKCG1ldGFkYXRhGAEgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkxpc3RNZXRhEkkKBWl0ZW1zGAIgAygLMjouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkNsdXN0ZXJQcm9tb3Rpb25UYXNrIkkKDEN1cnJlbnRTdGFnZRI5CgVzaW5jZRgBIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lIrYCChNEaXNjb3ZlcmVkQXJ0aWZhY3RzEkAKDGRpc2NvdmVyZWRBdBgEIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lEkUKA2dpdBgBIAMoCzI4LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5HaXREaXNjb3ZlcnlSZXN1bHQSSgoGaW1hZ2VzGAIgAygLMjouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkltYWdlRGlzY292ZXJ5UmVzdWx0EkoKBmNoYXJ0cxgDIAMoCzI6LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DaGFydERpc2NvdmVyeVJlc3VsdCKwAQoQRGlzY292ZXJlZENvbW1pdBIKCgJpZBgBIAEoCRIOCgZicmFuY2gYAiABKAkSCwoDdGFnGAMgASgJEg8KB3N1YmplY3QYBCABKAkSDgoGYXV0aG9yGAUgASgJEhEKCWNvbW1pdHRlchgGIAEoCRI/CgtjcmVhdG9yRGF0ZRgHIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lIqQCChhEaXNjb3ZlcmVkSW1hZ2VSZWZlcmVuY2USCwoDdGFnGAEgASgJEg4KBmRpZ2VzdBgCIAEoCRJkCgthbm5vdGF0aW9ucxgFIAMoCzJPLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5EaXNjb3ZlcmVkSW1hZ2VSZWZlcmVuY2UuQW5ub3RhdGlvbnNFbnRyeRISCgpnaXRSZXBvVVJMGAMgASgJEj0KCWNyZWF0ZWRBdBgEIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lGjIKEEFubm90YXRpb25zRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASIxChJFeHByZXNzaW9uVmFyaWFibGUSDAoEbmFtZRgBIAEoCRINCgV2YWx1ZRgCIAEoCSKiAwoHRnJlaWdodBJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEg0KBWFsaWFzGAcgASgJEkMKBm9yaWdpbhgJIAEoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0T3JpZ2luEkAKB2NvbW1pdHMYAyADKAsyLy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuR2l0Q29tbWl0EjsKBmltYWdlcxgEIAMoCzIrLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5JbWFnZRI7CgZjaGFydHMYBSADKAsyKy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQ2hhcnQSQwoGc3RhdHVzGAYgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRTdGF0dXMirQIKEUZyZWlnaHRDb2xsZWN0aW9uEgoKAmlkGAMgASgJElEKBWl0ZW1zGAEgAygLMkIuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRDb2xsZWN0aW9uLkl0ZW1zRW50cnkSUwoTdmVyaWZpY2F0aW9uSGlzdG9yeRgCIAMoCzI2LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5WZXJpZmljYXRpb25JbmZvGmQKCkl0ZW1zRW50cnkSCwoDa2V5GAEgASgJEkUKBXZhbHVlGAIgASgLMjYuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRSZWZlcmVuY2U6AjgBIo0BCgtGcmVpZ2h0TGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRI8CgVpdGVtcxgCIAMoCzItLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0IisKDUZyZWlnaHRPcmlnaW4SDAoEa2luZBgBIAEoCRIMCgRuYW1lGAIgASgJIqECChBGcmVpZ2h0UmVmZXJlbmNlEgwKBG5hbWUYASABKAkSQwoGb3JpZ2luGAggASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRPcmlnaW4SQAoHY29tbWl0cxgCIAMoCzIvLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5HaXRDb21taXQSOwoGaW1hZ2VzGAMgAygLMisuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkltYWdlEjsKBmNoYXJ0cxgEIAMoCzIrLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DaGFydCKcAQoORnJlaWdodFJlcXVlc3QSQwoGb3JpZ2luGAEgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRPcmlnaW4SRQoHc291cmNlcxgCIAEoCzI0LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0U291cmNlcyKYAQoORnJlaWdodFNvdXJjZXMSDgoGZGlyZWN0GAEgASgIEg4KBnN0YWdlcxgCIAMoCRJIChByZXF1aXJlZFNvYWtUaW1lGAMgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkR1cmF0aW9uEhwKFGF2YWlsYWJpbGl0eVN0cmF0ZWd5GAQgASgJItcECg1GcmVpZ2h0U3RhdHVzElkKC2N1cnJlbnRseUluGAMgAygLMkQuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRTdGF0dXMuQ3VycmVudGx5SW5FbnRyeRJXCgp2ZXJpZmllZEluGAEgAygLMkMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRTdGF0dXMuVmVyaWZpZWRJbkVudHJ5ElkKC2FwcHJvdmVkRm9yGAIgAygLMkQuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRTdGF0dXMuQXBwcm92ZWRGb3JFbnRyeRpmChBDdXJyZW50bHlJbkVudHJ5EgsKA2tleRgBIAEoCRJBCgV2YWx1ZRgCIAEoCzIyLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5DdXJyZW50U3RhZ2U6AjgBGmYKD1ZlcmlmaWVkSW5FbnRyeRILCgNrZXkYASABKAkSQgoFdmFsdWUYAiABKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuVmVyaWZpZWRTdGFnZToCOAEaZwoQQXBwcm92ZWRGb3JFbnRyeRILCgNrZXkYASABKAkSQgoFdmFsdWUYAiABKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQXBwcm92ZWRTdGFnZToCOAEieQoJR2l0Q29tbWl0Eg8KB3JlcG9VUkwYASABKAkSCgoCaWQYAiABKAkSDgoGYnJhbmNoGAMgASgJEgsKA3RhZxgEIAEoCRIPCgdtZXNzYWdlGAYgASgJEg4KBmF1dGhvchgHIAEoCRIRCgljb21taXR0ZXIYCCABKAkibgoSR2l0RGlzY292ZXJ5UmVzdWx0Eg8KB3JlcG9VUkwYASABKAkSRwoHY29tbWl0cxgCIAMoCzI2LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5EaXNjb3ZlcmVkQ29tbWl0Io4CCg9HaXRTdWJzY3JpcHRpb24SDwoHcmVwb1VSTBgBIAEoCRIfChdjb21taXRTZWxlY3Rpb25TdHJhdGVneRgCIAEoCRIOCgZicmFuY2gYAyABKAkSFQoNc3RyaWN0U2VtdmVycxgLIAEoCBIYChBzZW12ZXJDb25zdHJhaW50GAQgASgJEhEKCWFsbG93VGFncxgFIAEoCRISCgppZ25vcmVUYWdzGAYgAygJEh0KFWluc2VjdXJlU2tpcFRMU1ZlcmlmeRgHIAEoCBIUCgxpbmNsdWRlUGF0aHMYCCADKAkSFAoMZXhjbHVkZVBhdGhzGAkgAygJEhYKDmRpc2NvdmVyeUxpbWl0GAogASgFIsgBCgZIZWFsdGgSDgoGc3RhdHVzGAEgASgJEg4KBmlzc3VlcxgCIAMoCRJOCgZjb25maWcYBCABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OEk4KBm91dHB1dBgFIAEoCzI+Lms4cy5pby5hcGlleHRlbnNpb25zX2FwaXNlcnZlci5wa2cuYXBpcy5hcGlleHRlbnNpb25zLnYxLkpTT04ibwoPSGVhbHRoQ2hlY2tTdGVwEgwKBHVzZXMYASABKAkSTgoGY29uZmlnGAIgASgLMj4uazhzLmlvLmFwaWV4dGVuc2lvbnNfYXBpc2VydmVyLnBrZy5hcGlzLmFwaWV4dGVuc2lvbnMudjEuSlNPTiIeCgtIZWFsdGhTdGF0cxIPCgdoZWFsdGh5GAEgASgDItABCgVJbWFnZRIPCgdyZXBvVVJMGAEgASgJEhIKCmdpdFJlcG9VUkwYAiABKAkSCwoDdGFnGAMgASgJEg4KBmRpZ2VzdBgEIAEoCRJRCgthbm5vdGF0aW9ucxgFIAMoCzI8LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5JbWFnZS5Bbm5vdGF0aW9uc0VudHJ5GjIKEEFubm90YXRpb25zRW50cnkSCwoDa2V5GAEgASgJEg0KBXZhbHVlGAIgASgJOgI4ASKNAQoUSW1hZ2VEaXNjb3ZlcnlSZXN1bHQSDwoHcmVwb1VSTBgBIAEoCRIQCghwbGF0Zm9ybRgCIAEoCRJSCgpyZWZlcmVuY2VzGAMgAygLMj4uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkRpc2NvdmVyZWRJbWFnZVJlZmVyZW5jZSL5AQoRSW1hZ2VTdWJzY3JpcHRpb24SDwoHcmVwb1VSTBgBIAEoCRISCgpnaXRSZXBvVVJMGAIgASgJEh4KFmltYWdlU2VsZWN0aW9uU3RyYXRlZ3kYAyABKAkSFQoNc3RyaWN0U2VtdmVycxgKIAEoCBIYChBzZW12ZXJDb25zdHJhaW50GAQgASgJEhEKCWFsbG93VGFncxgFIAEoCRISCgppZ25vcmVUYWdzGAYgAygJEhAKCHBsYXRmb3JtGAcgASgJEh0KFWluc2VjdXJlU2tpcFRMU1ZlcmlmeRgIIAEoCBIWCg5kaXNjb3ZlcnlMaW1pdBgJIAEoBSLZAQoHUHJvamVjdBJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEkUKBHNwZWMYAiABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvamVjdENvbmZpZ1NwZWMSQwoGc3RhdHVzGAMgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb2plY3RTdGF0dXMimgEKDVByb2plY3RDb25maWcSQgoIbWV0YWRhdGEYASABKAsyMC5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuT2JqZWN0TWV0YRJFCgRzcGVjGAIgASgLMjcuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb2plY3RDb25maWdTcGVjIpkBChFQcm9qZWN0Q29uZmlnTGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRJCCgVpdGVtcxgCIAMoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9qZWN0Q29uZmlnImUKEVByb2plY3RDb25maWdTcGVjElAKEXByb21vdGlvblBvbGljaWVzGAEgAygLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblBvbGljeSKNAQoLUHJvamVjdExpc3QSQAoIbWV0YWRhdGEYASABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuTGlzdE1ldGESPAoFaXRlbXMYAiADKAsyLS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvamVjdCKaAQoMUHJvamVjdFN0YXRzEkgKCndhcmVob3VzZXMYASABKAsyNC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuV2FyZWhvdXNlU3RhdHMSQAoGc3RhZ2VzGAIgASgLMjAuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlN0YWdlU3RhdHMilwEKDVByb2plY3RTdGF0dXMSQwoKY29uZGl0aW9ucxgDIAMoCzIvLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5Db25kaXRpb24SQQoFc3RhdHMYBCABKAsyMi5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvamVjdFN0YXRzItkBCglQcm9tb3Rpb24SQgoIbWV0YWRhdGEYASABKAsyMC5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuT2JqZWN0TWV0YRJBCgRzcGVjGAIgASgLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblNwZWMSRQoGc3RhdHVzGAMgASgLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0YXR1cyKRAQoNUHJvbW90aW9uTGlzdBJACghtZXRhZGF0YRgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MaXN0TWV0YRI+CgVpdGVtcxgCIAMoCzIvLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb24ilAEKD1Byb21vdGlvblBvbGljeRINCgVzdGFnZRgBIAEoCRJUCg1zdGFnZVNlbGVjdG9yGAMgASgLMj0uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblBvbGljeVNlbGVjdG9yEhwKFGF1dG9Qcm9tb3Rpb25FbmFibGVkGAIgASgIInMKF1Byb21vdGlvblBvbGljeVNlbGVjdG9yEgwKBG5hbWUYASABKAkSSgoNbGFiZWxTZWxlY3RvchgCIAEoCzIzLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5MYWJlbFNlbGVjdG9yIvIBChJQcm9tb3Rpb25SZWZlcmVuY2USDAoEbmFtZRgBIAEoCRJHCgdmcmVpZ2h0GAIgASgLMjYuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRSZWZlcmVuY2USRQoGc3RhdHVzGAMgASgLMjUuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0YXR1cxI+CgpmaW5pc2hlZEF0GAQgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUiuwEKDVByb21vdGlvblNwZWMSDQoFc3RhZ2UYASABKAkSDwoHZnJlaWdodBgCIAEoCRJGCgR2YXJzGAQgAygLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkV4cHJlc3Npb25WYXJpYWJsZRJCCgVzdGVwcxgDIAMoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25TdGVwIrcECg9Qcm9tb3Rpb25TdGF0dXMSGgoSbGFzdEhhbmRsZWRSZWZyZXNoGAQgASgJEg0KBXBoYXNlGAEgASgJEg8KB21lc3NhZ2UYAiABKAkSRwoHZnJlaWdodBgFIAEoCzI2LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0UmVmZXJlbmNlElIKEWZyZWlnaHRDb2xsZWN0aW9uGAcgASgLMjcuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRDb2xsZWN0aW9uEksKDGhlYWx0aENoZWNrcxgIIAMoCzI1LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5IZWFsdGhDaGVja1N0ZXASPgoKZmluaXNoZWRBdBgGIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lEhMKC2N1cnJlbnRTdGVwGAkgASgDEloKFXN0ZXBFeGVjdXRpb25NZXRhZGF0YRgLIAMoCzI7LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5TdGVwRXhlY3V0aW9uTWV0YWRhdGESTQoFc3RhdGUYCiABKAsyPi5rOHMuaW8uYXBpZXh0ZW5zaW9uc19hcGlzZXJ2ZXIucGtnLmFwaXMuYXBpZXh0ZW5zaW9ucy52MS5KU09OIvsCCg1Qcm9tb3Rpb25TdGVwEgwKBHVzZXMYASABKAkSSgoEdGFzaxgFIAEoCzI8LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25UYXNrUmVmZXJlbmNlEgoKAmFzGAIgASgJEgoKAmlmGAcgASgJEhcKD2NvbnRpbnVlT25FcnJvchgIIAEoCBJHCgVyZXRyeRgEIAEoCzI4LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25TdGVwUmV0cnkSRgoEdmFycxgGIAMoCzI4LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5FeHByZXNzaW9uVmFyaWFibGUSTgoGY29uZmlnGAMgASgLMj4uazhzLmlvLmFwaWV4dGVuc2lvbnNfYXBpc2VydmVyLnBrZy5hcGlzLmFwaWV4dGVuc2lvbnMudjEuSlNPTiJtChJQcm9tb3Rpb25TdGVwUmV0cnkSPwoHdGltZW91dBgBIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5EdXJhdGlvbhIWCg5lcnJvclRocmVzaG9sZBgCIAEoDSKaAQoNUHJvbW90aW9uVGFzaxJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEkUKBHNwZWMYAiABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuUHJvbW90aW9uVGFza1NwZWMimQEKEVByb21vdGlvblRhc2tMaXN0EkAKCG1ldGFkYXRhGAEgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkxpc3RNZXRhEkIKBWl0ZW1zGAIgAygLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblRhc2siNAoWUHJvbW90aW9uVGFza1JlZmVyZW5jZRIMCgRuYW1lGAEgASgJEgwKBGtpbmQYAiABKAkinwEKEVByb21vdGlvblRhc2tTcGVjEkYKBHZhcnMYASADKAsyOC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuRXhwcmVzc2lvblZhcmlhYmxlEkIKBXN0ZXBzGAIgAygLMjMuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblN0ZXAiXgoRUHJvbW90aW9uVGVtcGxhdGUSSQoEc3BlYxgBIAEoCzI7LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25UZW1wbGF0ZVNwZWMiowEKFVByb21vdGlvblRlbXBsYXRlU3BlYxJGCgR2YXJzGAIgAygLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkV4cHJlc3Npb25WYXJpYWJsZRJCCgVzdGVwcxgBIAMoCzIzLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5Qcm9tb3Rpb25TdGVwIuYBChBSZXBvU3Vic2NyaXB0aW9uEkIKA2dpdBgBIAEoCzI1LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5HaXRTdWJzY3JpcHRpb24SRgoFaW1hZ2UYAiABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuSW1hZ2VTdWJzY3JpcHRpb24SRgoFY2hhcnQYAyABKAsyNy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQ2hhcnRTdWJzY3JpcHRpb24izQEKBVN0YWdlEkIKCG1ldGFkYXRhGAEgASgLMjAuazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLk9iamVjdE1ldGESPQoEc3BlYxgCIAEoCzIvLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5TdGFnZVNwZWMSQQoGc3RhdHVzGAMgASgLMjEuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlN0YWdlU3RhdHVzIokBCglTdGFnZUxpc3QSQAoIbWV0YWRhdGEYASABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuTGlzdE1ldGESOgoFaXRlbXMYAiADKAsyKy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuU3RhZ2Ui0AIKCVN0YWdlU3BlYxINCgVzaGFyZBgEIAEoCRJGCgR2YXJzGAcgAygLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkV4cHJlc3Npb25WYXJpYWJsZRJOChByZXF1ZXN0ZWRGcmVpZ2h0GAUgAygLMjQuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkZyZWlnaHRSZXF1ZXN0ElIKEXByb21vdGlvblRlbXBsYXRlGAYgASgLMjcuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblRlbXBsYXRlEkgKDHZlcmlmaWNhdGlvbhgDIAEoCzIyLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5WZXJpZmljYXRpb24iXgoKU3RhZ2VTdGF0cxINCgVjb3VudBgCIAEoAxJBCgZoZWFsdGgYASABKAsyMS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuSGVhbHRoU3RhdHMi1gMKC1N0YWdlU3RhdHVzEkMKCmNvbmRpdGlvbnMYDSADKAsyLy5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuQ29uZGl0aW9uEhoKEmxhc3RIYW5kbGVkUmVmcmVzaBgLIAEoCRJPCg5mcmVpZ2h0SGlzdG9yeRgEIAMoCzI3LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5GcmVpZ2h0Q29sbGVjdGlvbhIWCg5mcmVpZ2h0U3VtbWFyeRgMIAEoCRI8CgZoZWFsdGgYCCABKAsyLC5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuSGVhbHRoEhoKEm9ic2VydmVkR2VuZXJhdGlvbhgGIAEoAxJSChBjdXJyZW50UHJvbW90aW9uGAcgASgLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblJlZmVyZW5jZRJPCg1sYXN0UHJvbW90aW9uGAogASgLMjguZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLlByb21vdGlvblJlZmVyZW5jZSLzAQoVU3RlcEV4ZWN1dGlvbk1ldGFkYXRhEg0KBWFsaWFzGAEgASgJEj0KCXN0YXJ0ZWRBdBgCIAEoCzIqLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5UaW1lEj4KCmZpbmlzaGVkQXQYAyABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZRISCgplcnJvckNvdW50GAQgASgNEg4KBnN0YXR1cxgFIAEoCRIPCgdtZXNzYWdlGAYgASgJEhcKD2NvbnRpbnVlT25FcnJvchgHIAEoCCKLAgoMVmVyaWZpY2F0aW9uEloKEWFuYWx5c2lzVGVtcGxhdGVzGAEgAygLMj8uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkFuYWx5c2lzVGVtcGxhdGVSZWZlcmVuY2USVgoTYW5hbHlzaXNSdW5NZXRhZGF0YRgCIAEoCzI5LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5BbmFseXNpc1J1bk1ldGFkYXRhEkcKBGFyZ3MYAyADKAsyOS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuQW5hbHlzaXNSdW5Bcmd1bWVudCKdAgoQVmVyaWZpY2F0aW9uSW5mbxIKCgJpZBgEIAEoCRINCgVhY3RvchgHIAEoCRI9CglzdGFydFRpbWUYBSABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZRINCgVwaGFzZRgBIAEoCRIPCgdtZXNzYWdlGAIgASgJEk8KC2FuYWx5c2lzUnVuGAMgASgLMjouZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkFuYWx5c2lzUnVuUmVmZXJlbmNlEj4KCmZpbmlzaFRpbWUYBiABKAsyKi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuVGltZSKUAQoNVmVyaWZpZWRTdGFnZRI+Cgp2ZXJpZmllZEF0GAEgASgLMiouazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLlRpbWUSQwoLbG9uZ2VzdFNvYWsYAiABKAsyLi5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuRHVyYXRpb24i2QEKCVdhcmVob3VzZRJCCghtZXRhZGF0YRgBIAEoCzIwLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5PYmplY3RNZXRhEkEKBHNwZWMYAiABKAsyMy5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuV2FyZWhvdXNlU3BlYxJFCgZzdGF0dXMYAyABKAsyNS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTEuV2FyZWhvdXNlU3RhdHVzIpEBCg1XYXJlaG91c2VMaXN0EkAKCG1ldGFkYXRhGAEgASgLMi4uazhzLmlvLmFwaW1hY2hpbmVyeS5wa2cuYXBpcy5tZXRhLnYxLkxpc3RNZXRhEj4KBWl0ZW1zGAIgAygLMi8uZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLldhcmVob3VzZSLOAQoNV2FyZWhvdXNlU3BlYxINCgVzaGFyZBgCIAEoCRJACghpbnRlcnZhbBgEIAEoCzIuLms4cy5pby5hcGltYWNoaW5lcnkucGtnLmFwaXMubWV0YS52MS5EdXJhdGlvbhIdChVmcmVpZ2h0Q3JlYXRpb25Qb2xpY3kYAyABKAkSTQoNc3Vic2NyaXB0aW9ucxgBIAMoCzI2LmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5SZXBvU3Vic2NyaXB0aW9uImIKDldhcmVob3VzZVN0YXRzEg0KBWNvdW50GAIgASgDEkEKBmhlYWx0aBgBIAEoCzIxLmdpdGh1Yi5jb20uYWt1aXR5LmthcmdvLmFwaS52MWFscGhhMS5IZWFsdGhTdGF0cyL9AQoPV2FyZWhvdXNlU3RhdHVzEkMKCmNvbmRpdGlvbnMYCSADKAsyLy5rOHMuaW8uYXBpbWFjaGluZXJ5LnBrZy5hcGlzLm1ldGEudjEuQ29uZGl0aW9uEhoKEmxhc3RIYW5kbGVkUmVmcmVzaBgGIAEoCRIaChJvYnNlcnZlZEdlbmVyYXRpb24YBCABKAMSFQoNbGFzdEZyZWlnaHRJRBgIIAEoCRJWChNkaXNjb3ZlcmVkQXJ0aWZhY3RzGAcgASgLMjkuZ2l0aHViLmNvbS5ha3VpdHkua2FyZ28uYXBpLnYxYWxwaGExLkRpc2NvdmVyZWRBcnRpZmFjdHNClwIKKGNvbS5naXRodWIuY29tLmFrdWl0eS5rYXJnby5hcGkudjFhbHBoYTFCDkdlbmVyYXRlZFByb3RvUAFaJGdpdGh1Yi5jb20vYWt1aXR5L2thcmdvL2FwaS92MWFscGhhMaICBUdDQUtBqgIkR2l0aHViLkNvbS5Ba3VpdHkuS2FyZ28uQXBpLlYxYWxwaGExygIkR2l0aHViXENvbVxBa3VpdHlcS2FyZ29cQXBpXFYxYWxwaGEx4gIwR2l0aHViXENvbVxBa3VpdHlcS2FyZ29cQXBpXFYxYWxwaGExXEdQQk1ldGFkYXRh6gIpR2l0aHViOjpDb206OkFrdWl0eTo6S2FyZ286OkFwaTo6VjFhbHBoYTE", [file_k8s_io_apiextensions_apiserver_pkg_apis_apiextensions_v1_generated, file_k8s_io_apimachinery_pkg_apis_meta_v1_generated, file_k8s_io_apimachinery_pkg_runtime_generated, file_k8s_io_apimachinery_pkg_runtime_schema_generated]);
 
 /**
  * AnalysisRunArgument represents an argument to be added to an AnalysisRun.
@@ -2321,6 +2321,16 @@ export type PromotionStep = Message<"github.com.akuity.kargo.api.v1alpha1.Promot
    */
   if: string;
 
+  /**
+   * ContinueOnError is a boolean value that, if set to true, will cause the
+   * Promotion to continue executing the next step even if this step fails. It
+   * also will not permit this failure to impact the overall status of the
+   * Promotion.
+   *
+   * @generated from field: optional bool continueOnError = 8;
+   */
+  continueOnError: boolean;
+
   /**
    * Retry is the retry policy for this step.
    *
@@ -2926,6 +2936,16 @@ export type StepExecutionMetadata = Message<"github.com.akuity.kargo.api.v1alpha
    * @generated from field: optional string message = 6;
    */
   message: string;
+
+  /**
+   * ContinueOnError is a boolean value that, if set to true, will cause the
+   * Promotion to continue executing the next step even if this step fails. It
+   * also will not permit this failure to impact the overall status of the
+   * Promotion.
+   *
+   * @generated from field: optional bool continueOnError = 7;
+   */
+  continueOnError: boolean;
 };
 
 /**
diff --git a/ui/src/gen/schema/clusterpromotiontasks.kargo.akuity.io_v1alpha1.json b/ui/src/gen/schema/clusterpromotiontasks.kargo.akuity.io_v1alpha1.json
index d53e31b1..5a832795 100644
--- a/ui/src/gen/schema/clusterpromotiontasks.kargo.akuity.io_v1alpha1.json
+++ b/ui/src/gen/schema/clusterpromotiontasks.kargo.akuity.io_v1alpha1.json
@@ -28,6 +28,10 @@
                 "description": "Config is opaque configuration for the PromotionStep that is understood\nonly by each PromotionStep's implementation. It is legal to utilize\nexpressions in defining values at any level of this block.\nSee https://docs.kargo.io/user-guide/reference-docs/expressions for details.",
                 "x-kubernetes-preserve-unknown-fields": true
               },
+              "continueOnError": {
+                "description": "ContinueOnError is a boolean value that, if set to true, will cause the\nPromotion to continue executing the next step even if this step fails. It\nalso will not permit this failure to impact the overall status of the\nPromotion.",
+                "type": "boolean"
+              },
               "if": {
                 "description": "If is an optional expression that, if present, must evaluate to a boolean\nvalue. If the expression evaluates to false, the step will be skipped.\nIf the expression does not evaluate to a boolean value, the step will be\nconsidered to have failed.",
                 "type": "string"
diff --git a/ui/src/gen/schema/promotions.kargo.akuity.io_v1alpha1.json b/ui/src/gen/schema/promotions.kargo.akuity.io_v1alpha1.json
index c7db83d4..9a6a5501 100644
--- a/ui/src/gen/schema/promotions.kargo.akuity.io_v1alpha1.json
+++ b/ui/src/gen/schema/promotions.kargo.akuity.io_v1alpha1.json
@@ -43,6 +43,10 @@
                 "description": "Config is opaque configuration for the PromotionStep that is understood\nonly by each PromotionStep's implementation. It is legal to utilize\nexpressions in defining values at any level of this block.\nSee https://docs.kargo.io/user-guide/reference-docs/expressions for details.",
                 "x-kubernetes-preserve-unknown-fields": true
               },
+              "continueOnError": {
+                "description": "ContinueOnError is a boolean value that, if set to true, will cause the\nPromotion to continue executing the next step even if this step fails. It\nalso will not permit this failure to impact the overall status of the\nPromotion.",
+                "type": "boolean"
+              },
               "if": {
                 "description": "If is an optional expression that, if present, must evaluate to a boolean\nvalue. If the expression evaluates to false, the step will be skipped.\nIf the expression does not evaluate to a boolean value, the step will be\nconsidered to have failed.",
                 "type": "string"
@@ -545,6 +549,10 @@
                 "description": "Alias is the alias of the step.",
                 "type": "string"
               },
+              "continueOnError": {
+                "description": "ContinueOnError is a boolean value that, if set to true, will cause the\nPromotion to continue executing the next step even if this step fails. It\nalso will not permit this failure to impact the overall status of the\nPromotion.",
+                "type": "boolean"
+              },
               "errorCount": {
                 "description": "ErrorCount tracks consecutive failed attempts to execute the step.",
                 "format": "int32",
diff --git a/ui/src/gen/schema/promotiontasks.kargo.akuity.io_v1alpha1.json b/ui/src/gen/schema/promotiontasks.kargo.akuity.io_v1alpha1.json
index cfc7be8d..5b8188a1 100644
--- a/ui/src/gen/schema/promotiontasks.kargo.akuity.io_v1alpha1.json
+++ b/ui/src/gen/schema/promotiontasks.kargo.akuity.io_v1alpha1.json
@@ -28,6 +28,10 @@
                 "description": "Config is opaque configuration for the PromotionStep that is understood\nonly by each PromotionStep's implementation. It is legal to utilize\nexpressions in defining values at any level of this block.\nSee https://docs.kargo.io/user-guide/reference-docs/expressions for details.",
                 "x-kubernetes-preserve-unknown-fields": true
               },
+              "continueOnError": {
+                "description": "ContinueOnError is a boolean value that, if set to true, will cause the\nPromotion to continue executing the next step even if this step fails. It\nalso will not permit this failure to impact the overall status of the\nPromotion.",
+                "type": "boolean"
+              },
               "if": {
                 "description": "If is an optional expression that, if present, must evaluate to a boolean\nvalue. If the expression evaluates to false, the step will be skipped.\nIf the expression does not evaluate to a boolean value, the step will be\nconsidered to have failed.",
                 "type": "string"
diff --git a/ui/src/gen/schema/stages.kargo.akuity.io_v1alpha1.json b/ui/src/gen/schema/stages.kargo.akuity.io_v1alpha1.json
index 63ce1ebc..5cb6eb4e 100644
--- a/ui/src/gen/schema/stages.kargo.akuity.io_v1alpha1.json
+++ b/ui/src/gen/schema/stages.kargo.akuity.io_v1alpha1.json
@@ -35,6 +35,10 @@
                         "description": "Config is opaque configuration for the PromotionStep that is understood\nonly by each PromotionStep's implementation. It is legal to utilize\nexpressions in defining values at any level of this block.\nSee https://docs.kargo.io/user-guide/reference-docs/expressions for details.",
                         "x-kubernetes-preserve-unknown-fields": true
                       },
+                      "continueOnError": {
+                        "description": "ContinueOnError is a boolean value that, if set to true, will cause the\nPromotion to continue executing the next step even if this step fails. It\nalso will not permit this failure to impact the overall status of the\nPromotion.",
+                        "type": "boolean"
+                      },
                       "if": {
                         "description": "If is an optional expression that, if present, must evaluate to a boolean\nvalue. If the expression evaluates to false, the step will be skipped.\nIf the expression does not evaluate to a boolean value, the step will be\nconsidered to have failed.",
                         "type": "string"
@@ -910,6 +914,10 @@
                         "description": "Alias is the alias of the step.",
                         "type": "string"
                       },
+                      "continueOnError": {
+                        "description": "ContinueOnError is a boolean value that, if set to true, will cause the\nPromotion to continue executing the next step even if this step fails. It\nalso will not permit this failure to impact the overall status of the\nPromotion.",
+                        "type": "boolean"
+                      },
                       "errorCount": {
                         "description": "ErrorCount tracks consecutive failed attempts to execute the step.",
                         "format": "int32",
@@ -1708,6 +1716,10 @@
                         "description": "Alias is the alias of the step.",
                         "type": "string"
                       },
+                      "continueOnError": {
+                        "description": "ContinueOnError is a boolean value that, if set to true, will cause the\nPromotion to continue executing the next step even if this step fails. It\nalso will not permit this failure to impact the overall status of the\nPromotion.",
+                        "type": "boolean"
+                      },
                       "errorCount": {
                         "description": "ErrorCount tracks consecutive failed attempts to execute the step.",
                         "format": "int32",



Test patch:
diff --git a/api/v1alpha1/promotion_types_test.go b/api/v1alpha1/promotion_types_test.go
index c18759f2..8583e241 100644
--- a/api/v1alpha1/promotion_types_test.go
+++ b/api/v1alpha1/promotion_types_test.go
@@ -9,6 +9,118 @@ import (
 	"k8s.io/utils/ptr"
 )
 
+func TestPromotionStepStatus_Compare(t *testing.T) {
+	tests := []struct {
+		name     string
+		lhs      PromotionStepStatus
+		rhs      PromotionStepStatus
+		expected int
+	}{
+		{
+			name:     "Succeeded < Skipped",
+			lhs:      PromotionStepStatusSucceeded,
+			rhs:      PromotionStepStatusSkipped,
+			expected: -1,
+		},
+		{
+			name:     "Skipped < Running",
+			lhs:      PromotionStepStatusSkipped,
+			rhs:      PromotionStepStatusRunning,
+			expected: -1,
+		},
+		{
+			name:     "Running < Aborted",
+			lhs:      PromotionStepStatusRunning,
+			rhs:      PromotionStepStatusAborted,
+			expected: -1,
+		},
+		{
+			name:     "Aborted < Failed",
+			lhs:      PromotionStepStatusAborted,
+			rhs:      PromotionStepStatusFailed,
+			expected: -1,
+		},
+		{
+			name:     "Failed < Errored",
+			lhs:      PromotionStepStatusFailed,
+			rhs:      PromotionStepStatusErrored,
+			expected: -1,
+		},
+		{
+			name:     "Succeeded == Succeeded",
+			lhs:      PromotionStepStatusSucceeded,
+			rhs:      PromotionStepStatusSucceeded,
+			expected: 0,
+		},
+		{
+			name:     "Skipped == Skipped",
+			lhs:      PromotionStepStatusSkipped,
+			rhs:      PromotionStepStatusSkipped,
+			expected: 0,
+		},
+		{
+			name:     "Running == Running",
+			lhs:      PromotionStepStatusRunning,
+			rhs:      PromotionStepStatusRunning,
+			expected: 0,
+		},
+		{
+			name:     "Aborted == Aborted",
+			lhs:      PromotionStepStatusAborted,
+			rhs:      PromotionStepStatusAborted,
+			expected: 0,
+		},
+		{
+			name:     "Failed == Failed",
+			lhs:      PromotionStepStatusFailed,
+			rhs:      PromotionStepStatusFailed,
+			expected: 0,
+		},
+		{
+			name:     "Errored == Errored",
+			lhs:      PromotionStepStatusErrored,
+			rhs:      PromotionStepStatusErrored,
+			expected: 0,
+		},
+		{
+			name:     "Skipped > Succeeded",
+			lhs:      PromotionStepStatusSkipped,
+			rhs:      PromotionStepStatusSucceeded,
+			expected: 1,
+		},
+		{
+			name:     "Running > Skipped",
+			lhs:      PromotionStepStatusRunning,
+			rhs:      PromotionStepStatusSkipped,
+			expected: 1,
+		},
+		{
+			name:     "Aborted > Running",
+			lhs:      PromotionStepStatusAborted,
+			rhs:      PromotionStepStatusRunning,
+			expected: 1,
+		},
+		{
+			name:     "Failed > Aborted",
+			lhs:      PromotionStepStatusFailed,
+			rhs:      PromotionStepStatusAborted,
+			expected: 1,
+		},
+		{
+			name:     "Errored > Failed",
+			lhs:      PromotionStepStatusErrored,
+			rhs:      PromotionStepStatusFailed,
+			expected: 1,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			result := tt.lhs.Compare(tt.rhs)
+			require.Equal(t, tt.expected, result)
+		})
+	}
+}
+
 func TestPromotionRetry_GetTimeout(t *testing.T) {
 	tests := []struct {
 		name     string
@@ -74,3 +186,68 @@ func TestPromotionRetry_GetErrorThreshold(t *testing.T) {
 		require.Equal(t, tt.want, tt.retry.GetErrorThreshold(tt.fallback))
 	}
 }
+
+func TestStepExecutionMetadataList_HasFailures(t *testing.T) {
+	tests := []struct {
+		name     string
+		metadata StepExecutionMetadataList
+		expected bool
+	}{
+		{
+			name: "no errors/failures at all",
+			metadata: StepExecutionMetadataList{
+				{Status: PromotionStepStatusSucceeded},
+				{Status: PromotionStepStatusSucceeded},
+				{Status: PromotionStepStatusSucceeded},
+			},
+			expected: false,
+		},
+		{
+			name: "has an error",
+			metadata: StepExecutionMetadataList{
+				{Status: PromotionStepStatusSucceeded},
+				{Status: PromotionStepStatusErrored},
+				{Status: PromotionStepStatusSucceeded},
+			},
+			expected: true,
+		},
+		{
+			name: "has an error with continueOnError == true",
+			metadata: StepExecutionMetadataList{
+				{Status: PromotionStepStatusSucceeded},
+				{
+					ContinueOnError: true,
+					Status:          PromotionStepStatusErrored,
+				},
+				{Status: PromotionStepStatusSucceeded},
+			},
+			expected: false,
+		},
+		{
+			name: "has a failure",
+			metadata: StepExecutionMetadataList{
+				{Status: PromotionStepStatusSucceeded},
+				{Status: PromotionStepStatusFailed},
+				{Status: PromotionStepStatusSucceeded},
+			},
+			expected: true,
+		},
+		{
+			name: "has a failure with continueOnError == true",
+			metadata: StepExecutionMetadataList{
+				{Status: PromotionStepStatusSucceeded},
+				{
+					ContinueOnError: true,
+					Status:          PromotionStepStatusFailed,
+				},
+				{Status: PromotionStepStatusSucceeded},
+			},
+			expected: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			require.Equal(t, tt.expected, tt.metadata.HasFailures())
+		})
+	}
+}
diff --git a/internal/promotion/promotion_test.go b/internal/promotion/promotion_test.go
index e32c7b65..aa65f100 100644
--- a/internal/promotion/promotion_test.go
+++ b/internal/promotion/promotion_test.go
@@ -875,7 +875,20 @@ func TestStep_Skip(t *testing.T) {
 		assertions func(*testing.T, bool, error)
 	}{
 		{
-			name: "no if condition",
+			name: "no if condition with failures",
+			step: &Step{},
+			ctx: Context{
+				StepExecutionMetadata: kargoapi.StepExecutionMetadataList{{
+					Status: kargoapi.PromotionStepStatusFailed,
+				}},
+			},
+			assertions: func(t *testing.T, b bool, err error) {
+				assert.True(t, b)
+				assert.NoError(t, err)
+			},
+		},
+		{
+			name: "no if condition without failures",
 			step: &Step{},
 			assertions: func(t *testing.T, b bool, err error) {
 				assert.False(t, b)
diff --git a/internal/promotion/simple_engine_test.go b/internal/promotion/simple_engine_test.go
index b6476767..a24ac865 100644
--- a/internal/promotion/simple_engine_test.go
+++ b/internal/promotion/simple_engine_test.go
@@ -54,9 +54,8 @@ func TestSimpleEngine_Promote(t *testing.T) {
 				{Kind: "error-step"},
 			},
 			assertions: func(t *testing.T, result Result, err error) {
-				assert.Error(t, err)
+				assert.ErrorContains(t, err, "error running step")
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
-				assert.ErrorContains(t, err, "step execution failed")
 			},
 		},
 		{
@@ -68,7 +67,7 @@ func TestSimpleEngine_Promote(t *testing.T) {
 				{Kind: "context-waiter"},
 			},
 			assertions: func(t *testing.T, result Result, err error) {
-				assert.ErrorContains(t, err, "met error threshold")
+				assert.ErrorContains(t, err, context.Canceled.Error())
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
 				assert.Len(t, result.StepExecutionMetadata, 1)
 				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
@@ -145,26 +144,59 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 		stepRunners []promotion.StepRunner
 		promoCtx    Context
 		steps       []Step
-		assertions  func(*testing.T, Result, error)
+		assertions  func(*testing.T, Result)
 	}{
 		{
 			name: "fail on invalid step alias",
 			steps: []Step{
 				{Kind: "success-step", Alias: "step-1"},
 			},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.ErrorContains(t, err, "is forbidden")
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
+				assert.Contains(t, result.Message, "is forbidden")
 				assert.Equal(t, int64(0), result.CurrentStep)
+
+				assert.Len(t, result.StepExecutionMetadata, 1)
+
+				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
+				assert.Contains(t, result.StepExecutionMetadata[0].Message, "is forbidden")
+				assert.Nil(t, result.StepExecutionMetadata[0].StartedAt)
+				assert.Nil(t, result.StepExecutionMetadata[0].FinishedAt)
 			},
 		},
 		{
 			name:  "runner not found",
 			steps: []Step{{Kind: "unknown-step"}},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.ErrorContains(t, err, "no promotion step runner found for kind")
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
+				assert.Contains(t, result.Message, "no promotion step runner found for kind")
 				assert.Equal(t, int64(0), result.CurrentStep)
+
+				assert.Len(t, result.StepExecutionMetadata, 1)
+
+				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
+				assert.Contains(t, result.StepExecutionMetadata[0].Message, "no promotion step runner found for kind")
+				assert.Nil(t, result.StepExecutionMetadata[0].StartedAt)
+				assert.Nil(t, result.StepExecutionMetadata[0].FinishedAt)
+			},
+		},
+		{
+			name:  "error determining whether to skip step",
+			steps: []Step{{If: "${{ bogus() }}"}},
+			assertions: func(t *testing.T, result Result) {
+				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
+				assert.Contains(t, result.Message, "error checking if step")
+				assert.Contains(t, result.Message, "should be skipped")
+				assert.Equal(t, int64(0), result.CurrentStep)
+
+				assert.Len(t, result.StepExecutionMetadata, 1)
+
+				stepExecMeta := result.StepExecutionMetadata[0]
+				assert.Equal(t, kargoapi.PromotionStepStatusErrored, stepExecMeta.Status)
+				assert.Contains(t, stepExecMeta.Message, "error checking if step")
+				assert.Contains(t, stepExecMeta.Message, "should be skipped")
+				assert.Nil(t, stepExecMeta.StartedAt)
+				assert.Nil(t, stepExecMeta.FinishedAt)
 			},
 		},
 		{
@@ -173,9 +205,9 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				{Kind: "success-step", Alias: "step1"},
 				{Kind: "success-step", Alias: "step2"},
 			},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.NoError(t, err)
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status)
+				assert.Empty(t, result.Message)
 				assert.Equal(t, int64(1), result.CurrentStep)
 
 				// Verify the result contains metadata from both steps
@@ -204,9 +236,9 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				{Kind: "error-step", Alias: "step2", If: "${{ false }}"},
 				{Kind: "success-step", Alias: "step3", If: "${{ true }}"},
 			},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.NoError(t, err)
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status)
+				assert.Empty(t, result.Message)
 				assert.Equal(t, int64(2), result.CurrentStep)
 
 				// Verify the result contains metadata from all steps
@@ -241,7 +273,9 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				StartFromStep: 1,
 				// Dummy metadata for the 0 step, which must have succeeded already if
 				// we're starting from step 1
-				StepExecutionMetadata: kargoapi.StepExecutionMetadataList{{}},
+				StepExecutionMetadata: kargoapi.StepExecutionMetadataList{{
+					Status: kargoapi.PromotionStepStatusSucceeded,
+				}},
 			},
 			steps: []Step{
 				// This step must have already succeeded and should not be run again
@@ -250,9 +284,9 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				// This step should be run
 				{Kind: "success-step", Alias: "step2"},
 			},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.NoError(t, err)
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status)
+				assert.Empty(t, result.Message)
 				assert.Equal(t, int64(1), result.CurrentStep)
 
 				// Verify the result contains metadata from both steps
@@ -277,14 +311,17 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				{Kind: "success-step", Alias: "step1"},
 				{Kind: "terminal-error-step", Alias: "step2"},
 			},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.ErrorContains(t, err, "an unrecoverable error occurred")
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
+				assert.Contains(t, result.Message, "an unrecoverable error occurred")
 				assert.Equal(t, int64(1), result.CurrentStep)
+
 				assert.Len(t, result.StepExecutionMetadata, 2)
+
 				assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
+
 				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[1].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[1].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[1].FinishedAt)
@@ -305,14 +342,17 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				{Kind: "success-step", Alias: "step1"},
 				{Kind: "error-step", Alias: "step2"},
 			},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.ErrorContains(t, err, "met error threshold")
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
+				assert.Contains(t, result.Message, "met error threshold")
 				assert.Equal(t, int64(1), result.CurrentStep)
+
 				assert.Len(t, result.StepExecutionMetadata, 2)
+
 				assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
+
 				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[1].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[1].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[1].FinishedAt)
@@ -336,11 +376,13 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 					Retry: &kargoapi.PromotionStepRetry{ErrorThreshold: 3},
 				},
 			},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.NoError(t, err)
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseRunning, result.Status)
+				assert.Empty(t, result.Message)
 				assert.Equal(t, int64(0), result.CurrentStep)
+
 				assert.Len(t, result.StepExecutionMetadata, 1)
+
 				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.Nil(t, result.StepExecutionMetadata[0].FinishedAt)
@@ -367,12 +409,13 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 					},
 				},
 			},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.ErrorContains(t, err, "timeout")
-				assert.ErrorContains(t, err, "has elapsed")
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
+				assert.Contains(t, result.Message, "timed out after")
 				assert.Equal(t, int64(0), result.CurrentStep)
+
 				assert.Len(t, result.StepExecutionMetadata, 1)
+
 				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
@@ -397,13 +440,14 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 					},
 				},
 			},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.ErrorContains(t, err, "timeout")
-				assert.ErrorContains(t, err, "has elapsed")
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
+				assert.Contains(t, result.Message, "timed out after")
 				assert.Equal(t, int64(0), result.CurrentStep)
+
 				assert.Len(t, result.StepExecutionMetadata, 1)
-				assert.Equal(t, kargoapi.PromotionStepStatusRunning, result.StepExecutionMetadata[0].Status)
+
+				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
 			},
@@ -411,26 +455,40 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 		{
 			name:  "step is still running; timeout not elapsed",
 			steps: []Step{{Kind: "running-step"}},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.NoError(t, err)
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseRunning, result.Status)
+				assert.Empty(t, result.Message)
 				assert.Equal(t, int64(0), result.CurrentStep)
+
 				assert.Len(t, result.StepExecutionMetadata, 1)
+
 				assert.Equal(t, kargoapi.PromotionStepStatusRunning, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.Nil(t, result.StepExecutionMetadata[0].FinishedAt)
 			},
 		},
 		{
-			name:  "context cancellation",
-			steps: []Step{{Kind: "context-waiter"}},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.ErrorContains(t, err, "met error threshold")
+			name: "context cancellation",
+			steps: []Step{
+				{Kind: "context-waiter"}, // Closes context and errors
+				{Kind: "success-step"},   // Won't run because of canceled context
+			},
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status)
-				assert.Equal(t, int64(0), result.CurrentStep)
-				assert.Len(t, result.StepExecutionMetadata, 1)
+				assert.Contains(t, result.Message, context.Canceled.Error())
+				assert.Equal(t, int64(1), result.CurrentStep)
+
+				assert.Len(t, result.StepExecutionMetadata, 2)
+
 				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[0].Status)
 				assert.Contains(t, result.StepExecutionMetadata[0].Message, context.Canceled.Error())
+				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
+				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
+
+				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.StepExecutionMetadata[1].Status)
+				assert.Contains(t, result.StepExecutionMetadata[1].Message, context.Canceled.Error())
+				assert.Nil(t, result.StepExecutionMetadata[1].StartedAt)
+				assert.Nil(t, result.StepExecutionMetadata[1].FinishedAt)
 			},
 		},
 		{
@@ -448,11 +506,13 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				Kind:  ComposeOutputStepKind,
 				Alias: "task-1::custom-output",
 			}},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.NoError(t, err)
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status)
+				assert.Empty(t, result.Message)
 				assert.Equal(t, int64(0), result.CurrentStep)
+
 				assert.Len(t, result.StepExecutionMetadata, 1)
+
 				assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
@@ -483,11 +543,13 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				Kind:  ComposeOutputStepKind,
 				Alias: "custom-output",
 			}},
-			assertions: func(t *testing.T, result Result, err error) {
-				assert.NoError(t, err)
+			assertions: func(t *testing.T, result Result) {
 				assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status)
+				assert.Empty(t, result.Message)
 				assert.Equal(t, int64(0), result.CurrentStep)
+
 				assert.Len(t, result.StepExecutionMetadata, 1)
+
 				assert.Equal(t, kargoapi.PromotionStepStatusSucceeded, result.StepExecutionMetadata[0].Status)
 				assert.NotNil(t, result.StepExecutionMetadata[0].StartedAt)
 				assert.NotNil(t, result.StepExecutionMetadata[0].FinishedAt)
@@ -549,8 +611,135 @@ func TestSimpleEngine_executeSteps(t *testing.T) {
 				kargoClient: fake.NewClientBuilder().Build(),
 			}
 
-			result, err := engine.executeSteps(ctx, tt.promoCtx, tt.steps, t.TempDir())
-			tt.assertions(t, result, err)
+			tt.assertions(t, engine.executeSteps(ctx, tt.promoCtx, tt.steps, t.TempDir()))
+		})
+	}
+}
+
+func TestDeterminePromoPhase(t *testing.T) {
+	tests := []struct {
+		name          string
+		steps         []Step
+		stepExecMetas kargoapi.StepExecutionMetadataList
+		expectedPhase kargoapi.PromotionPhase
+	}{
+		{
+			name:  "success",
+			steps: []Step{{}},
+			stepExecMetas: kargoapi.StepExecutionMetadataList{{
+				Status: kargoapi.PromotionStepStatusSucceeded,
+			}},
+			expectedPhase: kargoapi.PromotionPhaseSucceeded,
+		},
+		{
+			name:  "worst step result was skipped",
+			steps: []Step{{}, {}},
+			stepExecMetas: kargoapi.StepExecutionMetadataList{
+				{
+					Status: kargoapi.PromotionStepStatusSucceeded,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusSkipped,
+				},
+			},
+			expectedPhase: kargoapi.PromotionPhaseSucceeded,
+		},
+		{
+			name:  "worst step result was aborted",
+			steps: []Step{{}, {}, {}},
+			stepExecMetas: kargoapi.StepExecutionMetadataList{
+				{
+					Status: kargoapi.PromotionStepStatusSucceeded,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusSkipped,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusAborted,
+				},
+			},
+			expectedPhase: kargoapi.PromotionPhaseAborted,
+		},
+		{
+			name:  "worst step result was failed",
+			steps: []Step{{}, {}, {}, {}},
+			stepExecMetas: kargoapi.StepExecutionMetadataList{
+				{
+					Status: kargoapi.PromotionStepStatusSucceeded,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusSkipped,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusAborted,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusFailed,
+				},
+			},
+			expectedPhase: kargoapi.PromotionPhaseFailed,
+		},
+		{
+			name:  "worst step result was errored",
+			steps: []Step{{}, {}, {}, {}, {}},
+			stepExecMetas: kargoapi.StepExecutionMetadataList{
+				{
+					Status: kargoapi.PromotionStepStatusSucceeded,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusSkipped,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusAborted,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusFailed,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusErrored,
+				},
+			},
+			expectedPhase: kargoapi.PromotionPhaseErrored,
+		},
+		{
+			name: "worst step result was running",
+			// This is a case that should never occur, but the logic does map this
+			// to an errored phase.
+			steps: []Step{{}, {}, {}},
+			stepExecMetas: kargoapi.StepExecutionMetadataList{
+				{
+					Status: kargoapi.PromotionStepStatusSucceeded,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusSkipped,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusRunning,
+				},
+			},
+			expectedPhase: kargoapi.PromotionPhaseErrored,
+		},
+		{
+			name:  "step with continueOnError does not affect phase",
+			steps: []Step{{}, {ContinueOnError: true}, {}},
+			stepExecMetas: kargoapi.StepExecutionMetadataList{
+				{
+					Status: kargoapi.PromotionStepStatusSucceeded,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusErrored,
+				},
+				{
+					Status: kargoapi.PromotionStepStatusSucceeded,
+				},
+			},
+			expectedPhase: kargoapi.PromotionPhaseSucceeded,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			phase, _ := determinePromoPhase(tt.steps, tt.stepExecMetas)
+			require.Equal(t, tt.expectedPhase, phase)
 		})
 	}
 }
@@ -587,7 +776,7 @@ func TestSimpleEngine_executeStep(t *testing.T) {
 				runErr: errors.New("something went wrong"),
 			},
 			assertions: func(t *testing.T, result promotion.StepResult, err error) {
-				assert.ErrorContains(t, err, "failed to run step \"error-step\"")
+				assert.ErrorContains(t, err, "error running step \"error-step\"")
 				assert.ErrorContains(t, err, "something went wrong")
 				assert.Equal(t, kargoapi.PromotionStepStatusErrored, result.Status)
 			},