blob: faace8be61fe89386152fc895431e14de67bdffd [file] [log] [blame]
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: go.chromium.org/luci/swarming/proto/config/bots.proto
package configpb
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
_ "go.chromium.org/luci/common/proto"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
// Schema for bots.cfg service config file in luci-config.
//
// It defines a function bot_id => (required credentials, trusted_dimensions,
// config), where
// * "bot_id" is identifier of a bot as sent by the bot itself (usually
// machine hostname, short one, not FQDN)
// * "required credentials" describes how server should authenticate calls
// from the bot.
// * "trusted_dimensions" is a set of dimension set by the server itself.
// Such dimensions can't be spoofed by the bot.
// * "config" is any additional bot configuration.
//
// Connections from bots that do not appear in this config are rejected.
//
// The default config (used if bots.cfg is missing) represents IP-whitelist only
// authentication, as was used before bots.cfg was implemented:
//
// bot_group {
// auth {
// ip_whitelist: "<swarming-app-id>-bots"
// }
// }
type BotsCfg struct {
// List of dimension names that are provided by the server.
//
// If bot attempts to set such dimension, it'll be ignored. Trusted dimensions
// are defined through bot_group configs below. Swarming users can trust such
// dimensions, since they are set by the server based on validated credentials
// (unlike other dimensions that can be arbitrary defined by the bot itself).
TrustedDimensions []string `protobuf:"bytes,1,rep,name=trusted_dimensions,json=trustedDimensions,proto3" json:"trusted_dimensions,omitempty"`
// A list of groups of bots. Each group defines a bunch of bots that all
// have same dimensions and authenticate in the same way.
//
// The order of entries here is irrelevant. The server uses the following
// search algorithm when trying to pick a group for a bot with some bot_id:
// 1) First it tries to find a direct match: a group that lists the bot in
// bot_id field.
// 2) Next it tries to find a group with matching bot_id_prefix. The config
// validation process makes sure prefixes do not "intersect", so there
// will be at most one matching group.
// 3) Finally, if there's a group with no defined bot_id or bot_id_prefix
// fields (the "default" group), the bot is categorized to that group.
// If there's no such group, the connection from the bot is rejected.
// Config validation process ensures there can be only one such group.
BotGroup []*BotGroup `protobuf:"bytes,2,rep,name=bot_group,json=botGroup,proto3" json:"bot_group,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *BotsCfg) Reset() { *m = BotsCfg{} }
func (m *BotsCfg) String() string { return proto.CompactTextString(m) }
func (*BotsCfg) ProtoMessage() {}
func (*BotsCfg) Descriptor() ([]byte, []int) {
return fileDescriptor_ecc3522ef1feaf58, []int{0}
}
func (m *BotsCfg) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BotsCfg.Unmarshal(m, b)
}
func (m *BotsCfg) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_BotsCfg.Marshal(b, m, deterministic)
}
func (m *BotsCfg) XXX_Merge(src proto.Message) {
xxx_messageInfo_BotsCfg.Merge(m, src)
}
func (m *BotsCfg) XXX_Size() int {
return xxx_messageInfo_BotsCfg.Size(m)
}
func (m *BotsCfg) XXX_DiscardUnknown() {
xxx_messageInfo_BotsCfg.DiscardUnknown(m)
}
var xxx_messageInfo_BotsCfg proto.InternalMessageInfo
func (m *BotsCfg) GetTrustedDimensions() []string {
if m != nil {
return m.TrustedDimensions
}
return nil
}
func (m *BotsCfg) GetBotGroup() []*BotGroup {
if m != nil {
return m.BotGroup
}
return nil
}
// A group of bots that share authentication method, dimensions and owners.
//
// Union of bot_id and bot_id_prefix define a set of bots that belong to this
// group. The rest of the fields define properties of this group.
//
// If bot_id and bot_id_prefix are both missing, the group defines all bots that
// didn't fit into other groups. There can be only one such "default" group.
//
// NOTE: Swarming allows 'derivative' bots where multiple bots run on the same
// host machine in some sort of container (such as Docker containers) and SHARE
// A SINGLE CREDENTIAL. These bots have hostnames such as 'hostmachine--001',
// where the "--001" suffix indicates which of the contained bots on
// 'hostmachine' it is. When Swarming checks the bot affiliation for this
// contained machine, it checks ONLY the 'hostmachine' portion. This means that
// if your contained bot is 'vm10-vlan2--001', it would match:
// `bot_id: "vm10-vlan2`
// `bot_id: "vm{0...100}-vlan2`
// `bot_id_prefix: "vm10-vlan`
// but would NOT match:
// `bot_id: "vm10-vlan2--001`
// `bot_id_prefix: "vm10-vlan2-`
// `bot_id_prefix: "vm10-vlan2--`
//
// TODO(vadimsh): Introduce explicit field "use_as_default" instead.
type BotGroup struct {
// Explicit enumeration of bot IDs belonging to this group.
//
// It supports subset of bash brace expansion syntax, in particular ranges
// and lists. For example:
// * vm{1..3}-m1 will expand into vm1-m1, vm2-m1 and vm3-m1.
// * vm{100,150,200}-m1 will expand into vm100-m1, vm150-m1 and vm200-m1.
//
// There can be only one "{...}" section in the string.
BotId []string `protobuf:"bytes,1,rep,name=bot_id,json=botId,proto3" json:"bot_id,omitempty"`
// A prefix to match against bot ID string.
BotIdPrefix []string `protobuf:"bytes,2,rep,name=bot_id_prefix,json=botIdPrefix,proto3" json:"bot_id_prefix,omitempty"`
// Defines authentication methods for bots from this group.
//
// Evaluated sequentially until first match.
Auth []*BotAuth `protobuf:"bytes,20,rep,name=auth,proto3" json:"auth,omitempty"`
// Emails of owners of these bots. Optional.
Owners []string `protobuf:"bytes,21,rep,name=owners,proto3" json:"owners,omitempty"`
// List of dimensions to assign to these bots.
//
// Each dimension is a "<key>:<value>" pair.
Dimensions []string `protobuf:"bytes,22,rep,name=dimensions,proto3" json:"dimensions,omitempty"`
// Path to an additional config script to inject into the swarming bot upon
// handshake.
//
// The path is relative to 'scripts/' directory in the service config repo.
BotConfigScript string `protobuf:"bytes,23,opt,name=bot_config_script,json=botConfigScript,proto3" json:"bot_config_script,omitempty"`
// The actual body of the config script to inject into the swarming bot upon
// handshake (in whatever encoding it happened to be in the config repo).
//
// For internal use (unless you fancy writing python scripts as single line
// escaped text proto string). If present, overrides 'bot_config_script'.
BotConfigScriptContent []byte `protobuf:"bytes,25,opt,name=bot_config_script_content,json=botConfigScriptContent,proto3" json:"bot_config_script_content,omitempty"`
// A service account to use on bots when authenticating calls to various
// system-level services (like Isolate and CIPD), required for correct
// operation of the bot.
//
// Tasks will be able to access this account too, but it is not recommended
// and should be used extremely rare.
//
// If set to a service account email (*@*.iam.gserviceaccount.com), bots will
// use this account, generating access token through Swarming server. For this
// to work, the server account (<app-id>@appspot.gserviceaccount.com) must
// have "serviceAccountActor" IAM role set on the account.
//
// If set to a special string "bot", bots will use exact same token they use
// when authenticating calls to Swarming server itself. This works only if
// bots use OAuth for authentication (see 'require_service_account' in
// BotAuth). This mode exists for cases when proliferation of various service
// accounts is undesirable. Note that in this mode Swarming processes won't be
// able to request a system account token with some new scopes: they get exact
// same token as returned by get_authentication_headers bot_config.py hook.
//
// If not set, bots will not use authentication at all.
SystemServiceAccount string `protobuf:"bytes,24,opt,name=system_service_account,json=systemServiceAccount,proto3" json:"system_service_account,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *BotGroup) Reset() { *m = BotGroup{} }
func (m *BotGroup) String() string { return proto.CompactTextString(m) }
func (*BotGroup) ProtoMessage() {}
func (*BotGroup) Descriptor() ([]byte, []int) {
return fileDescriptor_ecc3522ef1feaf58, []int{1}
}
func (m *BotGroup) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BotGroup.Unmarshal(m, b)
}
func (m *BotGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_BotGroup.Marshal(b, m, deterministic)
}
func (m *BotGroup) XXX_Merge(src proto.Message) {
xxx_messageInfo_BotGroup.Merge(m, src)
}
func (m *BotGroup) XXX_Size() int {
return xxx_messageInfo_BotGroup.Size(m)
}
func (m *BotGroup) XXX_DiscardUnknown() {
xxx_messageInfo_BotGroup.DiscardUnknown(m)
}
var xxx_messageInfo_BotGroup proto.InternalMessageInfo
func (m *BotGroup) GetBotId() []string {
if m != nil {
return m.BotId
}
return nil
}
func (m *BotGroup) GetBotIdPrefix() []string {
if m != nil {
return m.BotIdPrefix
}
return nil
}
func (m *BotGroup) GetAuth() []*BotAuth {
if m != nil {
return m.Auth
}
return nil
}
func (m *BotGroup) GetOwners() []string {
if m != nil {
return m.Owners
}
return nil
}
func (m *BotGroup) GetDimensions() []string {
if m != nil {
return m.Dimensions
}
return nil
}
func (m *BotGroup) GetBotConfigScript() string {
if m != nil {
return m.BotConfigScript
}
return ""
}
func (m *BotGroup) GetBotConfigScriptContent() []byte {
if m != nil {
return m.BotConfigScriptContent
}
return nil
}
func (m *BotGroup) GetSystemServiceAccount() string {
if m != nil {
return m.SystemServiceAccount
}
return ""
}
// Defines what kind of authentication to perform when handling requests from
// bots belonging to some bot group.
//
// The following combinations are valid:
// * Either one of require_* alone.
// * IP whitelist alone.
// * IP + require_luci_machine_token: requires both to pass.
// * IP + require_service_account: requires both to pass.
// * IP + require_gce_vm_token: requires both to pass.
//
// Next ID: 6.
type BotAuth struct {
// If true, log an error (but proceed) if this method didn't succeed.
//
// This field is totally optional and makes sense only when there are more
// than one auth method. Affects only logging levels.
//
// Doesn't apply to methods that were skipped because some method before them
// succeeded. Thus methods that have 'log_if_failed' should be in front of
// BotGroup.auth list.
//
// This is useful when migrating from one auth method to another to verify
// the new method is used in 100% of cases, while still keeping a fallback
// to an old method.
LogIfFailed bool `protobuf:"varint,5,opt,name=log_if_failed,json=logIfFailed,proto3" json:"log_if_failed,omitempty"`
// If true, the bot should provide valid X-Luci-Machine-Token header.
//
// The machine FQDN embedded in the token should have hostname equal to the
// bot_id.
RequireLuciMachineToken bool `protobuf:"varint,1,opt,name=require_luci_machine_token,json=requireLuciMachineToken,proto3" json:"require_luci_machine_token,omitempty"`
// If set, the bot should use OAuth access token belonging to any of these
// service accounts.
//
// The token should have "https://www.googleapis.com/auth/userinfo.email"
// scope.
RequireServiceAccount []string `protobuf:"bytes,2,rep,name=require_service_account,json=requireServiceAccount,proto3" json:"require_service_account,omitempty"`
// If set, the bot should provide valid X-Luci-Gce-Vm-Token header.
//
// This header should contain JWT with signed VM metadata with the following
// expectations:
// * Audience matches https://[*-dot-]<app>.appspot.com
// * google.compute_engine.project_id field matches the value of 'project'.
// * instance_name matches bot_id reported by the bot (case insensitive).
RequireGceVmToken *BotAuth_GCE `protobuf:"bytes,4,opt,name=require_gce_vm_token,json=requireGceVmToken,proto3" json:"require_gce_vm_token,omitempty"`
// If set, defines an IP whitelist name (in auth_service database) with a set
// of IPs allowed to be used by the bots in this group.
//
// Works in conjunction with other checks, e.g. if require_luci_machine_token
// is true, both valid X-Luci-Machine-Token and a whitelisted IP are needed to
// successfully authenticate.
//
// Can also be used on its own (when all other fields are empty). In that case
// the IP whitelist is the primary authentication mechanism. Note that in this
// case all bots that share the IP whitelist are effectively in a single trust
// domain (any bot can pretend to be some other bot).
IpWhitelist string `protobuf:"bytes,3,opt,name=ip_whitelist,json=ipWhitelist,proto3" json:"ip_whitelist,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *BotAuth) Reset() { *m = BotAuth{} }
func (m *BotAuth) String() string { return proto.CompactTextString(m) }
func (*BotAuth) ProtoMessage() {}
func (*BotAuth) Descriptor() ([]byte, []int) {
return fileDescriptor_ecc3522ef1feaf58, []int{2}
}
func (m *BotAuth) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BotAuth.Unmarshal(m, b)
}
func (m *BotAuth) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_BotAuth.Marshal(b, m, deterministic)
}
func (m *BotAuth) XXX_Merge(src proto.Message) {
xxx_messageInfo_BotAuth.Merge(m, src)
}
func (m *BotAuth) XXX_Size() int {
return xxx_messageInfo_BotAuth.Size(m)
}
func (m *BotAuth) XXX_DiscardUnknown() {
xxx_messageInfo_BotAuth.DiscardUnknown(m)
}
var xxx_messageInfo_BotAuth proto.InternalMessageInfo
func (m *BotAuth) GetLogIfFailed() bool {
if m != nil {
return m.LogIfFailed
}
return false
}
func (m *BotAuth) GetRequireLuciMachineToken() bool {
if m != nil {
return m.RequireLuciMachineToken
}
return false
}
func (m *BotAuth) GetRequireServiceAccount() []string {
if m != nil {
return m.RequireServiceAccount
}
return nil
}
func (m *BotAuth) GetRequireGceVmToken() *BotAuth_GCE {
if m != nil {
return m.RequireGceVmToken
}
return nil
}
func (m *BotAuth) GetIpWhitelist() string {
if m != nil {
return m.IpWhitelist
}
return ""
}
// See require_gce_vm_token below.
type BotAuth_GCE struct {
Project string `protobuf:"bytes,1,opt,name=project,proto3" json:"project,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *BotAuth_GCE) Reset() { *m = BotAuth_GCE{} }
func (m *BotAuth_GCE) String() string { return proto.CompactTextString(m) }
func (*BotAuth_GCE) ProtoMessage() {}
func (*BotAuth_GCE) Descriptor() ([]byte, []int) {
return fileDescriptor_ecc3522ef1feaf58, []int{2, 0}
}
func (m *BotAuth_GCE) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_BotAuth_GCE.Unmarshal(m, b)
}
func (m *BotAuth_GCE) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_BotAuth_GCE.Marshal(b, m, deterministic)
}
func (m *BotAuth_GCE) XXX_Merge(src proto.Message) {
xxx_messageInfo_BotAuth_GCE.Merge(m, src)
}
func (m *BotAuth_GCE) XXX_Size() int {
return xxx_messageInfo_BotAuth_GCE.Size(m)
}
func (m *BotAuth_GCE) XXX_DiscardUnknown() {
xxx_messageInfo_BotAuth_GCE.DiscardUnknown(m)
}
var xxx_messageInfo_BotAuth_GCE proto.InternalMessageInfo
func (m *BotAuth_GCE) GetProject() string {
if m != nil {
return m.Project
}
return ""
}
func init() {
proto.RegisterType((*BotsCfg)(nil), "swarming.config.BotsCfg")
proto.RegisterType((*BotGroup)(nil), "swarming.config.BotGroup")
proto.RegisterType((*BotAuth)(nil), "swarming.config.BotAuth")
proto.RegisterType((*BotAuth_GCE)(nil), "swarming.config.BotAuth.GCE")
}
func init() {
proto.RegisterFile("go.chromium.org/luci/swarming/proto/config/bots.proto", fileDescriptor_ecc3522ef1feaf58)
}
var fileDescriptor_ecc3522ef1feaf58 = []byte{
// 576 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x93, 0x51, 0x4f, 0x13, 0x41,
0x10, 0xc7, 0x53, 0x5a, 0xa0, 0xdd, 0x62, 0x90, 0x0d, 0x94, 0x85, 0x18, 0xad, 0xf5, 0xa5, 0x31,
0x72, 0x97, 0x80, 0x92, 0x08, 0x4f, 0xb4, 0x60, 0x83, 0x91, 0xc4, 0x1c, 0x46, 0x13, 0x5f, 0x36,
0x77, 0xdb, 0xbd, 0xbb, 0xd5, 0xde, 0xcd, 0xba, 0x3b, 0x07, 0xfa, 0xe0, 0x97, 0xf1, 0x3b, 0xf8,
0x35, 0xfc, 0x48, 0xc6, 0xdc, 0xde, 0x95, 0x20, 0x60, 0xe2, 0x53, 0xbb, 0xff, 0xdf, 0xcc, 0x7f,
0x66, 0x76, 0x6f, 0xc8, 0x8b, 0x04, 0x3c, 0x91, 0x1a, 0xc8, 0x54, 0x91, 0x79, 0x60, 0x12, 0x7f,
0x56, 0x08, 0xe5, 0xdb, 0xcb, 0xd0, 0x64, 0x2a, 0x4f, 0x7c, 0x6d, 0x00, 0xc1, 0x17, 0x90, 0xc7,
0x2a, 0xf1, 0x23, 0x40, 0xeb, 0x39, 0x85, 0xae, 0xce, 0x23, 0xbc, 0x8a, 0x6d, 0xfb, 0x77, 0xfa,
0x08, 0xc8, 0x32, 0xc8, 0x6b, 0x17, 0xd0, 0xa8, 0x20, 0xaf, 0x1d, 0x06, 0x9a, 0x2c, 0x8f, 0x00,
0xed, 0x38, 0x4e, 0xe8, 0x0e, 0xa1, 0x68, 0x0a, 0x8b, 0x72, 0xca, 0xa7, 0x2a, 0x93, 0xb9, 0x2d,
0xc3, 0x58, 0xa3, 0xdf, 0x1c, 0x76, 0x82, 0xb5, 0x9a, 0x1c, 0x5f, 0x01, 0xba, 0x4f, 0x3a, 0x11,
0x20, 0x4f, 0x0c, 0x14, 0x9a, 0x2d, 0xf4, 0x9b, 0xc3, 0xee, 0xee, 0x96, 0x77, 0xa3, 0x1f, 0x6f,
0x04, 0x38, 0x29, 0x03, 0x82, 0x76, 0x54, 0xff, 0x1b, 0xfc, 0x5a, 0x20, 0xed, 0xb9, 0x4c, 0x37,
0xc8, 0x52, 0x69, 0xa2, 0xa6, 0x75, 0x9d, 0xc5, 0x08, 0xf0, 0x74, 0x4a, 0x07, 0xe4, 0x5e, 0x25,
0x73, 0x6d, 0x64, 0xac, 0xbe, 0x3a, 0xff, 0x4e, 0xd0, 0x75, 0xf4, 0xad, 0x93, 0xe8, 0x33, 0xd2,
0x0a, 0x0b, 0x4c, 0xd9, 0xba, 0x2b, 0xcd, 0xee, 0x2a, 0x7d, 0x54, 0x60, 0x1a, 0xb8, 0x28, 0xda,
0x23, 0x4b, 0x70, 0x99, 0x4b, 0x63, 0xd9, 0x86, 0xb3, 0xaa, 0x4f, 0xf4, 0x21, 0x21, 0xd7, 0x86,
0xed, 0x39, 0x76, 0x4d, 0xa1, 0x4f, 0xc9, 0x5a, 0xd9, 0x49, 0xe5, 0xc9, 0xad, 0x30, 0x4a, 0x23,
0xdb, 0xec, 0x37, 0x86, 0x9d, 0x60, 0x35, 0x02, 0x1c, 0x3b, 0xfd, 0xdc, 0xc9, 0xf4, 0x25, 0xd9,
0xba, 0x15, 0x5b, 0x9e, 0x50, 0xe6, 0xc8, 0xb6, 0xfa, 0x8d, 0xe1, 0x4a, 0xd0, 0xbb, 0x91, 0x33,
0xae, 0x28, 0x7d, 0x4e, 0x7a, 0xf6, 0x9b, 0x45, 0x99, 0x71, 0x2b, 0xcd, 0x85, 0x12, 0x92, 0x87,
0x42, 0x40, 0x91, 0x23, 0x63, 0xae, 0xd6, 0x7a, 0x45, 0xcf, 0x2b, 0x78, 0x54, 0xb1, 0xd7, 0xad,
0x76, 0xf3, 0x7e, 0x6b, 0xf0, 0x73, 0xc1, 0xbd, 0x61, 0x39, 0x6c, 0x79, 0x71, 0x33, 0x48, 0xb8,
0x8a, 0x79, 0x1c, 0xaa, 0x99, 0x9c, 0xb2, 0xc5, 0x7e, 0x63, 0xd8, 0x0e, 0xba, 0x33, 0x48, 0x4e,
0xe3, 0x57, 0x4e, 0xa2, 0x87, 0x64, 0xdb, 0xc8, 0x2f, 0x85, 0x32, 0x92, 0x97, 0x5f, 0x07, 0xcf,
0x42, 0x91, 0xaa, 0x5c, 0x72, 0x84, 0xcf, 0x32, 0x67, 0x0d, 0x97, 0xb0, 0x59, 0x47, 0xbc, 0x29,
0x84, 0x3a, 0xab, 0xf8, 0xbb, 0x12, 0xd3, 0x7d, 0x32, 0x47, 0xb7, 0x3a, 0xad, 0xde, 0x68, 0xa3,
0xc6, 0x7f, 0xb7, 0x4a, 0xcf, 0xc8, 0xfa, 0x3c, 0x2f, 0x11, 0x92, 0x5f, 0x64, 0x75, 0xb9, 0x56,
0xbf, 0x31, 0xec, 0xee, 0x3e, 0xf8, 0xd7, 0xeb, 0x79, 0x93, 0xf1, 0x49, 0xb0, 0x56, 0x67, 0x4e,
0x84, 0x7c, 0x9f, 0x55, 0x6d, 0x3c, 0x26, 0x2b, 0x4a, 0xf3, 0xcb, 0x54, 0xa1, 0x9c, 0x29, 0x8b,
0xac, 0xe9, 0x6e, 0xa9, 0xab, 0xf4, 0x87, 0xb9, 0xb4, 0xfd, 0x88, 0x34, 0x27, 0xe3, 0x13, 0xca,
0xc8, 0xb2, 0x36, 0xf0, 0x49, 0x0a, 0x74, 0xa3, 0x75, 0x82, 0xf9, 0x71, 0xf4, 0xfd, 0xc7, 0xef,
0x27, 0xc7, 0x64, 0x94, 0x22, 0x6a, 0x7b, 0xe0, 0xbb, 0x4d, 0xd9, 0xa9, 0xab, 0x87, 0x5a, 0x5b,
0x0d, 0xe8, 0x09, 0xc8, 0x7c, 0x2b, 0x52, 0x99, 0x85, 0xd6, 0xaf, 0xc7, 0xb5, 0x57, 0x5b, 0x79,
0xe0, 0x16, 0x51, 0xc4, 0xc9, 0xc7, 0xbd, 0xff, 0xdf, 0xde, 0xc3, 0xea, 0x47, 0x47, 0xd1, 0x92,
0x93, 0xf7, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0x3d, 0xac, 0x01, 0x24, 0xfb, 0x03, 0x00, 0x00,
}