1// Copyright 2021 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// Code generated by protoc-gen-go_gapic. DO NOT EDIT. 16 17package scheduler 18 19import ( 20 "context" 21 "fmt" 22 "math" 23 "net/url" 24 "time" 25 26 gax "github.com/googleapis/gax-go/v2" 27 "google.golang.org/api/iterator" 28 "google.golang.org/api/option" 29 "google.golang.org/api/option/internaloption" 30 gtransport "google.golang.org/api/transport/grpc" 31 schedulerpb "google.golang.org/genproto/googleapis/cloud/scheduler/v1" 32 "google.golang.org/grpc" 33 "google.golang.org/grpc/codes" 34 "google.golang.org/grpc/metadata" 35 "google.golang.org/protobuf/proto" 36) 37 38var newCloudSchedulerClientHook clientHook 39 40// CloudSchedulerCallOptions contains the retry settings for each method of CloudSchedulerClient. 41type CloudSchedulerCallOptions struct { 42 ListJobs []gax.CallOption 43 GetJob []gax.CallOption 44 CreateJob []gax.CallOption 45 UpdateJob []gax.CallOption 46 DeleteJob []gax.CallOption 47 PauseJob []gax.CallOption 48 ResumeJob []gax.CallOption 49 RunJob []gax.CallOption 50} 51 52func defaultCloudSchedulerGRPCClientOptions() []option.ClientOption { 53 return []option.ClientOption{ 54 internaloption.WithDefaultEndpoint("cloudscheduler.googleapis.com:443"), 55 internaloption.WithDefaultMTLSEndpoint("cloudscheduler.mtls.googleapis.com:443"), 56 internaloption.WithDefaultAudience("https://cloudscheduler.googleapis.com/"), 57 internaloption.WithDefaultScopes(DefaultAuthScopes()...), 58 internaloption.EnableJwtWithScope(), 59 option.WithGRPCDialOption(grpc.WithDisableServiceConfig()), 60 option.WithGRPCDialOption(grpc.WithDefaultCallOptions( 61 grpc.MaxCallRecvMsgSize(math.MaxInt32))), 62 } 63} 64 65func defaultCloudSchedulerCallOptions() *CloudSchedulerCallOptions { 66 return &CloudSchedulerCallOptions{ 67 ListJobs: []gax.CallOption{ 68 gax.WithRetry(func() gax.Retryer { 69 return gax.OnCodes([]codes.Code{ 70 codes.DeadlineExceeded, 71 codes.Unavailable, 72 }, gax.Backoff{ 73 Initial: 100 * time.Millisecond, 74 Max: 60000 * time.Millisecond, 75 Multiplier: 1.30, 76 }) 77 }), 78 }, 79 GetJob: []gax.CallOption{ 80 gax.WithRetry(func() gax.Retryer { 81 return gax.OnCodes([]codes.Code{ 82 codes.DeadlineExceeded, 83 codes.Unavailable, 84 }, gax.Backoff{ 85 Initial: 100 * time.Millisecond, 86 Max: 60000 * time.Millisecond, 87 Multiplier: 1.30, 88 }) 89 }), 90 }, 91 CreateJob: []gax.CallOption{}, 92 UpdateJob: []gax.CallOption{}, 93 DeleteJob: []gax.CallOption{ 94 gax.WithRetry(func() gax.Retryer { 95 return gax.OnCodes([]codes.Code{ 96 codes.DeadlineExceeded, 97 codes.Unavailable, 98 }, gax.Backoff{ 99 Initial: 100 * time.Millisecond, 100 Max: 60000 * time.Millisecond, 101 Multiplier: 1.30, 102 }) 103 }), 104 }, 105 PauseJob: []gax.CallOption{}, 106 ResumeJob: []gax.CallOption{}, 107 RunJob: []gax.CallOption{}, 108 } 109} 110 111// internalCloudSchedulerClient is an interface that defines the methods availaible from Cloud Scheduler API. 112type internalCloudSchedulerClient interface { 113 Close() error 114 setGoogleClientInfo(...string) 115 Connection() *grpc.ClientConn 116 ListJobs(context.Context, *schedulerpb.ListJobsRequest, ...gax.CallOption) *JobIterator 117 GetJob(context.Context, *schedulerpb.GetJobRequest, ...gax.CallOption) (*schedulerpb.Job, error) 118 CreateJob(context.Context, *schedulerpb.CreateJobRequest, ...gax.CallOption) (*schedulerpb.Job, error) 119 UpdateJob(context.Context, *schedulerpb.UpdateJobRequest, ...gax.CallOption) (*schedulerpb.Job, error) 120 DeleteJob(context.Context, *schedulerpb.DeleteJobRequest, ...gax.CallOption) error 121 PauseJob(context.Context, *schedulerpb.PauseJobRequest, ...gax.CallOption) (*schedulerpb.Job, error) 122 ResumeJob(context.Context, *schedulerpb.ResumeJobRequest, ...gax.CallOption) (*schedulerpb.Job, error) 123 RunJob(context.Context, *schedulerpb.RunJobRequest, ...gax.CallOption) (*schedulerpb.Job, error) 124} 125 126// CloudSchedulerClient is a client for interacting with Cloud Scheduler API. 127// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. 128// 129// The Cloud Scheduler API allows external entities to reliably 130// schedule asynchronous jobs. 131type CloudSchedulerClient struct { 132 // The internal transport-dependent client. 133 internalClient internalCloudSchedulerClient 134 135 // The call options for this service. 136 CallOptions *CloudSchedulerCallOptions 137} 138 139// Wrapper methods routed to the internal client. 140 141// Close closes the connection to the API service. The user should invoke this when 142// the client is no longer required. 143func (c *CloudSchedulerClient) Close() error { 144 return c.internalClient.Close() 145} 146 147// setGoogleClientInfo sets the name and version of the application in 148// the `x-goog-api-client` header passed on each request. Intended for 149// use by Google-written clients. 150func (c *CloudSchedulerClient) setGoogleClientInfo(keyval ...string) { 151 c.internalClient.setGoogleClientInfo(keyval...) 152} 153 154// Connection returns a connection to the API service. 155// 156// Deprecated. 157func (c *CloudSchedulerClient) Connection() *grpc.ClientConn { 158 return c.internalClient.Connection() 159} 160 161// ListJobs lists jobs. 162func (c *CloudSchedulerClient) ListJobs(ctx context.Context, req *schedulerpb.ListJobsRequest, opts ...gax.CallOption) *JobIterator { 163 return c.internalClient.ListJobs(ctx, req, opts...) 164} 165 166// GetJob gets a job. 167func (c *CloudSchedulerClient) GetJob(ctx context.Context, req *schedulerpb.GetJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { 168 return c.internalClient.GetJob(ctx, req, opts...) 169} 170 171// CreateJob creates a job. 172func (c *CloudSchedulerClient) CreateJob(ctx context.Context, req *schedulerpb.CreateJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { 173 return c.internalClient.CreateJob(ctx, req, opts...) 174} 175 176// UpdateJob updates a job. 177// 178// If successful, the updated Job is returned. If the job does 179// not exist, NOT_FOUND is returned. 180// 181// If UpdateJob does not successfully return, it is possible for the 182// job to be in an Job.State.UPDATE_FAILED state. A job in this state may 183// not be executed. If this happens, retry the UpdateJob request 184// until a successful response is received. 185func (c *CloudSchedulerClient) UpdateJob(ctx context.Context, req *schedulerpb.UpdateJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { 186 return c.internalClient.UpdateJob(ctx, req, opts...) 187} 188 189// DeleteJob deletes a job. 190func (c *CloudSchedulerClient) DeleteJob(ctx context.Context, req *schedulerpb.DeleteJobRequest, opts ...gax.CallOption) error { 191 return c.internalClient.DeleteJob(ctx, req, opts...) 192} 193 194// PauseJob pauses a job. 195// 196// If a job is paused then the system will stop executing the job 197// until it is re-enabled via ResumeJob. The 198// state of the job is stored in state; if paused it 199// will be set to Job.State.PAUSED. A job must be in Job.State.ENABLED 200// to be paused. 201func (c *CloudSchedulerClient) PauseJob(ctx context.Context, req *schedulerpb.PauseJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { 202 return c.internalClient.PauseJob(ctx, req, opts...) 203} 204 205// ResumeJob resume a job. 206// 207// This method reenables a job after it has been Job.State.PAUSED. The 208// state of a job is stored in Job.state; after calling this method it 209// will be set to Job.State.ENABLED. A job must be in 210// Job.State.PAUSED to be resumed. 211func (c *CloudSchedulerClient) ResumeJob(ctx context.Context, req *schedulerpb.ResumeJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { 212 return c.internalClient.ResumeJob(ctx, req, opts...) 213} 214 215// RunJob forces a job to run now. 216// 217// When this method is called, Cloud Scheduler will dispatch the job, even 218// if the job is already running. 219func (c *CloudSchedulerClient) RunJob(ctx context.Context, req *schedulerpb.RunJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { 220 return c.internalClient.RunJob(ctx, req, opts...) 221} 222 223// cloudSchedulerGRPCClient is a client for interacting with Cloud Scheduler API over gRPC transport. 224// 225// Methods, except Close, may be called concurrently. However, fields must not be modified concurrently with method calls. 226type cloudSchedulerGRPCClient struct { 227 // Connection pool of gRPC connections to the service. 228 connPool gtransport.ConnPool 229 230 // flag to opt out of default deadlines via GOOGLE_API_GO_EXPERIMENTAL_DISABLE_DEFAULT_DEADLINE 231 disableDeadlines bool 232 233 // Points back to the CallOptions field of the containing CloudSchedulerClient 234 CallOptions **CloudSchedulerCallOptions 235 236 // The gRPC API client. 237 cloudSchedulerClient schedulerpb.CloudSchedulerClient 238 239 // The x-goog-* metadata to be sent with each request. 240 xGoogMetadata metadata.MD 241} 242 243// NewCloudSchedulerClient creates a new cloud scheduler client based on gRPC. 244// The returned client must be Closed when it is done being used to clean up its underlying connections. 245// 246// The Cloud Scheduler API allows external entities to reliably 247// schedule asynchronous jobs. 248func NewCloudSchedulerClient(ctx context.Context, opts ...option.ClientOption) (*CloudSchedulerClient, error) { 249 clientOpts := defaultCloudSchedulerGRPCClientOptions() 250 if newCloudSchedulerClientHook != nil { 251 hookOpts, err := newCloudSchedulerClientHook(ctx, clientHookParams{}) 252 if err != nil { 253 return nil, err 254 } 255 clientOpts = append(clientOpts, hookOpts...) 256 } 257 258 disableDeadlines, err := checkDisableDeadlines() 259 if err != nil { 260 return nil, err 261 } 262 263 connPool, err := gtransport.DialPool(ctx, append(clientOpts, opts...)...) 264 if err != nil { 265 return nil, err 266 } 267 client := CloudSchedulerClient{CallOptions: defaultCloudSchedulerCallOptions()} 268 269 c := &cloudSchedulerGRPCClient{ 270 connPool: connPool, 271 disableDeadlines: disableDeadlines, 272 cloudSchedulerClient: schedulerpb.NewCloudSchedulerClient(connPool), 273 CallOptions: &client.CallOptions, 274 } 275 c.setGoogleClientInfo() 276 277 client.internalClient = c 278 279 return &client, nil 280} 281 282// Connection returns a connection to the API service. 283// 284// Deprecated. 285func (c *cloudSchedulerGRPCClient) Connection() *grpc.ClientConn { 286 return c.connPool.Conn() 287} 288 289// setGoogleClientInfo sets the name and version of the application in 290// the `x-goog-api-client` header passed on each request. Intended for 291// use by Google-written clients. 292func (c *cloudSchedulerGRPCClient) setGoogleClientInfo(keyval ...string) { 293 kv := append([]string{"gl-go", versionGo()}, keyval...) 294 kv = append(kv, "gapic", versionClient, "gax", gax.Version, "grpc", grpc.Version) 295 c.xGoogMetadata = metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) 296} 297 298// Close closes the connection to the API service. The user should invoke this when 299// the client is no longer required. 300func (c *cloudSchedulerGRPCClient) Close() error { 301 return c.connPool.Close() 302} 303 304func (c *cloudSchedulerGRPCClient) ListJobs(ctx context.Context, req *schedulerpb.ListJobsRequest, opts ...gax.CallOption) *JobIterator { 305 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) 306 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 307 opts = append((*c.CallOptions).ListJobs[0:len((*c.CallOptions).ListJobs):len((*c.CallOptions).ListJobs)], opts...) 308 it := &JobIterator{} 309 req = proto.Clone(req).(*schedulerpb.ListJobsRequest) 310 it.InternalFetch = func(pageSize int, pageToken string) ([]*schedulerpb.Job, string, error) { 311 resp := &schedulerpb.ListJobsResponse{} 312 if pageToken != "" { 313 req.PageToken = pageToken 314 } 315 if pageSize > math.MaxInt32 { 316 req.PageSize = math.MaxInt32 317 } else if pageSize != 0 { 318 req.PageSize = int32(pageSize) 319 } 320 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 321 var err error 322 resp, err = c.cloudSchedulerClient.ListJobs(ctx, req, settings.GRPC...) 323 return err 324 }, opts...) 325 if err != nil { 326 return nil, "", err 327 } 328 329 it.Response = resp 330 return resp.GetJobs(), resp.GetNextPageToken(), nil 331 } 332 fetch := func(pageSize int, pageToken string) (string, error) { 333 items, nextPageToken, err := it.InternalFetch(pageSize, pageToken) 334 if err != nil { 335 return "", err 336 } 337 it.items = append(it.items, items...) 338 return nextPageToken, nil 339 } 340 341 it.pageInfo, it.nextFunc = iterator.NewPageInfo(fetch, it.bufLen, it.takeBuf) 342 it.pageInfo.MaxSize = int(req.GetPageSize()) 343 it.pageInfo.Token = req.GetPageToken() 344 345 return it 346} 347 348func (c *cloudSchedulerGRPCClient) GetJob(ctx context.Context, req *schedulerpb.GetJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { 349 if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { 350 cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) 351 defer cancel() 352 ctx = cctx 353 } 354 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 355 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 356 opts = append((*c.CallOptions).GetJob[0:len((*c.CallOptions).GetJob):len((*c.CallOptions).GetJob)], opts...) 357 var resp *schedulerpb.Job 358 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 359 var err error 360 resp, err = c.cloudSchedulerClient.GetJob(ctx, req, settings.GRPC...) 361 return err 362 }, opts...) 363 if err != nil { 364 return nil, err 365 } 366 return resp, nil 367} 368 369func (c *cloudSchedulerGRPCClient) CreateJob(ctx context.Context, req *schedulerpb.CreateJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { 370 if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { 371 cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) 372 defer cancel() 373 ctx = cctx 374 } 375 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "parent", url.QueryEscape(req.GetParent()))) 376 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 377 opts = append((*c.CallOptions).CreateJob[0:len((*c.CallOptions).CreateJob):len((*c.CallOptions).CreateJob)], opts...) 378 var resp *schedulerpb.Job 379 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 380 var err error 381 resp, err = c.cloudSchedulerClient.CreateJob(ctx, req, settings.GRPC...) 382 return err 383 }, opts...) 384 if err != nil { 385 return nil, err 386 } 387 return resp, nil 388} 389 390func (c *cloudSchedulerGRPCClient) UpdateJob(ctx context.Context, req *schedulerpb.UpdateJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { 391 if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { 392 cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) 393 defer cancel() 394 ctx = cctx 395 } 396 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "job.name", url.QueryEscape(req.GetJob().GetName()))) 397 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 398 opts = append((*c.CallOptions).UpdateJob[0:len((*c.CallOptions).UpdateJob):len((*c.CallOptions).UpdateJob)], opts...) 399 var resp *schedulerpb.Job 400 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 401 var err error 402 resp, err = c.cloudSchedulerClient.UpdateJob(ctx, req, settings.GRPC...) 403 return err 404 }, opts...) 405 if err != nil { 406 return nil, err 407 } 408 return resp, nil 409} 410 411func (c *cloudSchedulerGRPCClient) DeleteJob(ctx context.Context, req *schedulerpb.DeleteJobRequest, opts ...gax.CallOption) error { 412 if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { 413 cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) 414 defer cancel() 415 ctx = cctx 416 } 417 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 418 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 419 opts = append((*c.CallOptions).DeleteJob[0:len((*c.CallOptions).DeleteJob):len((*c.CallOptions).DeleteJob)], opts...) 420 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 421 var err error 422 _, err = c.cloudSchedulerClient.DeleteJob(ctx, req, settings.GRPC...) 423 return err 424 }, opts...) 425 return err 426} 427 428func (c *cloudSchedulerGRPCClient) PauseJob(ctx context.Context, req *schedulerpb.PauseJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { 429 if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { 430 cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) 431 defer cancel() 432 ctx = cctx 433 } 434 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 435 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 436 opts = append((*c.CallOptions).PauseJob[0:len((*c.CallOptions).PauseJob):len((*c.CallOptions).PauseJob)], opts...) 437 var resp *schedulerpb.Job 438 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 439 var err error 440 resp, err = c.cloudSchedulerClient.PauseJob(ctx, req, settings.GRPC...) 441 return err 442 }, opts...) 443 if err != nil { 444 return nil, err 445 } 446 return resp, nil 447} 448 449func (c *cloudSchedulerGRPCClient) ResumeJob(ctx context.Context, req *schedulerpb.ResumeJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { 450 if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { 451 cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) 452 defer cancel() 453 ctx = cctx 454 } 455 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 456 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 457 opts = append((*c.CallOptions).ResumeJob[0:len((*c.CallOptions).ResumeJob):len((*c.CallOptions).ResumeJob)], opts...) 458 var resp *schedulerpb.Job 459 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 460 var err error 461 resp, err = c.cloudSchedulerClient.ResumeJob(ctx, req, settings.GRPC...) 462 return err 463 }, opts...) 464 if err != nil { 465 return nil, err 466 } 467 return resp, nil 468} 469 470func (c *cloudSchedulerGRPCClient) RunJob(ctx context.Context, req *schedulerpb.RunJobRequest, opts ...gax.CallOption) (*schedulerpb.Job, error) { 471 if _, ok := ctx.Deadline(); !ok && !c.disableDeadlines { 472 cctx, cancel := context.WithTimeout(ctx, 600000*time.Millisecond) 473 defer cancel() 474 ctx = cctx 475 } 476 md := metadata.Pairs("x-goog-request-params", fmt.Sprintf("%s=%v", "name", url.QueryEscape(req.GetName()))) 477 ctx = insertMetadata(ctx, c.xGoogMetadata, md) 478 opts = append((*c.CallOptions).RunJob[0:len((*c.CallOptions).RunJob):len((*c.CallOptions).RunJob)], opts...) 479 var resp *schedulerpb.Job 480 err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error { 481 var err error 482 resp, err = c.cloudSchedulerClient.RunJob(ctx, req, settings.GRPC...) 483 return err 484 }, opts...) 485 if err != nil { 486 return nil, err 487 } 488 return resp, nil 489} 490 491// JobIterator manages a stream of *schedulerpb.Job. 492type JobIterator struct { 493 items []*schedulerpb.Job 494 pageInfo *iterator.PageInfo 495 nextFunc func() error 496 497 // Response is the raw response for the current page. 498 // It must be cast to the RPC response type. 499 // Calling Next() or InternalFetch() updates this value. 500 Response interface{} 501 502 // InternalFetch is for use by the Google Cloud Libraries only. 503 // It is not part of the stable interface of this package. 504 // 505 // InternalFetch returns results from a single call to the underlying RPC. 506 // The number of results is no greater than pageSize. 507 // If there are no more results, nextPageToken is empty and err is nil. 508 InternalFetch func(pageSize int, pageToken string) (results []*schedulerpb.Job, nextPageToken string, err error) 509} 510 511// PageInfo supports pagination. See the google.golang.org/api/iterator package for details. 512func (it *JobIterator) PageInfo() *iterator.PageInfo { 513 return it.pageInfo 514} 515 516// Next returns the next result. Its second return value is iterator.Done if there are no more 517// results. Once Next returns Done, all subsequent calls will return Done. 518func (it *JobIterator) Next() (*schedulerpb.Job, error) { 519 var item *schedulerpb.Job 520 if err := it.nextFunc(); err != nil { 521 return item, err 522 } 523 item = it.items[0] 524 it.items = it.items[1:] 525 return item, nil 526} 527 528func (it *JobIterator) bufLen() int { 529 return len(it.items) 530} 531 532func (it *JobIterator) takeBuf() interface{} { 533 b := it.items 534 it.items = nil 535 return b 536} 537