feat: Add user event tracking to GHA+K8s guide (#62192)

* Initial refactor existing guide (ssh)

* Add provider and state reducer

* Welcome step

* Connect GitHub step

* Configure access step

* Finish step

* Add guide to integrations

* Add completion confirmation

* Add .tf file formatting in TextEditor

* Support updating TextEditor content

* Fetch and generate templates

* Add CodePanel component

* Add code panel to GitHub step

* Add code panel to access step

* Add code panel to finish step

* Add Kubernetes labels select component

* Add labels to state

* Add labels selector to access step

* Add welcome step to tracking usage events

* Add `useTracking`

* Track start and stop events

* Track steps events

* Track section events

* Track field events

* Track link events

* Track code copy events

* Extend tests

* Update stories

* Simplify react context usage

* Rename `captureSuccess` to `userEventCaptureSuccess`

* Rename file `tracking-tester.ts` to `trackingTester.ts`

* fix: Allow `:` in label values

* Reference frontend label matching logic in backend

* Allow `:` in label names and values

* Use Set one-liner

* Remove unnecessary else

* Fix test

* Allow spaces in label values
This commit is contained in:
Nick Marais
2025-12-16 17:56:53 +00:00
committed by GitHub
parent 03d00159a3
commit a4ac509bc5
27 changed files with 1451 additions and 509 deletions
+405 -402
View File
@@ -423,6 +423,7 @@ const (
IntegrationEnrollStep_INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB IntegrationEnrollStep = 9
IntegrationEnrollStep_INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS IntegrationEnrollStep = 10
IntegrationEnrollStep_INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW IntegrationEnrollStep = 11
IntegrationEnrollStep_INTEGRATION_ENROLL_STEP_MWIGHAK8S_WELCOME IntegrationEnrollStep = 12
)
var IntegrationEnrollStep_name = map[int32]string{
@@ -438,6 +439,7 @@ var IntegrationEnrollStep_name = map[int32]string{
9: "INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB",
10: "INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS",
11: "INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW",
12: "INTEGRATION_ENROLL_STEP_MWIGHAK8S_WELCOME",
}
var IntegrationEnrollStep_value = map[string]int32{
@@ -453,6 +455,7 @@ var IntegrationEnrollStep_value = map[string]int32{
"INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB": 9,
"INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS": 10,
"INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW": 11,
"INTEGRATION_ENROLL_STEP_MWIGHAK8S_WELCOME": 12,
}
func (x IntegrationEnrollStep) String() string {
@@ -6317,413 +6320,413 @@ func init() {
}
var fileDescriptor_94cf2ca1c69fd564 = []byte{
// 6482 bytes of a gzipped FileDescriptorProto
// 6496 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x7d, 0x5b, 0x6c, 0x1c, 0xc9,
0x75, 0xe8, 0xf4, 0x90, 0x94, 0xc8, 0x92, 0x44, 0xb5, 0x5a, 0x12, 0x35, 0x22, 0x45, 0x3d, 0x46,
0x6f, 0xee, 0x2e, 0xb5, 0xd2, 0x6a, 0xbd, 0xda, 0x87, 0xbd, 0xdb, 0xec, 0x69, 0xce, 0xb4, 0x38,
0x33, 0x3d, 0x5b, 0xdd, 0x23, 0x9a, 0x6b, 0x18, 0x75, 0x9b, 0xd3, 0x45, 0xb2, 0x2f, 0x87, 0xd3,
0xe3, 0xee, 0x1e, 0x72, 0x89, 0x0b, 0xc3, 0xbe, 0xbe, 0xf7, 0x1a, 0x17, 0xd7, 0xf6, 0x75, 0x02,
0x24, 0x46, 0x80, 0x0d, 0xf2, 0x40, 0x9e, 0x80, 0x03, 0xe4, 0xcb, 0xf0, 0x57, 0x3e, 0xf2, 0x17,
0x20, 0xf9, 0x30, 0x90, 0xbf, 0xe4, 0x27, 0xf0, 0x57, 0xfe, 0xfc, 0x95, 0x00, 0x89, 0xf3, 0x42,
0x3d, 0x7a, 0xa6, 0x67, 0xa6, 0x7b, 0xba, 0xb5, 0xd1, 0xc6, 0x86, 0xf6, 0x8f, 0x53, 0x75, 0x5e,
0x75, 0xea, 0xd4, 0x39, 0xa7, 0xaa, 0x4e, 0x35, 0xc1, 0xfd, 0x00, 0xb7, 0x71, 0xd7, 0xf5, 0x82,
0x07, 0x3d, 0xdf, 0xda, 0xc5, 0xf8, 0x10, 0x77, 0x02, 0xff, 0xc1, 0xe1, 0xc3, 0xe8, 0xcf, 0xd5,
0xae, 0xe7, 0x06, 0xae, 0x74, 0x29, 0x04, 0x5d, 0x8d, 0xf6, 0x1d, 0x3e, 0x5c, 0xbc, 0xdb, 0xa7,
0x61, 0xb5, 0x5a, 0xd8, 0xf7, 0xdb, 0x8e, 0x1f, 0x10, 0x12, 0x83, 0x5f, 0x8c, 0x42, 0x71, 0x05,
0x48, 0x4d, 0x6d, 0xcd, 0xea, 0x74, 0xb0, 0xa7, 0xb4, 0x9d, 0xd6, 0xbe, 0x4a, 0x48, 0x48, 0x17,
0xc0, 0x8c, 0xd5, 0xc6, 0x5e, 0x50, 0x10, 0xae, 0x0b, 0xf7, 0xe6, 0x20, 0xfb, 0x51, 0x5c, 0x07,
0xf7, 0x9a, 0x9a, 0xde, 0xd9, 0x76, 0x2d, 0xcf, 0x56, 0xdc, 0x83, 0x6e, 0x1b, 0x07, 0xb8, 0xec,
0x9a, 0x6e, 0xc9, 0xf2, 0xf7, 0x58, 0xe3, 0x80, 0xc2, 0x22, 0x98, 0xed, 0xf9, 0xd8, 0xeb, 0x58,
0x07, 0x98, 0x13, 0xe9, 0xff, 0x2e, 0xde, 0x06, 0x37, 0xfb, 0x74, 0x64, 0xdb, 0x5e, 0x77, 0x3c,
0x3f, 0x80, 0xd8, 0x77, 0x7b, 0x5e, 0x0b, 0x0f, 0x48, 0x14, 0x57, 0x22, 0xec, 0x46, 0xc1, 0xaa,
0x56, 0x10, 0x15, 0xb8, 0xf8, 0x3e, 0xb8, 0xd1, 0x87, 0x35, 0x70, 0xa0, 0x78, 0xd8, 0xc6, 0x9d,
0xc0, 0xb1, 0xda, 0x46, 0x6f, 0xfb, 0xc0, 0x09, 0xd2, 0x65, 0x8a, 0x12, 0xf8, 0xb0, 0x87, 0xfd,
0xc0, 0x71, 0x3b, 0x1d, 0xcb, 0xf1, 0x70, 0x56, 0x02, 0x5f, 0x07, 0xb7, 0xfb, 0x04, 0x20, 0xde,
0x75, 0x7c, 0x22, 0xe0, 0x9e, 0xd5, 0x6e, 0xe3, 0xce, 0x6e, 0x56, 0x22, 0xd2, 0x65, 0x30, 0x7b,
0xb0, 0x63, 0xa1, 0xe0, 0xb8, 0x8b, 0x0b, 0x79, 0xda, 0x77, 0xf2, 0x60, 0xc7, 0x32, 0x8f, 0xbb,
0x58, 0x5a, 0x06, 0xa0, 0xed, 0xee, 0x3a, 0x1d, 0xb4, 0xd3, 0x76, 0x8f, 0x0a, 0x53, 0xb4, 0x73,
0x8e, 0xb6, 0xac, 0xb7, 0xdd, 0x23, 0x26, 0x3f, 0xc4, 0x2d, 0xf7, 0x10, 0x7b, 0xc7, 0x8a, 0x6b,
0x63, 0x5f, 0x71, 0x3b, 0x81, 0xd3, 0xe9, 0xe1, 0x8c, 0x93, 0xf2, 0x2e, 0x58, 0x1e, 0x23, 0xd0,
0x3d, 0xce, 0x88, 0xfc, 0x1e, 0xb8, 0x3a, 0x82, 0xdc, 0xf0, 0x9c, 0x4e, 0x90, 0x11, 0xbb, 0x08,
0xc4, 0x92, 0xe3, 0x53, 0xe4, 0x1a, 0x0e, 0x2c, 0xdb, 0x0a, 0x2c, 0x69, 0x1e, 0xe4, 0x1d, 0x9b,
0x43, 0xe6, 0x1d, 0xbb, 0x68, 0x81, 0x42, 0x08, 0x13, 0xda, 0x40, 0x1f, 0x56, 0x05, 0xb3, 0x1e,
0x6f, 0xa3, 0x18, 0xf3, 0x8f, 0xee, 0xaf, 0x26, 0x2c, 0x8c, 0xd5, 0x51, 0x22, 0xb0, 0x8f, 0x5a,
0xdc, 0x07, 0x52, 0xd8, 0x6b, 0x04, 0xb8, 0x6b, 0x04, 0x56, 0xd0, 0xf3, 0xa5, 0xf7, 0xc1, 0x09,
0x9f, 0xfe, 0xc5, 0x49, 0xdf, 0x4d, 0x25, 0xcd, 0x10, 0x21, 0x47, 0x23, 0x6b, 0x09, 0x7b, 0x9e,
0xeb, 0xf1, 0x09, 0x65, 0x3f, 0x8a, 0xbf, 0x2f, 0x80, 0x85, 0xa6, 0x16, 0x41, 0xf1, 0x02, 0x6c,
0x33, 0x55, 0xa9, 0x60, 0xf6, 0x80, 0x0f, 0x8d, 0xf2, 0x3c, 0x95, 0x61, 0x38, 0xa1, 0x2e, 0x60,
0x1f, 0x55, 0x52, 0xfa, 0x82, 0xe7, 0x29, 0x91, 0x57, 0x32, 0x08, 0x1e, 0x8e, 0x3a, 0x14, 0xbe,
0xf8, 0xaf, 0x02, 0xb8, 0x3e, 0x10, 0x33, 0x54, 0x9a, 0x81, 0xdb, 0xb8, 0x45, 0x56, 0xc8, 0x0b,
0x15, 0xb8, 0x16, 0x99, 0x46, 0x26, 0xf2, 0xc3, 0xcc, 0xd3, 0x38, 0x20, 0x17, 0x92, 0x88, 0x8c,
0x7f, 0xea, 0xd3, 0x8f, 0xff, 0xff, 0xe4, 0x89, 0x13, 0x0a, 0x01, 0xb4, 0x4e, 0x80, 0x77, 0x3d,
0x8b, 0x8c, 0x5c, 0xde, 0x34, 0x74, 0xad, 0xa4, 0x28, 0x6e, 0xa7, 0x83, 0x5b, 0xc1, 0x4b, 0xaf,
0x87, 0x1f, 0xe7, 0xa3, 0x76, 0x50, 0xb2, 0x02, 0x6b, 0xdb, 0xf2, 0x31, 0x2c, 0x19, 0x6a, 0xc7,
0x73, 0xdb, 0xed, 0x97, 0x7d, 0xfc, 0xd2, 0x13, 0x50, 0xf0, 0xa9, 0xd1, 0x63, 0x1b, 0x85, 0x94,
0x7d, 0xd4, 0x72, 0x7b, 0x9d, 0xa0, 0x30, 0x7d, 0x5d, 0xb8, 0x37, 0x05, 0x17, 0xc2, 0xfe, 0x50,
0x14, 0x5f, 0x21, 0xbd, 0xc5, 0x7f, 0x12, 0xc0, 0x95, 0x81, 0xe6, 0x36, 0x7a, 0xdb, 0x58, 0xdd,
0xf8, 0x9c, 0x68, 0xad, 0xf8, 0x14, 0x14, 0x9a, 0x9a, 0x62, 0xb5, 0xdb, 0xa6, 0x2b, 0x53, 0x7f,
0x11, 0x09, 0x08, 0xab, 0x60, 0xaa, 0xc5, 0x47, 0x3c, 0xff, 0xe8, 0x4a, 0x22, 0x75, 0xc5, 0x94,
0x21, 0x01, 0x2c, 0x7e, 0x6f, 0x26, 0xaa, 0xc7, 0x12, 0xee, 0xb6, 0xdd, 0x63, 0x03, 0x7b, 0x87,
0x4e, 0x0b, 0xbf, 0xf4, 0xd6, 0xb7, 0x0b, 0xce, 0xd8, 0x74, 0xc0, 0xe8, 0x00, 0x07, 0x7b, 0xae,
0x4d, 0x4d, 0x6e, 0xfe, 0xd1, 0x5a, 0x22, 0xad, 0x49, 0x8a, 0x5a, 0x65, 0x4d, 0x35, 0x4a, 0x09,
0x9e, 0xb6, 0x23, 0xbf, 0x24, 0x0b, 0x9c, 0xe2, 0x8c, 0x68, 0x0a, 0x32, 0x43, 0xd9, 0x7c, 0xf0,
0x9f, 0x61, 0x43, 0x72, 0x17, 0x08, 0xec, 0xfe, 0xdf, 0x45, 0x04, 0x4e, 0x47, 0x05, 0x90, 0x96,
0xc1, 0xe5, 0x92, 0xda, 0xa8, 0xea, 0x5b, 0xa8, 0xa6, 0x9a, 0x15, 0xbd, 0x84, 0x9a, 0x75, 0xa3,
0xa1, 0x2a, 0xda, 0xba, 0xa6, 0x96, 0xc4, 0x9c, 0xb4, 0x00, 0xa4, 0xe1, 0x6e, 0xb9, 0x69, 0xea,
0xa2, 0x20, 0x15, 0xc0, 0x85, 0xe1, 0xf6, 0x9a, 0x5c, 0x6f, 0xca, 0x55, 0x31, 0x5f, 0xc4, 0x00,
0x0c, 0x58, 0x4b, 0x4b, 0xe0, 0x12, 0x87, 0x33, 0xb7, 0x1a, 0xea, 0x08, 0xf1, 0xab, 0x60, 0x31,
0xda, 0xa9, 0xd5, 0x0d, 0x53, 0xae, 0x56, 0x91, 0xa1, 0x40, 0xad, 0x61, 0x8a, 0x82, 0xb4, 0x08,
0x16, 0xa2, 0xfd, 0x72, 0x4d, 0xfe, 0x48, 0xaf, 0x23, 0x55, 0x31, 0xc4, 0x7c, 0xf1, 0x93, 0x69,
0x70, 0x6b, 0x30, 0x7e, 0xc5, 0xc3, 0x56, 0x80, 0xc3, 0x5f, 0xc7, 0x8a, 0xdb, 0xd9, 0x71, 0x76,
0x5f, 0x7a, 0xbb, 0x74, 0xc1, 0x99, 0x16, 0x1d, 0xe9, 0xb0, 0x5d, 0x3e, 0xcd, 0x60, 0x30, 0xc9,
0x0a, 0x5b, 0x65, 0x7f, 0x87, 0xf6, 0xd9, 0x8a, 0xfc, 0x2a, 0xfe, 0xa1, 0x00, 0x4e, 0x47, 0xbb,
0x89, 0xf5, 0x28, 0x7a, 0x7d, 0x5d, 0x2b, 0xc7, 0x5b, 0xcf, 0x58, 0xb7, 0xbc, 0x69, 0x20, 0x55,
0x79, 0x84, 0x0c, 0xa3, 0x26, 0x0a, 0x64, 0xfe, 0xe3, 0xbb, 0x55, 0x4d, 0x51, 0xc5, 0x7c, 0x3c,
0x3a, 0x2c, 0x19, 0xd4, 0x04, 0xa6, 0xa4, 0xcb, 0xe0, 0x62, 0x0c, 0xfa, 0x86, 0x21, 0x4e, 0x17,
0xff, 0x45, 0x00, 0xd7, 0x62, 0xe2, 0x25, 0xdf, 0x17, 0xbc, 0xf4, 0x8e, 0xff, 0x7f, 0xe6, 0xa3,
0x8b, 0x23, 0x1c, 0x3e, 0x9b, 0xb9, 0x9e, 0x87, 0x6b, 0x66, 0xd5, 0x78, 0xe9, 0x75, 0xf0, 0xff,
0xf3, 0xe0, 0x61, 0xd4, 0x41, 0xfa, 0xfb, 0x81, 0xdb, 0x25, 0x61, 0xf0, 0x10, 0x97, 0x1c, 0x0f,
0xb7, 0x02, 0xd7, 0x3b, 0x36, 0x5d, 0xb7, 0xed, 0x6b, 0x1d, 0x3f, 0xb0, 0x3e, 0x07, 0xd9, 0xc0,
0x77, 0xf2, 0x60, 0x35, 0x4d, 0x21, 0x7d, 0x13, 0x79, 0xe9, 0xb5, 0xf1, 0x27, 0x79, 0x70, 0x67,
0xa0, 0x0d, 0xb9, 0x17, 0xb8, 0xe1, 0xdf, 0x91, 0x14, 0xf2, 0xa5, 0x8f, 0x20, 0x77, 0xc1, 0xd9,
0xf8, 0x74, 0x7a, 0xde, 0x1b, 0x4e, 0xa3, 0xbf, 0x99, 0x07, 0x37, 0x07, 0xea, 0x52, 0x95, 0x47,
0x74, 0xd5, 0x74, 0x3e, 0x4f, 0x7b, 0xd1, 0x7f, 0x14, 0xc0, 0xe5, 0xd1, 0x8c, 0x8b, 0x04, 0xaa,
0xcf, 0xd9, 0xc0, 0x59, 0xe6, 0x50, 0x77, 0xed, 0x97, 0xdf, 0x47, 0xfc, 0x5c, 0x00, 0x57, 0x47,
0x07, 0x2e, 0x77, 0xbb, 0x24, 0xcd, 0xfe, 0x1c, 0x24, 0x11, 0xdf, 0xce, 0x83, 0xfb, 0x13, 0x92,
0x08, 0x4d, 0xae, 0x35, 0xdc, 0xb6, 0xd3, 0x3a, 0x7e, 0xe9, 0x15, 0xf1, 0xef, 0x02, 0x28, 0x0e,
0x14, 0xd1, 0xf0, 0x9c, 0x4e, 0xcb, 0xe9, 0x5a, 0x6d, 0xff, 0xf3, 0x13, 0x2c, 0xff, 0x59, 0x00,
0xcb, 0x03, 0x0d, 0x98, 0xd8, 0x0f, 0xf8, 0xc1, 0xdb, 0xe7, 0xc1, 0xef, 0xff, 0x83, 0x00, 0x0a,
0x11, 0x2f, 0xc0, 0x2f, 0x5e, 0xec, 0x97, 0x7e, 0xdc, 0x4b, 0xc4, 0xeb, 0x73, 0x6f, 0x8f, 0x8f,
0xa0, 0xdb, 0x8e, 0x5e, 0x0e, 0xfd, 0x15, 0xb5, 0x88, 0xa1, 0x5e, 0xc3, 0x3a, 0x8c, 0x5e, 0x76,
0xdc, 0x04, 0x67, 0x48, 0x86, 0x60, 0x5b, 0x9e, 0x8d, 0x7a, 0x3e, 0x66, 0x97, 0x09, 0xb3, 0xf0,
0x74, 0xd8, 0xd8, 0xf4, 0xb1, 0x2d, 0x2d, 0x81, 0xb9, 0x63, 0xeb, 0xa0, 0xcd, 0x00, 0xf2, 0x14,
0x60, 0x96, 0x34, 0xd0, 0xce, 0x3b, 0xe0, 0xec, 0x81, 0x6b, 0x63, 0x74, 0xb4, 0x87, 0x3b, 0xc8,
0xb7, 0x0e, 0xb1, 0xcd, 0xef, 0x5d, 0xce, 0x90, 0xe6, 0xcd, 0x3d, 0xdc, 0x21, 0x2c, 0x6d, 0x49,
0x06, 0xcb, 0x3b, 0x0e, 0x6e, 0xdb, 0x3e, 0x3a, 0x72, 0x82, 0x3d, 0xd4, 0x72, 0x3b, 0x87, 0xd8,
0xf3, 0x1d, 0xb7, 0x83, 0xe8, 0x59, 0xbf, 0x5f, 0x98, 0xbe, 0x3e, 0x75, 0x6f, 0x0e, 0x2e, 0x32,
0xa0, 0x4d, 0x27, 0xd8, 0x53, 0xfa, 0x20, 0x2a, 0x85, 0x28, 0xde, 0x20, 0xdb, 0xc5, 0xe1, 0xb1,
0x92, 0xe4, 0xa6, 0x1d, 0x19, 0xf1, 0xab, 0x60, 0x65, 0x04, 0xe4, 0x99, 0x83, 0x8f, 0x4a, 0x6e,
0xab, 0x77, 0x80, 0x3b, 0x81, 0x35, 0x7c, 0xbc, 0x56, 0xfc, 0x91, 0x00, 0x2e, 0xca, 0xbe, 0xef,
0x90, 0x95, 0x42, 0x0d, 0xa6, 0xbf, 0x52, 0xee, 0x82, 0xb3, 0x5c, 0x42, 0x8a, 0x83, 0xfa, 0xd7,
0x2c, 0xf3, 0xd1, 0x66, 0xcd, 0x96, 0x6e, 0x80, 0xd3, 0x81, 0x1b, 0x58, 0x6d, 0x14, 0xb8, 0xfb,
0xb8, 0xc3, 0xae, 0x11, 0xa6, 0xe0, 0x29, 0xda, 0x66, 0xd2, 0x26, 0xa2, 0xe3, 0xae, 0xe7, 0x1e,
0x74, 0x83, 0x10, 0x66, 0x8a, 0xc2, 0x9c, 0x66, 0x8d, 0x1c, 0xe8, 0x15, 0x70, 0xae, 0xd5, 0x97,
0x21, 0x04, 0x64, 0x59, 0x9e, 0x38, 0xe8, 0x60, 0xc0, 0xc5, 0xbf, 0x16, 0xc0, 0x05, 0x26, 0xb7,
0xfa, 0x31, 0x6e, 0xf5, 0x3e, 0x85, 0xd8, 0xcb, 0x00, 0x74, 0xc8, 0xac, 0xb1, 0x6c, 0x92, 0x09,
0x3d, 0x47, 0x5a, 0x68, 0x22, 0x39, 0x36, 0xaa, 0xa9, 0x0c, 0xa3, 0x9a, 0xce, 0x3a, 0xaa, 0x99,
0x84, 0x51, 0x3d, 0x01, 0x8b, 0x6c, 0x50, 0x75, 0x7c, 0xa4, 0x44, 0xc4, 0xed, 0xdf, 0x8d, 0xb5,
0xac, 0x00, 0xef, 0xba, 0xde, 0x71, 0x78, 0x37, 0x16, 0xfe, 0x2e, 0xfe, 0xa9, 0x00, 0xce, 0x33,
0x54, 0x99, 0x5e, 0xdd, 0x42, 0xfc, 0xb5, 0x1e, 0xf6, 0xa9, 0x75, 0x87, 0xab, 0x8d, 0x9d, 0xd5,
0x31, 0xc4, 0xd3, 0x61, 0x23, 0x3d, 0xfc, 0xfa, 0x85, 0xcc, 0xe0, 0x27, 0x02, 0x38, 0x1d, 0x4a,
0x4c, 0x9a, 0xa5, 0x05, 0x70, 0xc2, 0xa2, 0x7f, 0x71, 0x19, 0xf9, 0xaf, 0x5f, 0x8c, 0x74, 0xb7,
0x80, 0xc4, 0x14, 0x59, 0x75, 0xfc, 0x20, 0xf1, 0xb6, 0xf1, 0x1b, 0xa0, 0x10, 0x85, 0x3a, 0xd8,
0x8e, 0xdc, 0x4c, 0x4a, 0x60, 0x3a, 0x72, 0x8b, 0x49, 0xff, 0x96, 0x74, 0x70, 0xf6, 0x80, 0x42,
0xf9, 0x7b, 0x4e, 0x17, 0xed, 0x3b, 0x1d, 0xe6, 0x4c, 0xe6, 0x1f, 0xdd, 0x19, 0x38, 0xbe, 0xc8,
0xd5, 0xfb, 0xe1, 0xc3, 0xd5, 0x5a, 0x1f, 0x7c, 0xc3, 0xe9, 0xd8, 0x70, 0xfe, 0x60, 0xe8, 0x77,
0xf1, 0x2b, 0x40, 0x1c, 0x08, 0xc0, 0x16, 0xbd, 0x54, 0x1e, 0x73, 0xf5, 0xc9, 0x6e, 0x75, 0x7c,
0x8c, 0x03, 0x67, 0x3f, 0x4c, 0xbc, 0xd9, 0xb5, 0x3f, 0x3b, 0xe2, 0x25, 0x4c, 0x42, 0xd5, 0x8b,
0x23, 0xfe, 0x67, 0x02, 0x58, 0x18, 0x9d, 0x98, 0x17, 0xac, 0x1d, 0xe9, 0xa3, 0x70, 0x2e, 0x51,
0x9f, 0x5e, 0x5a, 0x44, 0x4c, 0xb2, 0x95, 0x70, 0x5a, 0x6b, 0x93, 0xe4, 0x7f, 0xc1, 0x13, 0xf0,
0x5f, 0x2e, 0xff, 0x0b, 0x9e, 0xe3, 0xcf, 0x54, 0xfe, 0xdf, 0xce, 0x47, 0xe5, 0x2f, 0x7b, 0x56,
0x27, 0xf0, 0x4d, 0xb7, 0xe9, 0x63, 0x4f, 0x5a, 0x05, 0xe7, 0x69, 0xc4, 0x40, 0x9e, 0xdb, 0xc6,
0x3e, 0xda, 0x25, 0x7d, 0x3c, 0x69, 0x98, 0x81, 0xe7, 0x68, 0x17, 0x89, 0xb9, 0x7e, 0x99, 0x75,
0x90, 0xa0, 0xcf, 0xe0, 0x9d, 0xce, 0x1e, 0xf6, 0x1c, 0x7a, 0x31, 0x38, 0x84, 0x39, 0x45, 0x31,
0x17, 0x29, 0x90, 0x16, 0xc2, 0x0c, 0x91, 0x78, 0x1d, 0x5c, 0x60, 0x24, 0x02, 0xcf, 0x72, 0x82,
0x01, 0x66, 0x9e, 0x62, 0x4a, 0xb4, 0xcf, 0xa4, 0x5d, 0x21, 0x86, 0x02, 0xae, 0x8e, 0x32, 0x1d,
0xc1, 0x9d, 0xa6, 0xb8, 0x4b, 0xc3, 0x5c, 0x87, 0x89, 0x2c, 0x81, 0xb9, 0x9e, 0x8f, 0x3d, 0x44,
0xbd, 0xd8, 0xcc, 0xa0, 0x16, 0xa3, 0x6e, 0x1d, 0xe0, 0xe2, 0x0f, 0xa6, 0xa2, 0x1a, 0x82, 0xf8,
0xd0, 0xc1, 0x47, 0x2f, 0x7a, 0x85, 0x3d, 0x01, 0x97, 0x6d, 0xeb, 0xd8, 0x47, 0x5d, 0xcb, 0x0f,
0x50, 0x07, 0x7f, 0x1c, 0x20, 0xab, 0x67, 0x3b, 0x01, 0x22, 0xeb, 0x80, 0x0f, 0xfe, 0x22, 0x01,
0x68, 0x58, 0x24, 0x60, 0x7e, 0x1c, 0xc8, 0xa4, 0xb7, 0x44, 0x44, 0x58, 0x07, 0xd7, 0x22, 0x7e,
0xd6, 0xc3, 0x5f, 0xeb, 0x39, 0x1e, 0x26, 0xe9, 0x8f, 0x8f, 0x5a, 0x7b, 0x56, 0x67, 0x97, 0xab,
0x7d, 0x16, 0x2e, 0x0f, 0xc0, 0x60, 0x04, 0x4a, 0x61, 0x40, 0xd2, 0x13, 0x50, 0xf0, 0xe8, 0xd0,
0xd0, 0x0e, 0x21, 0x82, 0x3b, 0xad, 0xe3, 0x3e, 0x81, 0x69, 0x4a, 0x60, 0x81, 0xf5, 0xaf, 0x87,
0xdd, 0x21, 0xe6, 0x7b, 0x60, 0x89, 0x63, 0xda, 0xd6, 0x31, 0x72, 0x77, 0xd0, 0x81, 0xdb, 0x21,
0x39, 0x1f, 0x47, 0x9e, 0xa1, 0xc8, 0x97, 0x18, 0x48, 0xc9, 0x3a, 0xd6, 0x77, 0x6a, 0xa4, 0x3f,
0xc4, 0x7e, 0x1b, 0x5c, 0xee, 0xf4, 0xa8, 0x6d, 0xbb, 0x3b, 0xc8, 0xc3, 0x07, 0xee, 0x21, 0xb6,
0x11, 0x17, 0xb5, 0x70, 0x82, 0x8e, 0x7c, 0x81, 0x01, 0xe8, 0x3b, 0x90, 0x75, 0xf3, 0x40, 0x51,
0xfc, 0x35, 0x61, 0x7c, 0x62, 0x5e, 0xf4, 0xd2, 0x7b, 0x08, 0x2e, 0xb2, 0x28, 0x85, 0x48, 0x98,
0x42, 0x7c, 0xa0, 0x8e, 0xcd, 0x4b, 0x57, 0x24, 0x6b, 0x84, 0xbf, 0x66, 0x17, 0xbf, 0x2b, 0x80,
0xcb, 0x91, 0xb2, 0x08, 0x76, 0xb1, 0x9d, 0x14, 0x57, 0xa5, 0x35, 0x30, 0x1d, 0x09, 0x8e, 0xab,
0x89, 0x52, 0x8e, 0x51, 0xa4, 0x41, 0x92, 0xe2, 0x0e, 0x9b, 0xef, 0xd4, 0x88, 0xf9, 0xba, 0x64,
0x57, 0x30, 0x86, 0x4d, 0xcb, 0x6b, 0x58, 0xae, 0x55, 0x1f, 0xd3, 0xd5, 0xa3, 0xec, 0x52, 0xc4,
0x44, 0x24, 0x0f, 0x5c, 0x8f, 0x61, 0x18, 0x6e, 0xd2, 0x3e, 0x1b, 0x9e, 0x5f, 0x07, 0x4b, 0x31,
0x43, 0xec, 0x57, 0x2c, 0x55, 0xc0, 0x74, 0xcb, 0xb5, 0xc3, 0x52, 0xa8, 0xc7, 0xd9, 0x59, 0x31,
0x7c, 0xc5, 0xb5, 0x31, 0xa4, 0x14, 0x12, 0x4a, 0x97, 0xbe, 0x99, 0x07, 0x57, 0x62, 0x95, 0x8c,
0xbb, 0x9f, 0xc9, 0x78, 0x89, 0xd5, 0xf8, 0x01, 0xee, 0x3e, 0xbf, 0xd5, 0x10, 0x91, 0x20, 0xc5,
0x95, 0xaa, 0x23, 0x3b, 0xd2, 0xc7, 0xcf, 0x47, 0x65, 0xfc, 0x68, 0xea, 0x66, 0x9c, 0x0a, 0xd8,
0x89, 0x84, 0xde, 0xc5, 0x9d, 0x5f, 0x5e, 0x4d, 0x6c, 0x80, 0x93, 0x3e, 0x93, 0x93, 0xaa, 0x62,
0x7e, 0x42, 0x5c, 0x4d, 0x1a, 0x20, 0x0c, 0x29, 0x14, 0xbf, 0x95, 0x07, 0xb7, 0x63, 0x14, 0xb1,
0x4e, 0x76, 0xba, 0x9f, 0xe9, 0x22, 0x78, 0x21, 0xaa, 0x50, 0xc1, 0x0c, 0xdd, 0x93, 0x73, 0x45,
0x3c, 0xc8, 0x4e, 0x84, 0x0e, 0x10, 0x32, 0xec, 0xe2, 0xbf, 0x09, 0x09, 0x4e, 0x80, 0xec, 0x39,
0xbb, 0xc7, 0xbf, 0xbc, 0xe3, 0x5f, 0x07, 0xd3, 0x74, 0xef, 0xc8, 0x86, 0xff, 0x1c, 0xf2, 0x90,
0xa1, 0xd1, 0xca, 0x0e, 0x8a, 0x5f, 0xfc, 0x4b, 0x01, 0xdc, 0x88, 0x51, 0x40, 0xd5, 0xe9, 0xec,
0x47, 0x0e, 0x64, 0x7e, 0x19, 0x35, 0x20, 0x81, 0xe9, 0xb6, 0xd3, 0xd9, 0xe7, 0x71, 0x84, 0xfe,
0x5d, 0xfc, 0x5b, 0x01, 0x9c, 0xef, 0x97, 0x23, 0xd3, 0xd4, 0xa7, 0x7f, 0xa0, 0x94, 0xbe, 0xe5,
0x8e, 0x5c, 0x68, 0x21, 0xd7, 0x73, 0x76, 0x9d, 0x0e, 0x77, 0x9e, 0xfd, 0x0b, 0x2d, 0x9d, 0xb6,
0x4a, 0xb7, 0xc1, 0x7c, 0xab, 0xed, 0xf6, 0x6c, 0xd4, 0xf5, 0xdc, 0x43, 0xc7, 0xc6, 0x5e, 0x78,
0xb6, 0x44, 0x5b, 0x1b, 0xbc, 0x51, 0xd2, 0xc1, 0xac, 0xcd, 0x4f, 0xbe, 0x69, 0x66, 0x72, 0xea,
0xd1, 0x1b, 0xa9, 0x67, 0x69, 0xd8, 0x0e, 0x0f, 0xcb, 0x07, 0x5a, 0x0b, 0x89, 0x14, 0x9f, 0x81,
0xc5, 0x64, 0x38, 0xe9, 0x12, 0x38, 0x69, 0x6f, 0x47, 0x47, 0x77, 0xc2, 0xde, 0xa6, 0xe3, 0xba,
0x06, 0x4e, 0xd9, 0xdb, 0x88, 0xd6, 0x8c, 0xb7, 0xdc, 0x36, 0x1f, 0x13, 0xb0, 0xb7, 0x1b, 0xbc,
0xa5, 0xf8, 0x33, 0x01, 0x2c, 0xae, 0x63, 0x2b, 0xe8, 0x79, 0x18, 0xe2, 0x96, 0x7b, 0x70, 0x80,
0x3b, 0x76, 0xe4, 0x8c, 0x63, 0x28, 0x6a, 0x0b, 0xc3, 0x51, 0x5b, 0x7a, 0x07, 0x9c, 0xdc, 0x61,
0xa8, 0x7c, 0x32, 0xaf, 0x27, 0x8e, 0x31, 0x64, 0x11, 0x22, 0x48, 0x1f, 0x83, 0x65, 0xfe, 0x27,
0xf2, 0x86, 0xf8, 0xa2, 0x88, 0xbf, 0x9f, 0x14, 0x06, 0x63, 0x85, 0xe6, 0xfe, 0x7e, 0x69, 0x27,
0xb9, 0xb3, 0x78, 0x04, 0x2e, 0x98, 0x72, 0x99, 0x1d, 0x53, 0xe1, 0x0f, 0x7b, 0xd8, 0xe3, 0x2b,
0xfd, 0x1a, 0x60, 0x67, 0x18, 0xa8, 0xe3, 0xda, 0x98, 0x95, 0x0d, 0x4f, 0x41, 0x40, 0x9b, 0xea,
0xa4, 0x65, 0x00, 0x80, 0xed, 0x5d, 0x1c, 0x9e, 0x7b, 0x30, 0x00, 0x95, 0xb4, 0x48, 0xcb, 0x00,
0x38, 0x3e, 0xf2, 0x7b, 0x34, 0xdd, 0xe2, 0x19, 0xed, 0x9c, 0xe3, 0x1b, 0xac, 0xa1, 0xf8, 0xf7,
0x53, 0xe0, 0x12, 0xcb, 0xe3, 0xca, 0x9e, 0xd5, 0xdd, 0x93, 0x37, 0x0d, 0xa3, 0x65, 0x75, 0xc2,
0xb2, 0xba, 0xf3, 0x9c, 0x76, 0xeb, 0x11, 0x72, 0xf8, 0x1d, 0x29, 0x13, 0x62, 0x1a, 0x9e, 0x63,
0x3c, 0x5a, 0xfd, 0xcb, 0xd3, 0x88, 0x2c, 0x64, 0x32, 0x98, 0x2c, 0xd3, 0x5c, 0x16, 0xb2, 0x2d,
0xf2, 0x07, 0xa7, 0x34, 0xbb, 0x9e, 0xdb, 0xeb, 0x32, 0x69, 0xa6, 0xf9, 0x29, 0x4d, 0x99, 0x36,
0x0d, 0x68, 0xd0, 0x0d, 0x10, 0x35, 0xd3, 0x90, 0x06, 0xdd, 0xef, 0x10, 0x5b, 0x67, 0x00, 0x5d,
0xb7, 0xed, 0xb4, 0x1c, 0xcc, 0x0e, 0xca, 0xa6, 0xe1, 0x19, 0xda, 0xda, 0xe0, 0x8d, 0xd2, 0xab,
0x40, 0xe2, 0xb2, 0xef, 0xfb, 0xa8, 0xd5, 0xee, 0xf9, 0x41, 0x98, 0x16, 0x4f, 0x43, 0x91, 0x89,
0xbe, 0xef, 0x2b, 0xbc, 0x7d, 0x30, 0x52, 0xcf, 0xf6, 0x23, 0x23, 0x3d, 0x19, 0x19, 0x29, 0xb4,
0xfd, 0xc1, 0x48, 0xef, 0x01, 0x46, 0x03, 0xf9, 0x6f, 0xa0, 0xed, 0x5e, 0x6b, 0x1f, 0x07, 0x7e,
0x61, 0x96, 0x02, 0x33, 0xe1, 0x8c, 0x37, 0xd6, 0x58, 0x2b, 0xd9, 0x97, 0x71, 0x48, 0xeb, 0xa0,
0xdd, 0x5f, 0x9f, 0x7e, 0x61, 0x8e, 0x42, 0x33, 0x19, 0x0d, 0xeb, 0xa0, 0x1d, 0x2e, 0xd2, 0x08,
0x86, 0xeb, 0xd8, 0xad, 0x08, 0x06, 0x88, 0x60, 0xe8, 0x8e, 0xdd, 0x1a, 0x60, 0xf4, 0x55, 0x62,
0xb5, 0xe8, 0x5e, 0xcd, 0x2f, 0x9c, 0x8a, 0xa8, 0x44, 0xe6, 0x8d, 0xc5, 0x1f, 0x08, 0xe0, 0x56,
0x53, 0x8b, 0x4c, 0xb6, 0xe2, 0xb9, 0x47, 0x9d, 0xa7, 0xf8, 0x08, 0xb7, 0x4b, 0xce, 0xce, 0xce,
0x33, 0x07, 0x1f, 0xb1, 0x79, 0x7f, 0x02, 0x0a, 0xd6, 0xce, 0xce, 0x70, 0x81, 0x2a, 0x8a, 0xd4,
0xc4, 0xcf, 0xc1, 0x85, 0xb0, 0xbf, 0x5f, 0xc5, 0xcd, 0xce, 0xea, 0x1f, 0x83, 0x85, 0x71, 0xcc,
0xc8, 0x0b, 0x84, 0x0b, 0xa3, 0x78, 0xb4, 0x8c, 0x6f, 0x1d, 0x5c, 0x31, 0x70, 0xab, 0xe7, 0x39,
0xc1, 0x31, 0xa4, 0xcb, 0xaa, 0x8c, 0x03, 0x88, 0xfd, 0x5e, 0x9b, 0xe7, 0xd9, 0x71, 0xa7, 0x64,
0x12, 0x98, 0x26, 0xdb, 0x3a, 0xbe, 0xc5, 0xa3, 0x7f, 0x17, 0x2d, 0x70, 0xbe, 0x5f, 0x04, 0xb6,
0x8e, 0x83, 0xd6, 0x1e, 0x43, 0x1f, 0xf7, 0x8e, 0x42, 0x9c, 0x77, 0x1c, 0x73, 0xc9, 0xf9, 0x71,
0x97, 0x5c, 0xfc, 0xbe, 0x00, 0x24, 0x62, 0xcb, 0xa6, 0xe5, 0xef, 0x93, 0xa5, 0x8b, 0xfb, 0x1e,
0x29, 0xb0, 0xfc, 0xfd, 0xa8, 0xb3, 0x9b, 0x25, 0x0d, 0xe1, 0x6b, 0x0b, 0xc7, 0xf7, 0x7b, 0x43,
0x54, 0xe7, 0x68, 0x0b, 0xed, 0xbe, 0x00, 0x66, 0x88, 0x77, 0x09, 0xf7, 0x1f, 0xec, 0x07, 0xf1,
0xfd, 0x7d, 0x3b, 0x8c, 0x14, 0x33, 0xcc, 0xc0, 0xf9, 0x7e, 0x33, 0x2b, 0x66, 0xf8, 0xcd, 0x0f,
0xc0, 0xd9, 0x26, 0xf1, 0x42, 0x54, 0x12, 0xbd, 0x83, 0xf5, 0x1d, 0xa9, 0x09, 0xce, 0xf6, 0x1c,
0xb4, 0x4d, 0x5f, 0xe2, 0xa0, 0x16, 0x89, 0x9a, 0xa9, 0x7b, 0xb9, 0xf1, 0x87, 0x3b, 0x95, 0x1c,
0x3c, 0xd3, 0x73, 0x22, 0xad, 0xd2, 0x27, 0x02, 0xb8, 0xdf, 0x73, 0x90, 0xcb, 0x1e, 0xa6, 0x20,
0x7e, 0x1e, 0x8a, 0xd1, 0xae, 0x8b, 0x02, 0x17, 0xd9, 0xe1, 0xcb, 0x1d, 0xce, 0x91, 0xe5, 0xc6,
0xf2, 0x04, 0x8e, 0xd9, 0x9e, 0xff, 0x54, 0x72, 0xf0, 0x66, 0xcf, 0x49, 0x85, 0x95, 0xbe, 0x23,
0x80, 0x9b, 0x11, 0xe9, 0x2c, 0xdb, 0x46, 0x3b, 0x8e, 0x47, 0xb7, 0x9e, 0x7c, 0x56, 0x99, 0x5c,
0x2c, 0xf2, 0xbd, 0x97, 0x2e, 0x57, 0xf2, 0x73, 0xa2, 0x4a, 0x0e, 0x5e, 0xed, 0x8b, 0x14, 0x0b,
0x36, 0xaa, 0xab, 0x18, 0x69, 0xda, 0x56, 0xd0, 0x9f, 0x9d, 0x99, 0xac, 0xba, 0x4a, 0x79, 0xbb,
0x34, 0xa4, 0xab, 0x64, 0x58, 0xe9, 0x7f, 0x0b, 0xe0, 0x7a, 0x44, 0x3a, 0x1f, 0x07, 0xa8, 0xd5,
0x7f, 0xe6, 0x84, 0x7c, 0xfa, 0xc2, 0x88, 0x3a, 0xcb, 0x53, 0x8f, 0xde, 0x49, 0x17, 0x2a, 0xe9,
0x91, 0x54, 0x25, 0x07, 0xaf, 0xf4, 0xa5, 0x89, 0x01, 0x92, 0x7e, 0x45, 0x00, 0xb7, 0x22, 0x62,
0x78, 0xbc, 0xa4, 0x11, 0xb5, 0xc2, 0xb7, 0x4e, 0xa1, 0x28, 0x27, 0xa9, 0x28, 0x5f, 0x4a, 0x17,
0x65, 0xd2, 0x6b, 0xa9, 0x4a, 0x0e, 0x5e, 0xef, 0x8b, 0x93, 0x00, 0x18, 0x6a, 0xc6, 0xe3, 0xef,
0x8f, 0x10, 0xd9, 0xbb, 0x92, 0x05, 0xc8, 0xde, 0x3f, 0xf1, 0xe9, 0x9a, 0x4d, 0xd5, 0x4c, 0xca,
0xeb, 0x29, 0xa6, 0x99, 0x64, 0x20, 0xe9, 0x63, 0x70, 0x25, 0x4e, 0x8a, 0xee, 0x31, 0x97, 0x60,
0x8e, 0x4a, 0xf0, 0x85, 0xec, 0x12, 0x44, 0x9f, 0x5f, 0x55, 0x72, 0xb0, 0x30, 0xc6, 0x9d, 0x03,
0x48, 0xff, 0x03, 0x2c, 0x8f, 0x73, 0xee, 0x7a, 0x4e, 0x27, 0xe0, 0xac, 0x01, 0x65, 0xfd, 0x56,
0x56, 0xd6, 0x23, 0x8f, 0xb7, 0x2a, 0x39, 0x78, 0x79, 0x84, 0xf7, 0x00, 0x42, 0x6a, 0x83, 0xcb,
0x3d, 0x07, 0xd9, 0xdc, 0x89, 0x93, 0xac, 0xcb, 0x23, 0xa1, 0x84, 0x12, 0xa7, 0x41, 0xed, 0xd4,
0x84, 0x8d, 0x55, 0xfc, 0x13, 0xa8, 0x4a, 0x0e, 0x2e, 0xf4, 0x9c, 0xd8, 0xc7, 0x51, 0xdf, 0x61,
0xe6, 0xd7, 0x67, 0x37, 0x88, 0x75, 0x61, 0x1d, 0x18, 0xe7, 0x7c, 0x9a, 0x72, 0x7e, 0x3b, 0x03,
0xe7, 0xf8, 0x57, 0x4d, 0xcc, 0xf2, 0x52, 0x5e, 0x3e, 0x7d, 0x83, 0x1a, 0x5e, 0x5f, 0x18, 0x5e,
0x3b, 0xef, 0xb3, 0x32, 0x78, 0x2e, 0xc8, 0x19, 0x2a, 0xc8, 0x9b, 0x9f, 0xaa, 0x88, 0x9e, 0xd9,
0xdc, 0x84, 0x47, 0x0f, 0xff, 0x97, 0x39, 0xd0, 0x81, 0x04, 0x3c, 0xa1, 0x1f, 0xac, 0x4b, 0x26,
0xc4, 0x3c, 0x15, 0xe2, 0x49, 0x16, 0x21, 0xe2, 0x6a, 0x95, 0x2b, 0x39, 0x78, 0x2d, 0x22, 0x47,
0x6c, 0x39, 0xf3, 0x6f, 0x30, 0xef, 0x39, 0x2e, 0x4a, 0x2b, 0x2c, 0x53, 0x41, 0x07, 0x41, 0xdb,
0xe7, 0x02, 0x9d, 0xa5, 0x02, 0x7d, 0xf1, 0x39, 0x04, 0x1a, 0xaf, 0x1e, 0xae, 0xe4, 0xe0, 0xad,
0x71, 0xa9, 0x06, 0x70, 0x41, 0x9b, 0x17, 0x50, 0xfe, 0xb9, 0x00, 0x9e, 0x0c, 0xcf, 0x13, 0xad,
0x3d, 0x45, 0x16, 0x2d, 0x3e, 0x45, 0x76, 0x58, 0x7d, 0x8a, 0x02, 0xd7, 0x6d, 0xf3, 0x64, 0xb2,
0xdd, 0xe6, 0x92, 0x8a, 0x54, 0xd2, 0xa7, 0x99, 0xe6, 0x2f, 0x53, 0x8d, 0x6f, 0x25, 0x07, 0x1f,
0x46, 0x27, 0x35, 0x5b, 0x61, 0xf0, 0x8f, 0x05, 0xf0, 0x38, 0xd3, 0x18, 0x06, 0xea, 0x66, 0xf2,
0x9f, 0xa3, 0xf2, 0x97, 0x3f, 0xb5, 0xfc, 0xc3, 0x55, 0x46, 0x95, 0x1c, 0x5c, 0x4d, 0x13, 0x7e,
0xa4, 0x2e, 0xe9, 0xb7, 0x04, 0xf0, 0x4a, 0x54, 0x72, 0xab, 0x47, 0x32, 0x8f, 0xfe, 0x1e, 0x34,
0xf2, 0x9e, 0x8a, 0x09, 0x2c, 0x51, 0x81, 0xdf, 0xcf, 0x20, 0xf0, 0xa4, 0xaa, 0xd9, 0x4a, 0x0e,
0xde, 0x19, 0x08, 0x3a, 0xb1, 0xbe, 0xf6, 0x8f, 0x05, 0xf0, 0x20, 0xc5, 0x72, 0x1d, 0xeb, 0x80,
0x6d, 0x5e, 0x8e, 0xb9, 0x90, 0xe7, 0xa9, 0x90, 0x6b, 0x9f, 0xc6, 0x7e, 0x87, 0x0b, 0xd7, 0x2a,
0x39, 0x78, 0x7f, 0x82, 0x11, 0x6b, 0xd6, 0x41, 0xb4, 0xca, 0xed, 0x57, 0x05, 0x70, 0x27, 0x2a,
0x6a, 0xb7, 0x5f, 0x0c, 0x36, 0x36, 0xef, 0x17, 0xa8, 0x84, 0xef, 0x66, 0x90, 0x30, 0xa9, 0xa2,
0xac, 0x92, 0x83, 0xc5, 0x81, 0x68, 0x89, 0x75, 0x67, 0xdf, 0x12, 0xc0, 0x8d, 0xa8, 0x4c, 0x01,
0xf6, 0x03, 0x22, 0x4d, 0x67, 0xc8, 0x1f, 0x5f, 0x4c, 0x8d, 0x7e, 0x13, 0xca, 0xbb, 0x2a, 0x39,
0xb8, 0x3c, 0x90, 0x24, 0xae, 0xfe, 0xcb, 0x03, 0x4b, 0x51, 0x19, 0xc2, 0x3c, 0x37, 0x8c, 0x43,
0x0b, 0x29, 0x37, 0x88, 0x49, 0xf5, 0x55, 0x2c, 0xec, 0x26, 0xd4, 0x5e, 0xb5, 0x41, 0xa1, 0xe7,
0x90, 0x24, 0xcc, 0x0a, 0x30, 0xea, 0xe0, 0x23, 0xba, 0xff, 0xe5, 0x11, 0xf7, 0x52, 0xca, 0x01,
0x57, 0x62, 0x65, 0x53, 0x25, 0x07, 0x2f, 0xf4, 0x9c, 0xf1, 0x4e, 0xe9, 0x98, 0x06, 0xf9, 0x51,
0x6e, 0xbe, 0x75, 0x18, 0xb2, 0x2c, 0xa4, 0x6a, 0x78, 0x42, 0xb9, 0x14, 0x1b, 0x68, 0x3c, 0x80,
0xf4, 0x0d, 0x70, 0x2d, 0x6e, 0xa0, 0xb4, 0x42, 0x89, 0x33, 0xbf, 0x9c, 0x1a, 0x60, 0x26, 0x56,
0x37, 0x55, 0x72, 0x70, 0x71, 0x74, 0xd4, 0x03, 0x10, 0xe9, 0x77, 0x99, 0x0b, 0x19, 0x95, 0x80,
0xdd, 0xc3, 0x45, 0x2b, 0xa0, 0xb8, 0x34, 0x8b, 0x54, 0x1a, 0x25, 0xab, 0x34, 0x13, 0x0a, 0xa9,
0x2a, 0x39, 0x78, 0x7b, 0x44, 0xb0, 0x78, 0x68, 0xe9, 0x0f, 0x04, 0xb0, 0x1a, 0x35, 0x41, 0x67,
0x70, 0xec, 0x88, 0xac, 0x23, 0x9f, 0x1d, 0x0d, 0xf0, 0x65, 0xc1, 0xad, 0x72, 0x29, 0x75, 0x0b,
0x91, 0xed, 0xe5, 0x71, 0x25, 0x07, 0xef, 0x0d, 0xac, 0x34, 0x0a, 0x7b, 0xe4, 0xeb, 0x8e, 0xdd,
0x1a, 0x7a, 0xa5, 0xfc, 0x5d, 0x01, 0xdc, 0x8e, 0x4f, 0x19, 0x6c, 0x1f, 0x61, 0x7a, 0x40, 0xca,
0xc5, 0xbb, 0x92, 0x39, 0x85, 0x8a, 0x7f, 0x10, 0x3c, 0x9c, 0x42, 0xf5, 0x61, 0x6c, 0x3f, 0xfa,
0xfc, 0x35, 0x60, 0x66, 0x4d, 0xe2, 0x6d, 0xe0, 0x22, 0x56, 0x1a, 0xc4, 0x66, 0x91, 0x4b, 0xb1,
0x9c, 0xba, 0x74, 0xe3, 0x5f, 0x98, 0x72, 0x8b, 0x8e, 0x7f, 0x7d, 0xfa, 0x55, 0x70, 0xce, 0xa2,
0x35, 0x4a, 0x68, 0x50, 0x21, 0x54, 0xb8, 0x4a, 0x39, 0x25, 0x1f, 0x24, 0xc7, 0xd6, 0xd3, 0x55,
0x72, 0x50, 0xb4, 0x46, 0x3a, 0x42, 0x97, 0x18, 0x35, 0x01, 0xae, 0x59, 0x9a, 0x1e, 0xf3, 0x91,
0x5d, 0x4b, 0x5d, 0xb0, 0x13, 0x6e, 0x32, 0x99, 0x4b, 0x9c, 0x74, 0xd5, 0xc9, 0x53, 0xe5, 0x18,
0x21, 0xfa, 0xa7, 0x00, 0x4c, 0x8e, 0xeb, 0xa9, 0xf3, 0x3c, 0xf9, 0x82, 0x93, 0xcd, 0x73, 0xca,
0x25, 0xe8, 0xff, 0x12, 0xa8, 0x13, 0x09, 0xf7, 0x8d, 0x5f, 0x8b, 0x7e, 0x63, 0x23, 0xdc, 0x32,
0xde, 0xc8, 0xba, 0x7b, 0x4d, 0xfa, 0x42, 0xc7, 0xd0, 0xee, 0x35, 0x06, 0x48, 0xfa, 0x08, 0xf0,
0xc9, 0x42, 0x38, 0x2c, 0x2f, 0x2c, 0x14, 0x29, 0xd7, 0xd7, 0x52, 0xa6, 0x7d, 0xb8, 0x1c, 0xb1,
0x92, 0x83, 0x67, 0xad, 0xe1, 0x76, 0xe9, 0x00, 0x5c, 0xe2, 0xb4, 0x89, 0x83, 0x8a, 0x56, 0x25,
0x16, 0x6e, 0xa6, 0x9c, 0xdc, 0x27, 0x17, 0x07, 0x56, 0x72, 0xf0, 0xa2, 0x15, 0xd7, 0x2b, 0x6d,
0x83, 0x8b, 0x83, 0x53, 0x12, 0xe6, 0x18, 0xd9, 0x74, 0xde, 0xa2, 0xcc, 0x5e, 0x4d, 0x64, 0x16,
0x73, 0xb7, 0x51, 0xc9, 0xc1, 0xf3, 0x5e, 0xcc, 0x95, 0xc7, 0x11, 0xb8, 0x92, 0x70, 0xb8, 0xce,
0x58, 0xdd, 0x4e, 0x19, 0x57, 0xf2, 0x85, 0x00, 0x71, 0xf8, 0x3b, 0xc9, 0xd7, 0x05, 0xdb, 0x80,
0x8f, 0x1a, 0xf1, 0x82, 0x04, 0x8f, 0xd5, 0x3d, 0x16, 0xee, 0xa4, 0x0c, 0x2e, 0xa6, 0x56, 0x92,
0x0c, 0xce, 0x8a, 0x29, 0xa1, 0xac, 0x82, 0x33, 0x7d, 0x1e, 0x74, 0x96, 0xee, 0x52, 0xda, 0xb7,
0x53, 0x69, 0x13, 0xe0, 0x4a, 0x0e, 0x9e, 0xb6, 0xa2, 0x55, 0x8e, 0x5b, 0x40, 0x8a, 0xd6, 0x4e,
0xb0, 0x19, 0x29, 0xdc, 0x4b, 0x29, 0xc9, 0x1e, 0x2d, 0xf2, 0xa3, 0xde, 0x64, 0xb4, 0xf0, 0x6f,
0x84, 0x74, 0x8f, 0x16, 0x8c, 0x15, 0xee, 0x67, 0x26, 0xcd, 0x2a, 0xcc, 0x86, 0x49, 0xf3, 0xaa,
0xb3, 0x11, 0xd2, 0x36, 0x2d, 0x28, 0x29, 0xac, 0x64, 0x26, 0xcd, 0x2a, 0x50, 0x86, 0x49, 0xf3,
0xaa, 0x94, 0x36, 0xb8, 0x1c, 0x25, 0xcd, 0x6b, 0xba, 0xb8, 0x5e, 0x5e, 0x49, 0x39, 0x17, 0x88,
0x2f, 0xf2, 0xab, 0xe4, 0xe0, 0x82, 0x15, 0x5f, 0xfe, 0x17, 0xcf, 0x8d, 0xab, 0xea, 0xd5, 0xe7,
0xe4, 0xd6, 0x57, 0xd8, 0x18, 0x37, 0xae, 0xb6, 0x78, 0x6e, 0x5c, 0x7b, 0xaf, 0x3d, 0x27, 0xb7,
0xbe, 0x0e, 0xc7, 0xb8, 0x71, 0x4d, 0x1e, 0x80, 0xc5, 0x28, 0x37, 0x5a, 0xea, 0xe5, 0x93, 0x68,
0xd9, 0xf3, 0xb1, 0x57, 0x58, 0xcd, 0xcc, 0x2e, 0x5a, 0xef, 0x36, 0xcc, 0x6e, 0xa8, 0x12, 0xee,
0xff, 0x09, 0xa0, 0x18, 0x4d, 0x10, 0xa2, 0x37, 0x49, 0x83, 0x63, 0x96, 0xc2, 0x83, 0xd4, 0x33,
0xd9, 0xd4, 0xd7, 0x7a, 0xec, 0x4c, 0xb6, 0x0f, 0xd6, 0x1a, 0x07, 0x93, 0xf6, 0xc1, 0xa5, 0x98,
0x13, 0x16, 0xec, 0xb4, 0x70, 0xe1, 0xf5, 0xd4, 0x14, 0x3b, 0xe1, 0xad, 0x1c, 0x4b, 0xb1, 0x47,
0x3a, 0x9d, 0x16, 0x1e, 0x65, 0x16, 0xa6, 0x9b, 0xae, 0x8d, 0x0b, 0x0f, 0x33, 0x33, 0x1b, 0x79,
0x9f, 0x36, 0xcc, 0x6c, 0xd0, 0x29, 0x7d, 0x05, 0x9c, 0x0b, 0xac, 0x5d, 0x1e, 0x87, 0x30, 0x09,
0x88, 0xde, 0x71, 0xe1, 0x51, 0x4a, 0x2c, 0x8a, 0xbb, 0x70, 0x24, 0xb1, 0x28, 0xb0, 0x76, 0xa3,
0xed, 0x52, 0x00, 0x16, 0x7d, 0x7e, 0x3d, 0x83, 0x3c, 0x4a, 0x09, 0xed, 0x62, 0x7a, 0x90, 0xdd,
0x6b, 0x07, 0x85, 0x37, 0x52, 0x8e, 0xa4, 0x26, 0xdd, 0xec, 0x54, 0x72, 0xf0, 0x92, 0x1f, 0xdf,
0x3f, 0xba, 0x2c, 0x78, 0xfd, 0x18, 0x5f, 0xf2, 0x8f, 0x33, 0xdb, 0x69, 0xb4, 0xea, 0x70, 0xd8,
0x4e, 0x87, 0xea, 0x11, 0xe3, 0xb9, 0xf1, 0x45, 0xf8, 0xe6, 0x73, 0x72, 0x8b, 0x5b, 0x84, 0x43,
0x45, 0x76, 0xdb, 0xe0, 0x62, 0x68, 0x18, 0xc7, 0x68, 0x07, 0x07, 0xad, 0x3d, 0x1e, 0x03, 0xbf,
0x90, 0x12, 0x91, 0x62, 0xae, 0xb7, 0x48, 0x44, 0xb2, 0x63, 0x6e, 0xbd, 0xbe, 0x37, 0x72, 0x9a,
0xc7, 0x0d, 0x70, 0xc0, 0x97, 0xed, 0xf1, 0x0b, 0x6f, 0x65, 0x3e, 0x3c, 0x4b, 0xfe, 0xcc, 0xc2,
0xf0, 0x91, 0x5e, 0x2c, 0x9c, 0xf4, 0xcd, 0x91, 0x9d, 0xfd, 0x7e, 0x6f, 0x1b, 0xd3, 0xcb, 0xd9,
0xa1, 0x6d, 0xc2, 0x93, 0xcc, 0x07, 0x9c, 0xe3, 0x5f, 0xbf, 0x19, 0x3e, 0xe0, 0xa4, 0xfd, 0xfb,
0x43, 0xdb, 0x83, 0x6f, 0xc7, 0xab, 0xc4, 0xea, 0x76, 0xe9, 0x31, 0x6b, 0xff, 0x80, 0xf3, 0xed,
0xd4, 0x13, 0xee, 0x49, 0xcf, 0x28, 0x87, 0x1d, 0x51, 0xec, 0x43, 0xcb, 0x2e, 0x58, 0xe2, 0xd6,
0xb6, 0xeb, 0x59, 0xdd, 0x3d, 0xba, 0xa5, 0xf3, 0x5b, 0x56, 0x98, 0x09, 0xbd, 0x43, 0xf9, 0xbf,
0x9e, 0x62, 0x6f, 0x63, 0xf7, 0xf5, 0x64, 0x35, 0x59, 0x91, 0xae, 0x23, 0x7f, 0x70, 0x95, 0xff,
0x7d, 0xb6, 0x51, 0x1b, 0xe2, 0xda, 0xf2, 0xdc, 0xa3, 0x0e, 0xfa, 0xef, 0xf8, 0x08, 0xb7, 0x91,
0xed, 0xec, 0xec, 0xd0, 0x2d, 0x70, 0xe1, 0xdd, 0x54, 0x7b, 0x48, 0xbf, 0x41, 0x66, 0xf6, 0x30,
0x11, 0x4e, 0xfa, 0x6f, 0xe0, 0x22, 0x2d, 0xe2, 0xa0, 0xf7, 0xa6, 0xf4, 0xce, 0x93, 0x8f, 0xfe,
0xbd, 0xb4, 0x9b, 0xca, 0xb1, 0xeb, 0xd7, 0x4a, 0x0e, 0x4a, 0xbd, 0xf1, 0x4b, 0x59, 0x76, 0xa0,
0x1e, 0xbb, 0x6f, 0xc2, 0x5d, 0xce, 0xec, 0x8b, 0xa9, 0xf6, 0x96, 0x5c, 0x9b, 0xc8, 0xec, 0x6d,
0x42, 0xed, 0xe2, 0xaf, 0x0b, 0xe0, 0x5e, 0x82, 0x04, 0xfc, 0x38, 0xcb, 0xed, 0xe2, 0x70, 0xd2,
0xbf, 0x94, 0x1a, 0x02, 0x53, 0x4b, 0x04, 0xd9, 0xed, 0x5f, 0x7a, 0x25, 0xe1, 0x27, 0x02, 0x58,
0x89, 0x97, 0x8b, 0xd6, 0xa0, 0x8d, 0x6e, 0xe9, 0xde, 0x4f, 0xbd, 0x7c, 0xcb, 0x50, 0xb3, 0xc7,
0xce, 0x3e, 0xb2, 0x14, 0xf7, 0xf1, 0x33, 0x85, 0xd8, 0xad, 0x26, 0x7d, 0x8a, 0xd5, 0x0d, 0xcf,
0x4d, 0x3f, 0xf8, 0x34, 0x7b, 0xcd, 0x48, 0x1d, 0x5d, 0xe2, 0x5e, 0x33, 0x5a, 0x6b, 0xf7, 0x7d,
0x76, 0x4a, 0x1a, 0x23, 0x4e, 0xdb, 0xe9, 0xec, 0x0f, 0x9d, 0x2e, 0xc8, 0xa9, 0x5b, 0xce, 0x94,
0xb2, 0xb6, 0x4a, 0x0e, 0xde, 0x88, 0x11, 0x68, 0x18, 0x68, 0xed, 0x24, 0x98, 0xa1, 0x34, 0x9f,
0x4e, 0xcf, 0xe6, 0xc5, 0x29, 0x62, 0x83, 0xfd, 0x9d, 0x30, 0x89, 0xcb, 0xe1, 0xa5, 0x19, 0x95,
0x6c, 0xe5, 0x87, 0xe2, 0xe0, 0x83, 0x88, 0xe1, 0x66, 0x4d, 0xba, 0x01, 0x96, 0x4b, 0x9a, 0xa1,
0xe8, 0xcf, 0x54, 0x88, 0xa0, 0x6a, 0xe8, 0x4d, 0xa8, 0x8c, 0x7e, 0xce, 0xe8, 0x0a, 0x28, 0x8c,
0x83, 0x18, 0x2a, 0x7c, 0xa6, 0x42, 0x51, 0x90, 0xae, 0x83, 0x2b, 0xe3, 0xbd, 0x1b, 0xcd, 0x35,
0x15, 0xd6, 0x55, 0x53, 0x35, 0xc4, 0xbc, 0xf4, 0x06, 0x78, 0x30, 0x0e, 0x51, 0x92, 0x4d, 0x79,
0x4d, 0x36, 0x54, 0xd4, 0xd0, 0x0d, 0xb3, 0x0c, 0x55, 0x03, 0x19, 0x6a, 0x75, 0x1d, 0x55, 0x74,
0xc3, 0x54, 0x4b, 0xe2, 0x94, 0xf4, 0x3a, 0x78, 0x75, 0x02, 0x52, 0x6d, 0xcb, 0xf8, 0xb0, 0x3a,
0x84, 0x31, 0x2d, 0x3d, 0x02, 0xab, 0x93, 0x30, 0xf4, 0x7a, 0x59, 0x2f, 0xad, 0x0d, 0xe1, 0xcc,
0x48, 0xaf, 0x80, 0xbb, 0x59, 0x44, 0x83, 0x25, 0x43, 0x3c, 0x21, 0xdd, 0x03, 0xb7, 0x52, 0x45,
0x22, 0x90, 0x27, 0xa5, 0x3b, 0xa0, 0x38, 0x0e, 0x29, 0x37, 0x1a, 0x55, 0x4d, 0x91, 0x4d, 0x4d,
0xaf, 0xa3, 0x8a, 0x69, 0x36, 0xc4, 0x59, 0xe9, 0x36, 0xb8, 0x31, 0x19, 0xce, 0x54, 0x1a, 0xe2,
0x5c, 0x3c, 0xd8, 0xa6, 0x56, 0x2f, 0xe9, 0x9b, 0x06, 0x2a, 0xa9, 0xc6, 0x86, 0xa9, 0x37, 0x44,
0x20, 0xbd, 0x0a, 0xee, 0x4d, 0x90, 0xcf, 0xf8, 0xb0, 0xca, 0xe6, 0x8c, 0xca, 0x78, 0x2a, 0x45,
0xc1, 0x83, 0xa1, 0xab, 0x25, 0xa3, 0xa2, 0xad, 0x9b, 0xe2, 0x69, 0xe9, 0x31, 0x78, 0x3d, 0x13,
0xfd, 0xa8, 0x8a, 0xcf, 0xa4, 0xf0, 0x81, 0x6a, 0x49, 0x1b, 0x9e, 0xfa, 0xf9, 0xac, 0x93, 0x52,
0x56, 0x1a, 0xe2, 0xd9, 0x4c, 0x93, 0x42, 0x20, 0xc5, 0xcc, 0xea, 0x21, 0xd0, 0xe7, 0xa4, 0x77,
0xc1, 0x5b, 0xcf, 0xa3, 0x1e, 0xbe, 0x1e, 0xaa, 0xaa, 0x61, 0x88, 0x92, 0xf4, 0x1a, 0xb8, 0x9f,
0x05, 0x59, 0xfe, 0xa8, 0x09, 0x55, 0xf1, 0xbc, 0x74, 0x17, 0xdc, 0x9c, 0x00, 0x5e, 0xda, 0xaa,
0xcb, 0x35, 0xbd, 0xb4, 0x26, 0x5e, 0x48, 0x31, 0x71, 0x45, 0x36, 0x0c, 0xb9, 0x5e, 0x82, 0x32,
0xda, 0x50, 0xb7, 0x8c, 0x86, 0xac, 0xa8, 0x86, 0x78, 0x31, 0x65, 0xd6, 0x06, 0x38, 0xd1, 0x39,
0x58, 0x90, 0x9e, 0x80, 0xc7, 0x13, 0xb0, 0xd4, 0xaa, 0x6c, 0x98, 0x9a, 0x62, 0xa8, 0x32, 0x54,
0x2a, 0x43, 0x98, 0x97, 0x32, 0xcd, 0x37, 0xc7, 0x97, 0x95, 0x8a, 0x2a, 0x16, 0x52, 0xb4, 0xc5,
0x30, 0x6a, 0x6a, 0x4d, 0x87, 0x5b, 0xa5, 0x35, 0xf1, 0x72, 0x26, 0x06, 0x54, 0xb3, 0x88, 0x31,
0x58, 0x4c, 0x19, 0x0c, 0xc3, 0x50, 0xaa, 0x4d, 0xc3, 0x1c, 0x31, 0xde, 0x25, 0x69, 0x05, 0xdc,
0x49, 0xb5, 0x2e, 0x36, 0x8b, 0x57, 0xa4, 0x55, 0xb0, 0x92, 0xc9, 0xbe, 0x18, 0xfc, 0x72, 0xca,
0x64, 0x0e, 0xe0, 0x6b, 0x9a, 0x02, 0x75, 0x43, 0x5f, 0x37, 0xc5, 0xab, 0xd2, 0x17, 0xc0, 0xa3,
0x49, 0x93, 0xa9, 0x2b, 0x1b, 0x50, 0x97, 0x95, 0xca, 0x88, 0x9f, 0xbb, 0x96, 0x62, 0xfb, 0xa1,
0x6f, 0x94, 0xcd, 0xaa, 0x6c, 0x88, 0xd7, 0x53, 0xd6, 0x94, 0x51, 0xd7, 0x37, 0xd7, 0xab, 0xf2,
0x86, 0x2a, 0xde, 0x48, 0xa0, 0xab, 0x2b, 0x11, 0xed, 0x96, 0x0c, 0xd4, 0x80, 0xfa, 0x97, 0xb7,
0xc4, 0x62, 0x82, 0x29, 0x46, 0xa1, 0x2b, 0x5a, 0xb9, 0x82, 0xe4, 0x67, 0xb2, 0x56, 0x95, 0xd7,
0xb4, 0xaa, 0x66, 0x6e, 0x89, 0x37, 0xa5, 0xb7, 0xc0, 0x1b, 0x29, 0x58, 0x74, 0x85, 0x68, 0x0a,
0x82, 0x6a, 0x59, 0x33, 0x4c, 0x48, 0x5d, 0xa7, 0x78, 0x2b, 0xde, 0x0b, 0x1b, 0x72, 0xad, 0x1a,
0x75, 0xb1, 0xe2, 0x6d, 0xa9, 0x08, 0xae, 0x8e, 0xc3, 0xa9, 0xca, 0x23, 0xf6, 0xe1, 0xbe, 0xba,
0xa2, 0x8a, 0x77, 0x12, 0x8c, 0x4e, 0x57, 0x46, 0xdd, 0x30, 0xaa, 0xeb, 0x75, 0x24, 0x97, 0xc4,
0xbb, 0xd2, 0x2d, 0x70, 0x7d, 0x52, 0x5c, 0xa4, 0x1f, 0x74, 0xbb, 0x17, 0x6f, 0xfb, 0xd1, 0x08,
0x20, 0x6f, 0x1a, 0x48, 0xd1, 0xeb, 0x86, 0x5e, 0x55, 0xc5, 0xfb, 0xd2, 0x35, 0xb0, 0x34, 0x0e,
0x5e, 0x53, 0x1a, 0xc8, 0x30, 0x4b, 0x9a, 0x2e, 0xae, 0xd0, 0xcf, 0x1e, 0xc6, 0x03, 0x18, 0xaa,
0xf8, 0x8a, 0x74, 0x1f, 0xdc, 0x4e, 0xc2, 0x87, 0xaa, 0x5c, 0x93, 0xd7, 0xaa, 0x2a, 0x8b, 0x4d,
0xaf, 0xae, 0xfc, 0x9e, 0x00, 0xe6, 0x87, 0x3f, 0x3d, 0x3c, 0xc4, 0xdd, 0x30, 0x65, 0xb3, 0x69,
0x8c, 0x64, 0x0a, 0x4b, 0xe0, 0xd2, 0x28, 0x80, 0xd1, 0x54, 0x14, 0xe2, 0x14, 0x85, 0xd8, 0xce,
0x0d, 0xad, 0xd1, 0x50, 0x4b, 0x62, 0x5e, 0xba, 0x0c, 0x2e, 0x8e, 0x76, 0xaa, 0x10, 0xea, 0x50,
0x9c, 0x8a, 0xc3, 0x93, 0xd7, 0x74, 0x48, 0x83, 0xfe, 0xca, 0xcf, 0xf2, 0x60, 0x4a, 0x31, 0x65,
0xe9, 0x3c, 0x38, 0xab, 0x98, 0xf2, 0xf8, 0x47, 0x1e, 0x49, 0xa3, 0xdc, 0x34, 0x2b, 0x44, 0x87,
0x75, 0x55, 0x31, 0x75, 0x92, 0xb2, 0x5c, 0x02, 0xe7, 0x69, 0xbb, 0x62, 0x6a, 0xcf, 0x48, 0x26,
0x63, 0x18, 0x9a, 0x5e, 0x27, 0x99, 0x4a, 0xbf, 0x83, 0x88, 0x8c, 0xa0, 0xfa, 0x61, 0x53, 0x35,
0x4c, 0x43, 0x9c, 0x0a, 0x3b, 0x1a, 0x50, 0xad, 0x69, 0xcd, 0x1a, 0x32, 0x9a, 0x8d, 0x86, 0x0e,
0x4d, 0x71, 0x3a, 0xec, 0x30, 0x21, 0xf1, 0x1e, 0x25, 0x54, 0x52, 0x9f, 0x69, 0xc4, 0xed, 0xce,
0x84, 0xbc, 0x9b, 0x8d, 0x32, 0x94, 0x4b, 0x2a, 0x5a, 0x93, 0xeb, 0x75, 0x15, 0x8a, 0x27, 0x42,
0x84, 0x35, 0xad, 0x5a, 0xd5, 0xea, 0x65, 0x64, 0x34, 0x6b, 0x35, 0x19, 0x6e, 0x89, 0x27, 0xc3,
0x11, 0x70, 0xde, 0x55, 0xcd, 0x30, 0xc5, 0x59, 0xfa, 0x29, 0xc0, 0x41, 0x63, 0x4d, 0xaf, 0x6b,
0xa6, 0x0e, 0xb5, 0x7a, 0x59, 0x9c, 0xa3, 0x1f, 0x19, 0x34, 0x65, 0xa4, 0x7e, 0xd9, 0x54, 0x61,
0x5d, 0xae, 0x22, 0xb9, 0x59, 0xd2, 0x4c, 0x64, 0x98, 0x3a, 0x94, 0xcb, 0xaa, 0x08, 0x42, 0x01,
0xf4, 0x0d, 0x22, 0x85, 0x41, 0x74, 0xb7, 0x55, 0x57, 0xc4, 0x53, 0x92, 0x08, 0x4e, 0x53, 0xbc,
0xba, 0x09, 0x65, 0xa4, 0x95, 0xc4, 0xd3, 0xd2, 0x39, 0x70, 0xa6, 0x0f, 0x69, 0x28, 0x5a, 0x4d,
0x3c, 0x13, 0xf2, 0xd5, 0x4a, 0x6a, 0xdd, 0xd4, 0xcc, 0x2d, 0x64, 0xa8, 0x4a, 0x13, 0x92, 0xe5,
0x38, 0xbf, 0xf2, 0x23, 0x00, 0x2e, 0xc6, 0xbe, 0xa3, 0x23, 0x61, 0x4c, 0xab, 0x9b, 0x6a, 0x99,
0x2d, 0x40, 0xa4, 0xd6, 0xa1, 0x5e, 0xad, 0xa2, 0x0d, 0xad, 0x3e, 0xfa, 0xf9, 0xc4, 0x1b, 0x60,
0x39, 0x09, 0xd0, 0xa8, 0xca, 0xca, 0x86, 0x28, 0x90, 0xd5, 0x93, 0x04, 0x42, 0x56, 0x84, 0xae,
0x95, 0x14, 0x31, 0x4f, 0x12, 0xa3, 0x24, 0xa8, 0x86, 0x5c, 0x56, 0x61, 0xa9, 0x69, 0x6e, 0x89,
0x53, 0x93, 0xf8, 0xa9, 0x35, 0x59, 0xab, 0x8a, 0xd3, 0x24, 0x8b, 0x4d, 0x02, 0x79, 0xaa, 0x41,
0x59, 0x9c, 0x91, 0x6e, 0x82, 0x6b, 0x49, 0x10, 0xd4, 0x3c, 0x61, 0x49, 0x3c, 0x41, 0x5c, 0x4e,
0x12, 0x50, 0x4d, 0x36, 0x4d, 0x15, 0xd6, 0x74, 0xc3, 0x14, 0x4f, 0x4e, 0x1a, 0x5e, 0xcd, 0x40,
0xa6, 0x2a, 0xd7, 0x0c, 0x71, 0x76, 0x12, 0x94, 0xde, 0x30, 0xca, 0x6a, 0x5d, 0x53, 0xc5, 0xb9,
0x49, 0xa2, 0x93, 0x29, 0x15, 0xc1, 0xc4, 0xc1, 0xc9, 0xb5, 0x75, 0xf1, 0xd4, 0x64, 0xb9, 0x95,
0x8a, 0x56, 0x57, 0x99, 0xa9, 0xbc, 0x09, 0x1e, 0xa6, 0xc3, 0xa1, 0xb2, 0x66, 0x56, 0x9a, 0x6b,
0x74, 0x7d, 0x91, 0x75, 0x75, 0x46, 0x7a, 0x00, 0x5e, 0xc9, 0x80, 0xa6, 0x68, 0x50, 0xa9, 0xaa,
0x8a, 0x26, 0xce, 0x13, 0xb7, 0x98, 0x8d, 0x4f, 0x55, 0x5e, 0x13, 0xcf, 0x92, 0xd0, 0x9b, 0x01,
0xfc, 0xa9, 0x5a, 0xdf, 0xd0, 0xea, 0x86, 0x28, 0x66, 0x84, 0x97, 0xeb, 0x86, 0xb6, 0x56, 0x55,
0xc5, 0x73, 0x93, 0xd4, 0x43, 0x82, 0xb4, 0xa6, 0xa8, 0x75, 0x7d, 0x53, 0x94, 0x26, 0x4d, 0x58,
0x7f, 0xbd, 0x9d, 0x27, 0x01, 0x2d, 0xd1, 0x92, 0x64, 0x53, 0x2e, 0xe9, 0x65, 0xa4, 0xd5, 0x15,
0xba, 0xf6, 0x50, 0x4d, 0xae, 0xcb, 0x65, 0xb5, 0xa6, 0xd6, 0x4d, 0xf1, 0x02, 0xc9, 0x46, 0xb2,
0x88, 0xbd, 0x49, 0xd2, 0xbe, 0x6c, 0xb0, 0x24, 0xd7, 0x5d, 0x20, 0x51, 0x3c, 0x0b, 0x5d, 0x9a,
0xb7, 0xd0, 0x04, 0x2f, 0x03, 0x34, 0xcd, 0x3f, 0xab, 0x64, 0xe3, 0x50, 0x90, 0x1e, 0x82, 0xd7,
0x32, 0x60, 0x44, 0xf6, 0x8c, 0x97, 0x27, 0x59, 0x0c, 0x59, 0xff, 0x7d, 0xc7, 0xa4, 0xa8, 0x75,
0x53, 0x85, 0xe2, 0xe2, 0xa4, 0x29, 0xe5, 0xe6, 0x08, 0xd5, 0x86, 0xce, 0x3d, 0xa9, 0xb8, 0x94,
0xd1, 0xc2, 0x64, 0x58, 0xd6, 0x95, 0x92, 0x78, 0x45, 0xfa, 0x00, 0xbc, 0xf7, 0xdc, 0x86, 0x1f,
0x1d, 0xd1, 0xf2, 0xca, 0x1f, 0xcd, 0xc4, 0xf8, 0x4d, 0x23, 0xc0, 0xdd, 0x04, 0xbf, 0x69, 0x98,
0x6a, 0x63, 0xc4, 0x6f, 0xc6, 0x8f, 0x91, 0x02, 0xca, 0x9b, 0x86, 0xa6, 0x84, 0x41, 0x8e, 0xb9,
0x47, 0x41, 0xfa, 0x12, 0x78, 0x67, 0x32, 0xbc, 0xa1, 0x9a, 0x5c, 0x23, 0x24, 0xde, 0xa0, 0x92,
0xba, 0x2e, 0x37, 0xab, 0x26, 0xd2, 0x37, 0x49, 0xac, 0xca, 0x4b, 0x5f, 0x04, 0x6f, 0x4f, 0xc6,
0x6f, 0x36, 0xaa, 0xba, 0xcc, 0x66, 0x84, 0xe6, 0x55, 0x46, 0x03, 0xd5, 0x54, 0x53, 0x26, 0x56,
0x2c, 0x4e, 0x91, 0x64, 0x75, 0x32, 0xba, 0xa9, 0x1a, 0x26, 0x8d, 0x38, 0xa1, 0xe0, 0x24, 0x1f,
0x9b, 0x4e, 0x58, 0x1f, 0x14, 0x8f, 0x29, 0x18, 0xca, 0x48, 0x81, 0xaa, 0x6c, 0xaa, 0x28, 0x02,
0x27, 0xce, 0x4c, 0x62, 0x38, 0x8a, 0x58, 0xd6, 0xc2, 0x2d, 0x9b, 0x78, 0x22, 0x1b, 0x43, 0xfa,
0x45, 0x5e, 0xb2, 0xab, 0x30, 0x8c, 0x0a, 0x52, 0x54, 0x48, 0xdc, 0x78, 0xfc, 0x52, 0x88, 0x65,
0x08, 0x49, 0x02, 0x37, 0x4b, 0x52, 0xe0, 0x24, 0x8c, 0xda, 0xa6, 0x56, 0xae, 0xc8, 0x1b, 0x4f,
0x8c, 0xfe, 0x34, 0x32, 0x1a, 0xe2, 0xdc, 0xa4, 0x81, 0x0d, 0x61, 0x71, 0x09, 0xb9, 0x91, 0x83,
0x6c, 0xdc, 0x0c, 0xd5, 0x6c, 0x36, 0xd0, 0xa6, 0x0e, 0x37, 0xd6, 0xab, 0xfa, 0xa6, 0x78, 0x6a,
0xe5, 0xe7, 0x42, 0xec, 0x43, 0xf0, 0xf0, 0x11, 0x77, 0xa2, 0x19, 0xd2, 0xd4, 0x4c, 0xd1, 0x4b,
0xa3, 0xe7, 0x47, 0xf1, 0xae, 0x28, 0x0a, 0x3f, 0x48, 0x12, 0x33, 0xc0, 0xf6, 0x73, 0xc6, 0x7b,
0xe0, 0x56, 0x0a, 0x6c, 0x98, 0x42, 0xa6, 0x53, 0x1d, 0x64, 0x94, 0x7f, 0x93, 0x07, 0x85, 0xa4,
0x73, 0xd3, 0x24, 0x42, 0xcc, 0x74, 0x47, 0x86, 0x1d, 0xef, 0x32, 0x42, 0xd8, 0x81, 0xfe, 0x43,
0xa7, 0x51, 0x7a, 0x46, 0xf6, 0x1a, 0x24, 0xb4, 0xb3, 0xb0, 0x29, 0x64, 0xa6, 0x10, 0xd9, 0x55,
0x54, 0xe5, 0x35, 0xb5, 0x8a, 0x1a, 0x9a, 0xb2, 0x41, 0x57, 0x70, 0x09, 0x7c, 0xf0, 0xbc, 0x14,
0xc6, 0xe4, 0x98, 0x92, 0x2a, 0xa0, 0xf4, 0xbc, 0x54, 0xfa, 0x9b, 0x0b, 0xd8, 0xac, 0xaa, 0xa1,
0x3c, 0xd3, 0x2b, 0x3f, 0x99, 0x01, 0x0b, 0xf1, 0x07, 0xbf, 0x09, 0xb3, 0xb9, 0xae, 0xa9, 0xd5,
0xd1, 0xf4, 0xf1, 0x3d, 0xf0, 0x24, 0x11, 0x72, 0x4c, 0xad, 0xc4, 0xeb, 0x1b, 0x24, 0x6b, 0xde,
0x42, 0x4d, 0x58, 0x15, 0x85, 0x84, 0x35, 0x91, 0x80, 0xbd, 0x06, 0xe5, 0xba, 0x52, 0x11, 0xf3,
0x09, 0x2b, 0x30, 0x01, 0xab, 0xbf, 0x96, 0xa6, 0xa4, 0xb7, 0xc1, 0x9b, 0xd9, 0xf1, 0xd4, 0xfa,
0x33, 0x0d, 0xea, 0x75, 0x1a, 0xed, 0xa7, 0x13, 0xa2, 0x66, 0xe2, 0x30, 0xd7, 0xc5, 0x99, 0x04,
0x87, 0x9d, 0xc8, 0xcd, 0x54, 0x61, 0x03, 0x6a, 0x64, 0x4b, 0x5f, 0x6d, 0x96, 0xc5, 0x13, 0x09,
0xd6, 0x92, 0x01, 0xdd, 0x94, 0x4d, 0x4d, 0x41, 0x4f, 0x37, 0x37, 0x0c, 0xf1, 0xa4, 0xf4, 0x04,
0x3c, 0xce, 0x40, 0x65, 0xd4, 0x66, 0x49, 0xbe, 0xfb, 0xdc, 0x98, 0x65, 0xa8, 0x37, 0x1b, 0x86,
0x38, 0x97, 0xe0, 0xc1, 0x27, 0x60, 0x92, 0x1d, 0x11, 0xf1, 0x90, 0xf1, 0x4b, 0x6c, 0x02, 0xe2,
0x90, 0x61, 0x1b, 0xe2, 0xa9, 0x95, 0x1f, 0xc6, 0x7d, 0xa9, 0x24, 0x7c, 0xc8, 0x9e, 0x90, 0x5a,
0x51, 0x97, 0x13, 0xf3, 0x8f, 0x03, 0xe2, 0xdd, 0xcb, 0x00, 0xda, 0x54, 0x21, 0x94, 0xd7, 0x75,
0x58, 0x4b, 0xb4, 0xe3, 0x01, 0xec, 0x48, 0x2e, 0xb2, 0x25, 0xd7, 0xaa, 0x62, 0x7e, 0xe5, 0x7d,
0x70, 0x92, 0x17, 0x4f, 0x91, 0x9d, 0xe8, 0xba, 0x2a, 0x9b, 0x24, 0x60, 0x8c, 0xed, 0xe2, 0xc3,
0x8e, 0xd1, 0x7d, 0xad, 0xb0, 0xf2, 0x3b, 0x02, 0x58, 0x9a, 0xf0, 0xb4, 0x99, 0xe4, 0x55, 0x21,
0x32, 0x54, 0x15, 0xbd, 0x56, 0x53, 0xeb, 0x25, 0x26, 0x61, 0xec, 0x89, 0xc1, 0x0a, 0xb8, 0x33,
0x19, 0xbc, 0xae, 0x9b, 0x0c, 0x56, 0x20, 0x59, 0xf8, 0x64, 0xd8, 0x92, 0x5e, 0x57, 0xc5, 0xfc,
0xda, 0x57, 0xff, 0xe2, 0xa7, 0x57, 0x85, 0x9f, 0xfc, 0xf4, 0xaa, 0xf0, 0x77, 0x3f, 0xbd, 0x2a,
0x7c, 0xa4, 0xef, 0x3a, 0xc1, 0x5e, 0x6f, 0x7b, 0xb5, 0xe5, 0x1e, 0x3c, 0xd8, 0xf5, 0xac, 0x43,
0x87, 0x15, 0xd7, 0x5a, 0xed, 0x07, 0x83, 0xff, 0x65, 0xd6, 0x75, 0x1e, 0xec, 0xe2, 0xce, 0x03,
0xfa, 0x0c, 0xfd, 0xc1, 0xae, 0x3b, 0xf2, 0x0f, 0xd2, 0xde, 0x8d, 0xfc, 0x3c, 0x7c, 0xb8, 0x7d,
0x82, 0x82, 0xbd, 0xf1, 0x1f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x27, 0xe9, 0x48, 0xd2, 0x50, 0x6d,
0x00, 0x00,
0x24, 0x46, 0x80, 0x0d, 0xf2, 0x40, 0x1e, 0x08, 0xe0, 0x00, 0xf9, 0x32, 0xfc, 0x95, 0x8f, 0xfc,
0x05, 0x48, 0x3e, 0x0c, 0x04, 0xc8, 0x47, 0xf2, 0x13, 0xf8, 0x2b, 0x7f, 0xfe, 0x4a, 0x80, 0xc4,
0x79, 0xa1, 0x1e, 0x3d, 0xd3, 0x33, 0xd3, 0x3d, 0xdd, 0xda, 0x68, 0x63, 0x43, 0xfb, 0xc7, 0xa9,
0x3a, 0xaf, 0x3a, 0x75, 0xea, 0x9c, 0x53, 0x55, 0xa7, 0x9a, 0xe0, 0x7e, 0x80, 0xdb, 0xb8, 0xeb,
0x7a, 0xc1, 0x83, 0x9e, 0x6f, 0xed, 0x62, 0x7c, 0x88, 0x3b, 0x81, 0xff, 0xe0, 0xf0, 0x61, 0xf4,
0xe7, 0x6a, 0xd7, 0x73, 0x03, 0x57, 0xba, 0x14, 0x82, 0xae, 0x46, 0xfb, 0x0e, 0x1f, 0x2e, 0xde,
0xed, 0xd3, 0xb0, 0x5a, 0x2d, 0xec, 0xfb, 0x6d, 0xc7, 0x0f, 0x08, 0x89, 0xc1, 0x2f, 0x46, 0xa1,
0xb8, 0x02, 0xa4, 0xa6, 0xb6, 0x66, 0x75, 0x3a, 0xd8, 0x53, 0xda, 0x4e, 0x6b, 0x5f, 0x25, 0x24,
0xa4, 0x0b, 0x60, 0xc6, 0x6a, 0x63, 0x2f, 0x28, 0x08, 0xd7, 0x85, 0x7b, 0x73, 0x90, 0xfd, 0x28,
0xae, 0x83, 0x7b, 0x4d, 0x4d, 0xef, 0x6c, 0xbb, 0x96, 0x67, 0x2b, 0xee, 0x41, 0xb7, 0x8d, 0x03,
0x5c, 0x76, 0x4d, 0xb7, 0x64, 0xf9, 0x7b, 0xac, 0x71, 0x40, 0x61, 0x11, 0xcc, 0xf6, 0x7c, 0xec,
0x75, 0xac, 0x03, 0xcc, 0x89, 0xf4, 0x7f, 0x17, 0x6f, 0x83, 0x9b, 0x7d, 0x3a, 0xb2, 0x6d, 0xaf,
0x3b, 0x9e, 0x1f, 0x40, 0xec, 0xbb, 0x3d, 0xaf, 0x85, 0x07, 0x24, 0x8a, 0x2b, 0x11, 0x76, 0xa3,
0x60, 0x55, 0x2b, 0x88, 0x0a, 0x5c, 0x7c, 0x1f, 0xdc, 0xe8, 0xc3, 0x1a, 0x38, 0x50, 0x3c, 0x6c,
0xe3, 0x4e, 0xe0, 0x58, 0x6d, 0xa3, 0xb7, 0x7d, 0xe0, 0x04, 0xe9, 0x32, 0x45, 0x09, 0x7c, 0xd8,
0xc3, 0x7e, 0xe0, 0xb8, 0x9d, 0x8e, 0xe5, 0x78, 0x38, 0x2b, 0x81, 0xaf, 0x83, 0xdb, 0x7d, 0x02,
0x10, 0xef, 0x3a, 0x3e, 0x11, 0x70, 0xcf, 0x6a, 0xb7, 0x71, 0x67, 0x37, 0x2b, 0x11, 0xe9, 0x32,
0x98, 0x3d, 0xd8, 0xb1, 0x50, 0x70, 0xdc, 0xc5, 0x85, 0x3c, 0xed, 0x3b, 0x79, 0xb0, 0x63, 0x99,
0xc7, 0x5d, 0x2c, 0x2d, 0x03, 0xd0, 0x76, 0x77, 0x9d, 0x0e, 0xda, 0x69, 0xbb, 0x47, 0x85, 0x29,
0xda, 0x39, 0x47, 0x5b, 0xd6, 0xdb, 0xee, 0x11, 0x93, 0x1f, 0xe2, 0x96, 0x7b, 0x88, 0xbd, 0x63,
0xc5, 0xb5, 0xb1, 0xaf, 0xb8, 0x9d, 0xc0, 0xe9, 0xf4, 0x70, 0xc6, 0x49, 0x79, 0x17, 0x2c, 0x8f,
0x11, 0xe8, 0x1e, 0x67, 0x44, 0x7e, 0x0f, 0x5c, 0x1d, 0x41, 0x6e, 0x78, 0x4e, 0x27, 0xc8, 0x88,
0x5d, 0x04, 0x62, 0xc9, 0xf1, 0x29, 0x72, 0x0d, 0x07, 0x96, 0x6d, 0x05, 0x96, 0x34, 0x0f, 0xf2,
0x8e, 0xcd, 0x21, 0xf3, 0x8e, 0x5d, 0xb4, 0x40, 0x21, 0x84, 0x09, 0x6d, 0xa0, 0x0f, 0xab, 0x82,
0x59, 0x8f, 0xb7, 0x51, 0x8c, 0xf9, 0x47, 0xf7, 0x57, 0x13, 0x16, 0xc6, 0xea, 0x28, 0x11, 0xd8,
0x47, 0x2d, 0xee, 0x03, 0x29, 0xec, 0x35, 0x02, 0xdc, 0x35, 0x02, 0x2b, 0xe8, 0xf9, 0xd2, 0xfb,
0xe0, 0x84, 0x4f, 0xff, 0xe2, 0xa4, 0xef, 0xa6, 0x92, 0x66, 0x88, 0x90, 0xa3, 0x91, 0xb5, 0x84,
0x3d, 0xcf, 0xf5, 0xf8, 0x84, 0xb2, 0x1f, 0xc5, 0xdf, 0x17, 0xc0, 0x42, 0x53, 0x8b, 0xa0, 0x78,
0x01, 0xb6, 0x99, 0xaa, 0x54, 0x30, 0x7b, 0xc0, 0x87, 0x46, 0x79, 0x9e, 0xca, 0x30, 0x9c, 0x50,
0x17, 0xb0, 0x8f, 0x2a, 0x29, 0x7d, 0xc1, 0xf3, 0x94, 0xc8, 0x2b, 0x19, 0x04, 0x0f, 0x47, 0x1d,
0x0a, 0x5f, 0xfc, 0x57, 0x01, 0x5c, 0x1f, 0x88, 0x19, 0x2a, 0xcd, 0xc0, 0x6d, 0xdc, 0x22, 0x2b,
0xe4, 0x85, 0x0a, 0x5c, 0x8b, 0x4c, 0x23, 0x13, 0xf9, 0x61, 0xe6, 0x69, 0x1c, 0x90, 0x0b, 0x49,
0x44, 0xc6, 0x3f, 0xf5, 0xe9, 0xc7, 0xff, 0x7f, 0xf2, 0xc4, 0x09, 0x85, 0x00, 0x5a, 0x27, 0xc0,
0xbb, 0x9e, 0x45, 0x46, 0x2e, 0x6f, 0x1a, 0xba, 0x56, 0x52, 0x14, 0xb7, 0xd3, 0xc1, 0xad, 0xe0,
0xa5, 0xd7, 0xc3, 0x8f, 0xf3, 0x51, 0x3b, 0x28, 0x59, 0x81, 0xb5, 0x6d, 0xf9, 0x18, 0x96, 0x0c,
0xb5, 0xe3, 0xb9, 0xed, 0xf6, 0xcb, 0x3e, 0x7e, 0xe9, 0x09, 0x28, 0xf8, 0xd4, 0xe8, 0xb1, 0x8d,
0x42, 0xca, 0x3e, 0x6a, 0xb9, 0xbd, 0x4e, 0x50, 0x98, 0xbe, 0x2e, 0xdc, 0x9b, 0x82, 0x0b, 0x61,
0x7f, 0x28, 0x8a, 0xaf, 0x90, 0xde, 0xe2, 0x3f, 0x09, 0xe0, 0xca, 0x40, 0x73, 0x1b, 0xbd, 0x6d,
0xac, 0x6e, 0x7c, 0x4e, 0xb4, 0x56, 0x7c, 0x0a, 0x0a, 0x4d, 0x4d, 0xb1, 0xda, 0x6d, 0xd3, 0x95,
0xa9, 0xbf, 0x88, 0x04, 0x84, 0x55, 0x30, 0xd5, 0xe2, 0x23, 0x9e, 0x7f, 0x74, 0x25, 0x91, 0xba,
0x62, 0xca, 0x90, 0x00, 0x16, 0xbf, 0x37, 0x13, 0xd5, 0x63, 0x09, 0x77, 0xdb, 0xee, 0xb1, 0x81,
0xbd, 0x43, 0xa7, 0x85, 0x5f, 0x7a, 0xeb, 0xdb, 0x05, 0x67, 0x6c, 0x3a, 0x60, 0x74, 0x80, 0x83,
0x3d, 0xd7, 0xa6, 0x26, 0x37, 0xff, 0x68, 0x2d, 0x91, 0xd6, 0x24, 0x45, 0xad, 0xb2, 0xa6, 0x1a,
0xa5, 0x04, 0x4f, 0xdb, 0x91, 0x5f, 0x92, 0x05, 0x4e, 0x71, 0x46, 0x34, 0x05, 0x99, 0xa1, 0x6c,
0x3e, 0xf8, 0xcf, 0xb0, 0x21, 0xb9, 0x0b, 0x04, 0x76, 0xff, 0xef, 0x22, 0x02, 0xa7, 0xa3, 0x02,
0x48, 0xcb, 0xe0, 0x72, 0x49, 0x6d, 0x54, 0xf5, 0x2d, 0x54, 0x53, 0xcd, 0x8a, 0x5e, 0x42, 0xcd,
0xba, 0xd1, 0x50, 0x15, 0x6d, 0x5d, 0x53, 0x4b, 0x62, 0x4e, 0x5a, 0x00, 0xd2, 0x70, 0xb7, 0xdc,
0x34, 0x75, 0x51, 0x90, 0x0a, 0xe0, 0xc2, 0x70, 0x7b, 0x4d, 0xae, 0x37, 0xe5, 0xaa, 0x98, 0x2f,
0x62, 0x00, 0x06, 0xac, 0xa5, 0x25, 0x70, 0x89, 0xc3, 0x99, 0x5b, 0x0d, 0x75, 0x84, 0xf8, 0x55,
0xb0, 0x18, 0xed, 0xd4, 0xea, 0x86, 0x29, 0x57, 0xab, 0xc8, 0x50, 0xa0, 0xd6, 0x30, 0x45, 0x41,
0x5a, 0x04, 0x0b, 0xd1, 0x7e, 0xb9, 0x26, 0x7f, 0xa4, 0xd7, 0x91, 0xaa, 0x18, 0x62, 0xbe, 0xf8,
0xc9, 0x34, 0xb8, 0x35, 0x18, 0xbf, 0xe2, 0x61, 0x2b, 0xc0, 0xe1, 0xaf, 0x63, 0xc5, 0xed, 0xec,
0x38, 0xbb, 0x2f, 0xbd, 0x5d, 0xba, 0xe0, 0x4c, 0x8b, 0x8e, 0x74, 0xd8, 0x2e, 0x9f, 0x66, 0x30,
0x98, 0x64, 0x85, 0xad, 0xb2, 0xbf, 0x43, 0xfb, 0x6c, 0x45, 0x7e, 0x15, 0xff, 0x50, 0x00, 0xa7,
0xa3, 0xdd, 0xc4, 0x7a, 0x14, 0xbd, 0xbe, 0xae, 0x95, 0xe3, 0xad, 0x67, 0xac, 0x5b, 0xde, 0x34,
0x90, 0xaa, 0x3c, 0x42, 0x86, 0x51, 0x13, 0x05, 0x32, 0xff, 0xf1, 0xdd, 0xaa, 0xa6, 0xa8, 0x62,
0x3e, 0x1e, 0x1d, 0x96, 0x0c, 0x6a, 0x02, 0x53, 0xd2, 0x65, 0x70, 0x31, 0x06, 0x7d, 0xc3, 0x10,
0xa7, 0x8b, 0xff, 0x22, 0x80, 0x6b, 0x31, 0xf1, 0x92, 0xef, 0x0b, 0x5e, 0x7a, 0xc7, 0xff, 0x3f,
0xf3, 0xd1, 0xc5, 0x11, 0x0e, 0x9f, 0xcd, 0x5c, 0xcf, 0xc3, 0x35, 0xb3, 0x6a, 0xbc, 0xf4, 0x3a,
0xf8, 0xff, 0x79, 0xf0, 0x30, 0xea, 0x20, 0xfd, 0xfd, 0xc0, 0xed, 0x92, 0x30, 0x78, 0x88, 0x4b,
0x8e, 0x87, 0x5b, 0x81, 0xeb, 0x1d, 0x9b, 0xae, 0xdb, 0xf6, 0xb5, 0x8e, 0x1f, 0x58, 0x9f, 0x83,
0x6c, 0xe0, 0x3b, 0x79, 0xb0, 0x9a, 0xa6, 0x90, 0xbe, 0x89, 0xbc, 0xf4, 0xda, 0xf8, 0xe3, 0x3c,
0xb8, 0x33, 0xd0, 0x86, 0xdc, 0x0b, 0xdc, 0xf0, 0xef, 0x48, 0x0a, 0xf9, 0xd2, 0x47, 0x90, 0xbb,
0xe0, 0x6c, 0x7c, 0x3a, 0x3d, 0xef, 0x0d, 0xa7, 0xd1, 0xdf, 0xcc, 0x83, 0x9b, 0x03, 0x75, 0xa9,
0xca, 0x23, 0xba, 0x6a, 0x3a, 0x9f, 0xa7, 0xbd, 0xe8, 0x3f, 0x0a, 0xe0, 0xf2, 0x68, 0xc6, 0x45,
0x02, 0xd5, 0xe7, 0x6c, 0xe0, 0x2c, 0x73, 0xa8, 0xbb, 0xf6, 0xcb, 0xef, 0x23, 0x7e, 0x2e, 0x80,
0xab, 0xa3, 0x03, 0x97, 0xbb, 0x5d, 0x92, 0x66, 0x7f, 0x0e, 0x92, 0x88, 0x6f, 0xe7, 0xc1, 0xfd,
0x09, 0x49, 0x84, 0x26, 0xd7, 0x1a, 0x6e, 0xdb, 0x69, 0x1d, 0xbf, 0xf4, 0x8a, 0xf8, 0x77, 0x01,
0x14, 0x07, 0x8a, 0x68, 0x78, 0x4e, 0xa7, 0xe5, 0x74, 0xad, 0xb6, 0xff, 0xf9, 0x09, 0x96, 0xff,
0x2c, 0x80, 0xe5, 0x81, 0x06, 0x4c, 0xec, 0x07, 0xfc, 0xe0, 0xed, 0xf3, 0xe0, 0xf7, 0xff, 0x41,
0x00, 0x85, 0x88, 0x17, 0xe0, 0x17, 0x2f, 0xf6, 0x4b, 0x3f, 0xee, 0x25, 0xe2, 0xf5, 0xb9, 0xb7,
0xc7, 0x47, 0xd0, 0x6d, 0x47, 0x2f, 0x87, 0xfe, 0x92, 0x5a, 0xc4, 0x50, 0xaf, 0x61, 0x1d, 0x46,
0x2f, 0x3b, 0x6e, 0x82, 0x33, 0x24, 0x43, 0xb0, 0x2d, 0xcf, 0x46, 0x3d, 0x1f, 0xb3, 0xcb, 0x84,
0x59, 0x78, 0x3a, 0x6c, 0x6c, 0xfa, 0xd8, 0x96, 0x96, 0xc0, 0xdc, 0xb1, 0x75, 0xd0, 0x66, 0x00,
0x79, 0x0a, 0x30, 0x4b, 0x1a, 0x68, 0xe7, 0x1d, 0x70, 0xf6, 0xc0, 0xb5, 0x31, 0x3a, 0xda, 0xc3,
0x1d, 0xe4, 0x5b, 0x87, 0xd8, 0xe6, 0xf7, 0x2e, 0x67, 0x48, 0xf3, 0xe6, 0x1e, 0xee, 0x10, 0x96,
0xb6, 0x24, 0x83, 0xe5, 0x1d, 0x07, 0xb7, 0x6d, 0x1f, 0x1d, 0x39, 0xc1, 0x1e, 0x6a, 0xb9, 0x9d,
0x43, 0xec, 0xf9, 0x8e, 0xdb, 0x41, 0xf4, 0xac, 0xdf, 0x2f, 0x4c, 0x5f, 0x9f, 0xba, 0x37, 0x07,
0x17, 0x19, 0xd0, 0xa6, 0x13, 0xec, 0x29, 0x7d, 0x10, 0x95, 0x42, 0x14, 0x6f, 0x90, 0xed, 0xe2,
0xf0, 0x58, 0x49, 0x72, 0xd3, 0x8e, 0x8c, 0xf8, 0x55, 0xb0, 0x32, 0x02, 0xf2, 0xcc, 0xc1, 0x47,
0x25, 0xb7, 0xd5, 0x3b, 0xc0, 0x9d, 0xc0, 0x1a, 0x3e, 0x5e, 0x2b, 0xfe, 0x48, 0x00, 0x17, 0x65,
0xdf, 0x77, 0xc8, 0x4a, 0xa1, 0x06, 0xd3, 0x5f, 0x29, 0x77, 0xc1, 0x59, 0x2e, 0x21, 0xc5, 0x41,
0xfd, 0x6b, 0x96, 0xf9, 0x68, 0xb3, 0x66, 0x4b, 0x37, 0xc0, 0xe9, 0xc0, 0x0d, 0xac, 0x36, 0x0a,
0xdc, 0x7d, 0xdc, 0x61, 0xd7, 0x08, 0x53, 0xf0, 0x14, 0x6d, 0x33, 0x69, 0x13, 0xd1, 0x71, 0xd7,
0x73, 0x0f, 0xba, 0x41, 0x08, 0x33, 0x45, 0x61, 0x4e, 0xb3, 0x46, 0x0e, 0xf4, 0x0a, 0x38, 0xd7,
0xea, 0xcb, 0x10, 0x02, 0xb2, 0x2c, 0x4f, 0x1c, 0x74, 0x30, 0xe0, 0xe2, 0x5f, 0x09, 0xe0, 0x02,
0x93, 0x5b, 0xfd, 0x18, 0xb7, 0x7a, 0x9f, 0x42, 0xec, 0x65, 0x00, 0x3a, 0x64, 0xd6, 0x58, 0x36,
0xc9, 0x84, 0x9e, 0x23, 0x2d, 0x34, 0x91, 0x1c, 0x1b, 0xd5, 0x54, 0x86, 0x51, 0x4d, 0x67, 0x1d,
0xd5, 0x4c, 0xc2, 0xa8, 0x9e, 0x80, 0x45, 0x36, 0xa8, 0x3a, 0x3e, 0x52, 0x22, 0xe2, 0xf6, 0xef,
0xc6, 0x5a, 0x56, 0x80, 0x77, 0x5d, 0xef, 0x38, 0xbc, 0x1b, 0x0b, 0x7f, 0x17, 0xff, 0x44, 0x00,
0xe7, 0x19, 0xaa, 0x4c, 0xaf, 0x6e, 0x21, 0xfe, 0x5a, 0x0f, 0xfb, 0xd4, 0xba, 0xc3, 0xd5, 0xc6,
0xce, 0xea, 0x18, 0xe2, 0xe9, 0xb0, 0x91, 0x1e, 0x7e, 0xfd, 0x42, 0x66, 0xf0, 0x13, 0x01, 0x9c,
0x0e, 0x25, 0x26, 0xcd, 0xd2, 0x02, 0x38, 0x61, 0xd1, 0xbf, 0xb8, 0x8c, 0xfc, 0xd7, 0x2f, 0x46,
0xba, 0x5b, 0x40, 0x62, 0x8a, 0xac, 0x3a, 0x7e, 0x90, 0x78, 0xdb, 0xf8, 0x0d, 0x50, 0x88, 0x42,
0x1d, 0x6c, 0x47, 0x6e, 0x26, 0x25, 0x30, 0x1d, 0xb9, 0xc5, 0xa4, 0x7f, 0x4b, 0x3a, 0x38, 0x7b,
0x40, 0xa1, 0xfc, 0x3d, 0xa7, 0x8b, 0xf6, 0x9d, 0x0e, 0x73, 0x26, 0xf3, 0x8f, 0xee, 0x0c, 0x1c,
0x5f, 0xe4, 0xea, 0xfd, 0xf0, 0xe1, 0x6a, 0xad, 0x0f, 0xbe, 0xe1, 0x74, 0x6c, 0x38, 0x7f, 0x30,
0xf4, 0xbb, 0xf8, 0x15, 0x20, 0x0e, 0x04, 0x60, 0x8b, 0x5e, 0x2a, 0x8f, 0xb9, 0xfa, 0x64, 0xb7,
0x3a, 0x3e, 0xc6, 0x81, 0xb3, 0x1f, 0x26, 0xde, 0xec, 0xda, 0x9f, 0x1d, 0xf1, 0x12, 0x26, 0xa1,
0xea, 0xc5, 0x11, 0xff, 0x53, 0x01, 0x2c, 0x8c, 0x4e, 0xcc, 0x0b, 0xd6, 0x8e, 0xf4, 0x51, 0x38,
0x97, 0xa8, 0x4f, 0x2f, 0x2d, 0x22, 0x26, 0xd9, 0x4a, 0x38, 0xad, 0xb5, 0x49, 0xf2, 0xbf, 0xe0,
0x09, 0xf8, 0x2f, 0x97, 0xff, 0x05, 0xcf, 0xf1, 0x67, 0x2a, 0xff, 0x6f, 0xe7, 0xa3, 0xf2, 0x97,
0x3d, 0xab, 0x13, 0xf8, 0xa6, 0xdb, 0xf4, 0xb1, 0x27, 0xad, 0x82, 0xf3, 0x34, 0x62, 0x20, 0xcf,
0x6d, 0x63, 0x1f, 0xed, 0x92, 0x3e, 0x9e, 0x34, 0xcc, 0xc0, 0x73, 0xb4, 0x8b, 0xc4, 0x5c, 0xbf,
0xcc, 0x3a, 0x48, 0xd0, 0x67, 0xf0, 0x4e, 0x67, 0x0f, 0x7b, 0x0e, 0xbd, 0x18, 0x1c, 0xc2, 0x9c,
0xa2, 0x98, 0x8b, 0x14, 0x48, 0x0b, 0x61, 0x86, 0x48, 0xbc, 0x0e, 0x2e, 0x30, 0x12, 0x81, 0x67,
0x39, 0xc1, 0x00, 0x33, 0x4f, 0x31, 0x25, 0xda, 0x67, 0xd2, 0xae, 0x10, 0x43, 0x01, 0x57, 0x47,
0x99, 0x8e, 0xe0, 0x4e, 0x53, 0xdc, 0xa5, 0x61, 0xae, 0xc3, 0x44, 0x96, 0xc0, 0x5c, 0xcf, 0xc7,
0x1e, 0xa2, 0x5e, 0x6c, 0x66, 0x50, 0x8b, 0x51, 0xb7, 0x0e, 0x70, 0xf1, 0x07, 0x53, 0x51, 0x0d,
0x41, 0x7c, 0xe8, 0xe0, 0xa3, 0x17, 0xbd, 0xc2, 0x9e, 0x80, 0xcb, 0xb6, 0x75, 0xec, 0xa3, 0xae,
0xe5, 0x07, 0xa8, 0x83, 0x3f, 0x0e, 0x90, 0xd5, 0xb3, 0x9d, 0x00, 0x91, 0x75, 0xc0, 0x07, 0x7f,
0x91, 0x00, 0x34, 0x2c, 0x12, 0x30, 0x3f, 0x0e, 0x64, 0xd2, 0x5b, 0x22, 0x22, 0xac, 0x83, 0x6b,
0x11, 0x3f, 0xeb, 0xe1, 0xaf, 0xf5, 0x1c, 0x0f, 0x93, 0xf4, 0xc7, 0x47, 0xad, 0x3d, 0xab, 0xb3,
0xcb, 0xd5, 0x3e, 0x0b, 0x97, 0x07, 0x60, 0x30, 0x02, 0xa5, 0x30, 0x20, 0xe9, 0x09, 0x28, 0x78,
0x74, 0x68, 0x68, 0x87, 0x10, 0xc1, 0x9d, 0xd6, 0x71, 0x9f, 0xc0, 0x34, 0x25, 0xb0, 0xc0, 0xfa,
0xd7, 0xc3, 0xee, 0x10, 0xf3, 0x3d, 0xb0, 0xc4, 0x31, 0x6d, 0xeb, 0x18, 0xb9, 0x3b, 0xe8, 0xc0,
0xed, 0x90, 0x9c, 0x8f, 0x23, 0xcf, 0x50, 0xe4, 0x4b, 0x0c, 0xa4, 0x64, 0x1d, 0xeb, 0x3b, 0x35,
0xd2, 0x1f, 0x62, 0xbf, 0x0d, 0x2e, 0x77, 0x7a, 0xd4, 0xb6, 0xdd, 0x1d, 0xe4, 0xe1, 0x03, 0xf7,
0x10, 0xdb, 0x88, 0x8b, 0x5a, 0x38, 0x41, 0x47, 0xbe, 0xc0, 0x00, 0xf4, 0x1d, 0xc8, 0xba, 0x79,
0xa0, 0x28, 0xfe, 0x9a, 0x30, 0x3e, 0x31, 0x2f, 0x7a, 0xe9, 0x3d, 0x04, 0x17, 0x59, 0x94, 0x42,
0x24, 0x4c, 0x21, 0x3e, 0x50, 0xc7, 0xe6, 0xa5, 0x2b, 0x92, 0x35, 0xc2, 0x5f, 0xb3, 0x8b, 0xdf,
0x15, 0xc0, 0xe5, 0x48, 0x59, 0x04, 0xbb, 0xd8, 0x4e, 0x8a, 0xab, 0xd2, 0x1a, 0x98, 0x8e, 0x04,
0xc7, 0xd5, 0x44, 0x29, 0xc7, 0x28, 0xd2, 0x20, 0x49, 0x71, 0x87, 0xcd, 0x77, 0x6a, 0xc4, 0x7c,
0x5d, 0xb2, 0x2b, 0x18, 0xc3, 0xa6, 0xe5, 0x35, 0x2c, 0xd7, 0xaa, 0x8f, 0xe9, 0xea, 0x51, 0x76,
0x29, 0x62, 0x22, 0x92, 0x07, 0xae, 0xc7, 0x30, 0x0c, 0x37, 0x69, 0x9f, 0x0d, 0xcf, 0xaf, 0x83,
0xa5, 0x98, 0x21, 0xf6, 0x2b, 0x96, 0x2a, 0x60, 0xba, 0xe5, 0xda, 0x61, 0x29, 0xd4, 0xe3, 0xec,
0xac, 0x18, 0xbe, 0xe2, 0xda, 0x18, 0x52, 0x0a, 0x09, 0xa5, 0x4b, 0xdf, 0xcc, 0x83, 0x2b, 0xb1,
0x4a, 0xc6, 0xdd, 0xcf, 0x64, 0xbc, 0xc4, 0x6a, 0xfc, 0x00, 0x77, 0x9f, 0xdf, 0x6a, 0x88, 0x48,
0x90, 0xe2, 0x4a, 0xd5, 0x91, 0x1d, 0xe9, 0xe3, 0xe7, 0xa3, 0x32, 0x7e, 0x34, 0x75, 0x33, 0x4e,
0x05, 0xec, 0x44, 0x42, 0xef, 0xe2, 0xce, 0x2f, 0xaf, 0x26, 0x36, 0xc0, 0x49, 0x9f, 0xc9, 0x49,
0x55, 0x31, 0x3f, 0x21, 0xae, 0x26, 0x0d, 0x10, 0x86, 0x14, 0x8a, 0xdf, 0xca, 0x83, 0xdb, 0x31,
0x8a, 0x58, 0x27, 0x3b, 0xdd, 0xcf, 0x74, 0x11, 0xbc, 0x10, 0x55, 0xa8, 0x60, 0x86, 0xee, 0xc9,
0xb9, 0x22, 0x1e, 0x64, 0x27, 0x42, 0x07, 0x08, 0x19, 0x76, 0xf1, 0xdf, 0x84, 0x04, 0x27, 0x40,
0xf6, 0x9c, 0xdd, 0xe3, 0x5f, 0xde, 0xf1, 0xaf, 0x83, 0x69, 0xba, 0x77, 0x64, 0xc3, 0x7f, 0x0e,
0x79, 0xc8, 0xd0, 0x68, 0x65, 0x07, 0xc5, 0x2f, 0xfe, 0x85, 0x00, 0x6e, 0xc4, 0x28, 0xa0, 0xea,
0x74, 0xf6, 0x23, 0x07, 0x32, 0xbf, 0x8c, 0x1a, 0x90, 0xc0, 0x74, 0xdb, 0xe9, 0xec, 0xf3, 0x38,
0x42, 0xff, 0x2e, 0xfe, 0xad, 0x00, 0xce, 0xf7, 0xcb, 0x91, 0x69, 0xea, 0xd3, 0x3f, 0x50, 0x4a,
0xdf, 0x72, 0x47, 0x2e, 0xb4, 0x90, 0xeb, 0x39, 0xbb, 0x4e, 0x87, 0x3b, 0xcf, 0xfe, 0x85, 0x96,
0x4e, 0x5b, 0xa5, 0xdb, 0x60, 0xbe, 0xd5, 0x76, 0x7b, 0x36, 0xea, 0x7a, 0xee, 0xa1, 0x63, 0x63,
0x2f, 0x3c, 0x5b, 0xa2, 0xad, 0x0d, 0xde, 0x28, 0xe9, 0x60, 0xd6, 0xe6, 0x27, 0xdf, 0x34, 0x33,
0x39, 0xf5, 0xe8, 0x8d, 0xd4, 0xb3, 0x34, 0x6c, 0x87, 0x87, 0xe5, 0x03, 0xad, 0x85, 0x44, 0x8a,
0xcf, 0xc0, 0x62, 0x32, 0x9c, 0x74, 0x09, 0x9c, 0xb4, 0xb7, 0xa3, 0xa3, 0x3b, 0x61, 0x6f, 0xd3,
0x71, 0x5d, 0x03, 0xa7, 0xec, 0x6d, 0x44, 0x6b, 0xc6, 0x5b, 0x6e, 0x9b, 0x8f, 0x09, 0xd8, 0xdb,
0x0d, 0xde, 0x52, 0xfc, 0x99, 0x00, 0x16, 0xd7, 0xb1, 0x15, 0xf4, 0x3c, 0x0c, 0x71, 0xcb, 0x3d,
0x38, 0xc0, 0x1d, 0x3b, 0x72, 0xc6, 0x31, 0x14, 0xb5, 0x85, 0xe1, 0xa8, 0x2d, 0xbd, 0x03, 0x4e,
0xee, 0x30, 0x54, 0x3e, 0x99, 0xd7, 0x13, 0xc7, 0x18, 0xb2, 0x08, 0x11, 0xa4, 0x8f, 0xc1, 0x32,
0xff, 0x13, 0x79, 0x43, 0x7c, 0x51, 0xc4, 0xdf, 0x4f, 0x0a, 0x83, 0xb1, 0x42, 0x73, 0x7f, 0xbf,
0xb4, 0x93, 0xdc, 0x59, 0x3c, 0x02, 0x17, 0x4c, 0xb9, 0xcc, 0x8e, 0xa9, 0xf0, 0x87, 0x3d, 0xec,
0xf1, 0x95, 0x7e, 0x0d, 0xb0, 0x33, 0x0c, 0xd4, 0x71, 0x6d, 0xcc, 0xca, 0x86, 0xa7, 0x20, 0xa0,
0x4d, 0x75, 0xd2, 0x32, 0x00, 0xc0, 0xf6, 0x2e, 0x0e, 0xcf, 0x3d, 0x18, 0x80, 0x4a, 0x5a, 0xa4,
0x65, 0x00, 0x1c, 0x1f, 0xf9, 0x3d, 0x9a, 0x6e, 0xf1, 0x8c, 0x76, 0xce, 0xf1, 0x0d, 0xd6, 0x50,
0xfc, 0xfb, 0x29, 0x70, 0x89, 0xe5, 0x71, 0x65, 0xcf, 0xea, 0xee, 0xc9, 0x9b, 0x86, 0xd1, 0xb2,
0x3a, 0x61, 0x59, 0xdd, 0x79, 0x4e, 0xbb, 0xf5, 0x08, 0x39, 0xfc, 0x8e, 0x94, 0x09, 0x31, 0x0d,
0xcf, 0x31, 0x1e, 0xad, 0xfe, 0xe5, 0x69, 0x44, 0x16, 0x32, 0x19, 0x4c, 0x96, 0x69, 0x2e, 0x0b,
0xd9, 0x16, 0xf9, 0x83, 0x53, 0x9a, 0x5d, 0xcf, 0xed, 0x75, 0x99, 0x34, 0xd3, 0xfc, 0x94, 0xa6,
0x4c, 0x9b, 0x06, 0x34, 0xe8, 0x06, 0x88, 0x9a, 0x69, 0x48, 0x83, 0xee, 0x77, 0x88, 0xad, 0x33,
0x80, 0xae, 0xdb, 0x76, 0x5a, 0x0e, 0x66, 0x07, 0x65, 0xd3, 0xf0, 0x0c, 0x6d, 0x6d, 0xf0, 0x46,
0xe9, 0x55, 0x20, 0x71, 0xd9, 0xf7, 0x7d, 0xd4, 0x6a, 0xf7, 0xfc, 0x20, 0x4c, 0x8b, 0xa7, 0xa1,
0xc8, 0x44, 0xdf, 0xf7, 0x15, 0xde, 0x3e, 0x18, 0xa9, 0x67, 0xfb, 0x91, 0x91, 0x9e, 0x8c, 0x8c,
0x14, 0xda, 0xfe, 0x60, 0xa4, 0xf7, 0x00, 0xa3, 0x81, 0xfc, 0x37, 0xd0, 0x76, 0xaf, 0xb5, 0x8f,
0x03, 0xbf, 0x30, 0x4b, 0x81, 0x99, 0x70, 0xc6, 0x1b, 0x6b, 0xac, 0x95, 0xec, 0xcb, 0x38, 0xa4,
0x75, 0xd0, 0xee, 0xaf, 0x4f, 0xbf, 0x30, 0x47, 0xa1, 0x99, 0x8c, 0x86, 0x75, 0xd0, 0x0e, 0x17,
0x69, 0x04, 0xc3, 0x75, 0xec, 0x56, 0x04, 0x03, 0x44, 0x30, 0x74, 0xc7, 0x6e, 0x0d, 0x30, 0xfa,
0x2a, 0xb1, 0x5a, 0x74, 0xaf, 0xe6, 0x17, 0x4e, 0x45, 0x54, 0x22, 0xf3, 0xc6, 0xe2, 0x0f, 0x04,
0x70, 0xab, 0xa9, 0x45, 0x26, 0x5b, 0xf1, 0xdc, 0xa3, 0xce, 0x53, 0x7c, 0x84, 0xdb, 0x25, 0x67,
0x67, 0xe7, 0x99, 0x83, 0x8f, 0xd8, 0xbc, 0x3f, 0x01, 0x05, 0x6b, 0x67, 0x67, 0xb8, 0x40, 0x15,
0x45, 0x6a, 0xe2, 0xe7, 0xe0, 0x42, 0xd8, 0xdf, 0xaf, 0xe2, 0x66, 0x67, 0xf5, 0x8f, 0xc1, 0xc2,
0x38, 0x66, 0xe4, 0x05, 0xc2, 0x85, 0x51, 0x3c, 0x5a, 0xc6, 0xb7, 0x0e, 0xae, 0x18, 0xb8, 0xd5,
0xf3, 0x9c, 0xe0, 0x18, 0xd2, 0x65, 0x55, 0xc6, 0x01, 0xc4, 0x7e, 0xaf, 0xcd, 0xf3, 0xec, 0xb8,
0x53, 0x32, 0x09, 0x4c, 0x93, 0x6d, 0x1d, 0xdf, 0xe2, 0xd1, 0xbf, 0x8b, 0x16, 0x38, 0xdf, 0x2f,
0x02, 0x5b, 0xc7, 0x41, 0x6b, 0x8f, 0xa1, 0x8f, 0x7b, 0x47, 0x21, 0xce, 0x3b, 0x8e, 0xb9, 0xe4,
0xfc, 0xb8, 0x4b, 0x2e, 0x7e, 0x5f, 0x00, 0x12, 0xb1, 0x65, 0xd3, 0xf2, 0xf7, 0xc9, 0xd2, 0xc5,
0x7d, 0x8f, 0x14, 0x58, 0xfe, 0x7e, 0xd4, 0xd9, 0xcd, 0x92, 0x86, 0xf0, 0xb5, 0x85, 0xe3, 0xfb,
0xbd, 0x21, 0xaa, 0x73, 0xb4, 0x85, 0x76, 0x5f, 0x00, 0x33, 0xc4, 0xbb, 0x84, 0xfb, 0x0f, 0xf6,
0x83, 0xf8, 0xfe, 0xbe, 0x1d, 0x46, 0x8a, 0x19, 0x66, 0xe0, 0x7c, 0xbf, 0x99, 0x15, 0x33, 0xfc,
0xe6, 0x07, 0xe0, 0x6c, 0x93, 0x78, 0x21, 0x2a, 0x89, 0xde, 0xc1, 0xfa, 0x8e, 0xd4, 0x04, 0x67,
0x7b, 0x0e, 0xda, 0xa6, 0x2f, 0x71, 0x50, 0x8b, 0x44, 0xcd, 0xd4, 0xbd, 0xdc, 0xf8, 0xc3, 0x9d,
0x4a, 0x0e, 0x9e, 0xe9, 0x39, 0x91, 0x56, 0xe9, 0x13, 0x01, 0xdc, 0xef, 0x39, 0xc8, 0x65, 0x0f,
0x53, 0x10, 0x3f, 0x0f, 0xc5, 0x68, 0xd7, 0x45, 0x81, 0x8b, 0xec, 0xf0, 0xe5, 0x0e, 0xe7, 0xc8,
0x72, 0x63, 0x79, 0x02, 0xc7, 0x6c, 0xcf, 0x7f, 0x2a, 0x39, 0x78, 0xb3, 0xe7, 0xa4, 0xc2, 0x4a,
0xdf, 0x11, 0xc0, 0xcd, 0x88, 0x74, 0x96, 0x6d, 0xa3, 0x1d, 0xc7, 0xa3, 0x5b, 0x4f, 0x3e, 0xab,
0x4c, 0x2e, 0x16, 0xf9, 0xde, 0x4b, 0x97, 0x2b, 0xf9, 0x39, 0x51, 0x25, 0x07, 0xaf, 0xf6, 0x45,
0x8a, 0x05, 0x1b, 0xd5, 0x55, 0x8c, 0x34, 0x6d, 0x2b, 0xe8, 0xcf, 0xce, 0x4c, 0x56, 0x5d, 0xa5,
0xbc, 0x5d, 0x1a, 0xd2, 0x55, 0x32, 0xac, 0xf4, 0xbf, 0x05, 0x70, 0x3d, 0x22, 0x9d, 0x8f, 0x03,
0xd4, 0xea, 0x3f, 0x73, 0x42, 0x3e, 0x7d, 0x61, 0x44, 0x9d, 0xe5, 0xa9, 0x47, 0xef, 0xa4, 0x0b,
0x95, 0xf4, 0x48, 0xaa, 0x92, 0x83, 0x57, 0xfa, 0xd2, 0xc4, 0x00, 0x49, 0xbf, 0x22, 0x80, 0x5b,
0x11, 0x31, 0x3c, 0x5e, 0xd2, 0x88, 0x5a, 0xe1, 0x5b, 0xa7, 0x50, 0x94, 0x93, 0x54, 0x94, 0x2f,
0xa5, 0x8b, 0x32, 0xe9, 0xb5, 0x54, 0x25, 0x07, 0xaf, 0xf7, 0xc5, 0x49, 0x00, 0x0c, 0x35, 0xe3,
0xf1, 0xf7, 0x47, 0x88, 0xec, 0x5d, 0xc9, 0x02, 0x64, 0xef, 0x9f, 0xf8, 0x74, 0xcd, 0xa6, 0x6a,
0x26, 0xe5, 0xf5, 0x14, 0xd3, 0x4c, 0x32, 0x90, 0xf4, 0x31, 0xb8, 0x12, 0x27, 0x45, 0xf7, 0x98,
0x4b, 0x30, 0x47, 0x25, 0xf8, 0x42, 0x76, 0x09, 0xa2, 0xcf, 0xaf, 0x2a, 0x39, 0x58, 0x18, 0xe3,
0xce, 0x01, 0xa4, 0xff, 0x01, 0x96, 0xc7, 0x39, 0x77, 0x3d, 0xa7, 0x13, 0x70, 0xd6, 0x80, 0xb2,
0x7e, 0x2b, 0x2b, 0xeb, 0x91, 0xc7, 0x5b, 0x95, 0x1c, 0xbc, 0x3c, 0xc2, 0x7b, 0x00, 0x21, 0xb5,
0xc1, 0xe5, 0x9e, 0x83, 0x6c, 0xee, 0xc4, 0x49, 0xd6, 0xe5, 0x91, 0x50, 0x42, 0x89, 0xd3, 0xa0,
0x76, 0x6a, 0xc2, 0xc6, 0x2a, 0xfe, 0x09, 0x54, 0x25, 0x07, 0x17, 0x7a, 0x4e, 0xec, 0xe3, 0xa8,
0xef, 0x30, 0xf3, 0xeb, 0xb3, 0x1b, 0xc4, 0xba, 0xb0, 0x0e, 0x8c, 0x73, 0x3e, 0x4d, 0x39, 0xbf,
0x9d, 0x81, 0x73, 0xfc, 0xab, 0x26, 0x66, 0x79, 0x29, 0x2f, 0x9f, 0xbe, 0x41, 0x0d, 0xaf, 0x2f,
0x0c, 0xaf, 0x9d, 0xf7, 0x59, 0x19, 0x3c, 0x17, 0xe4, 0x0c, 0x15, 0xe4, 0xcd, 0x4f, 0x55, 0x44,
0xcf, 0x6c, 0x6e, 0xc2, 0xa3, 0x87, 0xff, 0xcb, 0x1c, 0xe8, 0x40, 0x02, 0x9e, 0xd0, 0x0f, 0xd6,
0x25, 0x13, 0x62, 0x9e, 0x0a, 0xf1, 0x24, 0x8b, 0x10, 0x71, 0xb5, 0xca, 0x95, 0x1c, 0xbc, 0x16,
0x91, 0x23, 0xb6, 0x9c, 0xf9, 0x37, 0x98, 0xf7, 0x1c, 0x17, 0xa5, 0x15, 0x96, 0xa9, 0xa0, 0x83,
0xa0, 0xed, 0x73, 0x81, 0xce, 0x52, 0x81, 0xbe, 0xf8, 0x1c, 0x02, 0x8d, 0x57, 0x0f, 0x57, 0x72,
0xf0, 0xd6, 0xb8, 0x54, 0x03, 0xb8, 0xa0, 0xcd, 0x0b, 0x28, 0xff, 0x4c, 0x00, 0x4f, 0x86, 0xe7,
0x89, 0xd6, 0x9e, 0x22, 0x8b, 0x16, 0x9f, 0x22, 0x3b, 0xac, 0x3e, 0x45, 0x81, 0xeb, 0xb6, 0x79,
0x32, 0xd9, 0x6e, 0x73, 0x49, 0x45, 0x2a, 0xe9, 0xd3, 0x4c, 0xf3, 0x97, 0xa9, 0xc6, 0xb7, 0x92,
0x83, 0x0f, 0xa3, 0x93, 0x9a, 0xad, 0x30, 0xf8, 0xc7, 0x02, 0x78, 0x9c, 0x69, 0x0c, 0x03, 0x75,
0x33, 0xf9, 0xcf, 0x51, 0xf9, 0xcb, 0x9f, 0x5a, 0xfe, 0xe1, 0x2a, 0xa3, 0x4a, 0x0e, 0xae, 0xa6,
0x09, 0x3f, 0x52, 0x97, 0xf4, 0x5b, 0x02, 0x78, 0x25, 0x2a, 0xb9, 0xd5, 0x23, 0x99, 0x47, 0x7f,
0x0f, 0x1a, 0x79, 0x4f, 0xc5, 0x04, 0x96, 0xa8, 0xc0, 0xef, 0x67, 0x10, 0x78, 0x52, 0xd5, 0x6c,
0x25, 0x07, 0xef, 0x0c, 0x04, 0x9d, 0x58, 0x5f, 0xfb, 0x47, 0x02, 0x78, 0x90, 0x62, 0xb9, 0x8e,
0x75, 0xc0, 0x36, 0x2f, 0xc7, 0x5c, 0xc8, 0xf3, 0x54, 0xc8, 0xb5, 0x4f, 0x63, 0xbf, 0xc3, 0x85,
0x6b, 0x95, 0x1c, 0xbc, 0x3f, 0xc1, 0x88, 0x35, 0xeb, 0x20, 0x5a, 0xe5, 0xf6, 0xab, 0x02, 0xb8,
0x13, 0x15, 0xb5, 0xdb, 0x2f, 0x06, 0x1b, 0x9b, 0xf7, 0x0b, 0x54, 0xc2, 0x77, 0x33, 0x48, 0x98,
0x54, 0x51, 0x56, 0xc9, 0xc1, 0xe2, 0x40, 0xb4, 0xc4, 0xba, 0xb3, 0x6f, 0x09, 0xe0, 0x46, 0x54,
0xa6, 0x00, 0xfb, 0x01, 0x91, 0xa6, 0x33, 0xe4, 0x8f, 0x2f, 0xa6, 0x46, 0xbf, 0x09, 0xe5, 0x5d,
0x95, 0x1c, 0x5c, 0x1e, 0x48, 0x12, 0x57, 0xff, 0xe5, 0x81, 0xa5, 0xa8, 0x0c, 0x61, 0x9e, 0x1b,
0xc6, 0xa1, 0x85, 0x94, 0x1b, 0xc4, 0xa4, 0xfa, 0x2a, 0x16, 0x76, 0x13, 0x6a, 0xaf, 0xda, 0xa0,
0xd0, 0x73, 0x48, 0x12, 0x66, 0x05, 0x18, 0x75, 0xf0, 0x11, 0xdd, 0xff, 0xf2, 0x88, 0x7b, 0x29,
0xe5, 0x80, 0x2b, 0xb1, 0xb2, 0xa9, 0x92, 0x83, 0x17, 0x7a, 0xce, 0x78, 0xa7, 0x74, 0x4c, 0x83,
0xfc, 0x28, 0x37, 0xdf, 0x3a, 0x0c, 0x59, 0x16, 0x52, 0x35, 0x3c, 0xa1, 0x5c, 0x8a, 0x0d, 0x34,
0x1e, 0x40, 0xfa, 0x06, 0xb8, 0x16, 0x37, 0x50, 0x5a, 0xa1, 0xc4, 0x99, 0x5f, 0x4e, 0x0d, 0x30,
0x13, 0xab, 0x9b, 0x2a, 0x39, 0xb8, 0x38, 0x3a, 0xea, 0x01, 0x88, 0xf4, 0xbb, 0xcc, 0x85, 0x8c,
0x4a, 0xc0, 0xee, 0xe1, 0xa2, 0x15, 0x50, 0x5c, 0x9a, 0x45, 0x2a, 0x8d, 0x92, 0x55, 0x9a, 0x09,
0x85, 0x54, 0x95, 0x1c, 0xbc, 0x3d, 0x22, 0x58, 0x3c, 0xb4, 0xf4, 0x07, 0x02, 0x58, 0x8d, 0x9a,
0xa0, 0x33, 0x38, 0x76, 0x44, 0xd6, 0x91, 0xcf, 0x8e, 0x06, 0xf8, 0xb2, 0xe0, 0x56, 0xb9, 0x94,
0xba, 0x85, 0xc8, 0xf6, 0xf2, 0xb8, 0x92, 0x83, 0xf7, 0x06, 0x56, 0x1a, 0x85, 0x3d, 0xf2, 0x75,
0xc7, 0x6e, 0x0d, 0xbd, 0x52, 0xfe, 0xae, 0x00, 0x6e, 0xc7, 0xa7, 0x0c, 0xb6, 0x8f, 0x30, 0x3d,
0x20, 0xe5, 0xe2, 0x5d, 0xc9, 0x9c, 0x42, 0xc5, 0x3f, 0x08, 0x1e, 0x4e, 0xa1, 0xfa, 0x30, 0xb6,
0x1f, 0x7d, 0xfe, 0x1a, 0x30, 0xb3, 0x26, 0xf1, 0x36, 0x70, 0x11, 0x2b, 0x0d, 0x62, 0xb3, 0xc8,
0xa5, 0x58, 0x4e, 0x5d, 0xba, 0xf1, 0x2f, 0x4c, 0xb9, 0x45, 0xc7, 0xbf, 0x3e, 0xfd, 0x2a, 0x38,
0x67, 0xd1, 0x1a, 0x25, 0x34, 0xa8, 0x10, 0x2a, 0x5c, 0xa5, 0x9c, 0x92, 0x0f, 0x92, 0x63, 0xeb,
0xe9, 0x2a, 0x39, 0x28, 0x5a, 0x23, 0x1d, 0xa1, 0x4b, 0x8c, 0x9a, 0x00, 0xd7, 0x2c, 0x4d, 0x8f,
0xf9, 0xc8, 0xae, 0xa5, 0x2e, 0xd8, 0x09, 0x37, 0x99, 0xcc, 0x25, 0x4e, 0xba, 0xea, 0xe4, 0xa9,
0x72, 0x8c, 0x10, 0xfd, 0x53, 0x00, 0x26, 0xc7, 0xf5, 0xd4, 0x79, 0x9e, 0x7c, 0xc1, 0xc9, 0xe6,
0x39, 0xe5, 0x12, 0xf4, 0x7f, 0x09, 0xd4, 0x89, 0x84, 0xfb, 0xc6, 0xaf, 0x45, 0xbf, 0xb1, 0x11,
0x6e, 0x19, 0x6f, 0x64, 0xdd, 0xbd, 0x26, 0x7d, 0xa1, 0x63, 0x68, 0xf7, 0x1a, 0x03, 0x24, 0x7d,
0x04, 0xf8, 0x64, 0x21, 0x1c, 0x96, 0x17, 0x16, 0x8a, 0x94, 0xeb, 0x6b, 0x29, 0xd3, 0x3e, 0x5c,
0x8e, 0x58, 0xc9, 0xc1, 0xb3, 0xd6, 0x70, 0xbb, 0x74, 0x00, 0x2e, 0x71, 0xda, 0xc4, 0x41, 0x45,
0xab, 0x12, 0x0b, 0x37, 0x53, 0x4e, 0xee, 0x93, 0x8b, 0x03, 0x2b, 0x39, 0x78, 0xd1, 0x8a, 0xeb,
0x95, 0xb6, 0xc1, 0xc5, 0xc1, 0x29, 0x09, 0x73, 0x8c, 0x6c, 0x3a, 0x6f, 0x51, 0x66, 0xaf, 0x26,
0x32, 0x8b, 0xb9, 0xdb, 0xa8, 0xe4, 0xe0, 0x79, 0x2f, 0xe6, 0xca, 0xe3, 0x08, 0x5c, 0x49, 0x38,
0x5c, 0x67, 0xac, 0x6e, 0xa7, 0x8c, 0x2b, 0xf9, 0x42, 0x80, 0x38, 0xfc, 0x9d, 0xe4, 0xeb, 0x82,
0x6d, 0xc0, 0x47, 0x8d, 0x78, 0x41, 0x82, 0xc7, 0xea, 0x1e, 0x0b, 0x77, 0x52, 0x06, 0x17, 0x53,
0x2b, 0x49, 0x06, 0x67, 0xc5, 0x94, 0x50, 0x56, 0xc1, 0x99, 0x3e, 0x0f, 0x3a, 0x4b, 0x77, 0x29,
0xed, 0xdb, 0xa9, 0xb4, 0x09, 0x70, 0x25, 0x07, 0x4f, 0x5b, 0xd1, 0x2a, 0xc7, 0x2d, 0x20, 0x45,
0x6b, 0x27, 0xd8, 0x8c, 0x14, 0xee, 0xa5, 0x94, 0x64, 0x8f, 0x16, 0xf9, 0x51, 0x6f, 0x32, 0x5a,
0xf8, 0x37, 0x42, 0xba, 0x47, 0x0b, 0xc6, 0x0a, 0xf7, 0x33, 0x93, 0x66, 0x15, 0x66, 0xc3, 0xa4,
0x79, 0xd5, 0xd9, 0x08, 0x69, 0x9b, 0x16, 0x94, 0x14, 0x56, 0x32, 0x93, 0x66, 0x15, 0x28, 0xc3,
0xa4, 0x79, 0x55, 0x4a, 0x1b, 0x5c, 0x8e, 0x92, 0xe6, 0x35, 0x5d, 0x5c, 0x2f, 0xaf, 0xa4, 0x9c,
0x0b, 0xc4, 0x17, 0xf9, 0x55, 0x72, 0x70, 0xc1, 0x8a, 0x2f, 0xff, 0x8b, 0xe7, 0xc6, 0x55, 0xf5,
0xea, 0x73, 0x72, 0xeb, 0x2b, 0x6c, 0x8c, 0x1b, 0x57, 0x5b, 0x3c, 0x37, 0xae, 0xbd, 0xd7, 0x9e,
0x93, 0x5b, 0x5f, 0x87, 0x63, 0xdc, 0xb8, 0x26, 0x0f, 0xc0, 0x62, 0x94, 0x1b, 0x2d, 0xf5, 0xf2,
0x49, 0xb4, 0xec, 0xf9, 0xd8, 0x2b, 0xac, 0x66, 0x66, 0x17, 0xad, 0x77, 0x1b, 0x66, 0x37, 0x54,
0x09, 0xf7, 0xff, 0x04, 0x50, 0x8c, 0x26, 0x08, 0xd1, 0x9b, 0xa4, 0xc1, 0x31, 0x4b, 0xe1, 0x41,
0xea, 0x99, 0x6c, 0xea, 0x6b, 0x3d, 0x76, 0x26, 0xdb, 0x07, 0x6b, 0x8d, 0x83, 0x49, 0xfb, 0xe0,
0x52, 0xcc, 0x09, 0x0b, 0x76, 0x5a, 0xb8, 0xf0, 0x7a, 0x6a, 0x8a, 0x9d, 0xf0, 0x56, 0x8e, 0xa5,
0xd8, 0x23, 0x9d, 0x4e, 0x0b, 0x8f, 0x32, 0x0b, 0xd3, 0x4d, 0xd7, 0xc6, 0x85, 0x87, 0x99, 0x99,
0x8d, 0xbc, 0x4f, 0x1b, 0x66, 0x36, 0xe8, 0x94, 0xbe, 0x02, 0xce, 0x05, 0xd6, 0x2e, 0x8f, 0x43,
0x98, 0x04, 0x44, 0xef, 0xb8, 0xf0, 0x28, 0x25, 0x16, 0xc5, 0x5d, 0x38, 0x92, 0x58, 0x14, 0x58,
0xbb, 0xd1, 0x76, 0x29, 0x00, 0x8b, 0x3e, 0xbf, 0x9e, 0x41, 0x1e, 0xa5, 0x84, 0x76, 0x31, 0x3d,
0xc8, 0xee, 0xb5, 0x83, 0xc2, 0x1b, 0x29, 0x47, 0x52, 0x93, 0x6e, 0x76, 0x2a, 0x39, 0x78, 0xc9,
0x8f, 0xef, 0x1f, 0x5d, 0x16, 0xbc, 0x7e, 0x8c, 0x2f, 0xf9, 0xc7, 0x99, 0xed, 0x34, 0x5a, 0x75,
0x38, 0x6c, 0xa7, 0x43, 0xf5, 0x88, 0xf1, 0xdc, 0xf8, 0x22, 0x7c, 0xf3, 0x39, 0xb9, 0xc5, 0x2d,
0xc2, 0xa1, 0x22, 0xbb, 0x6d, 0x70, 0x31, 0x34, 0x8c, 0x63, 0xb4, 0x83, 0x83, 0xd6, 0x1e, 0x8f,
0x81, 0x5f, 0x48, 0x89, 0x48, 0x31, 0xd7, 0x5b, 0x24, 0x22, 0xd9, 0x31, 0xb7, 0x5e, 0xdf, 0x1b,
0x39, 0xcd, 0xe3, 0x06, 0x38, 0xe0, 0xcb, 0xf6, 0xf8, 0x85, 0xb7, 0x32, 0x1f, 0x9e, 0x25, 0x7f,
0x66, 0x61, 0xf8, 0x48, 0x2f, 0x16, 0x4e, 0xfa, 0xe6, 0xc8, 0xce, 0x7e, 0xbf, 0xb7, 0x8d, 0xe9,
0xe5, 0xec, 0xd0, 0x36, 0xe1, 0x49, 0xe6, 0x03, 0xce, 0xf1, 0xaf, 0xdf, 0x0c, 0x1f, 0x70, 0xd2,
0xfe, 0xfd, 0xa1, 0xed, 0xc1, 0xb7, 0xe3, 0x55, 0x62, 0x75, 0xbb, 0xf4, 0x98, 0xb5, 0x7f, 0xc0,
0xf9, 0x76, 0xea, 0x09, 0xf7, 0xa4, 0x67, 0x94, 0xc3, 0x8e, 0x28, 0xf6, 0xa1, 0x65, 0x17, 0x2c,
0x71, 0x6b, 0xdb, 0xf5, 0xac, 0xee, 0x1e, 0xdd, 0xd2, 0xf9, 0x2d, 0x2b, 0xcc, 0x84, 0xde, 0xa1,
0xfc, 0x5f, 0x4f, 0xb1, 0xb7, 0xb1, 0xfb, 0x7a, 0xb2, 0x9a, 0xac, 0x48, 0xd7, 0x91, 0x3f, 0xb8,
0xca, 0xff, 0x3e, 0xdb, 0xa8, 0x0d, 0x71, 0x6d, 0x79, 0xee, 0x51, 0x07, 0xfd, 0x77, 0x7c, 0x84,
0xdb, 0xc8, 0x76, 0x76, 0x76, 0xe8, 0x16, 0xb8, 0xf0, 0x6e, 0xaa, 0x3d, 0xa4, 0xdf, 0x20, 0x33,
0x7b, 0x98, 0x08, 0x27, 0xfd, 0x37, 0x70, 0x91, 0x16, 0x71, 0xd0, 0x7b, 0x53, 0x7a, 0xe7, 0xc9,
0x47, 0xff, 0x5e, 0xda, 0x4d, 0xe5, 0xd8, 0xf5, 0x6b, 0x25, 0x07, 0xa5, 0xde, 0xf8, 0xa5, 0x2c,
0x3b, 0x50, 0x8f, 0xdd, 0x37, 0xe1, 0x2e, 0x67, 0xf6, 0xc5, 0x54, 0x7b, 0x4b, 0xae, 0x4d, 0x64,
0xf6, 0x36, 0xa1, 0x76, 0xf1, 0xd7, 0x05, 0x70, 0x2f, 0x41, 0x02, 0x7e, 0x9c, 0xe5, 0x76, 0x71,
0x38, 0xe9, 0x5f, 0x4a, 0x0d, 0x81, 0xa9, 0x25, 0x82, 0xec, 0xf6, 0x2f, 0xbd, 0x92, 0xf0, 0x13,
0x01, 0xac, 0xc4, 0xcb, 0x45, 0x6b, 0xd0, 0x46, 0xb7, 0x74, 0xef, 0xa7, 0x5e, 0xbe, 0x65, 0xa8,
0xd9, 0x63, 0x67, 0x1f, 0x59, 0x8a, 0xfb, 0xf8, 0x99, 0x42, 0xec, 0x56, 0x93, 0x3e, 0xc5, 0xea,
0x86, 0xe7, 0xa6, 0x1f, 0x7c, 0x9a, 0xbd, 0x66, 0xa4, 0x8e, 0x2e, 0x71, 0xaf, 0x19, 0xad, 0xb5,
0xfb, 0x3e, 0x3b, 0x25, 0x8d, 0x11, 0xa7, 0xed, 0x74, 0xf6, 0x87, 0x4e, 0x17, 0xe4, 0xd4, 0x2d,
0x67, 0x4a, 0x59, 0x5b, 0x25, 0x07, 0x6f, 0xc4, 0x08, 0x34, 0x0c, 0xb4, 0x76, 0x12, 0xcc, 0x50,
0x9a, 0x4f, 0xa7, 0x67, 0xf3, 0xe2, 0x14, 0xb1, 0xc1, 0xfe, 0x4e, 0x98, 0xc4, 0xe5, 0xf0, 0xd2,
0x8c, 0x4a, 0xb6, 0xf2, 0x43, 0x71, 0xf0, 0x41, 0xc4, 0x70, 0xb3, 0x26, 0xdd, 0x00, 0xcb, 0x25,
0xcd, 0x50, 0xf4, 0x67, 0x2a, 0x44, 0x50, 0x35, 0xf4, 0x26, 0x54, 0x46, 0x3f, 0x67, 0x74, 0x05,
0x14, 0xc6, 0x41, 0x0c, 0x15, 0x3e, 0x53, 0xa1, 0x28, 0x48, 0xd7, 0xc1, 0x95, 0xf1, 0xde, 0x8d,
0xe6, 0x9a, 0x0a, 0xeb, 0xaa, 0xa9, 0x1a, 0x62, 0x5e, 0x7a, 0x03, 0x3c, 0x18, 0x87, 0x28, 0xc9,
0xa6, 0xbc, 0x26, 0x1b, 0x2a, 0x6a, 0xe8, 0x86, 0x59, 0x86, 0xaa, 0x81, 0x0c, 0xb5, 0xba, 0x8e,
0x2a, 0xba, 0x61, 0xaa, 0x25, 0x71, 0x4a, 0x7a, 0x1d, 0xbc, 0x3a, 0x01, 0xa9, 0xb6, 0x65, 0x7c,
0x58, 0x1d, 0xc2, 0x98, 0x96, 0x1e, 0x81, 0xd5, 0x49, 0x18, 0x7a, 0xbd, 0xac, 0x97, 0xd6, 0x86,
0x70, 0x66, 0xa4, 0x57, 0xc0, 0xdd, 0x2c, 0xa2, 0xc1, 0x92, 0x21, 0x9e, 0x90, 0xee, 0x81, 0x5b,
0xa9, 0x22, 0x11, 0xc8, 0x93, 0xd2, 0x1d, 0x50, 0x1c, 0x87, 0x94, 0x1b, 0x8d, 0xaa, 0xa6, 0xc8,
0xa6, 0xa6, 0xd7, 0x51, 0xc5, 0x34, 0x1b, 0xe2, 0xac, 0x74, 0x1b, 0xdc, 0x98, 0x0c, 0x67, 0x2a,
0x0d, 0x71, 0x2e, 0x1e, 0x6c, 0x53, 0xab, 0x97, 0xf4, 0x4d, 0x03, 0x95, 0x54, 0x63, 0xc3, 0xd4,
0x1b, 0x22, 0x90, 0x5e, 0x05, 0xf7, 0x26, 0xc8, 0x67, 0x7c, 0x58, 0x65, 0x73, 0x46, 0x65, 0x3c,
0x95, 0xa2, 0xe0, 0xc1, 0xd0, 0xd5, 0x92, 0x51, 0xd1, 0xd6, 0x4d, 0xf1, 0xb4, 0xf4, 0x18, 0xbc,
0x9e, 0x89, 0x7e, 0x54, 0xc5, 0x67, 0x52, 0xf8, 0x40, 0xb5, 0xa4, 0x0d, 0x4f, 0xfd, 0x7c, 0xd6,
0x49, 0x29, 0x2b, 0x0d, 0xf1, 0x6c, 0xa6, 0x49, 0x21, 0x90, 0x62, 0x66, 0xf5, 0x10, 0xe8, 0x73,
0xd2, 0xbb, 0xe0, 0xad, 0xe7, 0x51, 0x0f, 0x5f, 0x0f, 0x55, 0xd5, 0x30, 0x44, 0x49, 0x7a, 0x0d,
0xdc, 0xcf, 0x82, 0x2c, 0x7f, 0xd4, 0x84, 0xaa, 0x78, 0x5e, 0xba, 0x0b, 0x6e, 0x4e, 0x00, 0x2f,
0x6d, 0xd5, 0xe5, 0x9a, 0x5e, 0x5a, 0x13, 0x2f, 0xa4, 0x98, 0xb8, 0x22, 0x1b, 0x86, 0x5c, 0x2f,
0x41, 0x19, 0x6d, 0xa8, 0x5b, 0x46, 0x43, 0x56, 0x54, 0x43, 0xbc, 0x98, 0x32, 0x6b, 0x03, 0x9c,
0xe8, 0x1c, 0x2c, 0x48, 0x4f, 0xc0, 0xe3, 0x09, 0x58, 0x6a, 0x55, 0x36, 0x4c, 0x4d, 0x31, 0x54,
0x19, 0x2a, 0x95, 0x21, 0xcc, 0x4b, 0x99, 0xe6, 0x9b, 0xe3, 0xcb, 0x4a, 0x45, 0x15, 0x0b, 0x29,
0xda, 0x62, 0x18, 0x35, 0xb5, 0xa6, 0xc3, 0xad, 0xd2, 0x9a, 0x78, 0x39, 0x13, 0x03, 0xaa, 0x59,
0xc4, 0x18, 0x2c, 0xa6, 0x0c, 0x86, 0x61, 0x28, 0xd5, 0xa6, 0x61, 0x8e, 0x18, 0xef, 0x92, 0xb4,
0x02, 0xee, 0xa4, 0x5a, 0x17, 0x9b, 0xc5, 0x2b, 0xd2, 0x2a, 0x58, 0xc9, 0x64, 0x5f, 0x0c, 0x7e,
0x39, 0x65, 0x32, 0x07, 0xf0, 0x35, 0x4d, 0x81, 0xba, 0xa1, 0xaf, 0x9b, 0xe2, 0x55, 0xe9, 0x0b,
0xe0, 0xd1, 0xa4, 0xc9, 0xd4, 0x95, 0x0d, 0xa8, 0xcb, 0x4a, 0x65, 0xc4, 0xcf, 0x5d, 0x4b, 0xb1,
0xfd, 0xd0, 0x37, 0xca, 0x66, 0x55, 0x36, 0xc4, 0xeb, 0x29, 0x6b, 0xca, 0xa8, 0xeb, 0x9b, 0xeb,
0x55, 0x79, 0x43, 0x15, 0x6f, 0x24, 0xd0, 0xd5, 0x95, 0x88, 0x76, 0x4b, 0x06, 0x6a, 0x40, 0xfd,
0xcb, 0x5b, 0x62, 0x31, 0xc1, 0x14, 0xa3, 0xd0, 0x15, 0xad, 0x5c, 0x41, 0xf2, 0x33, 0x59, 0xab,
0xca, 0x6b, 0x5a, 0x55, 0x33, 0xb7, 0xc4, 0x9b, 0xd2, 0x5b, 0xe0, 0x8d, 0x14, 0x2c, 0xba, 0x42,
0x34, 0x05, 0x41, 0xb5, 0xac, 0x19, 0x26, 0xa4, 0xae, 0x53, 0xbc, 0x15, 0xef, 0x85, 0x0d, 0xb9,
0x56, 0x8d, 0xba, 0x58, 0xf1, 0xb6, 0x54, 0x04, 0x57, 0xc7, 0xe1, 0x54, 0xe5, 0x11, 0xfb, 0x70,
0x5f, 0x5d, 0x51, 0xc5, 0x3b, 0x09, 0x46, 0xa7, 0x2b, 0xa3, 0x6e, 0x18, 0xd5, 0xf5, 0x3a, 0x92,
0x4b, 0xe2, 0x5d, 0xe9, 0x16, 0xb8, 0x3e, 0x29, 0x2e, 0xd2, 0x0f, 0xba, 0xdd, 0x8b, 0xb7, 0xfd,
0x68, 0x04, 0x90, 0x37, 0x0d, 0xa4, 0xe8, 0x75, 0x43, 0xaf, 0xaa, 0xe2, 0x7d, 0xe9, 0x1a, 0x58,
0x1a, 0x07, 0xaf, 0x29, 0x0d, 0x64, 0x98, 0x25, 0x4d, 0x17, 0x57, 0xe8, 0x67, 0x0f, 0xe3, 0x01,
0x0c, 0x55, 0x7c, 0x45, 0xba, 0x0f, 0x6e, 0x27, 0xe1, 0x43, 0x55, 0xae, 0xc9, 0x6b, 0x55, 0x95,
0xc5, 0xa6, 0x57, 0x57, 0x7e, 0x4f, 0x00, 0xf3, 0xc3, 0x9f, 0x1e, 0x1e, 0xe2, 0x6e, 0x98, 0xb2,
0xd9, 0x34, 0x46, 0x32, 0x85, 0x25, 0x70, 0x69, 0x14, 0xc0, 0x68, 0x2a, 0x0a, 0x71, 0x8a, 0x42,
0x6c, 0xe7, 0x86, 0xd6, 0x68, 0xa8, 0x25, 0x31, 0x2f, 0x5d, 0x06, 0x17, 0x47, 0x3b, 0x55, 0x08,
0x75, 0x28, 0x4e, 0xc5, 0xe1, 0xc9, 0x6b, 0x3a, 0xa4, 0x41, 0x7f, 0xe5, 0x67, 0x79, 0x30, 0xa5,
0x98, 0xb2, 0x74, 0x1e, 0x9c, 0x55, 0x4c, 0x79, 0xfc, 0x23, 0x8f, 0xa4, 0x51, 0x6e, 0x9a, 0x15,
0xa2, 0xc3, 0xba, 0xaa, 0x98, 0x3a, 0x49, 0x59, 0x2e, 0x81, 0xf3, 0xb4, 0x5d, 0x31, 0xb5, 0x67,
0x24, 0x93, 0x31, 0x0c, 0x4d, 0xaf, 0x93, 0x4c, 0xa5, 0xdf, 0x41, 0x44, 0x46, 0x50, 0xfd, 0xb0,
0xa9, 0x1a, 0xa6, 0x21, 0x4e, 0x85, 0x1d, 0x0d, 0xa8, 0xd6, 0xb4, 0x66, 0x0d, 0x19, 0xcd, 0x46,
0x43, 0x87, 0xa6, 0x38, 0x1d, 0x76, 0x98, 0x90, 0x78, 0x8f, 0x12, 0x2a, 0xa9, 0xcf, 0x34, 0xe2,
0x76, 0x67, 0x42, 0xde, 0xcd, 0x46, 0x19, 0xca, 0x25, 0x15, 0xad, 0xc9, 0xf5, 0xba, 0x0a, 0xc5,
0x13, 0x21, 0xc2, 0x9a, 0x56, 0xad, 0x6a, 0xf5, 0x32, 0x32, 0x9a, 0xb5, 0x9a, 0x0c, 0xb7, 0xc4,
0x93, 0xe1, 0x08, 0x38, 0xef, 0xaa, 0x66, 0x98, 0xe2, 0x2c, 0xfd, 0x14, 0xe0, 0xa0, 0xb1, 0xa6,
0xd7, 0x35, 0x53, 0x87, 0x5a, 0xbd, 0x2c, 0xce, 0xd1, 0x8f, 0x0c, 0x9a, 0x32, 0x52, 0xbf, 0x6c,
0xaa, 0xb0, 0x2e, 0x57, 0x91, 0xdc, 0x2c, 0x69, 0x26, 0x32, 0x4c, 0x1d, 0xca, 0x65, 0x55, 0x04,
0xa1, 0x00, 0xfa, 0x06, 0x91, 0xc2, 0x20, 0xba, 0xdb, 0xaa, 0x2b, 0xe2, 0x29, 0x49, 0x04, 0xa7,
0x29, 0x5e, 0xdd, 0x84, 0x32, 0xd2, 0x4a, 0xe2, 0x69, 0xe9, 0x1c, 0x38, 0xd3, 0x87, 0x34, 0x14,
0xad, 0x26, 0x9e, 0x09, 0xf9, 0x6a, 0x25, 0xb5, 0x6e, 0x6a, 0xe6, 0x16, 0x32, 0x54, 0xa5, 0x09,
0xc9, 0x72, 0x9c, 0x5f, 0xf9, 0x11, 0x00, 0x17, 0x63, 0xdf, 0xd1, 0x91, 0x30, 0xa6, 0xd5, 0x4d,
0xb5, 0xcc, 0x16, 0x20, 0x52, 0xeb, 0x50, 0xaf, 0x56, 0xd1, 0x86, 0x56, 0x1f, 0xfd, 0x7c, 0xe2,
0x0d, 0xb0, 0x9c, 0x04, 0x68, 0x54, 0x65, 0x65, 0x43, 0x14, 0xc8, 0xea, 0x49, 0x02, 0x21, 0x2b,
0x42, 0xd7, 0x4a, 0x8a, 0x98, 0x27, 0x89, 0x51, 0x12, 0x54, 0x43, 0x2e, 0xab, 0xb0, 0xd4, 0x34,
0xb7, 0xc4, 0xa9, 0x49, 0xfc, 0xd4, 0x9a, 0xac, 0x55, 0xc5, 0x69, 0x92, 0xc5, 0x26, 0x81, 0x3c,
0xd5, 0xa0, 0x2c, 0xce, 0x48, 0x37, 0xc1, 0xb5, 0x24, 0x08, 0x6a, 0x9e, 0xb0, 0x24, 0x9e, 0x20,
0x2e, 0x27, 0x09, 0xa8, 0x26, 0x9b, 0xa6, 0x0a, 0x6b, 0xba, 0x61, 0x8a, 0x27, 0x27, 0x0d, 0xaf,
0x66, 0x20, 0x53, 0x95, 0x6b, 0x86, 0x38, 0x3b, 0x09, 0x4a, 0x6f, 0x18, 0x65, 0xb5, 0xae, 0xa9,
0xe2, 0xdc, 0x24, 0xd1, 0xc9, 0x94, 0x8a, 0x60, 0xe2, 0xe0, 0xe4, 0xda, 0xba, 0x78, 0x6a, 0xb2,
0xdc, 0x4a, 0x45, 0xab, 0xab, 0xcc, 0x54, 0xde, 0x04, 0x0f, 0xd3, 0xe1, 0x50, 0x59, 0x33, 0x2b,
0xcd, 0x35, 0xba, 0xbe, 0xc8, 0xba, 0x3a, 0x23, 0x3d, 0x00, 0xaf, 0x64, 0x40, 0x53, 0x34, 0xa8,
0x54, 0x55, 0x45, 0x13, 0xe7, 0x89, 0x5b, 0xcc, 0xc6, 0xa7, 0x2a, 0xaf, 0x89, 0x67, 0x49, 0xe8,
0xcd, 0x00, 0xfe, 0x54, 0xad, 0x6f, 0x68, 0x75, 0x43, 0x14, 0x33, 0xc2, 0xcb, 0x75, 0x43, 0x5b,
0xab, 0xaa, 0xe2, 0xb9, 0x49, 0xea, 0x21, 0x41, 0x5a, 0x53, 0xd4, 0xba, 0xbe, 0x29, 0x4a, 0x93,
0x26, 0xac, 0xbf, 0xde, 0xce, 0x93, 0x80, 0x96, 0x68, 0x49, 0xb2, 0x29, 0x97, 0xf4, 0x32, 0xd2,
0xea, 0x0a, 0x5d, 0x7b, 0xa8, 0x26, 0xd7, 0xe5, 0xb2, 0x5a, 0x53, 0xeb, 0xa6, 0x78, 0x81, 0x64,
0x23, 0x59, 0xc4, 0xde, 0x24, 0x69, 0x5f, 0x36, 0x58, 0x92, 0xeb, 0x2e, 0x90, 0x28, 0x9e, 0x85,
0x2e, 0xcd, 0x5b, 0x68, 0x82, 0x97, 0x01, 0x9a, 0xe6, 0x9f, 0x55, 0xb2, 0x71, 0x28, 0x48, 0x0f,
0xc1, 0x6b, 0x19, 0x30, 0x22, 0x7b, 0xc6, 0xcb, 0x93, 0x2c, 0x86, 0xac, 0xff, 0xbe, 0x63, 0x52,
0xd4, 0xba, 0xa9, 0x42, 0x71, 0x71, 0xd2, 0x94, 0x72, 0x73, 0x84, 0x6a, 0x43, 0xe7, 0x9e, 0x54,
0x5c, 0xca, 0x68, 0x61, 0x32, 0x2c, 0xeb, 0x4a, 0x49, 0xbc, 0x22, 0x7d, 0x00, 0xde, 0x7b, 0x6e,
0xc3, 0x8f, 0x8e, 0x68, 0x79, 0xe5, 0xaf, 0x67, 0x62, 0xfc, 0xa6, 0x11, 0xe0, 0x6e, 0x82, 0xdf,
0x34, 0x4c, 0xb5, 0x31, 0xe2, 0x37, 0xe3, 0xc7, 0x48, 0x01, 0xe5, 0x4d, 0x43, 0x53, 0xc2, 0x20,
0xc7, 0xdc, 0xa3, 0x20, 0x7d, 0x09, 0xbc, 0x33, 0x19, 0xde, 0x50, 0x4d, 0xae, 0x11, 0x12, 0x6f,
0x50, 0x49, 0x5d, 0x97, 0x9b, 0x55, 0x13, 0xe9, 0x9b, 0x24, 0x56, 0xe5, 0xa5, 0x2f, 0x82, 0xb7,
0x27, 0xe3, 0x37, 0x1b, 0x55, 0x5d, 0x66, 0x33, 0x42, 0xf3, 0x2a, 0xa3, 0x81, 0x6a, 0xaa, 0x29,
0x13, 0x2b, 0x16, 0xa7, 0x48, 0xb2, 0x3a, 0x19, 0xdd, 0x54, 0x0d, 0x93, 0x46, 0x9c, 0x50, 0x70,
0x92, 0x8f, 0x4d, 0x27, 0xac, 0x0f, 0x8a, 0xc7, 0x14, 0x0c, 0x65, 0xa4, 0x40, 0x55, 0x36, 0x55,
0x14, 0x81, 0x13, 0x67, 0x26, 0x31, 0x1c, 0x45, 0x2c, 0x6b, 0xe1, 0x96, 0x4d, 0x3c, 0x91, 0x8d,
0x21, 0xfd, 0x22, 0x2f, 0xd9, 0x55, 0x18, 0x46, 0x05, 0x29, 0x2a, 0x24, 0x6e, 0x3c, 0x7e, 0x29,
0xc4, 0x32, 0x84, 0x24, 0x81, 0x9b, 0x25, 0x29, 0x70, 0x12, 0x46, 0x6d, 0x53, 0x2b, 0x57, 0xe4,
0x8d, 0x27, 0x46, 0x7f, 0x1a, 0x19, 0x0d, 0x71, 0x6e, 0xd2, 0xc0, 0x86, 0xb0, 0xb8, 0x84, 0xdc,
0xc8, 0x41, 0x36, 0x6e, 0x86, 0x6a, 0x36, 0x1b, 0x68, 0x53, 0x87, 0x1b, 0xeb, 0x55, 0x7d, 0x53,
0x3c, 0x95, 0xb0, 0x34, 0x46, 0xb0, 0x36, 0xd5, 0xaa, 0xa2, 0xd7, 0x54, 0xf1, 0xf4, 0xca, 0xcf,
0x85, 0xd8, 0x77, 0xe3, 0xe1, 0x9b, 0xef, 0x44, 0xab, 0xa5, 0x99, 0x9c, 0xa2, 0x97, 0x46, 0x8f,
0x9b, 0xe2, 0x3d, 0x57, 0x14, 0x7e, 0x90, 0x53, 0x66, 0x80, 0xed, 0xa7, 0x98, 0xf7, 0xc0, 0xad,
0x14, 0xd8, 0x30, 0xe3, 0x4c, 0xa7, 0x3a, 0x48, 0x40, 0xff, 0x26, 0x0f, 0x0a, 0x49, 0xc7, 0xac,
0x49, 0x84, 0x98, 0xa5, 0x8f, 0x0c, 0x3b, 0xde, 0xc3, 0x84, 0xb0, 0x03, 0xc5, 0x87, 0x3e, 0xa6,
0xf4, 0x8c, 0x6c, 0x4d, 0x48, 0x26, 0xc0, 0xa2, 0xac, 0x90, 0x99, 0x42, 0x64, 0x13, 0x52, 0x95,
0xd7, 0xd4, 0x2a, 0x6a, 0x68, 0xca, 0x06, 0x5d, 0xf0, 0x25, 0xf0, 0xc1, 0xf3, 0x52, 0x18, 0x93,
0x63, 0x4a, 0xaa, 0x80, 0xd2, 0xf3, 0x52, 0xe9, 0xef, 0x45, 0x60, 0xb3, 0xaa, 0x86, 0xf2, 0x4c,
0xaf, 0xfc, 0x64, 0x06, 0x2c, 0xc4, 0x9f, 0x13, 0x27, 0xcc, 0xe6, 0xba, 0xa6, 0x56, 0x47, 0xb3,
0xcd, 0xf7, 0xc0, 0x93, 0x44, 0xc8, 0x31, 0xb5, 0x92, 0x20, 0x61, 0x90, 0x24, 0x7b, 0x0b, 0x35,
0x61, 0x55, 0x14, 0x12, 0x96, 0x50, 0x02, 0xf6, 0x1a, 0x94, 0xeb, 0x4a, 0x45, 0xcc, 0x27, 0x2c,
0xd8, 0x04, 0xac, 0xfe, 0xd2, 0x9b, 0x92, 0xde, 0x06, 0x6f, 0x66, 0xc7, 0x53, 0xeb, 0xcf, 0x34,
0xa8, 0xd7, 0x69, 0x72, 0x30, 0x9d, 0x10, 0x64, 0x13, 0x87, 0xb9, 0x2e, 0xce, 0x24, 0xf8, 0xf7,
0x44, 0x6e, 0xa6, 0x0a, 0x1b, 0x50, 0x33, 0x54, 0x64, 0x54, 0x9b, 0x65, 0xf1, 0x44, 0x82, 0xb5,
0x64, 0x40, 0x37, 0x65, 0x53, 0x53, 0xd0, 0xd3, 0xcd, 0x0d, 0x43, 0x3c, 0x29, 0x3d, 0x01, 0x8f,
0x33, 0x50, 0x19, 0xb5, 0x59, 0x92, 0x1e, 0x3f, 0x37, 0x66, 0x19, 0xea, 0xcd, 0x86, 0x21, 0xce,
0x25, 0x38, 0xfc, 0x09, 0x98, 0x64, 0x03, 0x45, 0x1c, 0x6a, 0xfc, 0x12, 0x9b, 0x80, 0x38, 0x64,
0xd8, 0x86, 0x78, 0x6a, 0xe5, 0x87, 0x71, 0x1f, 0x36, 0x09, 0xdf, 0xbd, 0x27, 0x64, 0x62, 0xd4,
0xe5, 0xc4, 0xfc, 0x9f, 0x81, 0x78, 0xf7, 0x32, 0x80, 0x36, 0x55, 0x08, 0xe5, 0x75, 0x1d, 0xd6,
0x12, 0xed, 0x78, 0x00, 0x3b, 0x92, 0xba, 0x6c, 0xc9, 0xb5, 0xaa, 0x98, 0x5f, 0x79, 0x1f, 0x9c,
0xe4, 0xb5, 0x56, 0x64, 0xe3, 0xba, 0xae, 0xca, 0x26, 0x89, 0x2f, 0x63, 0x9b, 0xfe, 0xb0, 0x63,
0x74, 0x1b, 0x2c, 0xac, 0xfc, 0x8e, 0x00, 0x96, 0x26, 0xbc, 0x84, 0x26, 0xb1, 0x26, 0x44, 0x86,
0xaa, 0xa2, 0xd7, 0x6a, 0x6a, 0xbd, 0xc4, 0x24, 0x8c, 0x3d, 0x60, 0x58, 0x01, 0x77, 0x26, 0x83,
0xd7, 0x75, 0x93, 0xc1, 0x0a, 0x24, 0x69, 0x9f, 0x0c, 0x5b, 0xd2, 0xeb, 0xaa, 0x98, 0x5f, 0xfb,
0xea, 0x9f, 0xff, 0xf4, 0xaa, 0xf0, 0x93, 0x9f, 0x5e, 0x15, 0xfe, 0xee, 0xa7, 0x57, 0x85, 0x8f,
0xf4, 0x5d, 0x27, 0xd8, 0xeb, 0x6d, 0xaf, 0xb6, 0xdc, 0x83, 0x07, 0xbb, 0x9e, 0x75, 0xe8, 0xb0,
0x5a, 0x5c, 0xab, 0xfd, 0x60, 0xf0, 0xaf, 0xcf, 0xba, 0xce, 0x83, 0x5d, 0xdc, 0x79, 0x40, 0x5f,
0xad, 0x3f, 0xd8, 0x75, 0x47, 0xfe, 0x9f, 0xda, 0xbb, 0x91, 0x9f, 0x87, 0x0f, 0xb7, 0x4f, 0x50,
0xb0, 0x37, 0xfe, 0x23, 0x00, 0x00, 0xff, 0xff, 0xc7, 0xc7, 0x14, 0xee, 0x7f, 0x6d, 0x00, 0x00,
}
func (m *UIBannerClickEvent) Marshal() (dAtA []byte, err error) {
@@ -666,6 +666,7 @@ enum IntegrationEnrollStep {
INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB = 9;
INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS = 10;
INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW = 11;
INTEGRATION_ENROLL_STEP_MWIGHAK8S_WELCOME = 12;
}
// IntegrationEnrollStatusCode defines status code for an integration enroll step.
+6 -2
View File
@@ -732,6 +732,7 @@ const (
IntegrationEnrollStep_INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB IntegrationEnrollStep = 9
IntegrationEnrollStep_INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS IntegrationEnrollStep = 10
IntegrationEnrollStep_INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW IntegrationEnrollStep = 11
IntegrationEnrollStep_INTEGRATION_ENROLL_STEP_MWIGHAK8S_WELCOME IntegrationEnrollStep = 12
)
// Enum value maps for IntegrationEnrollStep.
@@ -749,6 +750,7 @@ var (
9: "INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB",
10: "INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS",
11: "INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW",
12: "INTEGRATION_ENROLL_STEP_MWIGHAK8S_WELCOME",
}
IntegrationEnrollStep_value = map[string]int32{
"INTEGRATION_ENROLL_STEP_UNSPECIFIED": 0,
@@ -763,6 +765,7 @@ var (
"INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB": 9,
"INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS": 10,
"INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW": 11,
"INTEGRATION_ENROLL_STEP_MWIGHAK8S_WELCOME": 12,
}
)
@@ -11354,7 +11357,7 @@ const file_prehog_v1alpha_teleport_proto_rawDesc = "" +
"+INTEGRATION_ENROLL_KIND_AWS_IDENTITY_CENTER\x10\x1a\x12.\n" +
"*INTEGRATION_ENROLL_KIND_GITHUB_REPO_ACCESS\x10\x1b\x12-\n" +
")INTEGRATION_ENROLL_KIND_MACHINE_ID_ARGOCD\x10\x1c\x12@\n" +
"<INTEGRATION_ENROLL_KIND_MACHINE_ID_GITHUB_ACTIONS_KUBERNETES\x10\x1d*\xa7\x05\n" +
"<INTEGRATION_ENROLL_KIND_MACHINE_ID_GITHUB_ACTIONS_KUBERNETES\x10\x1d*\xd6\x05\n" +
"\x15IntegrationEnrollStep\x12'\n" +
"#INTEGRATION_ENROLL_STEP_UNSPECIFIED\x10\x00\x12.\n" +
"*INTEGRATION_ENROLL_STEP_AWSIC_CONNECT_OIDC\x10\x01\x12>\n" +
@@ -11368,7 +11371,8 @@ const file_prehog_v1alpha_teleport_proto_rawDesc = "" +
"0INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB\x10\t\x126\n" +
"2INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS\x10\n" +
"\x124\n" +
"0INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW\x10\v*\xfb\x01\n" +
"0INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW\x10\v\x12-\n" +
")INTEGRATION_ENROLL_STEP_MWIGHAK8S_WELCOME\x10\f*\xfb\x01\n" +
"\x1bIntegrationEnrollStatusCode\x12.\n" +
"*INTEGRATION_ENROLL_STATUS_CODE_UNSPECIFIED\x10\x00\x12*\n" +
"&INTEGRATION_ENROLL_STATUS_CODE_SUCCESS\x10\x01\x12*\n" +
+5 -1
View File
@@ -4344,7 +4344,11 @@ export enum IntegrationEnrollStep {
/**
* @generated from protobuf enum value: INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW = 11;
*/
MWIGHAK8S_SETUP_WORKFLOW = 11
MWIGHAK8S_SETUP_WORKFLOW = 11,
/**
* @generated from protobuf enum value: INTEGRATION_ENROLL_STEP_MWIGHAK8S_WELCOME = 12;
*/
MWIGHAK8S_WELCOME = 12
}
/**
* IntegrationEnrollStatusCode defines status code for an integration enroll step.
+1
View File
@@ -1202,6 +1202,7 @@ enum IntegrationEnrollStep {
INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB = 9;
INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS = 10;
INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW = 11;
INTEGRATION_ENROLL_STEP_MWIGHAK8S_WELCOME = 12;
}
// IntegrationEnrollStatusCode defines status code for an integration enroll step.
@@ -127,6 +127,16 @@ class TextEditor extends Component {
this.session = null;
}
handleCopy() {
copyToClipboard(this.editor.session.getValue());
this.props.onCopy?.();
}
handleDownload() {
downloadObject(this.props.downloadFileName, this.editor.session.getValue());
this.props.onDownload?.();
}
render() {
const { bg = 'levels.sunken' } = this.props;
const hasButton = this.props.copyButton || this.props.downloadButton;
@@ -139,7 +149,7 @@ class TextEditor extends Component {
{this.props.copyButton && (
<EditorButton
title="Copy to clipboard"
onClick={() => copyToClipboard(this.editor.session.getValue())}
onClick={() => this.handleCopy()}
>
<Copy size="medium" />
</EditorButton>
@@ -147,12 +157,7 @@ class TextEditor extends Component {
{this.props.downloadButton && (
<EditorButton
title="Download"
onClick={() =>
downloadObject(
this.props.downloadFileName,
this.editor.session.getValue()
)
}
onClick={() => this.handleDownload()}
>
<Download size="medium" />
</EditorButton>
@@ -21,13 +21,22 @@ import { useState } from 'react';
import { Tabs } from 'shared/components/Editor/Tabs';
import TextEditor from 'shared/components/TextEditor/TextEditor';
import {
IntegrationEnrollCodeType,
IntegrationEnrollStep,
} from 'teleport/services/userEvent';
import { useTracking } from '../Shared/useTracking';
import { useGitHubK8sFlow } from './useGitHubK8sFlow';
export function CodePanel() {
export function CodePanel(props: { trackingStep: IntegrationEnrollStep }) {
const { trackingStep } = props;
const [activeCodeTab, setActiveCodeTab] = useState(0);
const { template } = useGitHubK8sFlow();
const tracking = useTracking();
return (
<>
<Tabs
@@ -52,12 +61,22 @@ export function CodePanel() {
copyButton={true}
downloadButton={true}
downloadFileName={files[activeCodeTab]}
onCopy={() => {
tracking.codeCopy(trackingStep, trackingTypes[activeCodeTab]);
}}
onDownload={() => {
tracking.codeCopy(trackingStep, trackingTypes[activeCodeTab]);
}}
/>
</>
);
}
const files = ['main.tf', 'gha-workflow.yaml'];
const trackingTypes = [
IntegrationEnrollCodeType.Terraform,
IntegrationEnrollCodeType.GitHubActionsYAML,
];
function makeTerraformContent(
template: ReturnType<typeof useGitHubK8sFlow>['template']
@@ -30,7 +30,9 @@ import {
genWizardCiCdSuccess,
} from 'teleport/test/helpers/bots';
import { fetchUnifiedResourcesSuccess } from 'teleport/test/helpers/resources';
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
import { TrackingProvider } from '../Shared/useTracking';
import { ConfigureAccess } from './ConfigureAccess';
import { GitHubK8sFlowProvider } from './useGitHubK8sFlow';
@@ -49,7 +51,11 @@ export default meta;
export const Happy: Story = {
parameters: {
msw: {
handlers: [genWizardCiCdSuccess(), fetchUnifiedResourcesSuccess()],
handlers: [
genWizardCiCdSuccess(),
fetchUnifiedResourcesSuccess(),
userEventCaptureSuccess(),
],
},
},
};
@@ -60,6 +66,7 @@ export const TemplateFetchFailed: Story = {
handlers: [
genWizardCiCdError(500, 'something went wrong'),
fetchUnifiedResourcesSuccess(),
userEventCaptureSuccess(),
],
},
},
@@ -68,7 +75,11 @@ export const TemplateFetchFailed: Story = {
export const TemplateFetching: Story = {
parameters: {
msw: {
handlers: [genWizardCiCdForever(), fetchUnifiedResourcesSuccess()],
handlers: [
genWizardCiCdForever(),
fetchUnifiedResourcesSuccess(),
userEventCaptureSuccess(),
],
},
},
};
@@ -87,11 +98,13 @@ function Wrapper() {
return (
<QueryClientProvider client={queryClient}>
<ContextProvider ctx={ctx}>
<GitHubK8sFlowProvider>
<Container>
<ConfigureAccess />
</Container>
</GitHubK8sFlowProvider>
<TrackingProvider>
<GitHubK8sFlowProvider>
<Container>
<ConfigureAccess />
</Container>
</GitHubK8sFlowProvider>
</TrackingProvider>
</ContextProvider>
</QueryClientProvider>
);
@@ -24,6 +24,7 @@ import selectEvent from 'react-select-event';
import darkTheme from 'design/theme/themes/darkTheme';
import { ConfiguredThemeProvider } from 'design/ThemeProvider';
import {
act,
render,
screen,
testQueryClient,
@@ -35,7 +36,10 @@ import { ContextProvider } from 'teleport/index';
import { createTeleportContext } from 'teleport/mocks/contexts';
import { genWizardCiCdSuccess } from 'teleport/test/helpers/bots';
import { fetchUnifiedResourcesSuccess } from 'teleport/test/helpers/resources';
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
import { trackingTester } from '../Shared/trackingTester';
import { TrackingProvider } from '../Shared/useTracking';
import { ConfigureAccess } from './ConfigureAccess';
import { GitHubK8sFlowProvider, useGitHubK8sFlow } from './useGitHubK8sFlow';
@@ -47,9 +51,17 @@ beforeAll(() => {
// Basic mock for all tests
server.use(genWizardCiCdSuccess());
server.use(fetchUnifiedResourcesSuccess());
server.use(userEventCaptureSuccess());
jest.useFakeTimers();
});
afterAll(() => server.close());
afterAll(() => {
server.close();
jest.useRealTimers();
jest.resetAllMocks();
});
describe('ConfigureAccess', () => {
test('renders', async () => {
@@ -109,6 +121,8 @@ describe('ConfigureAccess', () => {
});
test('input groups', async () => {
const tracking = trackingTester();
const { user } = renderComponent();
const input = screen.getByLabelText('Kubernetes Groups');
@@ -117,9 +131,22 @@ describe('ConfigureAccess', () => {
expect(screen.getByText('system:masters')).toBeInTheDocument();
expect(screen.getByText('viewers')).toBeInTheDocument();
// Skip start event
tracking.skip();
// Field tracking is debounced, so move time along to send the event
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
expect.any(String),
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_GROUPS'
);
});
test('input labels', async () => {
const tracking = trackingTester();
const { user } = renderComponent();
const input = screen.getByLabelText('Labels');
@@ -132,9 +159,24 @@ describe('ConfigureAccess', () => {
expect(modal).not.toBeInTheDocument();
expect(screen.getByText('foo: bar')).toBeInTheDocument();
// Skip start event
tracking.skip();
// Skip section event
tracking.skip();
// Field tracking is debounced, so move time along to send the event
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
expect.any(String),
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_LABELS'
);
});
test('input users', async () => {
const tracking = trackingTester();
const { user } = renderComponent();
const input = screen.getByLabelText('Kubernetes Users');
@@ -143,13 +185,27 @@ describe('ConfigureAccess', () => {
expect(screen.getByText('user1@example.com')).toBeInTheDocument();
expect(screen.getByText('user2@example.com')).toBeInTheDocument();
// Skip start event
tracking.skip();
// Field tracking is debounced, so move time along to send the event
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
expect.any(String),
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_KUBERNETES_USERS'
);
});
});
function renderComponent(opts?: {
initialState?: ReturnType<typeof useGitHubK8sFlow>['state'];
disableTracking?: boolean;
}) {
const user = userEvent.setup();
const user = userEvent.setup({
advanceTimers: t => jest.advanceTimersByTime(t),
});
const onNextStep = jest.fn();
const onPrevStep = jest.fn();
return {
@@ -164,8 +220,9 @@ function renderComponent(opts?: {
function makeWrapper(opts?: {
initialState?: ReturnType<typeof useGitHubK8sFlow>['state'];
disableTracking?: boolean;
}) {
const { initialState } = opts ?? {};
const { initialState, disableTracking = false } = opts ?? {};
const ctx = createTeleportContext();
return ({ children }: PropsWithChildren) => {
@@ -173,9 +230,11 @@ function makeWrapper(opts?: {
<QueryClientProvider client={testQueryClient}>
<ContextProvider ctx={ctx}>
<ConfiguredThemeProvider theme={darkTheme}>
<GitHubK8sFlowProvider intitialState={initialState}>
{children}
</GitHubK8sFlowProvider>
<TrackingProvider disabled={disableTracking}>
<GitHubK8sFlowProvider intitialState={initialState}>
{children}
</GitHubK8sFlowProvider>
</TrackingProvider>
</ConfiguredThemeProvider>
</ContextProvider>
</QueryClientProvider>
@@ -27,8 +27,15 @@ import { FieldSelectCreatable } from 'shared/components/FieldSelect/FieldSelectC
import Validator, { Validation } from 'shared/components/Validation/Validation';
import { SectionBox } from 'teleport/Roles/RoleEditor/StandardEditor/sections';
import {
IntegrationEnrollField,
IntegrationEnrollSection,
IntegrationEnrollStatusCode,
IntegrationEnrollStep,
} from 'teleport/services/userEvent';
import { FlowStepProps } from '../Shared/GuidedFlow';
import { useTracking } from '../Shared/useTracking';
import { CodePanel } from './CodePanel';
import { KubernetesLabelsSelect } from './KubernetesLabelsSelect';
import { useGitHubK8sFlow } from './useGitHubK8sFlow';
@@ -37,12 +44,22 @@ export function ConfigureAccess(props: FlowStepProps) {
const { nextStep, prevStep } = props;
const { dispatch, state } = useGitHubK8sFlow();
const tracking = useTracking();
const handleNext = (validator: Validator) => {
if (!validator.validate()) {
tracking.error(
IntegrationEnrollStep.MWIGHAK8SConfigureAccess,
'validation error'
);
return;
}
tracking.step(
IntegrationEnrollStep.MWIGHAK8SConfigureAccess,
IntegrationEnrollStatusCode.Success
);
nextStep?.();
};
@@ -68,19 +85,29 @@ export function ConfigureAccess(props: FlowStepProps) {
<KubernetesLabelsSelect
mt={2}
selected={state.kubernetesLabels}
onChange={labels =>
onChange={labels => {
dispatch({
type: 'kubernetes-labels-changed',
value: labels,
})
}
});
tracking.field(
IntegrationEnrollStep.MWIGHAK8SConfigureAccess,
IntegrationEnrollField.MWIGHAK8SKubernetesLabels
);
}}
/>
<Text mt={3} mb={3}>
Your workflow will have access to Kubernetes clusters which
satisfy the labels you specify. Visit the{' '}
<Link
target="_blank"
href="https://goteleport.com/docs/enroll-resources/kubernetes-access/controls/"
href={K8S_RBAC_LINK}
onClick={() => {
tracking.link(
IntegrationEnrollStep.MWIGHAK8SConfigureAccess,
K8S_RBAC_LINK
);
}}
>
Teleport Kubernetes Access Controls
</Link>{' '}
@@ -101,6 +128,10 @@ export function ConfigureAccess(props: FlowStepProps) {
type: 'kubernetes-groups-changed',
value: e.map(g => g.value),
});
tracking.field(
IntegrationEnrollStep.MWIGHAK8SConfigureAccess,
IntegrationEnrollField.MWIGHAK8SKubernetesGroups
);
}}
createOptionPosition="last"
/>
@@ -109,7 +140,13 @@ export function ConfigureAccess(props: FlowStepProps) {
ClusterRoleBinding resources. See the{' '}
<Link
target="_blank"
href="https://goteleport.com/docs/enroll-resources/kubernetes-access/controls/"
href={K8S_RBAC_LINK}
onClick={() => {
tracking.link(
IntegrationEnrollStep.MWIGHAK8SConfigureAccess,
K8S_RBAC_LINK
);
}}
>
Teleport Kubernetes Access Controls
</Link>{' '}
@@ -124,6 +161,12 @@ export function ConfigureAccess(props: FlowStepProps) {
validation={{
valid: true,
}}
onExpand={() => {
tracking.section(
IntegrationEnrollStep.MWIGHAK8SConfigureAccess,
IntegrationEnrollSection.MWIGHAK8SKubernetesAdvancedOptions
);
}}
>
<FieldSelectCreatable
label="Kubernetes Users"
@@ -139,6 +182,10 @@ export function ConfigureAccess(props: FlowStepProps) {
type: 'kubernetes-users-changed',
value: e.map(g => g.value),
});
tracking.field(
IntegrationEnrollStep.MWIGHAK8SConfigureAccess,
IntegrationEnrollField.MWIGHAK8SKubernetesUsers
);
}}
createOptionPosition="last"
/>
@@ -167,7 +214,9 @@ export function ConfigureAccess(props: FlowStepProps) {
</FormContainer>
<CodeContainer>
<CodePanel />
<CodePanel
trackingStep={IntegrationEnrollStep.MWIGHAK8SConfigureAccess}
/>
</CodeContainer>
</Container>
);
@@ -191,3 +240,6 @@ const CodeContainer = styled(Flex)`
flex-direction: column;
overflow: auto;
`;
const K8S_RBAC_LINK =
'https://goteleport.com/docs/enroll-resources/kubernetes-access/controls/';
@@ -29,7 +29,9 @@ import {
genWizardCiCdForever,
genWizardCiCdSuccess,
} from 'teleport/test/helpers/bots';
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
import { TrackingProvider } from '../Shared/useTracking';
import { ConnectGitHub } from './ConnectGitHub';
import { GitHubK8sFlowProvider } from './useGitHubK8sFlow';
@@ -48,7 +50,7 @@ export default meta;
export const Happy: Story = {
parameters: {
msw: {
handlers: [genWizardCiCdSuccess()],
handlers: [genWizardCiCdSuccess(), userEventCaptureSuccess()],
},
},
};
@@ -56,7 +58,10 @@ export const Happy: Story = {
export const TemplateFetchFailed: Story = {
parameters: {
msw: {
handlers: [genWizardCiCdError(500, 'something went wrong')],
handlers: [
genWizardCiCdError(500, 'something went wrong'),
userEventCaptureSuccess(),
],
},
},
};
@@ -64,7 +69,7 @@ export const TemplateFetchFailed: Story = {
export const TemplateFetching: Story = {
parameters: {
msw: {
handlers: [genWizardCiCdForever()],
handlers: [genWizardCiCdForever(), userEventCaptureSuccess()],
},
},
};
@@ -83,11 +88,13 @@ function Wrapper() {
return (
<QueryClientProvider client={queryClient}>
<ContextProvider ctx={ctx}>
<GitHubK8sFlowProvider>
<Container>
<ConnectGitHub />
</Container>
</GitHubK8sFlowProvider>
<TrackingProvider>
<GitHubK8sFlowProvider>
<Container>
<ConnectGitHub />
</Container>
</GitHubK8sFlowProvider>
</TrackingProvider>
</ContextProvider>
</QueryClientProvider>
);
@@ -24,6 +24,7 @@ import selectEvent from 'react-select-event';
import darkTheme from 'design/theme/themes/darkTheme';
import { ConfiguredThemeProvider } from 'design/ThemeProvider';
import {
act,
render,
screen,
testQueryClient,
@@ -34,7 +35,10 @@ import cfg from 'teleport/config';
import { ContextProvider } from 'teleport/index';
import { createTeleportContext } from 'teleport/mocks/contexts';
import { genWizardCiCdSuccess } from 'teleport/test/helpers/bots';
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
import { trackingTester } from '../Shared/trackingTester';
import { TrackingProvider } from '../Shared/useTracking';
import { ConnectGitHub } from './ConnectGitHub';
import { GitHubK8sFlowProvider } from './useGitHubK8sFlow';
@@ -45,9 +49,17 @@ beforeAll(() => {
// Basic mock for all tests
server.use(genWizardCiCdSuccess());
server.use(userEventCaptureSuccess());
jest.useFakeTimers();
});
afterAll(() => server.close());
afterAll(() => {
server.close();
jest.useRealTimers();
jest.resetAllMocks();
});
describe('ConnectGitHub', () => {
test('renders', async () => {
@@ -125,15 +137,30 @@ describe('ConnectGitHub', () => {
});
test('input github url', async () => {
const tracking = trackingTester();
const { user } = renderComponent();
const input = screen.getByLabelText('Repository URL');
await user.type(input, 'https://github.com/foo/bar');
expect(input).toHaveValue('https://github.com/foo/bar');
// Skip start event
tracking.skip();
// Field tracking is debounced, so move time along to send the event
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
expect.any(String),
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_GITHUB_REPOSITORY_URL'
);
});
test('input branch', async () => {
const tracking = trackingTester();
const { user } = renderComponent();
const input = screen.getByLabelText('Branch');
@@ -141,10 +168,21 @@ describe('ConnectGitHub', () => {
expect(input).toHaveValue('main');
expect(screen.getByLabelText('Git Ref')).toHaveValue('main');
// Skip start event
tracking.skip();
// Field tracking is debounced, so move time along to send the event
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
expect.any(String),
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_GITHUB_BRANCH'
);
});
test('toggle allow any branch', async () => {
const { user } = renderComponent();
const { user } = renderComponent({ disableTracking: true });
const input = screen.getByLabelText('Branch');
await user.type(input, 'main');
@@ -156,24 +194,52 @@ describe('ConnectGitHub', () => {
});
test('input workflow', async () => {
const tracking = trackingTester();
const { user } = renderComponent();
const input = screen.getByLabelText('Workflow');
await user.type(input, 'my-workflow');
expect(input).toHaveValue('my-workflow');
// Skip start event
tracking.skip();
// Field tracking is debounced, so move time along to send the event
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
expect.any(String),
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_GITHUB_WORKFLOW'
);
});
test('input environment', async () => {
const tracking = trackingTester();
const { user } = renderComponent();
const input = screen.getByLabelText('Environment');
await user.type(input, 'production');
expect(input).toHaveValue('production');
// Skip start event
tracking.skip();
// Field tracking is debounced, so move time along to send the event
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
expect.any(String),
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_GITHUB_ENVIRONMENT'
);
});
test('input ref and type', async () => {
const tracking = trackingTester();
const { user } = renderComponent();
const input = screen.getByLabelText('Git Ref');
@@ -182,11 +248,30 @@ describe('ConnectGitHub', () => {
expect(input).toHaveValue('release-*');
expect(screen.getByLabelText('Branch')).toHaveValue('release-*');
// Skip start event
tracking.skip();
// Field tracking is debounced, so move time along to send the event
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
expect.any(String),
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_GITHUB_REF'
);
const select = screen.getByLabelText('Ref Type');
await selectEvent.select(select, ['Tag']);
expect(input).toHaveValue('release-*');
expect(screen.getByLabelText('Branch')).toHaveValue('');
// Field tracking is debounced, so move time along to send the event
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
expect.any(String),
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_GITHUB_REF'
);
});
test('input slug disabled', async () => {
@@ -197,6 +282,8 @@ describe('ConnectGitHub', () => {
});
test('input slug', async () => {
const tracking = trackingTester();
const { user } = renderComponent({
isEnterprise: true,
});
@@ -205,6 +292,17 @@ describe('ConnectGitHub', () => {
await user.type(input, 'octo-enterprise');
expect(input).toHaveValue('octo-enterprise');
// Skip start event
tracking.skip();
// Field tracking is debounced, so move time along to send the event
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
expect.any(String),
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_GITHUB_ENTERPRISE_SLUG'
);
});
test('input jwks disabled', async () => {
@@ -215,6 +313,8 @@ describe('ConnectGitHub', () => {
});
test('input jwks', async () => {
const tracking = trackingTester();
const { user } = renderComponent({
isEnterprise: true,
initialState: {
@@ -231,14 +331,28 @@ describe('ConnectGitHub', () => {
await user.type(input, '{{"keys":[[]}'); // Note escaping of "{" and "["
expect(input).toHaveValue('{"keys":[]}');
// Skip start event
tracking.skip();
// Field tracking is debounced, so move time along to send the event
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
expect.any(String),
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_GITHUB_ENTERPRISE_STATIC_JWKS'
);
});
});
function renderComponent(opts?: {
initialState?: ComponentProps<typeof GitHubK8sFlowProvider>['intitialState'];
isEnterprise?: boolean;
disableTracking?: boolean;
}) {
const user = userEvent.setup();
const user = userEvent.setup({
advanceTimers: t => jest.advanceTimersByTime(t),
});
const onNextStep = jest.fn();
const onPrevStep = jest.fn();
return {
@@ -254,8 +368,9 @@ function renderComponent(opts?: {
function makeWrapper(opts?: {
initialState?: ComponentProps<typeof GitHubK8sFlowProvider>['intitialState'];
isEnterprise?: boolean;
disableTracking?: boolean;
}) {
const { initialState, isEnterprise = false } = opts ?? {};
const { initialState, isEnterprise = false, disableTracking } = opts ?? {};
cfg.isEnterprise = isEnterprise;
cfg.edition = isEnterprise ? 'ent' : 'oss';
@@ -267,9 +382,11 @@ function makeWrapper(opts?: {
<QueryClientProvider client={testQueryClient}>
<ContextProvider ctx={ctx}>
<ConfiguredThemeProvider theme={darkTheme}>
<GitHubK8sFlowProvider intitialState={initialState}>
{children}
</GitHubK8sFlowProvider>
<TrackingProvider disabled={disableTracking}>
<GitHubK8sFlowProvider intitialState={initialState}>
{children}
</GitHubK8sFlowProvider>
</TrackingProvider>
</ConfiguredThemeProvider>
</ContextProvider>
</QueryClientProvider>
@@ -30,6 +30,12 @@ import { requiredField } from 'shared/components/Validation/rules';
import cfg from 'teleport/config';
import { SectionBox } from 'teleport/Roles/RoleEditor/StandardEditor/sections';
import {
IntegrationEnrollField,
IntegrationEnrollSection,
IntegrationEnrollStatusCode,
IntegrationEnrollStep,
} from 'teleport/services/userEvent';
import {
GITHUB_HOST,
@@ -38,6 +44,7 @@ import {
requireValidRepository,
} from '../Shared/github';
import { FlowStepProps } from '../Shared/GuidedFlow';
import { useTracking } from '../Shared/useTracking';
import { CodePanel } from './CodePanel';
import { useGitHubK8sFlow } from './useGitHubK8sFlow';
@@ -46,11 +53,23 @@ export function ConnectGitHub(props: FlowStepProps) {
const { dispatch, state } = useGitHubK8sFlow();
const tracking = useTracking();
const handleNext = (validator: Validator) => {
if (!validator.validate()) {
tracking.error(
IntegrationEnrollStep.MWIGHAK8SConnectGitHub,
'validation error'
);
return;
}
tracking.step(
IntegrationEnrollStep.MWIGHAK8SConnectGitHub,
IntegrationEnrollStatusCode.Success
);
nextStep?.();
};
@@ -80,12 +99,17 @@ export function ConnectGitHub(props: FlowStepProps) {
label="Repository URL"
placeholder="https://github.com/gravitational/teleport"
value={state.gitHubUrl}
onChange={e =>
onChange={e => {
dispatch({
type: 'github-url-changed',
value: e.target.value,
})
}
});
tracking.field(
IntegrationEnrollStep.MWIGHAK8SConnectGitHub,
IntegrationEnrollField.MWIGHAK8SGitHubRepositoryURL,
!e.target.value.length
);
}}
/>
<FieldInput
@@ -98,12 +122,17 @@ export function ConnectGitHub(props: FlowStepProps) {
label="Branch"
placeholder="main"
value={state.branch}
onChange={e =>
onChange={e => {
dispatch({
type: 'branch-changed',
value: e.target.value,
})
}
});
tracking.field(
IntegrationEnrollStep.MWIGHAK8SConnectGitHub,
IntegrationEnrollField.MWIGHAK8SGitHubBranch,
!e.target.value.length
);
}}
/>
<FieldCheckbox
label="Allow any branch"
@@ -136,29 +165,45 @@ export function ConnectGitHub(props: FlowStepProps) {
validation={{
valid: true,
}}
onExpand={() => {
tracking.section(
IntegrationEnrollStep.MWIGHAK8SConnectGitHub,
IntegrationEnrollSection.MWIGHAK8SGitHubAdvancedOptions
);
}}
>
<FieldInput
label="Workflow"
placeholder="my-workflow"
value={state.workflow}
onChange={e =>
onChange={e => {
dispatch({
type: 'workflow-changed',
value: e.target.value,
})
}
});
tracking.field(
IntegrationEnrollStep.MWIGHAK8SConnectGitHub,
IntegrationEnrollField.MWIGHAK8SGitHubWorkflow,
!e.target.value.length
);
}}
/>
<FieldInput
label="Environment"
placeholder="production"
value={state.environment}
onChange={e =>
onChange={e => {
dispatch({
type: 'environment-changed',
value: e.target.value,
})
}
});
tracking.field(
IntegrationEnrollStep.MWIGHAK8SConnectGitHub,
IntegrationEnrollField.MWIGHAK8SGitHubEnvironment,
!e.target.value.length
);
}}
/>
<Flex mb={3} gap={2}>
@@ -167,12 +212,17 @@ export function ConnectGitHub(props: FlowStepProps) {
label={'Git Ref'}
placeholder="ref/heads/main"
value={state.ref}
onChange={e =>
onChange={e => {
dispatch({
type: 'ref-changed',
value: e.target.value,
})
}
});
tracking.field(
IntegrationEnrollStep.MWIGHAK8SConnectGitHub,
IntegrationEnrollField.MWIGHAK8SGitHubRef,
!e.target.value.length
);
}}
borderTopRightRadius={0}
borderBottomRightRadius={0}
/>
@@ -181,12 +231,16 @@ export function ConnectGitHub(props: FlowStepProps) {
label="Ref Type"
isMulti={false}
value={refTypeValue}
onChange={o =>
onChange={o => {
dispatch({
type: 'ref-type-changed',
value: o?.value ?? '',
})
}
});
tracking.field(
IntegrationEnrollStep.MWIGHAK8SConnectGitHub,
IntegrationEnrollField.MWIGHAK8SGitHubRef
);
}}
options={refTypeOptions}
menuPlacement="auto"
/>
@@ -221,12 +275,17 @@ export function ConnectGitHub(props: FlowStepProps) {
disabled={cfg.edition !== 'ent' || hasGHEHost}
placeholder="octo-enterprise"
value={state.enterpriseSlug}
onChange={e =>
onChange={e => {
dispatch({
type: 'slug-changed',
value: e.target.value,
})
}
});
tracking.field(
IntegrationEnrollStep.MWIGHAK8SConnectGitHub,
IntegrationEnrollField.MWIGHAK8SGitHubEnterpriseSlug,
!e.target.value.length
);
}}
toolTipContent="Allows the slug of a GitHub Enterprise (GHE) organisation to be included in the expected issuer of the OIDC tokens. This is for compatibility with the include_enterprise_slug option in GHE."
helperText={
hasGHEHost
@@ -240,12 +299,17 @@ export function ConnectGitHub(props: FlowStepProps) {
disabled={cfg.edition !== 'ent' || !hasGHEHost}
placeholder='{"keys":[ --snip-- ]}'
value={state.enterpriseJwks}
onChange={e =>
onChange={e => {
dispatch({
type: 'jwks-changed',
value: e.target.value,
})
}
});
tracking.field(
IntegrationEnrollStep.MWIGHAK8SConnectGitHub,
IntegrationEnrollField.MWIGHAK8SGitHubEnterpriseStaticJWKS,
!e.target.value.length
);
}}
toolTipContent="When using GitHub Enterprise Server (GHES), allows the JSON Web Key Set (JWKS) used to verify the token issued by GitHub Actions to be overridden. This can be used in scenarios where the Teleport Auth Service is unable to reach a GHE server."
helperText={
hasGHEHost
@@ -267,7 +331,9 @@ export function ConnectGitHub(props: FlowStepProps) {
</FormContainer>
<CodeContainer>
<CodePanel />
<CodePanel
trackingStep={IntegrationEnrollStep.MWIGHAK8SConnectGitHub}
/>
</CodeContainer>
</Container>
);
@@ -35,8 +35,13 @@ import Link from 'design/Link/Link';
import { H2, P2 } from 'design/Text/Text';
import cfg from 'teleport/config';
import {
IntegrationEnrollStatusCode,
IntegrationEnrollStep,
} from 'teleport/services/userEvent';
import { FlowStepProps } from '../Shared/GuidedFlow';
import { useTracking } from '../Shared/useTracking';
import { CodePanel } from './CodePanel';
export function Finish(props: FlowStepProps) {
@@ -45,8 +50,14 @@ export function Finish(props: FlowStepProps) {
const [showDoneCheck, setShowDoneCheck] = useState(false);
const history = useHistory();
const tracking = useTracking();
const handleDone = () => {
tracking.step(
IntegrationEnrollStep.MWIGHAK8SSetupWorkflow,
IntegrationEnrollStatusCode.Success
);
history.replace(cfg.getBotsRoute());
};
@@ -69,7 +80,13 @@ export function Finish(props: FlowStepProps) {
See the{' '}
<Link
target="_blank"
href="https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/"
href={IAC_LINK}
onClick={() => {
tracking.link(
IntegrationEnrollStep.MWIGHAK8SSetupWorkflow,
IAC_LINK
);
}}
>
Infrastructure as Code
</Link>{' '}
@@ -80,7 +97,13 @@ export function Finish(props: FlowStepProps) {
See the{' '}
<Link
target="_blank"
href="https://goteleport.com/docs/machine-workload-identity/deployment/github-actions/"
href={TBOT_GHA_LINK}
onClick={() => {
tracking.link(
IntegrationEnrollStep.MWIGHAK8SSetupWorkflow,
TBOT_GHA_LINK
);
}}
>
Deploying tbot on GitHub Actions
</Link>{' '}
@@ -96,7 +119,9 @@ export function Finish(props: FlowStepProps) {
</Box>
<CodeContainer>
<CodePanel />
<CodePanel
trackingStep={IntegrationEnrollStep.MWIGHAK8SSetupWorkflow}
/>
</CodeContainer>
<Dialog open={showDoneCheck} onClose={() => setShowDoneCheck(false)}>
@@ -140,3 +165,8 @@ const CodeContainer = styled(Flex)`
flex-direction: column;
overflow: auto;
`;
const IAC_LINK =
'https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/';
const TBOT_GHA_LINK =
'"https://goteleport.com/docs/machine-workload-identity/deployment/github-actions/"';
@@ -25,6 +25,7 @@ import { Router } from 'react-router';
import darkTheme from 'design/theme/themes/darkTheme';
import { ConfiguredThemeProvider } from 'design/ThemeProvider';
import {
act,
render,
screen,
testQueryClient,
@@ -38,36 +39,65 @@ import { ContextProvider } from 'teleport/index';
import { ContentMinWidth } from 'teleport/Main/Main';
import { createTeleportContext } from 'teleport/mocks/contexts';
import { genWizardCiCdSuccess } from 'teleport/test/helpers/bots';
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
import { GitHubActionsK8s } from './GitHubActionsK8s';
import { trackingTester } from '../Shared/trackingTester';
import { TrackingProvider } from '../Shared/useTracking';
import { GitHubActionsK8sWithoutTracking } from './GitHubActionsK8s';
const server = setupServer();
beforeAll(() => {
server.listen();
server.use(genWizardCiCdSuccess());
server.use(userEventCaptureSuccess());
jest.useFakeTimers();
});
afterAll(() => server.close());
afterAll(() => {
server.close();
jest.useRealTimers();
jest.resetAllMocks();
});
describe('GitHubActionsK8s', () => {
test('complete flow: minimal', async () => {
server.use(genWizardCiCdSuccess());
const tracking = trackingTester();
const { user, history } = renderComponent();
const { user, history, unmount } = renderComponent({
trackingEventId: 'test-tracking-event-id',
});
const replaceMock = jest.spyOn(history, 'replace');
tracking.assertStart('test-tracking-event-id');
expect(
screen.getByRole('heading', { name: 'GitHub Actions + Kubernetes' })
).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: 'Start' }));
tracking.assertStep(
'test-tracking-event-id',
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_WELCOME',
'INTEGRATION_ENROLL_STATUS_CODE_SUCCESS'
);
expect(
screen.getByRole('heading', { name: 'Connect to GitHub' })
).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: 'Next' }));
tracking.assertError(
'test-tracking-event-id',
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
'validation error'
);
expect(screen.getByText('Repository is required')).toBeInTheDocument();
expect(screen.getByText('A branch is required')).toBeInTheDocument();
@@ -76,16 +106,43 @@ describe('GitHubActionsK8s', () => {
'https://github.com/gravitational/teleport'
);
// Field tracking is debounced, so move time along to send the event
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
'test-tracking-event-id',
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_GITHUB_REPOSITORY_URL'
);
await user.type(screen.getByLabelText('Branch'), 'main');
await act(() => jest.advanceTimersByTimeAsync(1000));
tracking.assertField(
'test-tracking-event-id',
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
'INTEGRATION_ENROLL_FIELD_MWIGHAK8S_GITHUB_BRANCH'
);
await user.click(screen.getByRole('button', { name: 'Next' }));
tracking.assertStep(
'test-tracking-event-id',
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
'INTEGRATION_ENROLL_STATUS_CODE_SUCCESS'
);
expect(
screen.getByRole('heading', { name: 'Configure Access' })
).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: 'Next' }));
tracking.assertStep(
'test-tracking-event-id',
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS',
'INTEGRATION_ENROLL_STATUS_CODE_SUCCESS'
);
expect(
screen.getByRole('heading', { name: 'Setup Workflow' })
).toBeInTheDocument();
@@ -94,18 +151,31 @@ describe('GitHubActionsK8s', () => {
await user.click(screen.getByRole('button', { name: 'Confirm' }));
tracking.assertStep(
'test-tracking-event-id',
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW',
'INTEGRATION_ENROLL_STATUS_CODE_SUCCESS'
);
expect(replaceMock).toHaveBeenLastCalledWith('/web/bots');
unmount();
tracking.assertComplete('test-tracking-event-id');
});
});
function renderComponent() {
const user = userEvent.setup();
function renderComponent(opts?: { trackingEventId?: string }) {
const { trackingEventId } = opts ?? {};
const user = userEvent.setup({
advanceTimers: t => jest.advanceTimersByTime(t),
});
const history = createMemoryHistory({
initialEntries: [cfg.getBotsNewRoute(BotFlowType.GitHubActionsSsh)],
});
return {
...render(<GitHubActionsK8s />, {
wrapper: makeWrapper({ history }),
...render(<GitHubActionsK8sWithoutTracking />, {
wrapper: makeWrapper({ history, trackingEventId }),
}),
user,
history,
@@ -114,8 +184,9 @@ function renderComponent() {
function makeWrapper(opts: {
history: ReturnType<typeof createMemoryHistory>;
trackingEventId?: string;
}) {
const { history } = opts;
const { history, trackingEventId } = opts;
const ctx = createTeleportContext();
return ({ children }: PropsWithChildren) => {
@@ -125,7 +196,9 @@ function makeWrapper(opts: {
<ConfiguredThemeProvider theme={darkTheme}>
<InfoGuidePanelProvider>
<ContentMinWidth>
<Router history={history}>{children}</Router>
<TrackingProvider initialEventId={trackingEventId}>
<Router history={history}>{children}</Router>
</TrackingProvider>
</ContentMinWidth>
</InfoGuidePanelProvider>
</ConfiguredThemeProvider>
@@ -21,6 +21,7 @@ import { ResourceIcon } from 'design/ResourceIcon';
import { useNoMinWidth } from 'teleport/Main';
import { GuidedFlow, View } from '../Shared/GuidedFlow';
import { TrackingProvider } from '../Shared/useTracking';
import { ConfigureAccess } from './ConfigureAccess';
import { ConnectGitHub } from './ConnectGitHub';
import { Finish } from './Finish';
@@ -49,6 +50,16 @@ const views: View[] = [
export function GitHubActionsK8s() {
useNoMinWidth();
return (
<TrackingProvider>
<GitHubActionsK8sWithoutTracking />
</TrackingProvider>
);
}
export function GitHubActionsK8sWithoutTracking() {
useNoMinWidth();
return (
<GitHubK8sFlowProvider>
<GuidedFlow
@@ -32,8 +32,10 @@ import {
fetchUnifiedResourcesForever,
fetchUnifiedResourcesSuccess,
} from 'teleport/test/helpers/resources';
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
import { KubernetesLabel } from '../Shared/kubernetes';
import { TrackingProvider } from '../Shared/useTracking';
import { KubernetesLabelsSelect } from './KubernetesLabelsSelect';
const meta = {
@@ -51,7 +53,7 @@ export default meta;
export const Happy: Story = {
parameters: {
msw: {
handlers: [fetchUnifiedResourcesSuccess()],
handlers: [fetchUnifiedResourcesSuccess(), userEventCaptureSuccess()],
},
},
};
@@ -59,7 +61,10 @@ export const Happy: Story = {
export const FetchResourcesError: Story = {
parameters: {
msw: {
handlers: [fetchUnifiedResourcesError(500, 'something went wrong')],
handlers: [
fetchUnifiedResourcesError(500, 'something went wrong'),
userEventCaptureSuccess(),
],
},
},
};
@@ -67,7 +72,7 @@ export const FetchResourcesError: Story = {
export const FetchResourcesForever: Story = {
parameters: {
msw: {
handlers: [fetchUnifiedResourcesForever()],
handlers: [fetchUnifiedResourcesForever(), userEventCaptureSuccess()],
},
},
};
@@ -109,16 +114,18 @@ function Wrapper() {
return (
<QueryClientProvider client={queryClient}>
<TeleportProviderBasic teleportCtx={ctx}>
<Validation>
{({ validator }) => (
<Container>
<KubernetesLabelsSelect
selected={labels}
onChange={labels => handleLabelsChanged(labels, validator)}
/>
</Container>
)}
</Validation>
<TrackingProvider>
<Validation>
{({ validator }) => (
<Container>
<KubernetesLabelsSelect
selected={labels}
onChange={labels => handleLabelsChanged(labels, validator)}
/>
</Container>
)}
</Validation>
</TrackingProvider>
</TeleportProviderBasic>
</QueryClientProvider>
);
@@ -36,7 +36,10 @@ import { createTeleportContext } from 'teleport/mocks/contexts';
import { ResourcesResponse, UnifiedResource } from 'teleport/services/agents';
import { defaultAccess, makeAcl } from 'teleport/services/user/makeAcl';
import { fetchUnifiedResourcesSuccess } from 'teleport/test/helpers/resources';
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
import { trackingTester } from '../Shared/trackingTester';
import { TrackingProvider } from '../Shared/useTracking';
import { KubernetesLabelsSelect } from './KubernetesLabelsSelect';
const server = setupServer();
@@ -45,14 +48,23 @@ beforeAll(() => {
server.listen();
});
beforeEach(() => {
server.use(userEventCaptureSuccess());
});
afterEach(async () => {
server.resetHandlers();
await testQueryClient.resetQueries();
jest.clearAllMocks();
});
afterAll(() => server.close());
afterAll(() => {
server.close();
jest.resetAllMocks();
});
describe('KubernetesLabelsSelect', () => {
test('renders', async () => {
@@ -82,6 +94,8 @@ describe('KubernetesLabelsSelect', () => {
});
test('edit action', async () => {
const tracking = trackingTester();
withListUnifiedResourcesSuccess();
const { user } = renderComponent();
@@ -94,6 +108,12 @@ describe('KubernetesLabelsSelect', () => {
expect(
within(modal).getByText('Select one or more labels to configure access.')
).toBeInTheDocument();
tracking.assertSection(
expect.any(String),
'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS',
'INTEGRATION_ENROLL_SECTION_MWIGHAK8S_KUBERNETES_LABEL_PICKER'
);
});
test('cluster list empty', async () => {
@@ -351,8 +371,10 @@ describe('KubernetesLabelsSelect', () => {
function renderComponent(opts?: {
props?: Partial<ComponentProps<typeof KubernetesLabelsSelect>>;
customAcl?: ReturnType<typeof makeAcl>;
disableTracking?: boolean;
}) {
const { props } = opts ?? {};
const { props, customAcl, disableTracking } = opts ?? {};
const { selected = [], onChange = () => {} } = props ?? {};
const user = userEvent.setup();
@@ -361,14 +383,20 @@ function renderComponent(opts?: {
...render(
<KubernetesLabelsSelect selected={selected} onChange={onChange} />,
{
wrapper: makeWrapper(),
wrapper: makeWrapper({
customAcl,
disableTracking,
}),
}
),
user,
};
}
function makeWrapper(opts?: { customAcl?: ReturnType<typeof makeAcl> }) {
function makeWrapper(opts?: {
customAcl?: ReturnType<typeof makeAcl>;
disableTracking?: boolean;
}) {
const {
customAcl = makeAcl({
kubeServers: {
@@ -377,6 +405,7 @@ function makeWrapper(opts?: { customAcl?: ReturnType<typeof makeAcl> }) {
list: true,
},
}),
disableTracking,
} = opts ?? {};
const ctx = createTeleportContext({
@@ -388,7 +417,9 @@ function makeWrapper(opts?: { customAcl?: ReturnType<typeof makeAcl> }) {
<QueryClientProvider client={testQueryClient}>
<ConfiguredThemeProvider theme={darkTheme}>
<ContextProvider ctx={ctx}>
<Validation>{children}</Validation>
<TrackingProvider disabled={disableTracking}>
<Validation>{children}</Validation>
</TrackingProvider>
</ContextProvider>
</ConfiguredThemeProvider>
</QueryClientProvider>
@@ -17,7 +17,7 @@
*/
import { keepPreviousData, useInfiniteQuery } from '@tanstack/react-query';
import { ReactNode, useMemo, useState } from 'react';
import { ReactNode, useEffect, useMemo, useState } from 'react';
import styled from 'styled-components';
import { Alert } from 'design/Alert/Alert';
@@ -49,12 +49,17 @@ import { Rule } from 'shared/components/Validation/rules';
import cfg from 'teleport/config';
import { ResourceLabel } from 'teleport/services/agents';
import { Kube } from 'teleport/services/kube';
import {
IntegrationEnrollSection,
IntegrationEnrollStep,
} from 'teleport/services/userEvent';
import useTeleport from 'teleport/useTeleport';
import {
KubernetesLabel,
makeKubernetesAccessChecker,
} from '../Shared/kubernetes';
import { useTracking } from '../Shared/useTracking';
export function KubernetesLabelsSelect(
props: {
@@ -154,6 +159,16 @@ function Picker(props: {
const flags = ctx.getFeatureFlags();
const hasListPermission = flags.kubernetes;
const tracking = useTracking();
// This effect sends a tracking event when the component mounts
useEffect(() => {
tracking.section(
IntegrationEnrollStep.MWIGHAK8SConfigureAccess,
IntegrationEnrollSection.MWIGHAK8SKubernetesLabelPicker
);
}, [tracking]);
const {
data,
isLoading,
@@ -26,7 +26,13 @@ import Link from 'design/Link/Link';
import { H2, P2 } from 'design/Text/Text';
import { Theme } from 'design/theme/themes/types';
import {
IntegrationEnrollStatusCode,
IntegrationEnrollStep,
} from 'teleport/services/userEvent';
import { FlowStepProps } from '../Shared/GuidedFlow';
import { useTracking } from '../Shared/useTracking';
import welcomeDark from './gha-k8s-welcome-dark.svg';
import welcomeLight from './gha-k8s-welcome-light.svg';
@@ -34,12 +40,22 @@ export function Welcome(props: FlowStepProps) {
const { nextStep } = props;
const theme = useTheme();
const tracking = useTracking();
const welcomeImage: ImageSpec = {
light: welcomeLight,
dark: welcomeDark,
};
const handleNext = () => {
tracking.step(
IntegrationEnrollStep.MWIGHAK8SWelcome,
IntegrationEnrollStatusCode.Success
);
nextStep?.();
};
return (
<Container>
<Box>
@@ -62,7 +78,10 @@ export function Welcome(props: FlowStepProps) {
See the{' '}
<Link
target="_blank"
href="https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/"
href={IAC_LINK}
onClick={() => {
tracking.link(IntegrationEnrollStep.MWIGHAK8SWelcome, IAC_LINK);
}}
>
Infrastructure as Code
</Link>{' '}
@@ -70,7 +89,7 @@ export function Welcome(props: FlowStepProps) {
</P2>
<Flex gap={2} pt={5}>
<ButtonPrimary onClick={nextStep}>Start</ButtonPrimary>
<ButtonPrimary onClick={handleNext}>Start</ButtonPrimary>
</Flex>
</Box>
@@ -89,3 +108,6 @@ const Container = styled(Flex)`
type ImageSpec = {
[K in Theme['type']]: string;
};
const IAC_LINK =
'https://goteleport.com/docs/zero-trust-access/infrastructure-as-code/';
@@ -27,7 +27,9 @@ import { testQueryClient } from 'design/utils/testing';
import { ContextProvider } from 'teleport/index';
import { createTeleportContext } from 'teleport/mocks/contexts';
import { genWizardCiCdSuccess } from 'teleport/test/helpers/bots';
import { userEventCaptureSuccess } from 'teleport/test/helpers/userEvents';
import { TrackingProvider } from '../Shared/useTracking';
import { GitHubK8sFlowProvider, useGitHubK8sFlow } from './useGitHubK8sFlow';
const server = setupServer();
@@ -37,7 +39,9 @@ beforeAll(() => {
});
beforeEach(() => {
// The API call is debounced, so we'll need to time travel a little.
server.use(userEventCaptureSuccess());
// The templates API call is debounced, so we'll need to time travel a little.
jest.useFakeTimers();
});
@@ -486,7 +490,9 @@ function Wrapper(props: PropsWithChildren) {
return (
<QueryClientProvider client={testQueryClient}>
<ContextProvider ctx={ctx}>
<GitHubK8sFlowProvider>{props.children}</GitHubK8sFlowProvider>
<TrackingProvider>
<GitHubK8sFlowProvider>{props.children}</GitHubK8sFlowProvider>
</TrackingProvider>
</ContextProvider>
</QueryClientProvider>
);
@@ -31,6 +31,7 @@ import useTeleport from 'teleport/useTeleport';
import { GITHUB_HOST, parseRepoAddress } from '../Shared/github';
import { KubernetesLabel } from '../Shared/kubernetes';
import { useTracking } from '../Shared/useTracking';
import { makeGhaWorkflow } from './templates';
export function useGitHubK8sFlow() {
@@ -52,6 +53,16 @@ export function GitHubK8sFlowProvider(
const ctx = useTeleport();
const cluster = ctx.storeUser.state.cluster;
const tracking = useTracking();
// This effect sends a user event when the flow starts and ends
useEffect(() => {
tracking.start();
return () => {
tracking.complete();
};
}, [tracking]);
const { mutate, data, isPending, error } = useMutation({
mutationFn: (vars: Parameters<typeof generateGhaK8sTemplates>[0]) =>
generateGhaK8sTemplates(vars),
@@ -0,0 +1,119 @@
/**
* Teleport
* Copyright (C) 2025 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { userEventService } from 'teleport/services/userEvent';
beforeAll(() => {
jest.spyOn(userEventService, 'captureIntegrationEnrollEvent');
});
afterEach(() => {
jest.mocked(userEventService.captureIntegrationEnrollEvent).mockClear();
});
export function trackingTester() {
let nextIndex = 0;
const assertTracking = (data: unknown) => {
const { calls } = jest.mocked(
userEventService.captureIntegrationEnrollEvent
).mock;
const call = calls[nextIndex];
if (!call) {
throw new Error('expected a tracking call but received none');
}
expect(call[0]).toStrictEqual(data);
nextIndex += 1;
};
return {
skip: (count: number = 1) => {
nextIndex += count;
},
assertStart(eventId: string) {
assertTracking({
event: 'tp.ui.integrationEnroll.start',
eventData: {
id: eventId,
kind: 'INTEGRATION_ENROLL_KIND_MACHINE_ID_GITHUB_ACTIONS_KUBERNETES',
},
});
},
assertComplete(eventId: string) {
assertTracking({
event: 'tp.ui.integrationEnroll.complete',
eventData: {
id: eventId,
kind: 'INTEGRATION_ENROLL_KIND_MACHINE_ID_GITHUB_ACTIONS_KUBERNETES',
},
});
},
assertStep(eventId: string, step: string, status: string) {
assertTracking({
event: 'tp.ui.integrationEnroll.step',
eventData: {
id: eventId,
kind: 'INTEGRATION_ENROLL_KIND_MACHINE_ID_GITHUB_ACTIONS_KUBERNETES',
step,
status: {
code: status,
},
},
});
},
assertError(eventId: string, step: string, error: string) {
assertTracking({
event: 'tp.ui.integrationEnroll.step',
eventData: {
id: eventId,
kind: 'INTEGRATION_ENROLL_KIND_MACHINE_ID_GITHUB_ACTIONS_KUBERNETES',
step,
status: {
code: 'INTEGRATION_ENROLL_STATUS_CODE_ERROR',
error,
},
},
});
},
assertField(eventId: string, step: string, field: string) {
assertTracking({
event: 'tp.ui.integrationEnroll.fieldComplete',
eventData: {
id: eventId,
kind: 'INTEGRATION_ENROLL_KIND_MACHINE_ID_GITHUB_ACTIONS_KUBERNETES',
step,
field,
},
});
},
assertSection(eventId: string, step: string, section: string) {
assertTracking({
event: 'tp.ui.integrationEnroll.sectionOpen',
eventData: {
id: eventId,
kind: 'INTEGRATION_ENROLL_KIND_MACHINE_ID_GITHUB_ACTIONS_KUBERNETES',
step,
section,
},
});
},
};
}
@@ -0,0 +1,212 @@
/**
* Teleport
* Copyright (C) 2025 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import {
createContext,
PropsWithChildren,
useContext,
useMemo,
useRef,
} from 'react';
import { debounce } from 'shared/utils/highbar';
import {
IntegrationEnrollCodeType,
IntegrationEnrollEvent,
IntegrationEnrollEventData,
IntegrationEnrollField,
IntegrationEnrollKind,
IntegrationEnrollSection,
IntegrationEnrollStatusCode,
IntegrationEnrollStep,
} from 'teleport/services/userEvent/types';
import { userEventService } from 'teleport/services/userEvent/userEvent';
export function useTracking() {
const ctx = useContext(context);
if (!ctx) {
throw new Error(
'Tracking not implemented, do you need to add a TrackingProvider?'
);
}
return ctx;
}
export function TrackingProvider(
props: { initialEventId?: string; disabled?: boolean } & PropsWithChildren
) {
const { initialEventId = crypto.randomUUID(), disabled = false } = props;
// Changes to the eventId should not cause a re-render.
const eventId = useRef(initialEventId);
const debouncedField = useRef(
debounce(
(
eventId: string,
step: IntegrationEnrollStep,
field: IntegrationEnrollField
) => {
return sendEvent(IntegrationEnrollEvent.FieldComplete, {
id: eventId,
kind: IntegrationEnrollKind.MachineIDGitHubActionsKubernetes,
step,
field,
});
},
1000
)
);
// Keep a stable value as this is likely to be used in effects
const value = useMemo(
() => ({
reset(newId?: string) {
eventId.current = newId || crypto.randomUUID();
},
start() {
if (disabled) return;
return sendEvent(IntegrationEnrollEvent.Started, {
id: eventId.current,
kind: IntegrationEnrollKind.MachineIDGitHubActionsKubernetes,
});
},
complete() {
if (disabled) return;
return sendEvent(IntegrationEnrollEvent.Complete, {
id: eventId.current,
kind: IntegrationEnrollKind.MachineIDGitHubActionsKubernetes,
});
},
step(
step: IntegrationEnrollStep,
status: Exclude<
IntegrationEnrollStatusCode,
IntegrationEnrollStatusCode.Error
>
) {
if (disabled) return;
return sendEvent(IntegrationEnrollEvent.Step, {
id: eventId.current,
kind: IntegrationEnrollKind.MachineIDGitHubActionsKubernetes,
step,
status: {
code: status,
},
});
},
error(step: IntegrationEnrollStep, error: string) {
if (disabled) return;
return sendEvent(IntegrationEnrollEvent.Step, {
id: eventId.current,
kind: IntegrationEnrollKind.MachineIDGitHubActionsKubernetes,
step,
status: {
code: IntegrationEnrollStatusCode.Error,
error,
},
});
},
field(
step: IntegrationEnrollStep,
field: IntegrationEnrollField,
isEmpty?: boolean
) {
if (disabled || isEmpty) return;
return debouncedField.current(eventId.current, step, field);
},
section(step: IntegrationEnrollStep, section: IntegrationEnrollSection) {
if (disabled) return;
return sendEvent(IntegrationEnrollEvent.SectionOpen, {
id: eventId.current,
kind: IntegrationEnrollKind.MachineIDGitHubActionsKubernetes,
step,
section,
});
},
link(step: IntegrationEnrollStep, link: string) {
if (disabled) return;
return sendEvent(IntegrationEnrollEvent.LinkClick, {
id: eventId.current,
kind: IntegrationEnrollKind.MachineIDGitHubActionsKubernetes,
step,
link,
});
},
codeCopy(
step: IntegrationEnrollStep,
codeType: IntegrationEnrollCodeType
) {
if (disabled) return;
return sendEvent(IntegrationEnrollEvent.CodeCopy, {
id: eventId.current,
kind: IntegrationEnrollKind.MachineIDGitHubActionsKubernetes,
step,
codeType,
});
},
}),
[disabled]
);
return <context.Provider value={value}>{props.children}</context.Provider>;
}
function sendEvent(
event: IntegrationEnrollEvent,
eventData: IntegrationEnrollEventData
) {
userEventService.captureIntegrationEnrollEvent({
event,
eventData,
});
}
type Context = {
start: () => void;
complete: () => void;
step: (
step: IntegrationEnrollStep,
statusCode: IntegrationEnrollStatusCode
) => void;
error: (step: IntegrationEnrollStep, error: string) => void;
/**
* Track when a field's value changes. This call is debounced across all
* fields.
* @param step The step in the guide where the field appears
* @param field The field's identifier
* @param isEmpty If the field has no input
*/
field: (
step: IntegrationEnrollStep,
field: IntegrationEnrollField,
isEmpty?: boolean
) => void;
section: (
step: IntegrationEnrollStep,
section: IntegrationEnrollSection
) => void;
link: (step: IntegrationEnrollStep, link: string) => void;
codeCopy: (
step: IntegrationEnrollStep,
codeType: IntegrationEnrollCodeType
) => void;
};
const context = createContext<Context | null>(null);
@@ -94,6 +94,7 @@ export const SectionBox = ({
removable,
isProcessing = false,
validation,
onExpand,
onRemove,
initiallyCollapsed = false,
}: React.PropsWithChildren<{
@@ -102,6 +103,7 @@ export const SectionBox = ({
removable?: boolean;
isProcessing?: boolean;
validation?: ValidationResult;
onExpand?(): void;
onRemove?(): void;
initiallyCollapsed?: boolean;
}>) => {
@@ -140,6 +142,8 @@ export const SectionBox = ({
? ExpansionState.Collapsing
: ExpansionState.Measuring
);
onExpand?.();
};
// Triggered when the collapse animation is finished and we can finally make
@@ -112,8 +112,9 @@ export enum IntegrationEnrollStep {
/**
* MWIGHAK8S denotes the MWI GitHub Actions + Kubernetes wizard.
*/
MWIGHAK8SWelcome = 'INTEGRATION_ENROLL_STEP_MWIGHAK8S_WELCOME',
MWIGHAK8SConnectGitHub = 'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONNECT_GITHUB',
MWIGHAK8SConnectConfigureAccess = 'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS',
MWIGHAK8SConfigureAccess = 'INTEGRATION_ENROLL_STEP_MWIGHAK8S_CONFIGURE_ACCESS',
MWIGHAK8SSetupWorkflow = 'INTEGRATION_ENROLL_STEP_MWIGHAK8S_SETUP_WORKFLOW',
}
@@ -0,0 +1,49 @@
/**
* Teleport
* Copyright (C) 2025 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import { http, HttpResponse } from 'msw';
import cfg from 'teleport/config';
import { JsonObject } from 'teleport/types';
export const userEventCaptureSuccess = () => {
return http.post(cfg.api.captureUserEventPath, async () => {
return HttpResponse.json();
});
};
export const userEventCaptureError = (
status: number,
error: string | null = null,
extras: JsonObject = {}
) =>
http.post(cfg.api.captureUserEventPath, () => {
return HttpResponse.json(
{ error: { message: `${status} - ${error}` }, extras },
{ status }
);
});
export const userEventCaptureForever = () =>
http.post(
cfg.api.captureUserEventPath,
() =>
new Promise(() => {
/* never resolved */
})
);