From cdff23e8aa991bf58388301a5b333bbd4f6a44dc Mon Sep 17 00:00:00 2001 From: Richard Weerasinghe Date: Wed, 8 Nov 2023 16:52:49 +1300 Subject: [PATCH 01/62] add support for custom model resource and datasources --- internal/service/bedrock/custom_model.go | 385 ++++++++++++++++++ .../bedrock/custom_model_data_source.go | 184 +++++++++ .../bedrock/custom_model_data_source_test.go | 191 +++++++++ internal/service/bedrock/custom_model_test.go | 183 +++++++++ .../bedrock/custom_models_data_source.go | 129 ++++++ .../bedrock/custom_models_data_source_test.go | 176 ++++++++ internal/service/bedrock/generate.go | 1 + .../service/bedrock/service_package_gen.go | 15 + internal/service/bedrock/structures.go | 102 +++++ internal/service/bedrock/tags_gen.go | 146 +++++++ 10 files changed, 1512 insertions(+) create mode 100644 internal/service/bedrock/custom_model.go create mode 100644 internal/service/bedrock/custom_model_data_source.go create mode 100644 internal/service/bedrock/custom_model_data_source_test.go create mode 100644 internal/service/bedrock/custom_model_test.go create mode 100644 internal/service/bedrock/custom_models_data_source.go create mode 100644 internal/service/bedrock/custom_models_data_source_test.go create mode 100644 internal/service/bedrock/structures.go create mode 100644 internal/service/bedrock/tags_gen.go diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go new file mode 100644 index 00000000000..369dc59e60e --- /dev/null +++ b/internal/service/bedrock/custom_model.go @@ -0,0 +1,385 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package bedrock + +import ( + "context" + "fmt" + "time" + + "github.com/aws/aws-sdk-go-v2/service/bedrock" + bedrock_types "github.com/aws/aws-sdk-go-v2/service/bedrock/types" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource +// @Tags(identifierAttribute="model_arn") +func newResourceCustomModel(context.Context) (resource.ResourceWithConfigure, error) { + r := &resourceCustomModel{} + r.SetDefaultCreateTimeout(120 * time.Minute) + return r, nil +} + +type resourceCustomModel struct { + framework.ResourceWithConfigure + framework.WithTimeouts +} + +func (r *resourceCustomModel) Metadata(_ context.Context, request resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "aws_bedrock_custom_model" +} + +func (r *resourceCustomModel) Schema(ctx context.Context, request resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": framework.IDAttribute(), + "base_model_id": schema.StringAttribute{ + Required: true, + // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^(arn:aws(-[^:]+)?:bedrock:[a-z0-9-]{1,20}:(([0-9]{12}:custom-model/[a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}/[a-z0-9]{12})|(:foundation-model/[a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}([a-z0-9-]{1,63}[.]){0,2}[a-z0-9-]{1,63}([:][a-z0-9-]{1,63}){0,2})))|([a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}([.]?[a-z0-9-]{1,63})([:][a-z0-9-]{1,63}){0,2})|(([0-9a-zA-Z][_-]?)+)$`), "minimum length of 1. Maximum length of 2048."), + }, + "client_request_token": schema.StringAttribute{ + Optional: true, + // ForceNew: true, + // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^[a-zA-Z0-9](-*[a-zA-Z0-9])*$`), "minimum length of 1. Maximum length of 256."), + }, + "custom_model_kms_key_id": schema.StringAttribute{ + Optional: true, + // ForceNew: true, + // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^arn:aws(-[^:]+)?:kms:[a-zA-Z0-9-]*:[0-9]{12}:((key/[a-zA-Z0-9-]{36})|(alias/[a-zA-Z0-9-_/]+))$`), "minimum length of 1. Maximum length of 2048."), + }, + "custom_model_name": schema.StringAttribute{ + Required: true, + // ForceNew: true, + // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^([0-9a-zA-Z][_-]?)+$`), "minimum length of 1. Maximum length of 63."), + }, + "hyper_parameters": schema.MapAttribute{ + Required: true, + ElementType: types.StringType, + // ForceNew: true, + // Elem: &schema.Schema{Type: schema.TypeString}, + }, + "job_name": schema.StringAttribute{ + Required: true, + // ForceNew: true, + }, + "job_tags": tftags.TagsAttribute(), + "output_data_config": schema.StringAttribute{ + Required: true, + // ForceNew: true, + // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^s3://[a-z0-9][\.\-a-z0-9]{1,61}[a-z0-9](/.*)?$`), "minimum length of 1. Maximum length of 1024."), + }, + "role_arn": schema.StringAttribute{ + Required: true, + // ForceNew: true, + // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^arn:aws(-[^:]+)?:iam::([0-9]{12})?:role/.+$`), "minimum length of 1. Maximum length of 2048."), + }, + "training_data_config": schema.StringAttribute{ + Required: true, + // ForceNew: true, + // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^s3://[a-z0-9][\.\-a-z0-9]{1,61}[a-z0-9](/.*)?$`), "minimum length of 1. Maximum length of 1024."), + }, + "base_model_arn": schema.StringAttribute{ + Computed: true, + }, + "creation_time": schema.StringAttribute{ + Computed: true, + }, + "job_arn": schema.StringAttribute{ + Computed: true, + }, + "model_arn": schema.StringAttribute{ + Computed: true, + }, + "model_kms_key_arn": schema.StringAttribute{ + Computed: true, + }, + "model_name": schema.StringAttribute{ + Computed: true, + }, + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + }, + Blocks: map[string]schema.Block{ + "validation_data_config": schema.ListNestedBlock{ + Validators: []validator.List{ + listvalidator.SizeBetween(0, 10), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "validators": schema.SetAttribute{ + ElementType: types.StringType, + Optional: true, + }, + }, + }, + }, + "vpc_config": schema.ListNestedBlock{ + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "security_group_ids": schema.SetAttribute{ + ElementType: types.StringType, + Required: true, + }, + "subnet_ids": schema.SetAttribute{ + ElementType: types.StringType, + Required: true, + // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^[-0-9a-zA-Z]+$`), "minimum length of 1. Maximum length of 32."), + }, + }, + }, + }, + "training_metrics": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + "training_loss": schema.Float64Attribute{ + Computed: true, + }, + }, + }, + "validation_metrics": schema.ListNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "validation_loss": schema.Float64Attribute{ + Computed: true, + }, + }, + }, + }, + "timeouts": timeouts.Block(ctx, timeouts.Opts{ + Create: true, + }), + }, + } +} + +func (r *resourceCustomModel) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data resourceCustomModelModel + + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + conn := r.Meta().BedrockClient(ctx) + defaultTagsConfig := r.Meta().DefaultTagsConfig + job_tags := defaultTagsConfig.MergeTags(tftags.New(ctx, data.JobTags)) + + input := &bedrock.CreateModelCustomizationJobInput{ + BaseModelIdentifier: data.BaseModelId.ValueStringPointer(), + CustomModelName: data.CustomModelName.ValueStringPointer(), + JobName: data.JobName.ValueStringPointer(), + RoleArn: data.RoleArn.ValueStringPointer(), + TrainingDataConfig: &bedrock_types.TrainingDataConfig{ + S3Uri: data.TrainingDataConfig.ValueStringPointer(), + }, + OutputDataConfig: &bedrock_types.OutputDataConfig{ + S3Uri: data.OutputDataConfig.ValueStringPointer(), + }, + CustomModelTags: getTagsIn(ctx), + ValidationDataConfig: expandValidationDataConfig(ctx, data.ValidationDataConfig), + } + + var hp map[string]string + resp.Diagnostics.Append(data.HyperParameters.ElementsAs(ctx, &hp, false)...) + if resp.Diagnostics.HasError() { + return + } + input.HyperParameters = hp + + if !data.ClientRequestToken.IsNull() { + input.ClientRequestToken = data.ClientRequestToken.ValueStringPointer() + } + if !data.CustomModelKmsKeyId.IsNull() { + input.CustomModelKmsKeyId = data.CustomModelKmsKeyId.ValueStringPointer() + } + var vpcConfigs []vpcConfig + resp.Diagnostics.Append(data.VpcConfig.ElementsAs(ctx, &vpcConfigs, false)...) + if resp.Diagnostics.HasError() { + return + } + vpcConfig := expandVpcConfig(ctx, vpcConfigs) + if len(vpcConfigs) > 0 { + input.VpcConfig = &vpcConfig[0] + } + + if len(job_tags) > 0 { + input.JobTags = Tags(tftags.New(ctx, job_tags.IgnoreAWS())) + } + + tflog.Info(ctx, "CreateModelCustomizationJobInput:", map[string]any{ + "BaseModelIdentifier": input.BaseModelIdentifier, + "ClientRequestToken": input.ClientRequestToken, + "CustomModelName": input.CustomModelName, + "CustomModelKmsKeyId": input.CustomModelKmsKeyId, + "JobName": input.JobName, + "RoleArn": input.RoleArn, + "OutputDataConfig": input.OutputDataConfig.S3Uri, + "TrainingDataConfig": input.TrainingDataConfig.S3Uri, + "ValidationDataConfig": input.ValidationDataConfig, + "VpcConfig": input.VpcConfig, + }) + + jobStart, err := conn.CreateModelCustomizationJob(ctx, input) + if err != nil { + resp.Diagnostics.AddError("creating Bedrock Custom Model Customization Job", err.Error()) + return + } + + // Successfully started job. Save the id now + data.ID = data.CustomModelName + // Also save job arn into state now incase we need to cancel and destroy. + data.JobArn = flex.StringToFramework(ctx, jobStart.JobArn) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + createTimeout := r.CreateTimeout(ctx, data.Timeouts) + err = waitForModelCustomizationJob(ctx, conn, *jobStart.JobArn, createTimeout) + if err != nil { + resp.Diagnostics.AddError("failed to complete model customisation job", err.Error()) + return + } + + resp.Diagnostics.Append(data.refresh(ctx, conn)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *resourceCustomModel) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data resourceCustomModelModel + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + conn := r.Meta().BedrockClient(ctx) + + resp.Diagnostics.Append(data.refresh(ctx, conn)...) + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *resourceCustomModel) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + tflog.Trace(ctx, "Update not supported.") +} + +func (r *resourceCustomModel) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + conn := r.Meta().BedrockClient(ctx) + + _, err := conn.DeleteModelInvocationLoggingConfiguration(ctx, &bedrock.DeleteModelInvocationLoggingConfigurationInput{}) + if err != nil { + resp.Diagnostics.AddError("failed to delete model invocation logging configuration", err.Error()) + return + } +} + +func (r *resourceCustomModel) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +} + +func waitForModelCustomizationJob(ctx context.Context, conn *bedrock.Client, jobArn string, timeout time.Duration) error { + return retry.RetryContext(ctx, timeout, func() *retry.RetryError { + jobEnd, err := conn.GetModelCustomizationJob(ctx, &bedrock.GetModelCustomizationJobInput{ + JobIdentifier: &jobArn, + }) + if err != nil { + return retry.NonRetryableError(fmt.Errorf("getting model customization job: %s", err)) + } + + tflog.Info(ctx, "GetModelCustomizationJobOuput:", map[string]any{ + "Status": jobEnd.Status, + }) + + switch jobEnd.Status { + case "InProgress": + return retry.RetryableError(fmt.Errorf("expected instance to be Completed but was in state %s", jobEnd.Status)) + case "Completed": + return nil + default: + return retry.NonRetryableError(fmt.Errorf(*jobEnd.FailureMessage)) + } + }) +} + +type resourceCustomModelModel struct { + ID types.String `tfsdk:"id"` + BaseModelId types.String `tfsdk:"base_model_id"` + ClientRequestToken types.String `tfsdk:"client_request_token"` + CustomModelKmsKeyId types.String `tfsdk:"custom_model_kms_key_id"` + CustomModelName types.String `tfsdk:"custom_model_name"` + HyperParameters types.Map `tfsdk:"hyper_parameters"` + JobName types.String `tfsdk:"job_name"` + JobTags types.Map `tfsdk:"job_tags"` + OutputDataConfig types.String `tfsdk:"output_data_config"` + RoleArn types.String `tfsdk:"role_arn"` + TrainingDataConfig types.String `tfsdk:"training_data_config"` + BaseModelArn types.String `tfsdk:"base_model_arn"` + CreationTime types.String `tfsdk:"creation_time"` + JobArn types.String `tfsdk:"job_arn"` + ModelArn types.String `tfsdk:"model_arn"` + ModelKmsKeyArn types.String `tfsdk:"model_kms_key_arn"` + ModelName types.String `tfsdk:"model_name"` + ValidationDataConfig *validationDataConfig `tfsdk:"validation_data_config"` + VpcConfig types.List `tfsdk:"vpc_config"` + TrainingMetrics *trainingMetrics `tfsdk:"training_metrics"` + ValidationMetrics []validationMetrics `tfsdk:"validation_metrics"` + Tags types.Map `tfsdk:"tags"` + TagsAll types.Map `tfsdk:"tags_all"` + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +func (data *resourceCustomModelModel) refresh(ctx context.Context, conn *bedrock.Client) diag.Diagnostics { + var diags diag.Diagnostics + + modelId := data.ID + input := &bedrock.GetCustomModelInput{ + ModelIdentifier: modelId.ValueStringPointer(), + } + output, err := conn.GetCustomModel(ctx, input) + if err != nil { + // If we got here, the state has the model name and the job arn. + // Should we check for tainted state instead? + tflog.Info(ctx, "resourceCustomModelRead: Error reading Bedrock Custom Model. Ignoring to allow destroy to attempt to cleanup.") + return diags + } + + data.BaseModelArn = flex.StringToFramework(ctx, output.BaseModelArn) + data.CreationTime = flex.StringValueToFramework(ctx, output.CreationTime.Format((time.RFC3339))) + data.HyperParameters = flex.FlattenFrameworkStringValueMap(ctx, output.HyperParameters) + data.JobArn = flex.StringToFramework(ctx, output.JobArn) + // This is nil in the model object - could be a bug + // However this is already in state so we can skip setting this here and avoid a forced update due to value change. + // d.Set("job_name", model.JobName) + data.ModelArn = flex.StringToFramework(ctx, output.ModelArn) + data.ModelKmsKeyArn = flex.StringToFramework(ctx, output.ModelKmsKeyArn) + data.ModelName = flex.StringToFramework(ctx, output.ModelName) + data.OutputDataConfig = flex.StringToFramework(ctx, output.OutputDataConfig.S3Uri) + data.TrainingDataConfig = flex.StringToFramework(ctx, output.TrainingDataConfig.S3Uri) + data.TrainingMetrics = flattenTrainingMetrics(ctx, output.TrainingMetrics) + data.ValidationDataConfig = flattenValidationDataConfig(ctx, output.ValidationDataConfig) + data.ValidationMetrics = flattenValidationMetrics(ctx, output.ValidationMetrics) + + jobTags, err := listTags(ctx, conn, *output.JobArn) + if err != nil { + diags.AddError("reading Tags for Job", err.Error()) + return diags + } + data.JobTags = flex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) + + return diags +} diff --git a/internal/service/bedrock/custom_model_data_source.go b/internal/service/bedrock/custom_model_data_source.go new file mode 100644 index 00000000000..6684c592aee --- /dev/null +++ b/internal/service/bedrock/custom_model_data_source.go @@ -0,0 +1,184 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package bedrock + +import ( + "context" + "time" + + "github.com/aws/aws-sdk-go-v2/service/bedrock" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkDataSource +// @Tags(identifierAttribute="model_arn") +func newDataSourceCustomModel(context.Context) (datasource.DataSourceWithConfigure, error) { + return &dataSourceCustomModel{}, nil +} + +type dataSourceCustomModel struct { + framework.DataSourceWithConfigure +} + +// Metadata should return the full name of the data source, such as +// examplecloud_thing. +func (d *dataSourceCustomModel) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { + response.TypeName = "aws_bedrock_custom_model" +} + +// Schema returns the schema for this data source. +func (d *dataSourceCustomModel) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + }, + "model_id": schema.StringAttribute{ + Required: true, + }, + "base_model_arn": schema.StringAttribute{ + Computed: true, + }, + "creation_time": schema.StringAttribute{ + Computed: true, + }, + "hyper_parameters": schema.MapAttribute{ + ElementType: types.StringType, + Computed: true, + }, + "job_arn": schema.StringAttribute{ + Computed: true, + }, + "job_name": schema.StringAttribute{ + Computed: true, + }, + "job_tags": tftags.TagsAttributeComputedOnly(), + "model_arn": schema.StringAttribute{ + Computed: true, + }, + "model_kms_key_arn": schema.StringAttribute{ + Computed: true, + }, + "model_name": schema.StringAttribute{ + Computed: true, + }, + "training_data_config": schema.StringAttribute{ + Computed: true, + }, + "output_data_config": schema.StringAttribute{ + Computed: true, + }, + names.AttrTags: tftags.TagsAttributeComputedOnly(), + }, + Blocks: map[string]schema.Block{ + "training_metrics": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + "training_loss": schema.Float64Attribute{ + Computed: true, + }, + }, + }, + "validation_data_config": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + "validators": schema.ListAttribute{ + ElementType: types.StringType, + Computed: true, + }, + }, + }, + "validation_metrics": schema.ListNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "validation_loss": schema.Float64Attribute{ + Computed: true, + }, + }, + }, + }, + }, + } +} + +// Read is called when the provider must read data source values in order to update state. +// Config values should be read from the ReadRequest and new state values set on the ReadResponse. +func (d *dataSourceCustomModel) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { + var data customModel + + response.Diagnostics.Append(request.Config.Get(ctx, &data)...) + + if response.Diagnostics.HasError() { + return + } + + conn := d.Meta().BedrockClient(ctx) + + input := &bedrock.GetCustomModelInput{ + ModelIdentifier: data.ModelID.ValueStringPointer(), + } + model, err := conn.GetCustomModel(ctx, input) + if err != nil { + response.Diagnostics.AddError("reading Bedrock Custom Model", err.Error()) + return + } + + jobTags, err := listTags(ctx, conn, *model.JobArn) + if err != nil { + response.Diagnostics.AddError("reading Tags for Job", err.Error()) + } + data.JobTags = flex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) + + response.Diagnostics.Append(data.refreshFromOutput(ctx, model)...) + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +type customModel struct { + ID types.String `tfsdk:"id"` + ModelID types.String `tfsdk:"model_id"` + BaseModelArn types.String `tfsdk:"base_model_arn"` + CreationTime types.String `tfsdk:"creation_time"` + JobArn types.String `tfsdk:"job_arn"` + ModelArn types.String `tfsdk:"model_arn"` + ModelName types.String `tfsdk:"model_name"` + JobName types.String `tfsdk:"job_name"` + ModelKmsKeyArn types.String `tfsdk:"model_kms_key_arn"` + HyperParameters types.Map `tfsdk:"hyper_parameters"` + TrainingDataConfig types.String `tfsdk:"training_data_config"` + TrainingMetrics *trainingMetrics `tfsdk:"training_metrics"` + ValidationDataConfig *validationDataConfig `tfsdk:"validation_data_config"` + ValidationMetrics []validationMetrics `tfsdk:"validation_metrics"` + OutputDataConfig types.String `tfsdk:"output_data_config"` + JobTags types.Map `tfsdk:"job_tags"` + Tags types.Map `tfsdk:"tags"` +} + +func (data *customModel) refreshFromOutput(ctx context.Context, model *bedrock.GetCustomModelOutput) diag.Diagnostics { + var diags diag.Diagnostics + + if model == nil { + return diags + } + + data.ID = flex.StringToFramework(ctx, model.ModelArn) + data.BaseModelArn = flex.StringToFramework(ctx, model.BaseModelArn) + data.CreationTime = flex.StringValueToFramework[string](ctx, model.CreationTime.Format(time.RFC3339)) + data.JobArn = flex.StringToFramework(ctx, model.JobArn) + data.ModelArn = flex.StringToFramework(ctx, model.ModelArn) + data.ModelName = flex.StringToFramework(ctx, model.ModelName) + data.JobName = flex.StringToFramework(ctx, model.JobName) + data.ModelKmsKeyArn = flex.StringToFramework(ctx, model.ModelKmsKeyArn) + data.HyperParameters = flex.FlattenFrameworkStringValueMap(ctx, model.HyperParameters) + data.TrainingDataConfig = flex.StringToFramework(ctx, model.TrainingDataConfig.S3Uri) + data.TrainingMetrics = flattenTrainingMetrics(ctx, model.TrainingMetrics) + data.ValidationMetrics = flattenValidationMetrics(ctx, model.ValidationMetrics) + data.OutputDataConfig = flex.StringToFramework(ctx, model.OutputDataConfig.S3Uri) + + return diags +} diff --git a/internal/service/bedrock/custom_model_data_source_test.go b/internal/service/bedrock/custom_model_data_source_test.go new file mode 100644 index 00000000000..6e56689c4ff --- /dev/null +++ b/internal/service/bedrock/custom_model_data_source_test.go @@ -0,0 +1,191 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package bedrock_test + +import ( + "fmt" + "testing" + + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" +) + +func TestAccBedrockCustomModelDataSource_basic(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrock_custom_model.test" + dataSourceResourceName := "data.aws_bedrock_custom_model.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccCustomModelDataSourceConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceResourceName, "id"), + resource.TestCheckResourceAttrPair(resourceName, "base_model_arn", dataSourceResourceName, "base_model_arn"), + resource.TestCheckResourceAttrPair(resourceName, "creation_time", dataSourceResourceName, "creation_time"), + resource.TestCheckResourceAttrPair(resourceName, "hyper_parameters", dataSourceResourceName, "hyper_parameters"), + resource.TestCheckResourceAttrPair(resourceName, "job_arn", dataSourceResourceName, "job_arn"), + resource.TestCheckResourceAttrPair(resourceName, "job_name", dataSourceResourceName, "job_name"), + resource.TestCheckResourceAttrPair(resourceName, "job_tags", dataSourceResourceName, "job_tags"), + resource.TestCheckResourceAttrPair(resourceName, "model_arn", dataSourceResourceName, "model_arn"), + resource.TestCheckResourceAttrPair(resourceName, "model_kms_key_arn", dataSourceResourceName, "model_kms_key_arn"), + resource.TestCheckResourceAttrPair(resourceName, "model_name", dataSourceResourceName, "model_name"), + resource.TestCheckResourceAttrPair(resourceName, "output_data_config", dataSourceResourceName, "output_data_config"), + resource.TestCheckResourceAttrPair(resourceName, "training_data_config", dataSourceResourceName, "training_data_config"), + resource.TestCheckResourceAttrPair(resourceName, "training_metrics", dataSourceResourceName, "training_metrics"), + resource.TestCheckResourceAttrPair(resourceName, "validation_data_config", dataSourceResourceName, "validation_data_config"), + resource.TestCheckResourceAttrPair(resourceName, "validation_metrics", dataSourceResourceName, "validation_metrics"), + ), + }, + }, + }) +} + +func testAccCustomModelDataSourceConfig_basic(rName string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} +data "aws_partition" "current" {} + +resource aws_s3_bucket training_data { + bucket = "bedrock-training-data-%[1]s" +} + +resource aws_s3_bucket validation_data { + bucket = "bedrock-validation-data-%[1]s" +} + +resource aws_s3_bucket output_data { + bucket = "bedrock-output-data-%[1]s" + force_destroy = true +} + +resource "aws_s3_bucket_object" "training_data" { + bucket = aws_s3_bucket.training_data.id + key = "myfolder/training_data.jsonl" + source = "./testdata/training_data.jsonl" + etag = filemd5("./testdata/training_data.jsonl") +} + +resource "aws_s3_bucket_object" "validation_data" { + bucket = aws_s3_bucket.validation_data.id + key = "myfolder/validation_data.jsonl" + source = "./testdata/validation_data.jsonl" + etag = filemd5("./testdata/validation_data.jsonl") +} + +resource "aws_iam_role" "bedrock_fine_tuning" { + name = "bedrock-fine-tuning-%[1]s" + + assume_role_policy = < 0 { + return tags + } + } + + return nil +} + +// setTagsOut sets bedrock service tags in Context. +func setTagsOut(ctx context.Context, tags []awstypes.Tag) { + if inContext, ok := tftags.FromContext(ctx); ok { + inContext.TagsOut = types.Some(KeyValueTags(ctx, tags)) + } +} + +// updateTags updates bedrock service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func updateTags(ctx context.Context, conn *bedrock.Client, identifier string, oldTagsMap, newTagsMap any) error { + oldTags := tftags.New(ctx, oldTagsMap) + newTags := tftags.New(ctx, newTagsMap) + + ctx = tflog.SetField(ctx, logging.KeyResourceId, identifier) + + removedTags := oldTags.Removed(newTags) + removedTags = removedTags.IgnoreSystem(names.Bedrock) + if len(removedTags) > 0 { + input := &bedrock.UntagResourceInput{ + ResourceARN: aws.String(identifier), + TagKeys: removedTags.Keys(), + } + + _, err := conn.UntagResource(ctx, input) + + if err != nil { + return fmt.Errorf("untagging resource (%s): %w", identifier, err) + } + } + + updatedTags := oldTags.Updated(newTags) + updatedTags = updatedTags.IgnoreSystem(names.Bedrock) + if len(updatedTags) > 0 { + input := &bedrock.TagResourceInput{ + ResourceARN: aws.String(identifier), + Tags: Tags(updatedTags), + } + + _, err := conn.TagResource(ctx, input) + + if err != nil { + return fmt.Errorf("tagging resource (%s): %w", identifier, err) + } + } + + return nil +} + +// UpdateTags updates bedrock service tags. +// It is called from outside this package. +func (p *servicePackage) UpdateTags(ctx context.Context, meta any, identifier string, oldTags, newTags any) error { + return updateTags(ctx, meta.(*conns.AWSClient).BedrockClient(ctx), identifier, oldTags, newTags) +} From 49e470743a0ba9e3137e934f59fbfcd06ab7fc7a Mon Sep 17 00:00:00 2001 From: Richard Weerasinghe Date: Wed, 8 Nov 2023 21:43:33 +1300 Subject: [PATCH 02/62] better test --- internal/service/bedrock/custom_model_test.go | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index f7f4c08ee55..2c1ad9a606f 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -15,7 +15,7 @@ import ( func TestAccBedrockCustomModel_basic(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - // customModelResourceName := "aws_bedrock_custom_model.test" + customModelResourceName := "aws_bedrock_custom_model.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -24,20 +24,22 @@ func TestAccBedrockCustomModel_basic(t *testing.T) { { Config: testAccCustomModelConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( - // testAccCheckAddonExists(ctx, customModelResourceName, &addon), - // resource.TestCheckResourceAttr(customModelResourceName, "addon_name", addonName), + // testAccCheckAddonExists(ctx, customModelResourceName, &model), + resource.TestCheckResourceAttr(customModelResourceName, "custom_model_name", rName), + resource.TestCheckResourceAttr(customModelResourceName, "job_name", rName), + resource.TestCheckResourceAttr(customModelResourceName, "base_model_id", "amazon.titan-text-express-v1"), + resource.TestCheckResourceAttr(customModelResourceName, "tags.%", "0"), + // acctest.MatchResourceAttrRegionalARN(customModelResourceName, "arn", "bedrock", regexache.MustCompile(fmt.Sprintf("addon/%s/%s/.+$", rName, addonName))), // resource.TestCheckResourceAttrSet(customModelResourceName, "addon_version"), - // acctest.MatchResourceAttrRegionalARN(customModelResourceName, "arn", "eks", regexache.MustCompile(fmt.Sprintf("addon/%s/%s/.+$", rName, addonName))), - // resource.TestCheckResourceAttr(customModelResourceName, "configuration_values", ""), // resource.TestCheckNoResourceAttr(customModelResourceName, "preserve"), - // resource.TestCheckResourceAttr(customModelResourceName, "tags.%", "0"), + ), }, - // { - // ResourceName: customModelResourceName, - // ImportState: true, - // ImportStateVerify: true, - // }, + { + ResourceName: customModelResourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } From 88704f1eb048d1b6148ed9ebd68f57dd883bc30d Mon Sep 17 00:00:00 2001 From: Richard Weerasinghe Date: Wed, 8 Nov 2023 22:28:38 +1300 Subject: [PATCH 03/62] add test data --- internal/service/bedrock/custom_model_test.go | 5 - .../bedrock/testdata/training_data.jsonl | 100 ++++++++++++++++++ .../bedrock/testdata/validation_data.jsonl | 25 +++++ 3 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 internal/service/bedrock/testdata/training_data.jsonl create mode 100644 internal/service/bedrock/testdata/validation_data.jsonl diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index 2c1ad9a606f..42587473759 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -24,15 +24,10 @@ func TestAccBedrockCustomModel_basic(t *testing.T) { { Config: testAccCustomModelConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( - // testAccCheckAddonExists(ctx, customModelResourceName, &model), resource.TestCheckResourceAttr(customModelResourceName, "custom_model_name", rName), resource.TestCheckResourceAttr(customModelResourceName, "job_name", rName), resource.TestCheckResourceAttr(customModelResourceName, "base_model_id", "amazon.titan-text-express-v1"), resource.TestCheckResourceAttr(customModelResourceName, "tags.%", "0"), - // acctest.MatchResourceAttrRegionalARN(customModelResourceName, "arn", "bedrock", regexache.MustCompile(fmt.Sprintf("addon/%s/%s/.+$", rName, addonName))), - // resource.TestCheckResourceAttrSet(customModelResourceName, "addon_version"), - // resource.TestCheckNoResourceAttr(customModelResourceName, "preserve"), - ), }, { diff --git a/internal/service/bedrock/testdata/training_data.jsonl b/internal/service/bedrock/testdata/training_data.jsonl new file mode 100644 index 00000000000..4c42d378660 --- /dev/null +++ b/internal/service/bedrock/testdata/training_data.jsonl @@ -0,0 +1,100 @@ +{"input":"Organization: Penn State University\nFrom: Robbie Po \nSubject: Did The Blues Pull It Out?\nLines: 10\n\nWhen I left, it was 4-3, Blues with 2:00 to go! As I predicted in\n\"@#$%! I was right in the first place!!!\" Blues in 6! YES!!!\n\nOf course it's only one game -- that could be the 'Hawks stab in the face to\nwake them up -- that's what playoffs are about, on any given day... :-)\n-------------------------------------------------------------------------\n** Robbie Po ** PGH PENGUINS!!! \"We do what comes naturally!\nPatrick Division Semi's '91 STANLEY CUP You see now, wait for the\nPENGUINS 6, Devils 3 '92 CHAMPIONS possibility, don't you see a\nPenguins lead, 1-0 12 STRAIGHT WINS! strong resemblance...\"-DG '89\n\n###\n\n","output":" hockey"} +{"input":"From: kkeller@mail.sas.upenn.edu (Keith Keller)\nSubject: Re: Sad day for hockey\nArticle-I.D.: netnews.118520\nOrganization: University of Pennsylvania, School of Arts and Sciences\nLines: 39\nNntp-Posting-Host: mail.sas.upenn.edu\n\nIn article <1pq50fINN15b@abyss.West.Sun.COM> dvb@ick (David Van Beveren) writes:\n>NO NO NO! since all the penalties fall into three classes, there should\n>only be three penalties:\n>\n>1. Foul (Any illegal contact with the other player or his stick with your\n> body or stick). If you get 5 you are out for the game.\n>\n>2. Unsportsmanlike contact. (An intentional foul). This inlcludes all the\n> current flavours of roughing, fighting and boarding. If you get two you\n> are thrown out of the game, and fined.\n>\n>3. Technical foul. Bad mouthing the ref, by player or coach. Penalty shot\n> is awarded. Two and you are thrown out of the game.\n>\n>Besides the penalty shot for one technical, if the team gets 5 penalties\n>in a period, the opposing team gets a penalty shot for every additional one,\n>until the end of the period. The victim gets two shots if he\/she was in\n>the act of shooting when the foul ocured.\n\nThese new rule changes are great! However, I think that your rules are\nMUCH too complicated. How will the normal average fan be able to count\nhow many fouls a player has? And then we would even have to remember the\nnames of the players, in order to determine who drew the foul! And, of\ncourse, there will have to be new \"sub-positions\", like the power center\nwho just sits in the slot until the (blue, of course) puck comes near him,\nand the \"shooting defenseman\" and the \"point defenseman\". Finally, we'll\nbe able to keep stats on the best and the worst penalty-shot takers. \nSince almost everyone on the ice will be getting fouled, we'll be able to\nsee Ulf Samuellson (sp?) and Tie Domi miss penalty shots like crazy. \n\n;-) ;-) ;-)\n\n--\n Keith Keller\t\t\t\tLET'S GO RANGERS!!!!!\n\t\t\t\t\t\tLET'S GO QUAKERS!!!!!\n\tkkeller@mail.sas.upenn.edu\t\tIVY LEAGUE CHAMPS!!!!\n\n\"Next time you go over my head, I'll have yours on a platter.\"\n\t\t\t\t\t\t-- Cmdr. Benjamin Sisko, 1993\n\n###\n\n","output":" hockey"} +{"input":"From: v103r4g8@ubvmsb.cc.buffalo.edu (We will NOT cave in....GODS OF WAR, Def Leppard)\nSubject: HELP HELP HELP\nOrganization: University at Buffalo\nLines: 11\nNews-Software: VAX\/VMS VNEWS 1.41\nNntp-Posting-Host: ubvmsb.cc.buffalo.edu\n\n\nDoes anyone have the NHL STANDINGS for March 28th? I need them IMMEDIATELY\nfor a project. Please post or email. THANKS.\n\n\n\n\n*************************************************************************\n Andy Hillery --- School Of Architecture\t \t\n State University of New York at Buffalo \n*************************************************************************\n\n###\n\n","output":" hockey"} +{"input":"From: etxonss@ufsa.ericsson.se (Staffan Axelsson)\nSubject: Sweden-Finland, April 15\nNntp-Posting-Host: uipc104.ericsson.se\nOrganization: Ericsson Telecom, Stockholm, Sweden\nLines: 119\n\n\n Played in Scandinavium, Gothenburg, April 15 1993:\n ==================================================\n\n SWEDEN - FINLAND 6-6 (1-2,3-1,2-3)\n\n 1st: SWE 1-0 Peter Popovic (Markus Naslund) 6:10\n FIN 1-1 Ville Siren (Keijo Sailynoja) 8:44 (pp)\n FIN 1-2 Juha Riihijarvi (Timo Saarikoski,Vesa Viitakoski) 13:12 (pp)\n 2nd: FIN 1-3 Jari Korpisalo (Kari Harila,Rauli Raitanen) 6:48\n SWE 2-3 Jan Larsson (Mikael Renberg,Stefan Nilsson) 7:25\n SWE 3-3 Hakan Ahlund (Thomas Rundqvist) 8:56\n SWE 4-3 Roger Akerstrom (Roger Hansson) 9:13\n 3rd: SWE 5-3 Stefan Nilsson (Patrik Juhlin,Charles Berglund) 2:20\n FIN 5-4 Keijo Sailynoja 9:23\n FIN 5-5 Keijo Sailynoja 9:44 (ps)\n SWE 6-5 Mikael Renberg (Hakan Ahlund,Thomas Rundqvist) 17:16\n FIN 6-6 Jari Korpisalo 17:44\n\n Shots on goal: Penalties: Attendance: Referee:\n Sweden 8 10 10 - 28 5*2min 6,799 Peter Andersson\n Finland 12 10 11 - 33 6*2min,1*10min (Sweden)\n\n-------------------------------------------------------------------------------\n\n Sweden opened the scoring as Markus Naslund made a drop pass at the Finnish\n blue line, Popovic picked it up and advanced towards the Finnish goal and\n shot a nice hard wrist shot in Ketterer's top corner. Ville Siren's slap\n shot from the blue line on power play made it 1-1, and Juha Riihijarvi\n scored a nice goal in another power play when he close in front of goal\n put the puck high over Aslin, 1-2 after the first period.\n The Finns started the second period with really good pressure. Korpisalo\n made it 1-3 with another goal from close range high over Aslin. Then,\n during the Finnish pressure, Sweden turned the game around in 1:47.\n Mikael Renberg worked hard behind the Finnish goal, and passed the puck to\n Jan Larsson in front, who backhanded the puck low, 2-3. Rundqvist entered\n the Finnish zone and passed to Ahlund, and the Finnish defense let Ahlund \n skate in and take a shot that Ketterer dropped into the goal, 3-3.\n Next, Roger Hansson -behind the goal- sent the puck back to the blue line\n where Roger Akerstrom took a slap shot and Ketterer didn't see the puck since\n there was traffic in front, 4-3.\n Third period started with a nice goal by Stefan \"the Shadow\" Nilsson. Stefan\n and Patrik Juhlin entered the Finnish zone, Patrik passed the puck back to\n Stefan who alone with Ketterer made no mistake, 5-3.\n Then, Keijo Sailynoja show started. He reduce and equalized the lead in only\n 21 seconds! First he scored the 5-4 goal, and after that he came in alone \n with Aslin but was tripped by Aslin to get a penalty shot. Sailynoja\n made a nice penalty shot, showed forehand and put in with a low backhand shot.\n The Swedes seemed to head for a win when Mikael Renberg scored the 6-5 goal\n late in the game on a nice power play combination. Renberg waited in the slot,\n showed that he wanted the puck on the backhand side, Ahlund passed the puck\n and Renberg took a turnaround shot low in Ketterer's goal's far side.\n But Jari Korpisalo had other plans as he only 28 seconds later scored the\n game's final goal to make it 6-6. Korpisalo took a slap shot from a narrow\n angle that -maybe- Aslin should have saved.\n\n All in all, a decent game where the defense wasn't the best.\n Both teams juggled around the lines a bit in the second and third period\n to try no combinations.\n\n Renberg and Rundqvist plays well together in the Swedish team. Larsson-\n Nilsson-Juhlin best line overall again, it seems to be a working WC line.\n Stillman good on defense.\n Some players aren't good enough for the WC though. Hakan Ahlund (faell ner\n hjaelmen och jobba!), Roger Hansson, Challe Berglund, Kenny Jonsson\n will likely have to leave for NHL pros.\n\n Two-goal scorers Jari Korpisalo and Keijo Sailynoja played well in the\n Finnish team. Markus Ketterer didn't have a very good game, we've seen him\n a lot better, so Lindfors is probably Finland's starting goalie in the WC.\n I heard that Esa Tikkanen will join the Finnish team. It would be inter-\n resting to know which other pros coach Matikainen counts on for the WC.\n \n-------------------------------------------------------------------------------\n\n Starting lines:\n\n \tSWEDEN\t\t\t\t\tFINLAND\n\n 35. Peter Aslin\t\t\t30. Markus Ketterer\n\n 8. Kenneth Kennholt\t\t\t 2. Mikko Haapakoski\n 14. Fredrik Stillman\t\t\t 3. Ville Siren\n\n 10. Hakan Ahlund\t\t\t28. Jarkko Varvio\n 9. Thomas Rundqvist\t\t\t40. Mika Nieminen\n 29. Mikael Renberg \t\t\t18. Keijo Sailynoja\n\n 27. Roger Akerstrom\t\t\t 4. Erik Hamalainen\n 7. Arto Blomsten\t\t\t 8. Kari Harila\n\n 20. Jan Larsson \t \t\t25. Rauli Raitanen\n 4. Stefan Nilsson \t\t\t26. Petri Varis\n 5. Patrik Juhlin\t\t\t14. Jari Korpisalo\n\n 3. Peter Popovic\t\t\t 5. Timo Jutila\n 32. Stefan Larsson\t\t\t44. Harri Laurila\n\n 11. Roger Hansson\t\t\t24. Juha Riihijarvi\n 33. Fredrik Nilsson\t\t\t22. Timo Saarikoski\n 24. Peter Ottosson\t\t\t11. Vesa Viitakoski\n\n\t\t\t\t\t 6. Pasi Sormunen\n\t\t\t\t\t12. Janne Laukkanen\n\n 19. Markus Naslund\t\t\t29. Juha Ylonen\n 21. Peter Forsberg\t\t\t27. Timo Peltomaa\n 18. Jonas Bergqvist\t\t\t17. Marko Palo\n\n Played parts of the game:\n 22. Charles Berglund\t\t\t15. Mika Alatalo\n 6. Kenny Jonsson\t\t\t16. Saku Koivu\n\t\t\t\t\t20. Marko Palo\n\n-------------------------------------------------------------------------------\n--\n ((\\\\ \/\/| Staffan Axelsson \n \\\\ \/\/|| etxonss@ufsa.ericsson.se \n\\\\_))\/\/-|| r.s.h. contact for Swedish hockey\n\n###\n\n","output":" hockey"} +{"input":"From: brucek@Ingres.COM (Bruce Kleinman)\nSubject: Re: When did Dodgers move from NY to LA?\nArticle-I.D.: pony.1993Apr6.195730.20277\nOrganization: Ingres Corporation, A subsidiary of The ASK Group, Inc.\nLines: 6\n\nIn article <1993Apr5.160030.2328@ncar.ucar.edu> tparker@music.scd.ucar.edu (Tom Parker) writes:\n>I have a bet with my buddy on when the Dodgers moved from NY to LA. Does\n>anyone know what year they moved?\n>\n\nThe Dodgers' first year in LA was 1958.\n\n###\n\n","output":" baseball"} +{"input":"From: epp@mala.bc.ca (Lorne Epp)\nSubject: Re: LA ON ABC IN CANADA\nOrganization: Malaspina College\nLines: 27\n\nIn article , boora@kits.sfu.ca (The GodFather) writes:\n> \tWas the ABC coverage of the Kings\/Flames game supposed to be the\n> way it was shown in BC with CBC overriding the ABC coverage? When I flipped\n> to ABC, it was the same commentators, same commercials even. My question\n> is: Was this the real ABC coverage or did CBC just \"black out\" the \n> ABC coverage for its own?\n> \n> \n\nHere in Nanaimo (on Vancouver Island, for you furriners out there) we\ngot the ABC coverage on KOMO. It probably depends on your cable company.\n\nI started off switching between the CBC and ABC broadcasts, but finally\nsettled on ABC. I can't stand Don Whitman, and Al Michaels was doing a\ndecent job. He followed the play pretty well, knew all the players'\nnames, and only made a couple of \"rookie\" mistakes that I noticed.\nOne thing that surprised me is that they never once attempted to explain\nthe offside rule.\n\nAm-I-paranoid-or-is-this-really-happening department:\nThere were no fights in the game, but there were a couple of occasions\nwhere it looked like a fight was about to start. Both times ABC cut\naway to show a closeup of a coach or McNall or something. Has ABC\ndecided to adopt the \"Spicer policy?\"\n\n----------------------------------------------------------------------\nLorne Epp epp@mala.bc.ca\n\n###\n\n","output":" hockey"} +{"input":"From: golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy)\nSubject: Re: WC 93: Results, April 18\nOrganization: University of Toronto Chemistry Department\nLines: 43\n\nIn article <1993Apr19.211406.22528@iscnvx.lmsc.lockheed.com> spiegel@sgi413.msd.lmsc.lockheed.com (Mark Spiegel) writes:\n>\tAccording to the SJ Murky News the Team USA roster is (names and\n>\tteams played for in 1992-93 listed):\n>\n>\t\tGoalies\n>\t\t-------\n........\n>\t\tForwards\n>\t\t--------\n>\tTony Amonte\tNew York Rangers\n>\tTed Drury\tHarvard Univ\n>\tRob Gaudreau\tSan Jose' Sharks\n>\tCraig Johnson\tUniv of Minnesota\n>\tJeff Lazaro\tOttawa Senators\n>\tMike Modano\tMinnesota North Stars\n>\tEd Olczyk\tNew York Rangers\n>\tDerek Plante\tUniv of Minnesota-Duluth\n>\tShion Podein\tEdmonton Oilers\n>\tDavid Sacco\tBoston University\n>\tDarren Turcotte New York Rangers\n>\tDoug Weight\tEdmonton Oilers\n>\n\nIt looks like the Edmonton Oilers just decided to take a European\nvacation this spring...\n\nRanford, Tugnutt, Benning, Manson, Smith, Buchberger, and Corson\nare playing for Canada.\n\nPodein and Weight are playing for the US.\n\nIs Kravchuk playing for the Russians...I know he had nagging\ninjuries late in the season.\n\nPodein is an interesting case...because he was eligible to\nplay in Cape Breton in the AHL playoffs like Kovalev, Zubov,\nand Andersson...obviously Sather and Pocklington are not\nthe total scrooges everyone makes them out to be...certainly\nin this case they've massively outclassed Paramount and the\nNew York Rangers.\n\nGerald\n\n###\n\n","output":" hockey"} +{"input":"From: gp2011@andy.bgsu.edu (George Pavlic)\nSubject: Re: Ron Francis\nOrganization: Bowling Green State University B.G., Oh.\nLines: 10\n\nNot to mention, Mr. Francis is an incredibly nice person. Over Christmas\nbreak, a friend of mine had a little Xmas gathering. The two of us drove\nto Ron's house. While I stayed in the car out of shyness, my friend went\nto the door and rang the bell. Ron answered and my friend introduced\nhimself. He then proceeded to invite Francis to the party. Ron declined\nbecause he \"had to watch his daughter.\" He then reached out and shook my\nfriend's hand! I know this isn't r.s.b., but I don't think Barry Bonds\nwould be this polite in this situation.\n\nGeorge\n\n###\n\n","output":" hockey"} +{"input":"From: gspira@nyx.cs.du.edu (Greg Spira)\nSubject: Re: Sandberg, Runs, RBIs (was: Re: Notes on Jays vs. Indians Series)\nOrganization: University of Denver, Dept. of Math & Comp. Sci.\nDistribution: na\nLines: 28\n\nbratt@crchh7a9.NoSubdomain.NoDomain (John Bratt) writes:\n\n>RBIs and Runs scored are the two most important offensive statistics.\n\nActually, they're pretty worthless, if you want to evaluate players\nwith stats. RBIs and Runs Scored should be banned; all they do is\nconfuse victims of mediot brainwashing like yourself. \n\n You\n>can talk about OBP and SLG% all you want, but the fact remains:\n\n>\tThe team that scores more runs wins the game!\n>\t---------------------------------------------\n\nUh, so?\n\nYou've just explained why we use OBP and SLG to evaluate players.\nPrecisely because the team that scores more runs wins the game.\nTraditional baseball stats have gotten way too far away from methods\nwhich enable fans to see who contributes to those runs scored - that's\nwhere OBP, SLG, Runs Created, Linear Weights, etc. come in. These\nsimplify matters so that we can more easily measure a player's\noffensive contribution to the team's runs scored.\n\nThank you for making our case. Have a nice day.\n\nGreg\n\n###\n\n","output":" baseball"} +{"input":"From: d_jaracz@oz.plymouth.edu (David R. Jaracz)\nSubject: Re: Octopus in Detroit?\nOrganization: Plymouth State College - Plymouth, NH.\nLines: 16\n\nIn article <93106.092246DLMQC@CUNYVM.BITNET> Harold Zazula writes:\n>I was watching the Detroit-Minnesota game last night and thought I saw an\n>octopus on the ice after Ysebaert scored to tie the game at two. What gives?\n\nNo no no!!! It's a squid! Keep the tradition alive! (Kinda like the\nfish at UNH games....)\n\n>(is there some custom to throw octopuses on the ice in Detroit?)\n>-------\n>Not Responsible -- Dain Bramaged!!\n>\n>Harold Zazula\n>dlmqc@cunyvm.cuny.edu\n>hzazula@alehouse.acc.qc.edu\n\n###\n\n","output":" hockey"} +{"input":"From: erics@netcom.com (Eric Smith)\nSubject: Re: Infield Fly Rule\nOrganization: NETCOM On-line Communication Services (408 241-9760 guest)\nLines: 31\n\njrogoff@scott.skidmore.edu (jay rogoff) writes:\n\n>One last infield fly question that has always puzzled me and hasn't\n>yet been addressed. I believe the rule also does *not* deal with this\n>situation:\n\n>If Infield Fly is declared and the ball is caught, runners can tag up\n>and advance at their own risk, as on any fly ball.\n\n>However, if the Infield Fly is *not* caught, at what point can a\n>runner legally leave his base w\/o fear of being doubled off for\n>advancing too early? When the\n>ball hits the ground? When a fielder first touches the ball after it\n>hits the ground?\n\n>Enlightenment would be appreciated.\n\nI'm not sure I understand this question. When the IF rule is invoked,\nthe batter is automatically out. This relieves the runners from being\nforced to advance to the next base if the ball is not caught. Other\nthan that, isn't it just the same as any situation in which a runner on\na base is not forced to the next base on a dropped fly ball? That is,\nif the ball is caught he can tag up and run (or decide to stay), and\nif the ball is dropped he can have left the base at any time.\n\n-----\nEric Smith\nerics@netcom.com\nerics@infoserv.com\nCI$: 70262,3610\n\n###\n\n","output":" baseball"} +{"input":"From: j3david@sms.business.uwo.ca (James David)\nSubject: Plus minus stat...\nOrganization: University of Western Ontario\nNntp-Posting-Host: sms.business.uwo.ca\nLines: 65\n\nRoger Maynard shares his views, with the masses, on Bob Gainey\nand life in general:\n \n>In <1993Apr15.160450.27799@sol.UVic.CA> gballent@hudson.UVic.CA\n>(Greg Ballentine) writes:\n \n>>The Selke candidate forwards main purpose on a shift is to\n>>prevent goals from being scored- not to score them. When\n>>Lemieux or Gilmour play their number one purpose is to score-\n>>defence is secondary- especially considering the line that\n>>plays against them is probably a defensive one. That is why\n>>they are not Selke candidates.\n>>Gainey is the best defensive forward ever. I stand by that\n>>assessment. He was a very good player who belongs in the hall\n>>of fame. Did you ever watch him play? He never made a\n>>technical error.\n \n>I watched him over his entire career. I have NEVER seen a\n>player, and that includes Russell Courtnall and Davie Keon,\n>screw up as many breakaways as Bob Gainey. And I will never\n>forget the time Denis Potvin caught Gainey with his head down. \n>You have been sold a bill of goods on Bob Gainey.\n \nIt was Bryan Trottier, not Denis Potvin. It was a vicious\n'boarding' from behind...Trottier was given a major.\n \nBut Roger, what the hell does this have to do with Gainey's skill\nas a hockey player? If Probert smashes Gilmour's head into the\nboards next week, will that diminish your assessment of Gilmour's\nskills?\n \n>Gainey was a plugger. And when the press runs out of things to\n>say about the stars on dynasties they start to hype the\n>pluggers. Grant Fuhr, Essa Tikkannen, Butch Goring, Bob\n>Nystrom, Bob Gainey, Doug Jarvis, Derek Sanderson, Wayne\n>Cashman, Bob Baun, Bob Pulford, Ralph Backstrom, Henri Richard,\n>Dick Duff...and so on...\n \nI would take Fuhr and Sanderson off of the latter.\n \nI think Gainey would be honoured to know that you've included him\non this list. I also think you have a relatively naive view\nabout what wins a hockey game...pluggers are an integral part of\nany team. The Selke is designed to acknowledge their\ncontribution...I think that most people understand that it's not\nthe Nobel Prize...so settle down.\n \n>cordially, as always,\n \n>rm\n \n>-- \n>Roger Maynard \n>maynard@ramsey.cs.laurentian.ca \n \ncongenially, as always,\n \njd\n \n--\nJames David\ndavid@student.business.uwo.ca\n\nj3david@sms.business.uwo.ca (James David)\nWestern Business School -- London, Ontario\n\n###\n\n","output":" hockey"} +{"input":"From: gspira@nyx.cs.du.edu (Greg Spira)\nSubject: Re: Notes on Jays vs. Indians Series\nOrganization: University of Denver, Dept. of Math & Comp. Sci.\nDistribution: na\nLines: 30\n\n\n>Something else to consider:\n\n>Alomar's H-R splits were .500-.363 SLG, .444-.369 OBP! Baerga's was .486-.424\n>and .392-.318. Pretty clearly, Alomar got a HUGE boost from his home park.\n\nNot necessarily. It could mean that, or it could mean that he just hit\na lot better at home than he did on the road (see Frank Thomas' home\/road\nsplits in '91 for an example). I would guess that some of Alomar's split\nis due to the Skydome, but most of it is probably due just to coincidence.\nThere's no way to be sure, of course, but the only hitters the Skydome\nseems to regularly help a lot are right handed home run hitters, and\nAlomar is not a home run hitter.\n\n>I'd say you could make a good for them being about equal right now. T&P\n>rated Baerga higher, actually.\n\nOnly because of t&P's bogus fielding stats, which rate Alomar as the worst\ndefensive second baseman in the league. On a career basis, I think T&P's\nfielding stats may mean something, but on a seasonal basis it comes up\nwith ridiculous results like this. Alomar may not be the god of fielding\nthe media says he is, but he sure isn't the worst in baseball.\n\nOffensively, T&P rate Alomar much higher last year.\n\nRegarding the A vs. B argument, I'll just say they're both very good players\nwith different strengths and a bright future.\n\n\nGreg\n\n###\n\n","output":" baseball"} +{"input":"From: rauser@fraser.sfu.ca (Richard John Rauser)\nSubject: Too Many Europeans in NHL\nOrganization: Simon Fraser University, Burnaby, B.C., Canada\nLines: 50\n\n\n\n Ten years ago, the number of Europeans in the NHL was roughly a quarter\nof what it is now. Going into the 1992\/93 season, the numbers of Euros on\nNHL teams have escalated to the following stats:\n\nCanadians: 400\nAmericans: 100\nEuropeans: 100\n\n Please note that these numbers are rounded off, and taken from the top\n25 players on each of the 24 teams. My source is the Vancouver Sun.\n\n Here's the point: there are far too many Europeans in the NHL. I am sick\nof watching a game between an American and a Canadian team (let's say, the\nRed Wings and the Canucks) and seeing names like \"Bure\" \"Konstantinov\" and\n\"Borshevshky\". Is this North America or isn't it? Toronto, Detriot, Quebec,\nand Edmonton are particularly annoying, but the numbers of Euros on other\nteams is getting worse as well. \n\n I live in Vancouver and if I hear one more word about \"Pavel Bure, the\nRussian Rocket\" I will completely throw up. As it is now, every time I see\nthe Canucks play I keep hoping someone will cross-check Bure into the plexiglassso hard they have to carry him out on a stretcher. (By the way, I'm not a\nCanucks fan to begin with ;-). \n\n Okay, the stretcher remark was a little carried away. But the point is that\nI resent NHL owners drafting all these Europeans INSTEAD of Canadians (and\nsome Americans). It denies young Canadians the opportunity to play in THEIR\nNORTH AMERICAN LEAGUE and instead gives it to Europeans, who aren't even\nbetter hockey players. It's all hype. This \"European mystique\" is sickening,\nbut until NHL owners get over it, Canadian and American players will continue\nto have to fight harder to get drafted into their own league.\n\n With the numbers of Euros in the NHL escalating, the problem is clearly\nonly getting worse.\n\n I'm all for the creation of a European Hockey League, and let the Bures\nand Selannes of the world play on their own continent.\n\n I just don't want them on mine.\n\n\n \n \n-- \nRichard J. Rauser \"You have no idea what you're doing.\"\nrauser@sfu.ca \"Oh, don't worry about that. We're professional\nWNI outlaws - we do this for a living.\"\n-----------------\n\"Remember, no matter where you go, there you are.\" -Dr.Banzai\n\n###\n\n","output":" hockey"} +{"input":"From: dchhabra@stpl.ists.ca (Deepak Chhabra)\nSubject: Re: hawks vs leafs lastnight\nNntp-Posting-Host: stpl.ists.ca\nOrganization: Solar Terresterial Physics Laboratory, ISTS\nDistribution: na\nLines: 18\n\nIn article <1993Apr18.153820.10118@alchemy.chem.utoronto.ca> golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy) writes:\n\n>>on all replays, joe murphy's goal shouldn't have counted ! \n>>the game would have ended in 2-2 tie !\n\n>I thought the red light went on...thus, in the review, the presumption\n>would be to find conclusive evidence that the puck did not go in the\n>net...from the replays I say, even from the rear, the evidence wasn't\n>conclusive that the puck was in or out...in my opinion...\n\nI was under the impression that the objective is to find conclusive\nevidence that the puck _did_ cross the line. And, the replays I saw showed \nfairly conclusively that the puck did _not_ cross the goal line at any\ntime anyway. Somebody screwed up. \n\n\ndchhabra@stpl.ists.ca\n\n###\n\n","output":" hockey"} +{"input":"From: iacs3650@Oswego.EDU (Kevin Mundstock)\nSubject: Re: Yogi-isms\nReply-To: iacs3650@oswego.Oswego.EDU (Kevin Mundstock)\nOrganization: Instructional Computing Center, SUNY at Oswego, Oswego, NY\nLines: 14\n\nIn article <1993Apr2.153725.17543@bsu-ucs> 00mbstultz@leo.bsuvc.bsu.edu writes:\n>\n>Here's an interesting quote from Bill Veek from _Get that Nigger off\n>the Field_:\n> \"Josh (Gibson) was, at minimum, two Yogi Berras.\"\n>Speaking of Yogi, anybody know any good Yogi-isms?\n>Mike \"Curious George\" Stultz\n\nHere's one I remember: (sort of)\nYogi's asleep in a hotel room late at night and gets a call from someone.\nAfter he answers the phone the person at the other end asks if he woke Yogi\nup. Yogi answered, \"No, the phone did.\"\n\nKevin\n\n###\n\n","output":" baseball"} +{"input":"From: marc@yogi.austin.ibm.com (Marc J. Stephenson)\nSubject: Re: Astros Are Back!!!!!!!!!!!!!!!!!!!\nDistribution: usa\nOrganization: IBM, Austin\nLines: 63\n\nIn article <15APR199311534452@rosie.uh.edu> st1rp@rosie.uh.edu (Schwam, David S.) writes:\n>In article , marc@yogi.austin.ibm.com (Marc J. Stephenson) writes...\n>> 2) Astros relief corps holding together. If Doug Jones keeps his changeup\n>> effective and Xavier Hernandez can be effective, then it's passable.\n>> There's no reasonable left-handed help, and the middle relief is iffy.\n>> Tom Edens was expected to take over the Joe Boever setup man role, but\n>> he's been injured, and he was an expansion team acquisition anyway. \n>> Houston thought that Boever would demand too much money, so they let him\n>> go. Doug Jones can lose his touch - he went from Cleveland's all-star\n>> closer to the minors in a pretty short span.\n>\n> From what I understand, Boever and Murphy were considered expendable by the\n ^^^^^^\n>club. Houston felt that their positions could be filled by a number of\n>players.. Art Doug Jones is the key to Houston's success. He must have\n>another great year for Houston to challenge in the NL West. \nNo argument at all with Murphy. He scared the hell out of me when he came in\nlast year. On the other hand, the club though enough of Boever to put him into\nan awful lot of games (he may have led the league in appearances - he did at\nleast at some point). He seemed to be a very viable setup guy - but I guess\nthat's not considered that crucial by the club. I can just remember two years\nago so well, though...\n...\n> The unsuspected strength of the lower part of the order has saved the\n> club so far. Biggio and Finley just aren't doing their job of getting\n> on base. Instead of filling his role as an RBI man, Bagwell has had to\n> assume Biggio and Finley's job. Biggio concerns me, since he usually\n> starts the season very strong.\n\nI'm not that concerned. Those guys have been relatively consistent over the\nyears and they have no good reasons to decline (no injuries, not old, ...).\nI expect them to come through just fine. It's those guys that have not\nbeen consistently good that are the worrisome part, even if they are coming\nthrough right now.\n> * * * * * *\n>\n> On a side note, are you at all concerned with the rumors concerning\n>next year's uniform? There is talk that their road uniform will be\n>(blech..) traditional grey, with the word \"HOUSTON\" written across the\n>chest. If I'm not mistaken, their home uniforms may totally eliminate\n>the color orange (shiver..). McLane's favorite color is red, so...\n\nThis sounds like their old road unis. Pretty dull. Buttons or pullovers?\nI'll check through my uniform book to see if they've always had some orange.\n\n> I'm really upset.. the current unforms are dull and the new ones sound\n>horrible. I'd like to see the uniform of the mid-1980s return. They\n>may not have been pretty, but Houston had established a long precident of\n>wearing the ugliest uniforms in baseball -- and I liked it.\n\nWell, we'll see. I've got a Astros pullover shirt with the \"Astros stripes\"\nacross the shoulders and I have trouble making myself wear it in public. i\ncan see why they might want that to change. Gee, if they eliminate the\norange, will they reupholster the seats in the Astros stripes section (what\nused to be the gold and yellow levels - I don't know those numbers they use\nnow).\n\nI saw a pinstripe version of an Astros cap and I actually thought it looked \ngood!\n-- \nMarc Stephenson\t IBM AWS (Advanced Workstations & Systems - Austin,TX)\nDISCLAIMER: The content of this posting is independent of official IBM position.\nINTERNET->marc@austin.ibm.com VNET: MARC at AUSVMQ IBM T\/L: 678-3189\n\n###\n\n","output":" baseball"} +{"input":"From: nittmo@camelot.bradley.edu (Christopher Taylor)\nSubject: When Is Melido Due Back?\nNntp-Posting-Host: camelot.bradley.edu\nOrganization: Bradley University\nDistribution: na\nLines: 6\n\nWhen are the Yankees planning on activating Melido Perez? His 15 days on\nthe DL are up today, but are they bringing him back this weekend? \n\nThanks for any info.\n\n###\n\n","output":" baseball"} +{"input":"From: hbrooks@uiatma.atmos.uiuc.edu (Harold_Brooks)\nSubject: Re: Spanky Released\nKeywords: WHY!?!\nOrganization: Colorado Needs the Huckabay Kiteball Campaign Committee\nLines: 45\n\nIn article <1993Apr12.130652.22090@sei.cmu.edu> wp@sei.cmu.edu (William Pollak) writes:\n[Deletions]\n>\n>Spanky isn't very good defensively anymore, he's an offensive liability, and,\n>judging from his outburst this winter after the Bucs failed to sign Drabek,\n>he's a jerk with his head in the sand. Tommy Prince, on the other hand, can't\n>hit. In the paper, Simmons was citing the case of Tom Pagnozzi, who never hit\n>in the minors or majors, but suddenly somehow learned how. \n\nGeez, Dal must have slipped something into Ted's drink sometime. Comparing\nPrince to Pagnozzi offensively is laughable. Prince has never hit well in\nthe minors and he's now 27 years old, I think. Pagnozzi was not a bad hitter\nin the minors. (I'll bring in the numbers tomorrow assuming I don't have\nanother brain cramp and forget.) He had a very good year at Louisville \nbefore coming up to the majors. As I recall, the hype on Pagnozzi coming up\nin the organization was good hit, decent fielding. When he got to the \nmajors and didn't hit as well as expected (not as much playing time?), he \nbecame Exhibit 312 in Nichols' Law of Catcher Defense and got the reputation \nas an outstanding defensive catcher. It's not clear he ever learned to\nhit. His four years with more than 100 AB--\n\nBorn 31 July 1962\nYear AB BA SLG OBA \n1988 195 .282 .320 .328\n1990 220 .277 .373 .321\n1991 459 .264 .351 .317\n1992 485 .249 .359 .290 \n\nNo power, less-than-league-average walks, peak year when he turned 28, \nnow declining. If Ted is going to invoke Pagnozzi as a model for Prince,\ngiven that Prince has underperformed Pagnozzi in the minors, it's not\na rosy picture.\n\nBTW, I'm still unhappy with moving Zeile, who had the same reputation \ncoming up in the Cardinal organization as Pagnozzi, except that he was\na much, much better hitter, to 3rd where he could be an average hitter\nand a below average fielder instead of a well-above average hitter\nas an average (or below average) fielding catcher.\n\nHarold\n-- \nHarold Brooks hbrooks@uiatma.atmos.uiuc.edu\nNational Severe Storms Laboratory (Norman, OK)\n\"I used to work for a brewery, too, but I didn't drink on the job.\"\n-P. Bavasi on Dal Maxvill's view that Florida can win the NL East in '93\n\n###\n\n","output":" baseball"} +{"input":"Subject: McRae is (Re: Torre: The worst manager?)\nFrom: scott@mccall.com (Scott D. Davis)\nReply-To: scott@mccall.com (Scott D. Davis)\nOrganization: The McCall Pattern Co., Manhattan, KS, USA\nNntp-Posting-Host: mis2\nNntp-Posting-User: scott\nLines: 18\n\n\nIn article <16BB1C589.DAK988S@vma.smsu.edu.Ext>, DAK988S@vma.smsu.edu writes:\n>gt7469a@prism.gatech.EDU (Brian R. Landmann) writes:\n>>Joe Torre has to be the worst manager in baseball.\n>>brian, a very distressed cardinal fan.\n>No....Hal McRae is the worst manager in baseball. I've never seen a guy who\n>can waste talent like he can. One of the best raw-talent staffs in the league,\n>and he's still finding a way to lose. I'll be surprised if he makes it through\n>the next 2 weeks, unless drastic improvement is made.\n> \nKC(?) news was doing a report on that. They said that McRae is\nreally a batting coach and not a manager. But for some reason\nhe took the job. Whatever the reason, the Royals need a new\nmanager now...while it is too late.\n--\nScott D. Davis The McCall Pattern Company\n(uucp: ...!widener!depot!mccall!scott)\t615 McCall Road\n(800)255-2762, in Kansas (913)776-4041 Manhattan, KS 66502, USA\n\n###\n\n","output":" baseball"} +{"input":"From: jason@studsys.mscs.mu.edu (Jason Hanson)\nSubject: Re: NHL team in Milwaukee\nOrganization: UTexas Mail-to-News Gateway\nLines: 42\nNNTP-Posting-Host: cs.utexas.edu\n\nNewsgroups: rec.sport.hockey\nSubject: Re: NHL team in Milwaukee\nSummary: \nExpires: \nSender: \nDistribution: \nOrganization: Marquette University - Department MSCS\nKeywords: \n\nIn article <1993Apr16.131843.24012@walter.cray.com> cbetz@radioman.cray.com (Charles Betz {x66442 CF\/ENG}) writes:\n>\n>Bradley Center in Milwaukee is home to the Milwaukee Admirals minor leauge\n>hockey team. The owner of the Admirals (sorry, I can't remember his name)\n>either owns or at least shelled out the majority of the funds to build the\n>Bradley Center.\n\nLloyd Pettit married into Allen-Bradley Corp. (ab.com) family and owns the\nAdmirals. He donated the Bradley Center and the new Pettit National Ice\nCenter.\n\n>Supposedly he was approached by the NHL about an expansion franchise, but \n>turned it down because he thought the franchise fee of $50 million was too\n>high.\n\nThis is not the way I have heard it. See, Lloyd (as he is affectionately\nreferred to by Milwaukeeans and Bob Uecker) bought the Bradley Center *TO* get\nthe NHL to come here.\n\n>Like I said, I don't know whether this story is true or just a rumor, but if\n>it's true, don't look for an NHL team in Milwaukee anytime soon. The Admirals\n>aren't going to be forced out of the building and you won't see an NHL club\n>and a minor league club in the same building, especially since the NBA's\n>Milwaukee Bucks play there as well.\n\nYeah, the Bucks, the Milwaukee Wave (soccer), the Admirals, the Marquette\nWarriors, concerts and a bunch of other things...\n-- \nJason Hanson | 915 W. Wisconsin Ave #1010 | (414) 288-2179\nMarquette University | Milwaukee, WI 53233-2373 | Ham Radio: N9LEA\/AE\n-- jason@studsys.mscs.mu.edu ==+== n9lea@n0ary.#nocal.ca.usa.na --\n\n###\n\n","output":" hockey"} +{"input":"From: luriem@alleg.edu(Michael Lurie) The Liberalizer\nSubject: Yankee fears.\nOrganization: Allegheny College\nLines: 9\n\n\nI'll tell youm all one thing. Steve howe and FARR are much better then the \nworst pitcher in yankee Pitching ___________________\n\n\nWHO do you think I am talking about. I'll post the answers if you e-mail \nto me. Use reply. or post you're answers, but e-mailing them to me meaqns \nthat I will post the final results. I have one particular horrid pitcher \nin mind.\n\n###\n\n","output":" baseball"} +{"input":"From: rja@mahogany126.cray.com (Russ Anderson)\nSubject: Re: A surfeit of offense?\nOriginator: rja@mahogany126\nLines: 35\nNntp-Posting-Host: mahogany126\nOrganization: The 1991 World Champion Minnesota Twins!\n\n\nIn article <1qi008INNphe@jhunix.hcf.jhu.edu>, pablo@jhunix.hcf.jhu.edu (Pablo A Iglesias) writes:\n> In article <1993Apr14.160447.17835@cs.cornell.edu> tedward@cs.cornell.edu (Edward [Ted] Fischer) writes:\n> >Last year the American League scored 9802 runs in 1134 games, for a\n> >total of 8.6 runs per game, with 1.0 HR\/game. Through Tuesday, the AL\n> >has 477 runs in 48 games, for a total of 9.9 runs per game, and a\n> >total of 1.7 HR\/game. In 1987 there were 9.8 runs per game, and 2.3\n> >HR\/game.\n> \n> >The big question: How significant is this? Have we returned to 1987?\n> >Or is this just a minor abberation?\n> >\n> >Some thoughts:\n> \n> >d) I thought offense was generally down in April, rising as the\n> >weather got warm and pitchers got tired. This may be a bigger\n> >abberation from the norm than it seems.\n> \n> 1. I don't get a feeling that the weather has been an issue this year. \n> There doesn't seem to be a really cold spell in North America which \n> does makes it harder to hit (not to mention making the ball carry less)\n\nYou obviously did not watch the Twins in Chicago.\n\nNo cold spell? It's been snowing most of the week in Minnesota.\n(5 inches in Duluth last weekend)\n\n> I would still put things under the too early to tell category. \n\nYup.\n\n-- \nRuss Anderson | Disclaimer: Any statements are my own and do not reflect\n------------------ upon my employer or anyone else. (c) 1993\nEX-Twins' Jack Morris, 10 innings pitched, 0 runs (World Series MVP!)\n\n###\n\n","output":" baseball"} +{"input":"From: fierkelab@bchm.biochem.duke.edu (Eric Roush)\nSubject: Re: Young Catchers\nArticle-I.D.: news.12799\nOrganization: Biochemistry\nLines: 139\nNntp-Posting-Host: bruchner.biochem.duke.edu\n\nSince I was the one responsible for these divergent threads of\napprox. 40+ posts (going back to: The Braves could be better off\nif an injury happens), I may as well inject a little more\nfuel to the flame!\n\n1) Back at the beginning of Spring Training, I though\nLopez would make the squad easily. Olson was still\nrecovering from his late-season injury (knee, I believe),\nand there were questions as to whether he would be\nable to play before June. And then Berryhill was dinged up.\n\nI was looking forward to this, because I believe that Lopez\ncan hit AND field the position. Before last season, he was\nthe Braves \"Defensive Catcher\" prospect, while Brian Deak was\nthe Braves \"Offensive Catcher\" prospect. Besides, Olson\nand Berryhill couldn't hit their way out of a wet cardboard\nbox, and don't walk enough to be useful.\n\nBut Olson recovered quickly, Berryhill recovered, and the Braves went\nwith the two vets. I still say that if one of those two had been down\nat the start of the season, he wouldn't have gotten his job back.\n\n2) There is a certain logic to keeping Olson and Berryhill around.\nAfter all, ML catchers are in short supply and suffer from wear and\ntear. There are teams out there without ONE average ML catcher\n(California and Seattle come to mind). Certainly, trying to\nmove Olson or Berryhill through waivers would be unlikely to work.\nPlus, you'd have to eat that salary, which isn't huge, but isn't\ntiddleywinks either (I think Olson's at about $800,000, Berryhill\nat $450,000, but that's only what I recall).\n\n3) Yes, I think arbitration-eligibility may have a role to\nplay in this also. What is it, that 5\/6 of the 2+year players\naren't eligible for arbitration? Only the 1\/6 that were on the roster\nthe longest are eligible? Of course, the system may change,\nbut the extent of that change is not yet known. From a business\nstandpoint, it may make sense to keep Lopez down until June\/the\nfirst time Olson\/Berryhill go on the DL.\n\n4) I am still disappointed that Lopez isn't on the team.\nI still prefer to think of myself as a fan when it comes to the Braves,\nand the truth is that I'd rather see our best team on the field,\nwhich, IMO, includes Lopez.\n\nOf course,today we play the Cubs. Hopefully, we won't need him. ;)\n\nAs for the Schuerholz\/Cox conversation, I imagine it went\nlike this: (Remember, they've BOTH been GM's)\n(the following is not meant to be read by the humor-impaired)\n\nCox: OK, we've sent Jones down. His fielding could be a\nlittle smoother. Besides, Blauser can hit OK and his fielding\nis better than it used to be.\n\nSchuerholz: Well, we'll have to send Nieves down too. Deion\njust won't sign that baseball only contract. We can't count\non him in October, so we have to keep Nixon around for the\ndefense. Besides, Gorman's not ready to give up on\nBilly Hatcher yet. Once Hatcher's gone AND Deion signs,\nwe can move Nixon for Frankie Rodriguez. That ought to\ngive us some pitching depth in 1995.\n\nCox: Yep, that'll be nice. Too bad Deion won't sign.\nOK, I'll look for Nieves when Justice starts having\nBerry-Berry...er, back problems again. Now, what about\nKlesko?\n\nSchuerholz: Well, we've still got to fork out another 1.5 mil\nfor Bream. If we keep Klesko, we either lose the money\nor Cabrera. I keep dangling Sid in front of Dal Maxwell,\nbut somehow he doesn't seem to be the same GM. First\nJeffries for Jose, and now Whiten for Clark! If he\ngets rid of Brian Jordan, then I'd HAVE to believe that he\nand Whitey Herzog switched bodies at the Winter Meetings!\n\nCox: OK, keep trying on Bream, and I'll wait til the trading\ndeadline for my Hunter\/Klesko platoon. Maybe I can get a few\nextra at-bats for Cabrera while we wait. Try California...\nif Snow starts slowly, maybe WhiteyDal will bite on Sid.\nAnd if that doesn't work, then perhaps Sid's knees\ncould be \"persuaded\" to act up. There's always the\n15-day DL! Mwa-ha-ha-ha-ha!\n\nSchuerholz: What about Caraballo?\n\nCox: Well, he's not that much better than Lemke. Maybe if he starts\nin Richmond, he'll start walking more. Besides, if he's going to be\narbitration-eligible, better to stretch him out so that we actually\nget some value from him before he makes the big bucks.\n\nSchuerholz: Now, let's see. That leaves Lopez.\n\nCox: NOOOOO! I gotta keep Lopez! Sure, I didn't think Olson\nwould recover this quickly. Maybe I can talk Caminiti into\nrunning into him again?\n\nSchuerholz: Nope, Lopez has gotta go. You know that he'll get\n$3 million in arbitration. May as well put it off that one\nextra year. Besides, until Olson's shown his stuff a little\nbit, I can't trade him. Besides, Berryhill's a left-handed\nhitter. You know how rare that is?\n\nCox: Don't you mean a left-handed whiffer? Pretty common,\nif you ask me. I mean, he made Pat Borders look good in\nthe World Series. PAT BORDERS!!!\n\nSchuerholz: Hey, you're the one who wouldn't write Lopez\ninto the lineup.\n\nCox: Well, you're the one who went out and got me Jeff\nReardon! Besides, I thought Lopez wouldn't be used\nto our pitching staff's stuff. He got some time with\nthem this spring...looked pretty good. Come on, surely\nwe only need to keep one stiff behind the plate?\n\nSchuerholz: Yeah, but which stiff? Whichever one we keep\nwill be hurt by May.\n\nCox: OK, OK, you made your point. Keep them both. Surely\none of them will be on the DL by June at the latest. Then I\ncan call up Lopez, and then we can win 110 games! The Pennant!\nTHE WORLD SERIES! I'll be up there with John McGraw! Casey\nStengel! Earl Weaver! Oh, they laughed at me in Toronto,\nbut have you ever had to deal with George Bell? I'll finally\nget my just reward! Mwa-ha-ha-ha!\n\nSchuerholz: Easy, Bobby. Have you been taking those\n\"happy pills\" left around by Chuck Tanner? Why'd you\never hire that guy anyhow?\n\nCox: Don't ask me; ask Ted.\n\n-------------------------------------------------------\nEric Roush\t\tfierkelab@\tbchm.biochem.duke.edu\n\"I am a Marxist, of the Groucho sort\"\nGrafitti, Paris, 1968\n\nTANSTAAFL! (although the Internet comes close.)\n--------------------------------------------------------\n\n###\n\n","output":" baseball"} +{"input":"From: str@maredsous.Eng.Sun.COM (Todd Rader)\nSubject: Re: Rickey Henderson\nOrganization: Sun\nLines: 6\nDistribution: usa\nNNTP-Posting-Host: maredsous\n\nIn article <1993Apr5.173500.26383@ra.msstate.edu> js1@Isis.MsState.Edu (Jiann-ming Su) writes:\n%I say buy out Henderson's contract and let him go bag groceries. Next \n%season, you'll be able to sign him for nothing. That goes for any bitching\n%ball player.\n\nStay in school. You have a lot to learn.\n\n###\n\n","output":" baseball"} +{"input":"From: umturne4@ccu.umanitoba.ca (Daryl Turner)\nSubject: Re: Pens Info needed\nNntp-Posting-Host: ccu.umanitoba.ca\nOrganization: University of Manitoba, Winnipeg, Manitoba, Canada\nLines: 19\n\nIn article <1993Apr15.140541.28465@ericsson.se> etxonss@ufsa.ericsson.se (Staffan Axelsson) writes:\n>\n> Actually, Swedish coach Curt Lundmark is thinking about leaving two\n> spots open for additions from eliminated NHLers. It is Mats Sundin and\n> Calle Johansson that Curt hopes can join the team, although in a late\n> stage of the tournament. Technically, I seem to recall that you can leave\n> spots open until 24 hrs before the WC final.\n>\nHmmm...I also heard through the grapevine that Team Finland might try and\nleave a spot open for at least one NHLer. (Some guy named Sel{nne, ever\nhear of him? :) They might have to be content with Kurri, though, I hope. :)\n\n\nDaryl Turner : r.s.h contact for the Winnipeg Jets \nInternet: umturne4@ccu.umanitoba.ca \nFidoNET: 1:348\/701 -or- 1:348\/4 (please route through 348\/700)\nTkachuk over to Zhamnov, up to Sel{nne, he shoots, he scores! \nThe Jets win the Cup! The Jets win the Cup!\nEssensa for Vezina! Housley for Norris! Sel{nne for Calder!\n\n###\n\n","output":" hockey"} +{"input":"From: rickert@NeXTwork.Rose-Hulman.Edu (John H. Rickert)\nSubject: mile high runs\nArticle-I.D.: master.1psq90INNh93\nReply-To: rickert@NeXTwork.Rose-Hulman.Edu (John H. Rickert)\nOrganization: Computer Science Department at Rose-Hulman\nLines: 35\nNNTP-Posting-Host: g215a-1.nextwork.rose-hulman.edu\n\nHow many runs will be scored in Denver?\nI don't know.\n\nbut some idea can be gotten by looking at the runs scored in \nMile High Stadium during the last few years of the Bears\/Zephyrs \ntenure in the American Association.\n\nHere's the total runs scored per game in Zephyrs games, \nall league games and the ratio. I found the same ratios for HR.\n\nYear rpg lea ratio hrpg lea ratio \n1992 10.22 9.10 1.12 1.65 1.58 1.04\n1991 9.53 8.87 1.07 1.41 1.26 1.12\n1990 10.71 8.72 1.23 1.49 1.24 1.20\n1989 9.07 8.34 1.09 1.27 1.11 1.14\n1988 9.90 8.37 1.18 1.29 1.08 1.19\n1987 12.55 10.70 1.17 2.39 1.92 1.24\n1986 9.45 9.33 1.01 1.35 1.38 .98\n1985 9.50 8.54 1.11 1.53 1.34 1.14\n1984 9.99 9.10 1.10 1.55 1.59 .97\n1983 10.60 9.99 1.06 2.03 1.74 1.17\n1982 11.29 10.35 1.09 2.24 1.91 1.17\n1981 10.29 9.25 1.11 1.43 1.49 .96\n1980 10.59 9.43 1.12 1.63 1.46 1.12\n 1446\/13-->1.11 1444\/13-->1.11\n\nIt seems pretty clear that Denver will have a large effect \non runs scored (I'll stick with my prediction from last year \nthat it'll be one of the top 3 in the NL this year) \nand a fairly large effect on Homeruns - though apparently not as large as \nAtlanta, Wrigley, Cincinnati and San Diego.\nStill it ought to be a pretty decent home run park.\n\njohn rickert\nrickert@nextwork.rose-hulman.edu\n\n###\n\n","output":" baseball"} +{"input":"From: jrmst8+@pitt.edu (Joseph R Mcdonald)\nSubject: Re: Wirtz is a weenie\nOrganization: University of Pittsburgh\nLines: 27\n\nIn article rp16+@andrew.cmu.edu (Robert Angelo Pleshar) writes:\n>In other TV news, the Penguins announced yesterday that they will have 3\n>fewer broadcast TV games, and will have 22(!) games on some sort of\n>subscription \/ pay-per-view system. Yuck.\n\nThis is incorrect. This year the Pens had 61 games on \"free\" TV and 6\ngames on PPV. Next year they will have 62 games on free TV and 22 on \na subscription basis. \n\nYou actually get 1 more free game than last year, and there will be no\nmore \"radio-only\" games.\n\nIts a good deal. Last year, everybody bitched about Baldwin \"breaking\nup the team\". Now, he goes out of his way to keep the nucleus of this\nteam together and that takes money. He comes up with a creative way\nto generate more revenue so he can afford this team, and people bitch\nsome more.\n\nEverybody wants something for nothing.\n\nDean\n\n-- \n-------------------------------------------------------------------------------\nDean J. Falcione \"Badges? What badges? We \n(using jrmst8 by permission Don't need no stinkin'\n of the owner, Joe McDonald) badges!\"\n\n###\n\n","output":" hockey"} +{"input":"From: georgeh@gjhsun (George H)\nSubject: Re: President Trophy winner missing playoffs ???\nOrganization: Michigan State University\nLines: 17\nNNTP-Posting-Host: gjhsun.cl.msu.edu\n\njstrangi@hora.seas.upenn.edu (Jim Strangio) writes:\n\n>In article <13APR93.17376172.0059@VM1.MCGILL.CA> CCDB@MUSICA.MCGILL.CA (CCDB000) writes:\n\n>When was the last time a President's Trophy winner fell to last place\n>the following year? A long time, I'd bet.\n>--\n\nWell I think it in 1969 the Montreal Canadians finished 1st (although\nthere was no President's cup in those days) and missed the playoffs \nin 1970. I do recall that the 1970 playoff picture wasn't decided until\nthe final day, when the NY Rangers defeated the RedWings. The tie-breaker was\nthe number of goals for (if I remember correctly), so the Rangers played\nwith an empty net for the entire game. Some Hab loyalists accused \nthe Wings of 'throwing' the game to keep them out, but as I recall, \nGordie and Delvecchio had the flu, so coach Sid Abel sat them out,\nand the Rangers swarmed the RedWings most of the night.\n\n###\n\n","output":" hockey"} +{"input":"From: John Michael Santore \nSubject: Re: NHL Team Captains\nOrganization: Sophomore, Mathematics, Carnegie Mellon, Pittsburgh, PA\nLines: 31\n\t<1993Apr19.022113.12134@ann-arbor.applicon.slb.com>\n\t\nNNTP-Posting-Host: po5.andrew.cmu.edu\nIn-Reply-To: \n\n>Michael Collingridge writes:\n> \n>>And, while we are on the subject, has a captain ever been traded, \n>>resigned, or been striped of his title during the season? Any other \n>>team captain trivia would be appreciated.\n> \n>Wasn't Ron Francis captain of the Whalers when he was traded to\n>Pittsburgh?\n>\n>Mom.\n\nRick Tocchet was captain of the Flyers for several years before he was\ntraded to the Pens...\n\n -John Santore\n\n\n=============================================================================\n ____________________ \n\/ \\ \"We break the surface tension \n\\_________ ____ \\ with our wild kinetic dreams\"\n\/ \/ \\ \\ -Rush, Grand Designs\n\\_______ \/ (*) ) )\n\/ \/ \/\\___\/ \/ Go Philadelphia Flyers!\n\\_____ \/ \/ \/\n\/ \/ \\_______\/ John Santore (jsbh@andrew.cmu.edu)\n\\________\/ \n \nRush-Yes-King Crimson-Emerson, Lake and Palmer-Marillion-Genesis (w\/ Gabriel)\n=============================================================================\n\n###\n\n","output":" hockey"} +{"input":"From: adavis@mcl.bdm.com (Arthur Davis)\nSubject: Re: Ron Francis\nOrganization: BDM International, Inc.\nLines: 17\nNNTP-Posting-Host: jupiter.mcl.bdm.com\n\nIn article <1993Apr19.171223.11311@Virginia.EDU> mjr4u@Virginia.EDU (\"Matthew J. Rush\") writes:\n> I forgot to ask: Is this the highest points total Francis has\n>had in a season? Has he ever had a 100 point season before,\n>either with the Pens or the Whalers?\n>\n\nFrancis got 101 in 89-90, his last full season with Hartford.\n\nIn agreement with your previous post, I think Francis is a tremendous and\ngenerally underrated complete player. I would LOVE to have him here in a\nCapitals uniform where he would certainly be the #1 center (even though\nPivonka is also a very good complete player who is generally underrated).\nFrancis impresses me in many ways as an \"ethical Dale Hunter\". Tons of\nheart and can-do attitude with a lot of different skills, but none of\nthe cheap shots and few penalty minutes. Not to mention nearly always\ncoming through when it's important.\n\n###\n\n","output":" hockey"} +{"input":"From: filinuk@staff.dccs.upenn.edu (Geoff Filinuk)\nSubject: Get Real. Caps have no chance\nReply-To: filinuk@staff.dccs.upenn.edu (Geoff Filinuk)\nOrganization: University of Pennsylvania\nLines: 7\nNntp-Posting-Host: staff.dccs.upenn.edu\n\n\n\tAnyone who really believes that the Caps can beat\nthe Pens are kidding themselves. The Pens may not loose\none game in the playoffs.\n\nGeoff Filinuk\nFlyers Fan\n\n###\n\n","output":" hockey"} +{"input":"From: ma_ind25@blurt.oswego.edu\nSubject: Re:Jewish Baseball Players?\nOrganization: SUNY College at Oswego, Oswego, NY\nLines: 3\n\nI believe that Rusty Staub was also a jewish ball-player\nAlso, Mordaci Brown back in the early 20th century. He was a pitcher whose\nnickname was \"3 fingers\" Brown....for obvious reasons....he had 3 fingers.\n\n###\n\n","output":" baseball"} +{"input":"From: jtchern@ocf.berkeley.edu (Joseph Hernandez)\nSubject: MLB Standings and Scores for Thu., Apr. 15th, 1993\nOrganization: JTC Enterprises Sports Division (Major League Baseball Dept.)\nLines: 73\nDistribution: world\nNNTP-Posting-Host: monsoon.berkeley.edu\n\n\n\t MLB Standings and Scores for Thursday, April 15th, 1993\n\t (including yesterday's games)\n\nNATIONAL WEST\t Won Lost Pct. GB Last 10 Streak Home Road\nHouston Astros 05 03 .625 -- 5-3 Won 5 00-03 05-00\nAtlanta Braves 06 04 .600 -- 6-4 Lost 1 03-03 03-01\nSan Francisco Giants 05 04 .556 0.5 5-4 Lost 1 02-01 03-03\nLos Angeles Dodgers 03 06 .333 2.5 3-6 Lost 3 00-02 03-04\nColorado Rockies 02 05 .286 2.5 2-5 Lost 3 02-03 00-02\nSan Diego Padres 02 06 .250 3.0 2-6 Lost 3 00-03 02-03\nCincinnati Reds 02 07 .222 3.5 2-7 Lost 3 01-02 01-05\n\nNATIONAL EAST\nPhiladelphia Phillies 08 01 .889 -- 8-1 Won 5 05-01 03-00\nPittsburgh Pirates 06 02 .750 1.5 6-2 Won 3 03-02 03-00\nSt. Louis Cardinals 06 02 .750 1.5 6-2 Won 2 04-02 02-00\nNew York Mets 04 03 .571 3.0 4-3 Won 2 02-03 02-00\nChicago Cubs 04 05 .444 4.0 4-5 Won 1 01-02 03-03\nMontreal Expos 03 05 .375 4.5 3-5 Lost 2 00-02 03-03\nFlorida Marlins 03 06 .333 5.0 3-6 Won 2 02-04 01-02\n\n\nAMERICAN WEST Won Lost Pct. GB Last 10 Streak Home Road\nTexas Rangers 06 02 .750 -- 6-2 Lost 1 04-02 02-00\nCalifornia Angels 05 02 .714 0.5 5-2 Won 3 03-02 02-00\nOakland Athletics 04 03 .571 1.5 4-3 Lost 1 04-02 00-01\nSeattle Mariners 04 03 .571 1.5 4-3 Won 1 03-02 01-01\nChicago White Sox 04 04 .500 2.0 4-4 Won 1 02-03 02-01\nMinnesota Twins 04 04 .500 2.0 4-4 Lost 1 01-02 03-02\nKansas City Royals 01 07 .125 5.0 1-7 Lost 2 01-05 00-02\n\nAMERICAN EAST\nBoston Red Sox 06 02 .750 -- 6-2 Won 2 02-00 04-02\nNew York Yankees 05 03 .625 1.0 5-3 Won 2 02-00 03-03\nToronto Blue Jays 04 03 .571 1.5 4-3 Lost 1 03-02 01-01\nDetroit Tigers 03 04 .429 2.5 3-4 Won 1 01-00 02-04\nCleveland Indians 03 05 .375 3.0 3-5 Lost 2 02-01 01-04\nMilwaukee Brewers 02 05 .286 3.5 2-5 Lost 4 00-02 02-03\nBaltimore Orioles 02 06 .250 4.0 2-6 Won 1 00-02 02-04\n\n\n\t\t\t YESTERDAY'S SCORES\n (IDLE teams listed in alphabetical order)\n\nNATIONAL LEAGUE\t\t\t\tAMERICAN LEAGUE\n\nHouston\t\t9\t\t\tBaltimore\t6\nMontreal\t5\t\t\tTexas\t\t5\n\nPittsburgh 11\t\t\tSeattle\t 10\nSan Diego\t7\t\t\tToronto\t\t9 (10)\n\nChicago\t\t6\t\t\tCleveland\t7\nAtlanta\t\t0\t\t\tBoston\t 12\n\nCincinnati\t2\t\t\tCalifornia 12\nPhiladelphia\t9\t\t\tMilwaukee 2\n\nNew York\t6\t\t\tKansas City\t5\nColorado\t3\t\t\tNew York\t6\n\nFlorida\t\t6\t\t\tMinnesota PPD\nSan Francisco\t4\t\t\tChicago RAIN\n\nSt. Louis\t2\t\t\tDetroit IDLE\nLos Angeles\t1 (15)\t\t\tOakland IDLE\n-- \n-------------------------------------------------------------------------------\nJoseph Hernandez | RAMS | | \/.\\ ******* _|_|_ \/ | LAKERS\njtchern@ocf.Berkeley.EDU | KINGS | |__ | | DODGERS _|_|_ | | RAIDERS\njtcent@soda.Berkeley.EDU | ANGELS |____||_|_| ******* | | |___| CLIPPERS\n-------------------------------------------------------------------------------\n\n###\n\n","output":" baseball"} +{"input":"From: golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy)\nSubject: Re: Too Many Europeans in NHL\nArticle-I.D.: alchemy.1993Apr6.195022.6362\nOrganization: University of Toronto Chemistry Department\nLines: 24\n\nIn article <1993Apr6.155743.18798@adobe.com> snichols@adobe.com (Sherri Nichols) writes:\n>In article <1993Apr6.141557.8864@alchemy.chem.utoronto.ca> golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy) writes:\n>>Anyways, crawl back into the hole you crawled out of...the NBA doesn't\n>>care where they get basketball players from, major league baseball\n>>doesn't give a damn where they get baseball players from (except Cuba,\n>>that is).\n>\n>MLB is perfectly willing to take players from Cuba. They just have to\n>defect first. \n>\n>Sort of like the situation used to be with Russian\/Czech\/etc hockey\n>players, until the political situation in those countries changed.\n>\n\nMajor league baseball has told the Blue Jays and the Expos not to\nsign Oscar Linares (I think that is his name)\n...Canada does not have the restrictions against\nCubans that the US has and other major league teams have told the\nCanadian teams that they would be very unhappy if the Expos or the\nBlue Jays would do this. Cubans players would not have to defect\nto play in Canada and could play the 81 home games for the Expos\nand Blue Jays without any trouble.\n\nGerald\n\n###\n\n","output":" hockey"} +{"input":"From: roger@crux.Princeton.EDU (Roger Lustig)\nSubject: Re: New Home for the Bosox!!!\nOriginator: news@nimaster\nNntp-Posting-Host: crux.princeton.edu\nReply-To: roger@astro.princeton.edu (Roger Lustig)\nOrganization: Princeton University\nLines: 30\n\nIn article <1993Apr15.132741.11322@scott.skidmore.edu> jrogoff@scott.skidmore.edu (jay rogoff) writes:\n\n>> I agree, though I'd also be happy with a stadium that looks\n>> like new Comiskey. The new park was also made for baseball.\n>> Unlike Three Rivers, the Vet, Riverfront, etc., it's not a\n>> football park in which they also play baseball.\n\n>While we're on the multipurpose subject, let's not forget Shea, which\n>was designed to accommodate both the Mets & Jets. It was the first\n>stadium (I think) to have the box seats on rollers so they could be\n>oriented at right angles for baseball & in parallel for football.\n\nNot the first. RFK, olim DC Stadium, was built 2 years earlier.\nNowadays they don't move the seats back for the few exhibition\ngames; but the 3rd-base\/LF lower deck used to move. It was all \nmetal, which was pretty noisy on Bat Day.\n\n>Of course, with the Jets gone to Jersey (and a truly good football\n>stadium), the Mets are saddled with a multipurpose stadium where,\n>because it's circular, the seats are almost always too far from the\n>action. The Mets announcers--Kiner & Murphy in particular--have\n>always hyped it as \"beautiful Shea\n>Stadium,\" a tipoff to how unbeautiful it truly is.\n\nIt's vastly better than it was before they fixed it, though. Back in\nthe late 70's it was a *dump*.\n\nRoger (don't you*like* jet noise?)\n\n###\n\n","output":" baseball"} +{"input":"Subject: Remarks by President Clinton to NCAA Division I Champion Hockey Team\nFrom: \"nigel allen\" \nReply-To: \"nigel allen\" \nDistribution: rec\nOrganization: Canada Remote Systems\nLines: 158\n\n\nHere is a press release from the White House.\n\n Remarks by President Clinton to NCAA Division I Champion Hockey Team\nApril 19; Q&A Following\n To: National Desk\n Contact: White House Office of the Press Secretary, 202-456-2100\n\n WASHINGTON, April 19 -- Following is a transcript\nof remarks by President Clinton to the University of Maine \"Black\nBears\" NCAA Division I hockey champions:\n\n The Rose Garden\n\n 9:58 A.M. EDT\n\n THE PRESIDENT: Good morning ladies and gentlemen. It's\nan honor for me to welcome the University of Maine Black Bears, the\nwinner of the NCAA Division I hockey national championship to the\nRose Garden and the White House. I understand from Senator Mitchell\nthat this is the first team from the University of Maine every to win\na national championship. And we're glad to have them here.\n\n I'm inspired not only by how the team pulled together to\nwin the championship, but how the entire state pulled together to\ncheer them onto victory.\n\n Coming from a state that is also relatively small in\nsize, but also filled with pride and tradition and community, I can\nunderstand how the people of Maine must feel about the Black Bears.\nIn our state people are still talking about the time we won the\nOrange Bowl over the number one ranked football team, and that was\nback in 1978. I'm sure that 15 years from now, the people of Maine\nwill as proud of this team as they are today.\n\n You know, in my state football is a slightly more\npopular sport than hockey. We don't have a lot of ice. (Laughter.)\nBut after spending three months getting banged around in this town, I\ncan understand a little more about hockey than I did before I came\nhere. Hockey is a tough game. It's a hard-hitting sport. It does\nhave one virtue though, there's a penalty for delay of game. I wish\nwe had that rule in the Senate. (Laughter.)\n\n In government as in hockey, leadership is important. In\nthe United States Senate, our team has a great captain, the Majority\nLeader and the senior Senator from Maine, George Mitchell; junior\nSenator -- Cohen looks so young, I can't imagine. (Laughter.) I'm\nactually bitter about Senator Cohen because he looks so much younger\nthan me.\n\n On your hockey team, the captain Jim Montgomery has done\na great job. He scored the winning goal late in the championship\ngame, leading you to a come-from-behind victory -- something else I\nknow a little bit about.\n\n Sport brings out the best in individuals and in teams\nand in communities. I share the pride that Senator Mitchell and\nSenator Cohen and Congressman Andrews and all the people of Maine\nmust feel for the Black Bears who have shown us all how to play as a\nteam, how to bring out the best in one another, and how to come from\nbehind.\n\n I think it's important, as I ask young people from\naround America who have achieved outstanding things in working\ntogether, to come here to the White House to be recognized and\nappreciated by their country, to remember that those kinds of values\nand those kinds of virtues need to be ingrained in all of us for all\nof our lives.\n\n We now have another role model, and I'm glad to have\nthem here today. (Applause.)\n\n (The President is presented with team jersey.)\n(Applause.)\n\n THE PRESIDENT: That's great. I love it. It's beautiful.\n(Applause.)\n\n (The President is presented with an autographed stick.)\n\n THE PRESIDENT: Thank you. That's great. (Applause.)\n\n * * * * * *\n\n Q Mr. President, did you authorize the move on Waco\nthis morning, sir?\n\n THE PRESIDENT: I was aware of it. I think the Attorney\nGeneral made the decision. And I think I should refer all questions\nto her and to the FBI.\n\n Q Did you have any instructions for her as to how it\nshould be executed?\n\n THE PRESIDENT: No, they made the tactical decisions.\nThat was their judgment, the FBI.\n\n Q Is this a raid?\n\n THE PRESIDENT: And I will -- I want to refer you to --\ntalk to the Attorney General and the FBI. I knew it was going to be\ndone, but the decisions were entirely theirs, all the tactical\ndecisions.\n\n Q What did you and Senator Mitchell talk about this\nmorning?\n\n Q Any chance for that stimulus package?\n\n THE PRESIDENT: Senator Mitchell ought to pay my\nquarter. (Laughter.) I was in there -- (laughter).\n\n SENATOR MITCHELL: You have to pay that quarter.\n\n THE PRESIDENT: I was ready. (Laughter.) Senator\nMitchell, he's worth a quarter any day.\n\n Q Any chance for your bill, sir?\n\n THE PRESIDENT: We talked about what was going to happen\nthis week in the Senate and about what other meetings we're going to\nhave for the rest of the week. We only had about five minutes to\ntalk. And we agreed we'd get back together later, around noon, and\ntalk some more.\n\n Q Senator Dole said over the weekend that your\ncompromise is no compromise.\n\n THE PRESIDENT: Well, I know he did, but, look, Senator\nDole and a lot of the other Republicans now in the Senate voted for\nthe same kind of thing for Ronald Reagan in 1983; and our research\nindicates that a majority of them over time voted for a total of 28\nemergency spending measures totalling over $100 billion when Reagan\nand Bush were President, in those administrations. And many of those\npurposes were not nearly as worthy as putting the American people\nback to work. I don't want to go back and revisit every one, but you\n\n\ncan do it. You can look at the research there. So this position\nthey're taking is not credible. We have a very tough five-year\ndeficit reduction plan. All these costs are covered during that time\nand then some. And the very people that are saying this has all got\nto be paid for don't have much of a history on which to base their\nposition. They've got 12 years of vote for stimulus measures of this\nkind that had very little to with putting the American people back to\nwork. So I think we've got a chance to work it out, and I'm hopeful.\nWe'll see what happens today and tomorrow. I'm feeling pretty good\nabout it.\n\n THE PRESS: Thank you\n\n END 10:10 A.M. EDT\n\n -30-\n\n--\nCanada Remote Systems - Toronto, Ontario\n416-629-7000\/629-7044\n\n###\n\n","output":" hockey"} +{"input":"From: maynard@ramsey.cs.laurentian.ca (Roger Maynard)\nSubject: Re: Jack Morris\nOrganization: Dept. of Computer Science, Laurentian University, Sudbury, ON\nLines: 33\n\nIn <1993Apr19.024222.11181@newshub.ariel.yorku.ca> cs902043@ariel.yorku.ca (SHAWN LUDDINGTON) writes:\n\n>Hey Valentine, I don't see Boston with any world series rings on their\n>fingers. Damn, Morris now has three and probably the Hall of Fame in his \n>future. Therefore, I would have to say Toronto easily made the best \n>signing. And don't tell me Boston will win this year. They won't \n>even be in the top 4 in the division, more like 6th.\n\nYeah Valentine, how many rings does Clemens have? \n\nNothin' like good old fashioned Canadian logic...\n\nBTW: The only good thing I can say about the Jay's rotation this year\nis that it could have been worse. Stewart might have stayed healthy.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n-- \n\ncordially, as always, maynard@ramsey.cs.laurentian.ca \n \"So many morons...\nrm ...and so little time.\"\n\n###\n\n","output":" baseball"} +{"input":"From: tedward@cs.cornell.edu (Edward [Ted] Fischer)\nSubject: Re: Best Homeruns\nOrganization: Cornell Univ. CS Dept, Ithaca NY 14853\nLines: 18\n\nIn article <1qn6tqINNmnf@senator-bedfellow.MIT.EDU> cmk@athena.mit.edu (Charles M Kozierok) writes:\n>\n>the best home run i have *ever* seen came off, believe it or not,\n>Roger Clemens (sorry, Val) a couple of years ago. he threw a ball to\n>Incaviglia which was literally at Inky's neck, and he absolutely \n>hammered the crap out of it. after the swing, Clemens nonchalantly\n>motioned for a new ball--he didn't even turn around to look, or\n>even get upset. the ball hit the lights in the left-field standard,\n>some 70 or so feet about the Green Monster (over 100 feet above the\n>ground total!)\n>\n>truly an amazing shot.\n\nI agree. Home runs off Clemens are always memorable. Kinda like\neclipses and hurricanes. They don't happen very often.\n\nCheers,\n-Valentine\n\n###\n\n","output":" baseball"} +{"input":"From: niguma@ug.cs.dal.ca (Gord Niguma)\nSubject: Re: Notes on Jays vs. Indians Series\nNntp-Posting-Host: ug.cs.dal.ca\nOrganization: Math, Stats & CS, Dalhousie University, Halifax, NS, Canada\nDistribution: na\nLines: 22\n\nIn klopfens@andy.bgsu.edu (Bruce Klopfenstein) writes:\n\n>cmk@athena.mit.edu (Charles M Kozierok) writes:\n>> In article <1993Apr13.195301.22652@CSD-NewsHost.Stanford.EDU> nlu@Xenon.Stanford.EDU (Nelson Lu) writes:\n>> } \n>> } Guess which line is which:\n>> } \tBA\tOBP\tSLG\tAB\tH\t2B\t3B\tHR\tBB\n>> } X\t.310\t.405\t.427\t571\t177\t27\t8\t8\t87\n>> } Y\t.312\t.354\t.455\t657\t205\t32\t1\t20\t35\n\n\n>I just love how the Alomar fans left RBIs off this list. Give me a break!\n\n Alomar fans left RBI fans and Runs off this list because they are dependant\non the team. (To a large extent). If Frank Thomas hit first, he'd lose a LOT\nof RBI's; and anyways how many 2nd place hitters have you known to drive\nin 100 runs? Doesn't happen that often.....very unlikely with Devon White's\n~.300 OBP in front of you...\n\n\t\t\t\t\t\tGord Niguma\n\t\t\t\t\t\t(fav player: John Olerud)\n\n###\n\n","output":" baseball"} +{"input":"From: tedward@cs.cornell.edu (Edward [Ted] Fischer)\nSubject: Re: Notes on Jays vs. Indians Series\nOrganization: Cornell Univ. CS Dept, Ithaca NY 14853\nDistribution: na\nLines: 21\n\nIn article <1993Apr15.212014.1782@news.acns.nwu.edu> edo@casbah.acns.nwu.edu (Edward Ouellette) writes:\n>\n>My point? RBI might not be a perfect stat but nothing is. And no stat (or lack\n>of) can tell me there are no clutch hitters. Maybe no stat CAN tell me,\n>either, but some people are... I just know it!!! 8)\n\nI was *hoping* somebody would mention clutch. Clutch? Baerga? The\ntwo words simply do not go together. With runners in scoring\nposition, Baerga batted .308\/.366\/.418 last year. This doesn't quite\n*suck*, but most batters hit *better* in this situation.\n\nAlomar? He hit .354\/.439\/.517 with runners in scoring position!\n\nThe difference? Alomar had 68 RBIs in 147 such AB. Baerga had 81\nRBIs in 182 such AB. Baerga got 25% more chances, yet succeeded only\n20% more times.\n\nFrankly, I don't believe in clutch. But if I did, my vote would\ngo to Alomar for MVP (let alone \"best 2B in the AL\").\n\n-Valentine\n\n###\n\n","output":" baseball"} +{"input":"From: pereira@CAM.ORG (Dean Pereira)\nSubject: Canadiens - another Stanley Cup???\nOrganization: Champlain Regional College, St-Lambert QC CANADA\nLines: 12\n\n\n\t\tWith the kind of team Montreal has now, they can take the\ncup easily. The only problem they have right now is that everyone is\ntrying to steal the show and play alone. They need some massive teamwork.\n\tThey are also in a little of a slump because long-time hockey\nMontreal Canadiens announcer Claude Mouton died last tuesday and it was\nrough on everybody because he has worked with the organization for 21\nyears. But I know that is no excuse. But if the Habs manage to get some\ngood teamwork and get into the spirit, they should have no problem\nwinning in May.\n\n\t\t\t\t\t\tDean\n\n###\n\n","output":" hockey"} +{"input":"From: golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy)\nSubject: Re: RUMOUR - Keenan signs with Rangers?\nOrganization: University of Toronto Chemistry Department\nLines: 22\n\nIn article <1993Apr16.171347.784@news.columbia.edu> gld@cunixb.cc.columbia.edu (Gary L Dare) writes:\n>\n>UPI Clarinet has just relayed a \"scoop\" from the Toronto Sun\n>(or was that Star? I like the Star myself ...) that Iron Mike\n>Keenan has come to an agreement with the New York Rangers for\n>next season. Interestingly, this comes the day after the Times\n>Sports had an editorial about how the Rangers need their own\n>Pat Riley ... who cares about what happens after next season?\n>\n\nThe rumour was basically everywhere in Toronto based on reports\nthat Keenan has told both San Jose and Philadelphia that he\nwas no longer interested in pursuing further negotiations with\neither team. \n\nThe Ranger announcement is supposed to happen tomorrow supposedly.\n\nThe Rangers have so many veterans that they had to get a coach\nwith \"weight\" and a proven record...and whom they know Messier respects.\n\nGerald\n\n###\n\n","output":" hockey"} +{"input":"From: darling@cellar.org (Thomas Darling)\nSubject: Re: WHERE ARE THE DOUBTERS NOW? HMM?\nOrganization: The Cellar BBS and public access system\nLines: 18\n\njason@studsys.mscs.mu.edu (Jason Hanson) writes:\n\n> In article <1993Apr4.051942.27095@ramsey.cs.laurentian.ca> maynard@ramsey.cs.\n> >\n> >And after the Leafs make cream cheese of the Philadelphia side tomorrow\n> >night the Leafs will be without equal.\n> \n> Then again, maybe not.\n\nTo put it mildly. As I watched the Flyers demolish Toronto last night, 4-0,\nI realized that no matter how good the Leafs' #1 line may be, they'll need\none or two more decent lines to go far in the playoffs. And, of course, a\nhealthy Felix Potvin.\n\n^~^~^~^~^~^~^~^~^\\\\\\^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^\nThomas A. Darling \\\\\\ The Cellar BBS & Public Access System: 215.539.3043\ndarling@cellar.org \\\\\\ GEnie: T.DARLING \\\\ FactHQ \"Truth Thru Technology\"\nv~v~v~v~v~v~v~v~v~v~\\\\\\~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v\n\n###\n\n","output":" hockey"} +{"input":"From: layfield@cpsc.ucalgary.ca (Colin Layfield)\nSubject: Re: Smiths birthday goal was LEAFS GO ALL THE WAY !!!\nOrganization: University of Calgary Computer Science\nLines: 23\n\nIn article mwm@aps.anl.gov writes:\n>In article 5KL@undergrad.math.uwaterloo.ca, kwk2chow@descartes.uwaterloo.ca (KEVIN C.) writes:\n>> (Thanks for the goals by Steve Smith) \n>I don't see why more people don't blame grant fuhr for the goal that smith \n>put in his own net, it's common to play the puck back to your own goalie when\n>deep in your own end and under little or no pressure from the offensive team.\n>If fuhr had been in position the puck would have never crossed the line.\n>\n>Mike McDowell\n\nI have to disagree with you on this one. It is anything BUT common. In the\n4 or 5 years I have been watching hockey I have NEVER seen this happen EVER.\n\nI am not sure what league you have been watching. :-)\n\nAnyone else agree with this?\n\n Colin Layfield | \"Religion and Sex are power plays,\n | Manipulate the people for the money they pay,\n The University of Calgary | Selling Skin, Selling God\n Computer Science | The numbers look the same on their CREDIT CARDS!\"\n layfield@cpsc.ucalgary.ca | - Queensryche\n\n###\n\n","output":" hockey"} +{"input":"From: dchhabra@stpl.ists.ca (Deepak Chhabra)\nSubject: Re: div. and conf. names\nNntp-Posting-Host: stpl.ists.ca\nOrganization: Solar Terresterial Physics Laboratory, ISTS\nDistribution: na\nLines: 56\n\nIn article <1993Apr19.003221.11964@ramsey.cs.laurentian.ca> maynard@ramsey.cs.laurentian.ca (Roger Maynard) writes:\n[Evan Pritchard writes:]\n\n>>\tI think that you are incorrect, Roger. Patrick,\n>>Smythe and Adams all played or coached in the league before becoming\n>>front office types. Hence, they did help build the league, although\n>>they were not great players themselves. \n>\n>Punch Imlach's contributions as a coach and GM were far greater than\n>those of the above combined. Should we name a division or trophy after\n>him? [owner vs. player contributions deleted...]\n>Are we going to honour those who contributed to the league's evolution\n>or are we going to honour those who contributed to the glory of the \n>sport itself? \n\n[stuff deleted...]\n\n>The money issue is irrelevant to the point that we would agree on, and\n>that is: \"it is the players that are what make the game great and not the\n>people who put them on the ice\"\n \nAs I recall, the author of the _original_ article that started the thread\nclaimed that he disliked the changing of the names for a variety of reasons. \nRoger, on one front you flamed him rather severely on the grounds that his\nwas a \"jingoistic rant\", but you also supported the name-changing on the\ngrounds that the current names are inappropriate because of the individuals\nthey represent. FWIW, I do not think the flaming was warranted, nor do I \nthink you enhanced what credibility you have with it at all. Just an \nobservation...\n\nHowever, that aside, the real question is whether you like the idea of\nchanging the names based on the reasons given for it (making it easier for\nthe 'casual fan'), or whether you like the idea of unique divisional names\nbased on individuals who do deserve the honour. IMO, the latter is a nice\nand unique touch that differs from other sports. In addition, I do not\nthink that changing divisional names will have an effect on the number of\npeople that are interested in hockey, so it's a pointless exercise anyway.\n\nIf the current names are inappropriate, then that is a separate issue, not \ncentral to the original article. Something to consider additionally is\nwhether or not players like Orr who 'contributed to the glory of the sport'\nwould have been able to do so _without_ an organized professional league to\nplay in. In this case, honouring builders of the _league_ as opposed to\nbuilders of the _sport_ becomes a chicken-and-egg type question. (although\nit was the chicken.....)\n\n>Exactly true. Naming divisions and trophies after Smythe and the bunch\n>is the same kind of nepotism that put Stein in the hall of fame. I have\n>always thought that this was nonsense.\n\nDunno if the Stein comparison is justifiable, since it doesn't look as though\nhis 'unanimous acceptance' to the Hall will hold up.\n\n\n--\ndchhabra@stpl.ists.ca\n\n###\n\n","output":" hockey"} +{"input":"From: tvartiai@vipunen.hut.fi (Tommi Vartiainen)\nSubject: Re: TPS will stay on the top...\nNntp-Posting-Host: vipunen.hut.fi\nOrganization: Helsinki University of Technology, Finland\nLines: 15\n\nIn <1993Apr6.171611.1@tnclus.tele.nokia.fi> hahietanen@tnclus.tele.nokia.fi writes:\n>BTW. Is Juha Yl|nen (centre, HPK) drafted by the Jets?? During last year\n>he has reached the top level among Finnish centres. He had very good\n>playoff games against TPS!\n\nI'm not sure about Juha, but another top center, Rauli Raitanen([ss{t)\nis drafted by Jets. Raitanen had very good year and he has played in the\nFinnish nationalteam. I believe that he'll be one of the best finns in\nthis year's WC, if Matikainen(Head coach) elects him to the team.\n\n> Hannu\n\n Tommi\n\n###\n\n","output":" hockey"} +{"input":"From: ferguson@cs.rochester.edu (George Ferguson)\nSubject: Re: ABC coverage\nReply-To: ferguson@cs.rochester.edu (George Ferguson)\nOrganization: University of Rochester Hockey Science Dept.\nDistribution: usa\n\n\nIn article Anna Matyas writes:\n>Thorne is good and I've always been a fan of Clement (but I miss\n>Mike Emrick!). My boyfriend, who is not a hockey fan, even looked up\n>at one point and said, \"These guys are pretty good announcers.\" (This\n>is the same guy who said that Rick Tocchet looks like Charles Bronson...:)\n\nDid your boyfriend comment on the fact that Clement looks like a\nwalking ad for Brillo pad hair replacement therapy? The guy's just a\nstuffed shirt who thinks he's the greatest hockey analyst since Howie\nMeeker (for gosh sakes). I'll take Schoenie any day.\n\nGeorge\n\n-- \nGeorge Ferguson ARPA: ferguson@cs.rochester.edu\nDept. of Computer Science UUCP: rutgers!rochester!ferguson\nUniversity of Rochester VOX: (716) 275-2527\nRochester NY 14627-0226 FAX: (716) 461-2018\n\n###\n\n","output":" hockey"} +{"input":"From: gld@cunixb.cc.columbia.edu (Gary L Dare)\nSubject: Re: The guy who bad-mouthed Ulf...\nNntp-Posting-Host: cunixb.cc.columbia.edu\nReply-To: gld@cunixb.cc.columbia.edu (Gary L Dare)\nOrganization: PhDs In The Hall\nLines: 14\n\nPatrick Walker writes:\n>\n>If he ever tried some like that on a Yzerman, he'd \n>would have to deal with Probert now wouldn't he?\n\nDo you realize how many smiles are crossing faces after you wrote that?\n(-;\n\ngld\n--\n~~~~~~~~~~~~~~~~~~~~~~~~ Je me souviens ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGary L. Dare\n> gld@columbia.EDU \t\t\tGO Winnipeg Jets GO!!!\n> gld@cunixc.BITNET\t\t\tSelanne + Domi ==> Stanley\n\n###\n\n","output":" hockey"} +{"input":"From: binkley@let.rug.nl (P.A. Binkley)\nSubject: Re: Jewish Baseball Players?\nLines: 7\nNntp-Posting-Host: pco204a.let.rug.nl\nOrganization: Faculteit der Letteren, Rijksuniversiteit Groningen, NL\n\nThere was an article on Jewish major leaguers in a recent issue of \"Elysian \nFields\", what used to be the \"Minnesota Review of Baseball\". As I recall, \nit had an amazing amount of research, with a long list of players and a \nlarge bibliography.\n\nPeter Binkley\nbinkley@let.rug.nl\n\n###\n\n","output":" baseball"} +{"input":"From: hamlet@stein.u.washington.edu (Mitch McGowan)\nSubject: Minnesota recalls McGowan (HELP!!!)\nOrganization: University of Washington\nLines: 24\nNNTP-Posting-Host: stein.u.washington.edu\n\n Derian Hatcher's game-misconduct penalty was rescinded by the NHL, \nallowing the Minnesota defenseman to play in the North Stars' last two \nregular-season games. Hatcher was given the penalty during a fight at \nthe end of a loss at St. Louis on Sunday, April 11. But the league \ndidn't rescind the game-misconduct penalty Shane Churla received. The \nStars recalled center Cal McGowan from their top minor league club in \nKalamazoo, Mich., to replace Churla.\n\nThe above is courtesy of The Washington Times on-line service.\n\nNow, here's where I need help. If anyone out there has a tape of Tuesday's\nChicago-Minnesota game, please contact me. Terms will be favorable.\n\nAlso, if anyone can tape tonight's Minnesota-Detroit game, please contact\nme. This could be quite important. Once again, I will make it worth\nyour trouble.\n\nThanks to all.\n\n--\nrec.sport.hockey contact for Minnesota North Stars\nand maintainer of the r.s.h FAQ file\nMitch McGowan a.k.a. | KALAMAZOO WINGS | MINNESOTA NORTH STARS |\nhamlet@u.washington.edu | ST. KILDA SAINTS | TORONTO BLUE JAYS |\n\n###\n\n","output":" hockey"} +{"input":"From: st902415@pip.cc.brandeis.edu (Adam Levin)\nSubject: Early BBDDD Returns?\nReply-To: st902415@pip.cc.brandeis.edu\nOrganization: Brandeis University\nLines: 13\n\nJust curious if anyone has started to standout early in the season in the\nBB DDD this year. I expect the Phillies staff, while getting the wins,\nwould have to rank up there. Luis Gonzalez and Derrick May are among\nthe early league leaders, and all 6 of their bombs have come at the\nPhils' expense. Neither of them have exactly been know for their tater\nprowess in the past. \n\nHow have the Rockies been early? I know Mile High has produced a ton of \nruns, but is it the launching pad everyone expected yet? \n\nA concerned fan of the BB DDD,\n\nAdam \"Witness to the Phillies lone loss of the season so far\" Levin\n\n###\n\n","output":" baseball"} +{"input":"From: andrew@idacom.hp.com (Andrew Scott)\nSubject: Re: This year's biggest and worst (opinion)...\nOrganization: IDACOM, A division of Hewlett-Packard\nKeywords: NHL, awards\nLines: 35\n\nIn article smale@healthy.uwaterloo.ca (Bryan Smale) writes:\n>\n>I was thinking about who on each of the teams were the MVPs, biggest\n>surprises, and biggest disappointments this year. Now, these are just\n>my observations and are admittedly lacking because I have not had an\n>opportunity to see all the teams the same amount. Anyway....\n> \n>Team: MVP: Surprise: Disappointment:\n>-----------------------------------------------------------------------\n>Edmonton Oilers Manson Buchberger Mellanby\n\nWell, since the Oilers didn't win a heck of a lot of games, I'm not sure\nthey deserve and MVP (\"can't win without him\"). However, I'd suggest Kelly\nBuchberger instead of Dave Manson, who has had a brutal year, his pick for\nthe All-Star game notwithstanding.\n\nAs for biggest surprise, I'd say that Buchberger had higher expectations\nthis year due to his \"breakthrough\" year (for him) last year, so he didn't\nreally raise his game. My suggestion would be Shjon Podein, one of the\ncallups from Cape Breton during the year. He was quite far down on the\ndepth chart in the Oilers stable of prospects, but made a big impact on\nthe team. He has 12 goals in his 33 games and is only -1. Those are decent\nnumbers for a third-line player who was seemingly doomed to minor-league\noblivion. The Oilers coaching staff likens his style to John Tonelli.\nI think he'll be on the full-time roster next year.\n\nAs for biggest disappointment, you could name any of the players the Oilers\ndumped for lousy production this year (Nicholls, Gilchrist, Tikkanen) or\neven Shayne Corson, but Mellanby isn't far off.\n\n-- \nAndrew Scott | andrew@idacom.hp.com\nHP IDACOM Telecom Division | (403) 462-0666 ext. 253\n\nDuring the Roman Era, 28 was considered old...\n\n###\n\n","output":" hockey"} +{"input":"From: snichols@adobe.com (Sherri Nichols)\nSubject: Re: Why Spanky?\nOrganization: Adobe Systems Incorporated\nLines: 18\n\nIn article <1ql93bINN1s5@postoffice1.psc.edu> boone@psc.edu (Jon Boone) writes:\n> Spanky is too slow! If he were quicker, he would still be here.\n>But with Slaught and Tom Prince, they didn't want to lose Prince in order\n>to bring up that 11th pitcher. Slaught is about as good as Spanky and\n>Prince is coming along nicely!\n\nTom Prince is a 28 year old no-hit catcher. Think of him as a young Dann\nBilardello. I can't begin to fathom why the Pirates have been so afraid of\nlosing this guy, who's been in AAA most of the last 5 seasons. The Pirates\nreleased Kirk Gibson last year because Prince was out of options, then\neventually sent Prince down anyway, and he cleared waivers without a peep.\nHe's another year older, and still can't hit; why do they think he wouldn't\nclear waivers now? Why would they care?\n\nSherri Nichols\nsnichols@adobe.com\n\n###\n\n","output":" baseball"} +{"input":"From: dswartz@osf.org (Dan Swartzendruber)\nSubject: Re: Best Homeruns\nOrganization: Open Software Foundation - Research Institute\nLines: 16\n\nIn article <4200419@hpcc01.corp.hp.com> boell@hpcc01.corp.hp.com (Donald P Boell) writes:\n>I'd have to say the most impressive HRs I've ever see came from Dave Kingman\n>and his infamous moon-raker drives...\n\nI remember one he hit circa 1976 at Wrigley Field that went across\nthe street (in dead center field) and hit a house on the roof. He\nwhiffed a lot, but when he *did* connect, watch out!\n\n\n\n\n-- \n\n#include \n\nDan S.\n\n###\n\n","output":" baseball"} +{"input":"From: u96_msopher@vaxc.stevens-tech.edu\nSubject: With a surge in the last two weeks...\nLines: 24\nOrganization: Stevens Institute Of Technology\n\n\n\n\nLadies and gentlemen, boys and girls, lend me your ears for but a moment,\n\n\n\n\tThe National Legue Eastern Division Champions will be the...\n\n\n\n \t\t\tPhiladelphia Phillies\n\n\n\t\tI one hundred and ten percent guarantee!!!\n\n\n\n\tChamberlain Hollins Dykstra Incaviglia Jackson Williams\n\tDaulton Greene Kruk Mulholland Rivera Thompson Duncan\n\n\n\t\t\tWatch us soar in 1993!\n\n###\n\n","output":" baseball"} +{"input":"From: jimg@cybernet.cse.fau.edu (Jim Gorycki)\nSubject: Panther's President\nOrganization: Cybernet BBS, Boca Raton, Florida\nLines: 46\n\nAs I promised, I would give you the name of the Panther's president.\nAfter Huizenga announced the team name, he announced that Bill\nTorrey is named the first president of the Panthers.\n\nA little Bio from _Sun-Sentinel_\nTorrey, the architect of four consecutive Stanley Cup champions as \npersident and general manager of the New York Islanders.\nThroughout his 27 years in the NHL, Bill Torrey's bow ties have become\nas much of a signature as Andre Agassi's hair.\n\nThe Panthers will introduce a uniform, insignia, and ticket-price \ninformation in early next month. In the meantime, Huizenga leaves the\nday-to-day operation in the hands of Torrey and Bob Clarke, the VP and\nGM.\n\nThe Florida Panthers was chosen as the name of South Florida's NHL team\nto focus attention on an endangered species. There are 30 to 50 Florida\nPanthers in the Everglades National Park, the Big Cypress National \nPreserve and other parts of southwestern Florida.\n\n\"The Panther is the quickest-striking of all cats,\" Torrey said. \n\"Hopefully that's the way we'll play on ice.\"\n\nMore BIO:\nIn Torrey, Huizenga has the first man hired by the expansion Islanders\nin 1972 and the one most responsible for guiding the Islanders to four\nconsecutive Stanley Cup championships (their first after only eight\nseasons) and 14 consecutive winning seasons. As executive vice president\nof the California Golden Seals, Torrey watched the Seals go to the play-\noffs in 1968, only their second NHL season.\n\n\"I guess this completes my own personal hat trick\", said Torrey, 58, a\nnative of Montreal but a resident of Bear Lakes Country Club in Palm\nBeach.\n\nJim G.\nother accounts:\ngorycki@sol.cse.fau.edu\njimg@cybernet.cse.fau.edu\n\n--------------------------------------------------------------------\n\"I repeat myself when under stress. I repeat myself when under stress.\nI repeat myself when under stress. I repeat myself when under stress.\nI repeat...\" Adrian Belew, \"Indicipline\"\n---------------------------------------------------------------------\n\n###\n\n","output":" hockey"} +{"input":"From: cubrj@uxa.ecn.bgu.edu (Brian Johnson)\nSubject: the hawks WILL return to the finals!!!!!\nOrganization: Educational Computing Network\nLines: 11\nDistribution: world\nNNTP-Posting-Host: uxa.ecn.bgu.edu\n\nWell now that the hawks have won the division the road is a little\neasier for the playoffs. Let toronto and detroit beat the hell out of\neach other while Chicago sweeps st.louis. That just makes it easier in\nthe second round with all the rest they will get and tor\/det getting\nnone. For the conf. champ they will have a hard time versus the division\nbut that div. will be pretty battered also so the advantage goes to the\nHawks again. Then bring pitt. and sure the Hawks will probably lose but\nits better to get that far and lose than to not go.\n\nbrian\n\n###\n\n","output":" hockey"} +{"input":"From: maynard@ramsey.cs.laurentian.ca (Roger Maynard)\nSubject: Re: hawks vs leafs lastnight\nOrganization: Dept. of Computer Science, Laurentian University, Sudbury, ON\nDistribution: na\nLines: 33\n\nIn <1993Apr18.153820.10118@alchemy.chem.utoronto.ca> golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy) writes:\n\n>In article <93106.082502ACPS6992@RyeVm.Ryerson.Ca> Raj Ramnarace writes:\n>>did anyone else see this game last night ? just like a playoff game!!\n>>lots of hitting...but I was disappointed by the video goal judge...\n>>on all replays, joe murphy's goal shouldn't have counted ! it didn't go in net\n>>!! and according to the tsn broadcasters, the video goal judge said that he\n>>saw the water bottle on top of the cage move so he assumed the puck went in!\n>>this is terrible...hope crap like this doesn't occur in the playoffs!\n>>the game would have ended in 2-2 tie !\n\n>I thought the red light went on...thus, in the review, the presumption\n>would be to find conclusive evidence that the puck did not go in the\n>net...from the replays I say, even from the rear, the evidence wasn't\n>conclusive that the puck was in or out...in my opinion...\n\nIt seemed pretty conclusive to me. The puck clearly hit the crossbar\nand then came down on the line. And the announcers, admittedly homers,\nkept harping about how they \"must have had a different view upstairs\"\nbecause it was obvious to them, and, I would have thought, to anyone who\nsaw the replay, that the puck didn't go in. The referee originally \nsignalled no goal but the video replay \"judges\" initiated contact with\nthe referee to claim that a goal was in fact scored. This, to me, is\nunheard of. Seeing stuff like this happen gives me a bad feeling about\nthe Leaf chances this year.\n\ncordially, as always,\n\nrm\n\n-- \nRoger Maynard \nmaynard@ramsey.cs.laurentian.ca\n\n###\n\n","output":" hockey"} +{"input":"Organization: University of Notre Dame - Office of Univ. Computing\nFrom: \nSubject: Re: Boog Powell (was re: CAMDEN YARDS)\n <1993Apr13.150904.25249@alchemy.chem.utoronto.ca>\nLines: 9\n\nIn article <1993Apr13.150904.25249@alchemy.chem.utoronto.ca>, Mark B. says:\n>\n> Was he better than Balboni?\n>\n\nthis borders on blasphemy.\n\nbob vesterman.\n\n###\n\n","output":" baseball"} +{"input":"From: v124p7kk@ubvmsc.cc.buffalo.edu (Darryl S Brooks)\nSubject: Re: Too Many Europeans in NHL (Euro-bashing?)\nOrganization: University at Buffalo\nLines: 60\nNews-Software: VAX\/VMS VNEWS 1.41\nNntp-Posting-Host: ubvmsc.cc.buffalo.edu\n\nIn article , rauser@fraser.sfu.ca (Richard John Rauser) writes...\n> \n> \n> Here's the point: there are far too many Europeans in the NHL. I am sick\n>of watching a game between an American and a Canadian team (let's say, the\n>Red Wings and the Canucks) and seeing names like \"Bure\" \"Konstantinov\" and\n>\"Borshevshky\". Is this North America or isn't it? Toronto, Detriot, Quebec,\n>and Edmonton are particularly annoying, but the numbers of Euros on other\n>teams is getting worse as well. \n> \n> I live in Vancouver and if I hear one more word about \"Pavel Bure, the\n>Russian Rocket\" I will completely throw up. As it is now, every time I see\n>the Canucks play I keep hoping someone will cross-check Bure into the plexiglassso hard they have to carry him out on a stretcher. (By the way, I'm not a\n>Canucks fan to begin with ;-). \n> \n> Okay, the stretcher remark was a little carried away. But the point is that\n>I resent NHL owners drafting all these Europeans INSTEAD of Canadians (and\n>some Americans). It denies young Canadians the opportunity to play in THEIR\n>NORTH AMERICAN LEAGUE and instead gives it to Europeans, who aren't even\n>better hockey players. It's all hype. This \"European mystique\" is sickening,\n>but until NHL owners get over it, Canadian and American players will continue\n>to have to fight harder to get drafted into their own league.\n> \n> With the numbers of Euros in the NHL escalating, the problem is clearly\n>only getting worse.\n> \n> I'm all for the creation of a European Hockey League, and let the Bures\n>and Selannes of the world play on their own continent.\n> \n> I just don't want them on mine.\n> \n> \n\tAh, so now we're into European player bashing? What next? \nNo more French Canadiens? Yeah, there's an idea! Let them French-\nspeaking Canadiens have their own hockey league! We don't want them!\n\tAre you _CRAZY_? The NHL is one of the true international\nleagues, and yes, there _ARE_ many Europeans who deserve to play in\nthe NHL and are better than some North Americans, look at Teemu!!!\nI, for one, am glad to see Europeans in the NHL and I hope the\nNHL soon expands to Europe. Its nice to see all these different\npeople come together to form the (soon to be) 26 hockey teams.\n\t\n> \n> \n>-- \n>Richard J. Rauser \"You have no idea what you're doing.\"\n>rauser@sfu.ca \"Oh, don't worry about that. We're professional\n>WNI outlaws - we do this for a living.\"\n>-----------------\n>\"Remember, no matter where you go, there you are.\" -Dr.Banzai\n\nDarryl Brooks University at Buffalo\n __ ______ \/\/\/\n | | \/ \\ \\ \\ \/ \/ \/ _____ \/ \/ \/\/\/\/\n | | \/ \/\\ \\ \\ \\___\/ \/ ( \\ ---\/-\/--- \/\/\/\n | | \/ \/__\\ \\ \\ \/ \\ \\ ---\/-\/--- \/\/\/\n| |____| | \/ ____ \\ | | ____\\ ) \/ \/ \/\/\/\n \\______\/ \/ \/ \\ \\ | | ______\/ \/\/\/\/\/\/\/\n\n Go Bills, Sabres, and Magic!!\n\n###\n\n","output":" hockey"} +{"input":"From: tedward@cs.cornell.edu (Edward [Ted] Fischer)\nSubject: Re: Defensive Averages 1988-1992 -- Shortstop\nOrganization: Cornell Univ. CS Dept, Ithaca NY 14853\nLines: 13\n\nIn article <1993Apr17.200602.8229@leland.Stanford.EDU> addison@leland.Stanford.EDU (Brett Rogers) writes:\n>In article steph@pegasus.cs.uiuc.edu (Dale Stephenson) writes:\n>>>Smith, Ozzie .742 .717 .697 .672 .664 0.701\n>> The Wizard's 1988 is the second highest year ever. Still very good,\n>>but I don't like the way his numbers have declined every year. In a few\n>>years may be a defensive liability.\n>\n>That's rich... Ozzie Smith a defensive liability...\n\nWhy not? Brooks Robinson is a defensive liability too, and Ted\nWilliams is a weak hitter. Even great players decline as they age.\n\n-Valentine\n\n###\n\n","output":" baseball"} +{"input":"From: luriem@alleg.edu The Liberalizer (Michael Lurie)\nSubject: Yankee Meditations.\nArticle-I.D.: alleg.1993Apr6.205911.2654\nOrganization: Allegheny College\nLines: 14\n\n\nDo you realize that the yankees are paying Matt Nokes 2,500,000 dollars \nthis year!!!! GEESH. And Maas only gets 125,000. \n\n\n\nBy the way, the yankees are going to WIN IT ALL\n\n\nYankees are the BEST.\n\n\n\nBy the way, JT Snow, an ex-yankee, will be rookie of the year.\n\n###\n\n","output":" baseball"} +{"input":"From: bbs-comarow@jwt.oau.org (Bob Comarow)\nSubject: Re: Jewish Baseball Players?\nReply-To: bbs-comarow@jwt.oau.org\nOrganization: The Matrix\nLines: 4\n\nDave Kingman is Jewish\n\nbob\ncomarow@eisner.decus.org\n\n###\n\n","output":" baseball"} +{"input":"Subject: Re: Players Rushed to Majors\nFrom: admiral@jhunix.hcf.jhu.edu (Steve C Liu)\nExpires: 5\/9\/93\nDistribution: usa\nOrganization: Homewood Academic Computing, Johns Hopkins University, Baltimore, Md, USA\nSummary: Big Ben\nNNTP-Posting-Host: jhunix.hcf.jhu.edu\nLines: 25\n\nI don't know if you could call him rushed, but \"Big\" Ben McDonald didn't\nmuch time at all in the minors. Of course that was because the balls used\nin AAA had seams too large and gave McDonald blisters forcing him to go\non the DL several times. He's done most of his learning here in the majors.\nOf course Gregg \"Wild Thing\" Olson and Mike \"Deserved a Cy Young\" Mussina\ndidn't spend much time in the minors either. I read somewhere that pitchers\nare less likely to need that much time in the minors anyway so maybe that\nhas something to do with it.\nLet's go O's! Why Not?\nAdmiral Steve \"Still reliving Sept. 30, 1989\" Liu\n____________________________________________________________________________\n|Admiral Steve C. Liu Internet Address: admiral@jhunix.hcf.jhu.edu|\n|Commander-In-Chief of the Security Division of the Pi Club - Earth Chapter|\n| President of the Earth Chapter of the Pi Club - Founded April 1990 |\n|1993 World Champions - Baltimore Orioles - Why Not? - Series in the Yards|\n| 1992-1993 Stanley Cup Champions - Washington Capitals |\n| \"Committee for the Liberation and Intergration of Terrifying Organisms |\n| and their Rehabilitation Into Society, the only problem is that the |\n| abbreviation is CLITORIS.\" from the \"Polymorph\" episode of Red Dwarf |\n|*****The Bangles are the greatest female rock band that ever existed!*****|\n| This sig has been brought to you by... Frungy! The Sport of Kings! |\n|\"My God man, drilling holes through his head is not the answer!\" Dr. McCoy|\n|\"You know, Susanna Hoffs has a really nice ass.\" - comment by M. Flanagan |\n| The Pi Club - Creating the largest .signatures for the past nine months | \n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n###\n\n","output":" baseball"} +{"input":"From: Eastgate@world.std.com (Mark Bernstein)\nSubject: Jewish Broadcasters (was Jewish Baseball Players?)\nOrganization: The World Public Access UNIX, Brookline, MA\nLines: 8\n\nFor that matter, how many Gentleman of The Press Box have been Jewish? The\nonly Jewish sportscaster that comes to mind is Steve Williams (?), who had\na Phillies show on KYW in Philadelphia in the 80s.\n-- \nMark Bernstein\nEastgate Systems, Inc. 134 Main Street Watertown MA 02172 USA\nvoice: (800) 562-1638 in USA +1(617) 924-9044\nEastgate@world.std.com Compuserve: 76146,262 AppleLink:Eastgate\n\n###\n\n","output":" baseball"} +{"input":"From: gballent@hudson.UVic.CA (Greg Ballentine)\nSubject: Re: Wings will win\nNntp-Posting-Host: hudson.uvic.ca\nReply-To: gballent@hudson.UVic.CA\nOrganization: University of Victoria, Victoria, BC, Canada\nLines: 25\n\n\nIn article 735249453@vela.acs.oakland.edu, ragraca@vela.acs.oakland.edu (Randy A. Graca) writes:\n\n>I also think that they will have a hard time with Pittsburgh if they\n>face them in the finals (which is what all the Detroit sportswriters \n>are predicting). Although I think Bryan Murray is probably the best GM\n>I have ever seen in hockey\n\nHow do you figure that?? When Bryan Murray took over the Wings they were\na pretty good team that was contending for the Stanley Cup but looked\nunlikely to win it. Now they are a pretty good team that is contending for\nthe Stanley Cup but looks unlikely to win it. A truly great GM would\nhave been able to make the moves to push the team to the upper echelon\nof the NHL and maybe win the Stanley Cup. A good GM (like Murray) can\nmaintain the team's success but can't push them to the next level.\n\nIn the history of hockey there have been several better GM's than Murray-\nway too many to name. Murray isn't even the best GM in the league today.\nHe fails in comparison to Sinden, Sather, Savard, Caron, Fletcher and\nQuinn in my estimation.\n\nI can't imagine how Bryan Murray can be the best GM anyone has ever seen\nin hockey- unless they have seen VERY few GM's.\n\nGregmeister\n\n###\n\n","output":" hockey"} +{"input":"From: schaefer@owlnet.rice.edu (Andrew James Schaefer)\nSubject: Re: Best Sportwriters...\nKeywords: Sportswriters\nOrganization: Rice University\nLines: 31\n\nIn article rkoffler@ux4.cso.uiuc.edu (Bighelmet) writes:\n>csc2imd@cabell.vcu.edu (Ian M. Derby) writes:\n>\n>\n>>Since someone brought up sports radio, howabout sportswriting???\n>\n>I happen to be a big fan of Jayson Stark. He is a baseball writer for the \n>Philadelphia Inquirer. Every tuesday he writes a \"Week in Review\" column. \n>He writes about unusual situations that occured during the week. Unusual\n>stats. He has a section called \"Kinerisms of the Week\" which are stupid\n>lines by Mets brodcaster Ralph Kiner. Every year he has the LGTGAH contest.\n>That stands for \"Last guy to get a hit.\" He also writes for Baseball \n>America. That column is sort of a highlights of \"Week in Review.\" If you \n>can, check his column out sometime. He might make you laugh.\n>\n>Rob Koffler\n\nIsn't Stark that idiot who writes in Baseball America? Twice a month he\nwrites a \"Who woulda thunk it\" article which is really the same piece\nevery time. \"Who would have thought that [Buddy Biancalana] would have\nmore home runs than [the Colorado Rockies, Babe Ruth, Omar Vizquel and\nNolan Ryan] COMBINED!\" He's an idiot, if it's the same guy.\n\n>\n>-- \n>******************************************************************\n>|You live day to day and rkoffler@ux4.cso.uiuc.edu|\n>|dream about tomorrow --Don Henley |\n>******************************************************************\n\nAndrew\n\n###\n\n","output":" baseball"} +{"input":"From: brucek@Ingres.COM (Bruce Kleinman)\nSubject: Re: Best record ever in baseball\nArticle-I.D.: pony.1993Apr6.195932.20451\nDistribution: usa\nOrganization: Ingres Corporation, A subsidiary of The ASK Group, Inc.\nLines: 5\n\nIn article <1psl0jINNam3@jhunix.hcf.jhu.edu> admiral@jhunix.hcf.jhu.edu (Steve C Liu) writes:\n>Of all teams, I believe the Cubs have the best record ever in baseball.\n>Sometime way far back. 110+ and something.\n\nI think it was the 1954 Cleveland Indians with 111.\n\n###\n\n","output":" baseball"} +{"input":"From: golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy)\nSubject: Re: Daigle\/Kariya\nOrganization: University of Toronto Chemistry Department\nLines: 15\n\nIn article <1qsmhtINNt5l@senator-bedfellow.MIT.EDU> ddlin@athena.mit.edu (David D Lin) writes:\n>I hear Daigle will eb the first pick next year. What is the word on Kariya???\n>Anybody ever seen him play on TV???? Is he also entering the draft???\n\nPeople are seeming to be less concerned about Kariya's size as he leads\nteams to championships (World Junior and US College) and collects\nawards...everyone is watching with interest as to how he will perform\non left wing with Eric Lindros and Mark Recchi at the world\nchampionships.\n\n4 months of go...chances were not very good that he would go in the\ntop five...now it has become probable...a great world championship\ncould put him in the top 3 with Daigle and Pronger.\n\nGerald\n\n###\n\n","output":" hockey"} +{"input":"From: pavalin@bnr.ca (Paul Valin)\nSubject: Re: Canadiens - another Stanley Cup???\nNntp-Posting-Host: bcarm4b8\nOrganization: Bell-Northern Research Ltd.\nLines: 31\n\nIn article <1993Apr6.044045.5215@ramsey.cs.laurentian.ca>,\nmaynard@ramsey.cs.laurentian.ca (Roger Maynard) wrote:\n> \n> In rauser@fraser.sfu.ca (Richard John Rauser) writes:\n> \n>>pereira@CAM.ORG (Dean Pereira) writes:\n> \n> \n>>>\t\tWith the kind of team Montreal has now, they can take the\n>>>cup easily. The only problem they have right now is that everyone is\n>>>trying to steal the show and play alone. They need some massive teamwork.\n> \n>This is known as the Savard syndrome - and we are talking Denis, not Serge.\n>No team will ever win squat with the likes of Denis Savard in their lineup.\n> \n> \n>They could tell Savard to stay home and watch the games on TV.\n\nIf life were so simple! Savard has not played in three of the last \nfour games and they are still playing like crap. Montreal's problems\nrun deeper than Savard (and Mouton) unfortunately; I hope they can\nget their act together before the playoffs.\n\nThe line-up in their game coming up against PittsburgH is said to be\nthe one they're likely to use for the playoffs. Let's hope they can\nforget about the nice weather we're having and play hockey.\n--------------------------------------------------------------------\nPaul Valin Tel: + 1 613 763 7394\nBell-Northern Research Ltd. Email: pavalin@bnr.ca\nP.O. Box 3511, Station C\nOttawa, Ontario, Canada K1Y 4H7 'only my opinions...'\n\n###\n\n","output":" hockey"} +{"input":"From: sepinwal@mail.sas.upenn.edu (Alan Sepinwall)\nSubject: Re: Jewish Baseball Players?\nArticle-I.D.: netnews.120665\nOrganization: University of Pennsylvania, School of Arts and Sciences\nLines: 18\nNntp-Posting-Host: mail.sas.upenn.edu\n\nIn article <15APR93.14691229.0062@lafibm.lafayette.edu> VB30@lafibm.lafayette.edu (VB30) writes:\n>Just wondering. A friend and I were talking the other day, and\n>we were (for some reason) trying to come up with names of Jewish\n>baseball players, past and present. We weren't able to come up\n>with much, except for Sandy Koufax, (somebody) Stankowitz, and\n\nIt's Stankiewicz, not Stankowitz, and he's not Jewish - he's Polish\n(by the way, the correct pronunciation - according to Stanky himself,\nis \"ston-KEV-itch\". all the sportscasters get it wrong)\n\n>maybe John Lowenstein. Can anyone come up with any more. I know\n>it sounds pretty lame to be racking our brains over this, but\n>humor us. Thanks for your help.\n\nThe only other Jewish ballplayer I can think of is Ron Blomberg, who is\nbest known as being the first DH to appear in a major league ballgame.\n\n-Alan\n\n###\n\n","output":" baseball"} +{"input":"From: gsu0033@uxa.ecn.bgu.edu (Eric Molas)\nSubject: Re: Playoff predictions\nOrganization: Educational Computing Network\nLines: 53\nNNTP-Posting-Host: uxa.ecn.bgu.edu\n\n\n>1st round: \n>----------\n\n>PITT vs NYI: PITT in 4. \n>WASH vs NJD: WASH in 6. \n\n>BOS vs BUF: BOS in 5. \n>QUE vs MON: MON in 7. \nI'd have to take Quebec in 6.\n\n>CHI vs STL: CHI in 4. \n\nHawks will win, but it will take 5.\n>DET vs TOR: DET in 6. \n\n>VAN vs WIN: WIN in 6. \n>CAL vs LA: CAL in 5. \nCal in 7.\n>2nd round: \n>----------\n\n>PITT vs WASH: PITT in 4. \n>BOS vs MON: BOS in 6. \nBoston will beat Quebec in 6.\n>CHI vs DET: CHI in 7. \n>WIN vs CAL: CAL in 5. \n\n>3rd round: \n>----------\n\n>PITT vs BOS: PITT in 5. \nPitt in 6. The Bruins arent a pushover.\n>CHI vs CAL: CHI in 5. \nThe hawks havent had problems with them all year. Yep, I agree.\n>Finals:\n>------\n\n>PITT vs CHI: PITT in 5. \nUnless the Hawks can somehow change fate, you're right. \n\nWho knows, though. Maybe some intensive forechecking aka normal Hawks\nstyle will nullify a seemingly unbeatable team. Maybe the Pens are due\nfor a let-down. Hell, how could they _possibly_ extend their record\nmaking play all the way through the playoffs.? \n\n>=============================================\n>Walter\n\n-- \n\/\/Damien Endemyr the Unpure Knight of Doom \/\/\n\/\/\"So I've acquired a taste for blood and have adopted a nocturnal \/\/\n\/\/lifestyle. That Doesnt mean I'm a vampire.....\" \/\/\n\n###\n\n","output":" hockey"} +{"input":"From: rickc@krill.corp.sgi.com (Richard Casares)\nSubject: Re: Jim Lefebvre is an idiot.\nNntp-Posting-Host: krill.corp.sgi.com\nOrganization: Silicon Graphics, Inc.\nLines: 32\n\nIn article , ada41546@uxa.cso.uiuc.edu\n(Driftwood) writes:\n|> \n|> \tI totally agree with each point you made. Jose Viscaino looked\n|> like a single A hitter up there. Who swings on 3-1 count with Maddux \n|> pitching and your teams down by a run, and you haven't touched the ball\n|> all \n|> day. I also think too much is made of that lefty-righty thing. \n|> Watching\n|> the Cubs games I get the feeling Steve Stone knows a lot more about\n|> what\n|> the Cubs should be doing than Lefebre does. Harry said it best when he\n|> stated after another terrible Vizcaino at bat-- we can't wait til\n|> Sandberg returns!\n\nI tell you, Steve Stone is like a prophet.\nHe must be making a ton in the boradcoast booth because\nI can't understand why he's not actually back in the game itself.\n\nThe other day he called Sosa's homerun against the Sox and\nclaimed the game would be going into extra innings when the\nscore was 8-3 in the 5th.\n\nSo yesterday he notices that Sosa's ahead in the count against\nMaddux and says, \"This is a fastball situation and Sosa will be\nlooking for it. But this is also the spot where Maddux throws\nthe straight change.\" Sure enough. Sosa gets ahead on it and pops\nit up to the infield.\n\nStoney for Cubs manager!\n\n-Rick\n\n###\n\n","output":" baseball"} +{"input":"From: mep@phoenix.oulu.fi (Marko Poutiainen)\nSubject: Re: Finland\/Sweden vs.NHL teams (WAS:Helsinki\/Stockholm & NHL expansion)\nOrganization: University of Oulu, Finland\nX-Newsreader: TIN [version 1.1 PL6]\nLines: 40\n\n: FINLAND: \n: \n: D-Jyrki Lumme.......20\n: D-Teppo Numminen....20\n: D-Peter Ahola.......13\n: \nWell well, they don't like our defenders (mainly Lumme and Numminen)...\n\n: C-Jari Kurri........25\n: C-Christian Ruuttu..16\n: \nNow, do YOU think that Ruuttu is only worth 16 ? I think it might be 20.\n\n: R-Teemu Selanne.....27\n: \nCompared to Kurri, Selanne's points are too high, lets make it 25 or 26.\n\n\n: well in the Canada Cup and World Championships largely due to the efforts of\n: Markus Ketterer (the goalie), 3-4 or the players listed above and luck. There's\n: presumably a lot of decent players in Finland that wouldn't be superstars at\n: the highest level but still valuable role players, however. My guess would be\n: that the Finnish Canada Cup team would be a .500 team in the NHL.\n\nWow, now, it looks like you don't like our players? What about guys like:\nNieminen, Jutila, Riihijarvi, Varvio, Laukkanen, Makela, Keskinen and (even\nif he is aging) Ruotsalainen? The main difference between finnish and North-\nAmerican players is, that our players tend to be better in the larger rink.\nThe Canadian defenders are usually slower that defenders in Europe. \nAnd I think that there was more in our success than Ketterer and luck (though\nthey helped). I think that the main reason was, that the team worked well\ntogether.\n--\n***********************************************************************\n* 'Howl howl gargle howl gargle howl howl howl gargle howl gargle howl* \n* howl gargle gargle howl gargle gargle gargle howl slurrp uuuurgh' *\n* -Prostetnic Vogon Jeltz *\n***********************************************************************\n\t-Marko Poutiainen\n\t mep@phoenix.oulu.fi\n\n###\n\n","output":" hockey"} +{"input":"From: paula@koufax.cv.hp.com (Paul Andresen)\nSubject: Re: A true story - Way to go Omar\nKeywords: Mariners, grand slam, Omar Vizquel\nNntp-Posting-Host: koufax.cv.hp.com\nOrganization: Hewlett-Packard Company, Corvallis, Oregon USA\nLines: 23\n\nIn article <1993Apr14.173236.14321@esca.com>, vigil@esca.com (Sandra Vigil) writes:\n|> Yesterday, April 14th, a friend and I were discussing the theory put\n|> forth by a local sports radio station personality that the\n|> Commissioner-less baseball owners had snuck a live ball into this years\n|> baseball games in an effort to increase home run numbers and attract\n|> fans. \n\nIt's always possible, but if this is the case, I think that there is some\nblatant discrimination going on here. Clearly Selig is allowing the opposition\nto use pre-1920 baseballs against the Dodgers.\n \n|> Well, guess who stepped up to the plate for his first career grand slam\n|> last night against the Jays? None other than my boy. It was truly a\n|> sight to behold.\n\nAnd almost more impressive was that he also got an intentional walk.\n--------------------------------------------------------------------------------\n We will stretch no farm animal beyond its natural length\n\n paula@koufax.cv.hp.com Paul Andresen Hewlett-Packard (503)-750-3511\n\n home: 3006 NW McKinley Corvallis, OR 97330 (503)-752-8424\n A SABR member since 1979\n\n###\n\n","output":" baseball"} +{"input":"From: gtd597a@prism.gatech.EDU (Hrivnak)\nSubject: Goalie mask poll\nArticle-I.D.: hydra.93158\nOrganization: Georgia Institute of Technology\nLines: 31\n\n\n\tHere is an update on the Goalie mask poll...\n\tFirst, since so many people gave me their 3 best, I decided to\ngive 3 pts for their favorite, 2 pts for 2nd, 1 for 3rd. If you e-mailed\na response with only one, I gave it 3 pts. Please feel free to send me\nyour 2 other favorites, if you only sent one before. \n\tAlso, votes are still welcome! Any mask you like will do, as I \nhave received votes for players not in the NHL. Please mention what team\nthey play for, though.\n\tSo here are the up-to-date results so far:\n\nPlayer Team Pts Votes\n-------------------------------------------------------\n1. Ed Belfour Chicago 8 4\n Andy Moog Boston 8 3\n3. Curtis Joseph St. Louis 5 2\n4. Brian Hayward San Jose 4 2\n5. Grant Fuhr Buffalo 3 1\n Ron Hextall Quebec 3 1\n7. Clint Malarchuk Buffalo 2 1\n Manon Rheaume Atlanta (IHL) 2 1\n9. John Casey Minnesota 1 1\n Rick Wamsley Toronto (retired) 1 1\n\n\tThanks to all that voted, and keep 'em coming!\n\n-- \nGO SKINS! ||\"Now for the next question... Does emotional music have quite\nGO BRAVES! || an effect on you?\" - Mike Patton, Faith No More \nGO HORNETS! ||\nGO CAPITALS! ||Mike Friedman (Hrivnak fan!) Internet: gtd597a@prism.gatech.edu\n\n###\n\n","output":" hockey"} +{"input":"From: jae2001@andy.bgsu.edu (Jason Ehas)\nSubject: Re: Giveaways\nOrganization: Home of 1984 NCAA hockey champs\nLines: 43\n\nIn article <1qi44l$kqr@access.digex.net>, steveg@cadkey.com (Steve\nGallichio) wrote:\n> \n> \n> John P. Curcio (jpc@philabs.philips.com) responded to my drivel:\n> \n> >steveg@cadkey.com (Steve Gallichio) writes:\n> > \n> >>I still am surprised that no one has tried giving away the goodies at the end\n> >>of the game. The two problems with that, of course, are that you would want\n> >>to make sure the first people in the building would be assured of getting\n> >>them (probably redeemable vouchers), and that the building managers want to\n> >>avoid at all costs delaying people as they leave the building, if, for\n> >>instance, the goodies are given to people as they exit.\n> >\n> >I went to the New Jersey Devils\/Carvel Ice Cream Puck Night (tm) last year to\n> >see the beloved Bruins play. The pucks were given out at the end of the game.\n> >I could just imagine what would have happened late in the third if the Bruins\n> >were winning....\n> \n> It figures, after I posted the first article, I found out that the Whalers are\n> going to be using coupons for the the giveaway on Friday Night. I believe that\n> is is the \"Some Big Corporation (Probably a Bank) Flying Disk Night.\" I think\n> that we could all see the potential for danger here...\n> \n> >|> All in all, I have seen a whole bunch of giveaways land on the ice, and it\n> >|> never ceases to amuse me. I'm just thankful for the players that no one has\n> >|> yet to sponsor 'Lead Pipe Night' at any arenas...\n> >\n> >That's probably because they couldn't find anyone to sponser it... Maybe USS\n> >could sponser the Pittsburgh Penguins\/US Steel Steel Rod Night-- close enough?\n> \n> Naah, it'd probably bounce off of Jay Caufield.\n> \n> -SG\n\nI was at a Cincinnati Cyclones game a year ago when the local country\nstation sponsored a kazoo giveaway. After a particularly bad call by the\nunderexperienced ECHL ref, it was Kazoostorm time down on the ice. I\nthought this was a pathetic display by the fans, but they were rightfully\nunhappy.\n\nJason\n\n###\n\n","output":" hockey"} +{"input":"From: jclouse@discover.wright.edu (Jim Clouse)\nSubject: World Series Stats\nNntp-Posting-Host: discgate\nOrganization: Wright State University\nX-Newsreader: TIN [version 1.1 PL8]\nLines: 3\n\nDoes anybody else think that WS stats should become part of\na player's career stats? Why not?\n\n###\n\n","output":" baseball"} +{"input":"From: snichols@adobe.com (Sherri Nichols)\nSubject: Re: Young Catchers\nOrganization: Adobe Systems Incorporated\nLines: 38\n\nIn article <7975@blue.cis.pitt.edu> genetic+@pitt.edu (David M. Tate) writes:\n>As for rushing... If there really is a qualitative difference between the\n>minors and the majors that requires a period of adjustment (and I don't\n>believe there is), then wouldn't you rather waste Lopez's 22-year old good\n>season than his 23-year old very good season or his 24-year-old excellent\n>season? The sooner you get him acclimated, the more of his prime you get to\n>use.\n\nCan anybody name a player who was 'rushed' to the majors (let's, for\nargument's sake, define \"rushed\" as brought up to the majors for more than\na cup of coffee prior at age 22 or younger, and performing below\nexpectations), whose career was damaged by this rushing? I'm serious; I\ntend to agree with David that bringing the player up sooner is better, but\nI'd like to look at players for whom this theory didn't work, if there are\nany. I'd prefer players within the last 10 years or so, because then I can\nlook up their minor league stats. (It's important to distinguish between\nplayers who legitimately had careers below what their minor league numbers\nwould have projected, as opposed to players who were hyped and failed, but\nactually had careers not out of line with their minor league numbers). \n\nLet's kick it off with an example of a player who was \"rushed\", although\nthere doesn't seem to have been any damage to his career. Jay Bell was\ngiven 135 PAs in the major leagues at age 21, and performed well below what\nyou would expect from his AAA numbers the same season. He got 236 PAs the\nnext year at age 22, and still underperformed. However, the next year, at\nage 24, his performance improved, and he won the everyday shortstop job,\nand has been there ever since. It's really hard for me to see where he\nwould have been better off staying in the minor league (where he was\nperformed quite well in AAA) during this time, rather than being \"rushed\";\nCleveland might have been better off, I suppose, because they might have\nbeen less likely to give up on him.\n\nYes, if you bring a player up early, he's likely going to struggle. But\ndoes that delay the time at which he stops struggling, and starts\nperforming up to expectations?\n\nSherri Nichols\nsnichols@adobe.com\n\n###\n\n","output":" baseball"} +{"input":"From: farenebt@logic.camp.clarkson.edu (Droopy)\nSubject: AHL final standings\nOrganization: Clarkson University\nLines: 35\nNntp-Posting-Host: logic.clarkson.edu\nX-Newsreader: TIN [version 1.1 PL8]\n\nFINAL 1992-93 AMERICAN HOCKEY LEAGUE STANDINGS\n\nNORTHERN DIVISION\tW\tL\tT\tPTS\tGF\tGA\tLYF*\nProvidence Bruins\t46\t32\t2\t94\t384\t348\t56\nAdirondack Red Wings\t36\t35\t9\t81\t331\t308\t84\nCapital District Isles\t34\t34\t12\t80\t280\t285\t75\nSpringfield Indians\t25\t41\t14\t64\t282\t336\t94\nNew Haven Senators\t22\t47\t11\t55\t262\t343\t--\n\nSOUTHERN DIVISION\tW\tL\tT\tPTS\tGF\tGA\tLYF\nBinghamton Rangers\t57\t13\t10\t124#\t392\t246\t91\nRochester Americans\t40\t33\t7\t87\t348\t332\t86\nUtica Devils\t\t33\t36\t11\t77\t325\t354\t74\nBaltimore Skipjacks\t28\t40\t12\t68\t318\t353\t66\nHershey Bears\t\t27\t41\t12\t66\t316\t339\t83\nHamilton Canucks\t29\t45\t6\t64\t284\t327\t--\n\nATLANTIC DIVISION\tW\tL\tT\tPTS\tGF\tGA\tLYF\nSt John's Maple Leafs\t41\t26\t13\t95\t351\t308\t90\nFredericton Canadiens\t38\t31\t11\t87\t314\t278\t96\nCape Breton Oilers\t36\t32\t12\t84\t356\t336\t82\nMoncton Hawks\t\t31\t33\t16\t78\t292\t306\t74\nHalifax Citadels\t33\t37\t10\t76\t312\t348\t67\n\n*- Last year's point total\n#- League record total\t\t\t\n\n ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n + Bri Farenell\t\t\tfarenebt@craft.camp.clarkson.edu +\n + AHL, ECAC and Boston Bruins contact for rec.sport.hockey\t\t +\n + Adirondack Red Wings, Calder Cup Champs: '81 '86 '89 '92\t +\n + Clarkson Hockey, ECAC Tournament Champs: '66 '91 '93\t\t +\n + Glens Falls High Hockey, NY Division II State Champs: '90 '91 +\n + AHL fans: join the AHL mailing list: ahl-news-request@andrew.cmu.edu +\n ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n###\n\n","output":" hockey"} +{"input":"From: fierkelab@bchm.biochem.duke.edu (Eric Roush)\nSubject: Re: quick way to tell if your local beat writer is dumb.\nArticle-I.D.: news.12787\nOrganization: Biochemistry\nLines: 28\nNntp-Posting-Host: bruchner.biochem.duke.edu\n\nIn article <1993Apr06.062907.108109@locus.com> aardvark@spica.la.locus.com\n(Warren Usui) writes:\n>In article gajarsky@pilot.njin.net\n(Bob Gajarsky - Hobokenite) writes:\n>>anyone who writes \"dean palmer has 2 homers - at this pace, he'll\n>> have 324 home runs!\" should be shot.\n\n\n\nNow, on the other hand, Juan Gonzales probably DOES have a shot at\n324 HR's. ;).\n\n>The Dodgers after one inning of play have committed one error. At this rate\n>they'll have 1,455 errors this season!\n\n>Well maybe I'm right this time...\n\n\n\nActually, you might be underpredicting? ;)\n\n-------------------------------------------------------\nEric Roush\t\tfierkelab@\tbchm.biochem.duke.edu\n\"I am a Marxist, of the Groucho sort\"\nGrafitti, Paris, 1968\n\nTANSTAAFL! (although the Internet comes close.)\n--------------------------------------------------------\n\n###\n\n","output":" baseball"} +{"input":"From: (jmhodapp@aplcomm.jhuapl.edu)\nSubject: Re: ALL-TIME BEST PLAYERS\nOrganization: master\/peon\nLines: 19\n\nIn article <1993Apr14.173428.12056@Princeton.EDU>, roger@crux.Princeton.EDU (Roger Lustig) writes:\n> \n\n> >In article <1993Apr13.115313.17986@bsu-ucs>, 00mbstultz@leo.bsuvc.bsu.edu \n> > writes...\n> \n> >>I've recently been working on project to determine the greatest\n> >>players at their respective postions. \n> \n> >>2B Career \n\nWhat about U. Johnny Hodapp, the greatest 2nd baseman in Cleveland Indians\nhistory? 225 hits in 1930, consistantly over .300. A great, great second baseman.\n\n\nJon \"Johnny\" Hodapp\njmhodapp@aplcomm.jhuapl.edu\n=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n\n###\n\n","output":" baseball"} +{"input":"From: vergolin@euler.lbs.msu.edu (David Vergolini)\nSubject: Detroit Tigers\nOrganization: Michigan State University\nLines: 7\nNNTP-Posting-Host: euler.lbs.msu.edu\nSummary: Who can stop the roar of the Tiger's bats.\nKeywords: Detroit is the top offensive team in the league\n\n The roar at Michigan and Trumbull should be loader than ever this year. With\nMike Illitch at the head and Ernie Harwell back at the booth, the tiger bats\nwill bang this summer. Already they have scored 20 runs in two games and with\nFielder, Tettleton, and Deer I think they can win the division. No pitching!\nBull! Gully, Moore, Wells, and Krueger make up a decent staff that will keep\nthe team into many games. Then there is Henneman to close it out. Watch out\nBoston, Toronto, and Baltimore - the Motor City Kittys are back.\n\n###\n\n","output":" baseball"} +{"input":"From: traven@pitt.edu (Neal Traven)\nSubject: Re: The 1964 Phillies: deja vu?\nLines: 25\nX-Newsreader: TIN [version 1.1 PL8]\n\nRobert C Hite (philly@bach.udel.edu) wrote:\n: I think most of the problems mainly arose from Manager Gene Mauch's\n: ineptitude in managing the pitching staff. Down the stretch, he\n: abused Jim Bunning, Chris Short, and Robin Roberts (I think those\n: are the three) pitching each on only 2 days rest for quite some\n: time. By the time they hit the last 2 weeks of the season,\n: obviously none of these guys had an ounce left in their arm. Oh\n: well.\n\nRoberts was long gone -- he was probably an Oriole in 1964. Or maybe a\nColt .45. The 3rd starter was Art Mahaffey, the previous year's ace.\nDennis Bennett was the 4th starter.\n\nThey were indeed 6.5 up with 12 to go, but they won their final two\ngames after the horrid 10-loss streak. The final game victory\n(Bunning's 19th win, if memory serves) kept the Reds from tying for the\ntitle; they and the Phils were both 1 game behind the Cards, with the\nGiants(?) another game back. The Mets couldn't hold an early lead\nagainst the Cards that final Sunday, or there would have been a 3-way\ntie. Too bad they couldn't have saved some of the 15 or so runs they\nscored on Saturday when they crushed St. Louis.\n--\n-----------------------------------------------------------------------------\nneal\ttraven+@pitt.edu\t You're only young once, but you can be\n\ttraven@vms.cis.pitt.edu\t immature forever. -- Larry Andersen\n\n###\n\n","output":" baseball"} +{"input":"From: thornley@micro.cs.umn.edu (David H. Thornley)\nSubject: Re: Erickson, Keith Miller?\nArticle-I.D.: news2.C5LHyD.GEx\nOrganization: University of Minnesota, Minneapolis, CSci dept.\nLines: 17\nNntp-Posting-Host: micro.cs.umn.edu\n\nIn article <1993Apr16.032554.12401@mintaka.lcs.mit.edu> frankkim@CATFISH.LCS.MIT.EDU (Frank Kim) writes:\n>\n>HI,\n>\n>I was just wondering if anyone knew when Erickson\n>and Keith Miller are expected to come back and what\n>exactly ails them.\n>\nDunno about Miller.\n\nIf you mean Scott Erickson, currently the reigning Twins Least Consistent\nGood Player, he pulled a muscle in the neighborhood of the rib cage that\nmade it essentially impossible for him to pitch temporarily, and is\nexpected back on the mound Sunday.\n\nDavid Thornley\n\"With tickets to see one of the Scott Ericksons pitch\"\n\n###\n\n","output":" baseball"} +{"input":"From: cr292@cleveland.Freenet.Edu (Jim Schenk)\nSubject: Re: the hawks WILL return to the finals!!!!!\nOrganization: Case Western Reserve University, Cleveland, Ohio (USA)\nLines: 9\nNNTP-Posting-Host: hela.ins.cwru.edu\n\n\nThe Hawks won the Norris div, and sealed their fate. It's bad luck\nto win the Norris. The Hawks will sweep the Blues in their dreams but will\nlose in 6 in reality. I predict that in the 6 game with the Blues Belfour\nwill go down on his knees 7000 time s and will spend the rest of the time \nlooking behind him self. Butcher will pound Roenick and The warthawks have\nno one tough enough to prevent it\n\nBye Bye Wart HAwks\n\n###\n\n","output":" hockey"} +{"input":"From: philly@ravel.udel.edu (Robert C Hite)\nSubject: Re: Old Predictions to laugh at...\nNntp-Posting-Host: ravel.udel.edu\nOrganization: University of Delaware\nLines: 24\n\n\nIn article <1993Apr15.160316.9170@cs.cornell.edu> tedward@cs.cornell.edu (Edward [Ted] Fischer) writes:\n>\n>Oops! I came across this file from last year. Thought you might\n>enjoy some of these thoughts. The predictions were made on the\n>date indicated. They are largely out of order.\n\nmuch crap deleted\n\n>>3. Managers to be fired this year (1992) in chronological order:\n>>Fregosi, Showalter, Valentine, Riddoch\n>\n>Three of them went, right? Showalter is still around (and likely to\n>stick, it seems).\n\nDEAD WRONG! Last time I checked, Jim Fregosi was still managing the\nPhillies, and doing quite a fine job thank you...best record in\nbaseball at 8-1\n\nMY PREDICTION FOR 1993:\nJim Fregosi will win manager of the year in the NL\n\n(don't flame me..flame the bum who thinks he got fired last year.\nPAY ATTENTION KIDDO!)\n\n###\n\n","output":" baseball"} +{"input":"From: steve@sep.Stanford.EDU (Steve Cole)\nSubject: Re: SHARKS: Kingston Fired!!!\nOrganization: Stanford Exploration Project\nLines: 38\nDistribution: world\nNNTP-Posting-Host: himalaya.stanford.edu\n\nIn article <1993Apr20.165132.9777@adobe.com>, snichols@adobe.com (Sherri Nichols) writes:\n|> In article <1993Apr20.085337.27224@leland.Stanford.EDU> terry@garfield.Stanford.EDU (Terry Wong) writes:\n|> >I think that Jack Ferreira's firing eventually led to Kingston's\n|> >firing. You mention consistency of vision. I think the\n|> >Sharks lost that with the loss of Ferreira. There has never\n|> >been a 3 headed G.M. that has ever worked. You need one\n|> >person making the personnel decisions at the top, not\n|> >management by committee. The conventional wisdom\n|> >from around the league is that Ferreira would have\n|> >made the moves that would have fielded a better product\n|> >on the ice.\n|> \n|> How exactly would Ferreira accomplished this? The three-headed GM-ship has\n|> taken a lot of heat, but nobody's explained how things would have been any\n|> different had Ferreira still been there. Would Ferreira have made more\n|> trades? Who would have he had traded? Would he have made fewer trades?\n|> Who should not have been traded?\n\nI think the three-headed GM's guiding principle was to keep veterans\nin favor of youngsters only if they offered a \"significant\" advantage.\nAt the end of last season, the contracts of several veterans with somewhat\nmaginal contributions (Fenton, Bozek, Anderson, and a couple others I\ncan't remember) were bought out. The idea was that youngsters could\nplay almost as well, and had the potential to improve where these\nolder guys did not. \nAnd they traded Mullen, because he wanted to go, not because he\nwasn't good enough, but I think they were a bit too optimistic\nin thinking they could make up for his contributions.\nAn example from this season, Skriko was brought in on a trial basis\nbut not kept, because of his age. I thought he was a decent\ncontributor worth keeping around.\n\nThe youth movement has its advantages; look at Gaudreau who\nmight still be in KC if more veterans had been kept around. But\nyou have to find the right balance.\n-----------------------------------------------------------------\nSteve Cole (steve@sep.stanford.edu, apple!sep!steve)\nDepartment of Geophysics, Stanford University, Stanford, CA 94305\n\n###\n\n","output":" hockey"} +{"input":"From: luriem@alleg.edu The Liberalizer (Michael Lurie)\nSubject: Re: Joe Robbie Stadium \"NOT FOR BASEBALL\"\nArticle-I.D.: alleg.1993Apr6.210510.2943\nOrganization: Allegheny College\nLines: 10\n\nIn article <1993Apr6.025027.4846@oswego.Oswego.EDU> iacs3650@Oswego.EDU \n(Kevin Mundstock) writes:\n> Did anyone notice the words \"NOT FOR BASEBALL\" printed on the picture\n> of Joe Robbie Stadium in the Opening Day season preview section in USA\n> Today? Any reason given for this?\n\n\n\nYes, and the answer is simple. To create a better feeling in the park, the \nseats will be folded back for baseball games where you saw those words.\n\n###\n\n","output":" baseball"} +{"input":"From: smale@healthy.uwaterloo.ca (Bryan Smale)\nSubject: This year's biggest and worst (opinion)...\nKeywords: NHL, awards\nOrganization: University of Waterloo\nLines: 55\n\n\nI was thinking about who on each of the teams were the MVPs, biggest\nsurprises, and biggest disappointments this year. Now, these are just\nmy observations and are admittedly lacking because I have not had an\nopportunity to see all the teams the same amount. Anyway....\n \nMVP = most valuable player to his team both in terms of points and\n in terms of leadership (\"can't win without him\")\n \nBiggest surprise = the player who rose above expectation -- the player\n that may have raised the level of his game to a new height, even\n if that new level doesn't necessarily warrant an allstar berth\n (includes those players who at the outset of the season, may not\n even have been in the team's plans).\n \nBiggest disappointment = the player from whom we expected more (e.g., I\n picked Denis Savard in Montreal because with the new emphasis on\n offence brought by Demers, shouldn't Savard have done better?)\n \n-----------------------------------------------------------------------\n \n Team Biggest Biggest\nTeam: MVP: Surprise: Disappointment:\n-----------------------------------------------------------------------\nBoston Bruins Oates D.Sweeney Wesley\nBuffalo Sabres Lafontaine Mogilny Audette (jinx?)\nCalgary Flames Roberts Reichel Petit\nChicago Blackhawks Roenick Ruuttu Goulet\nDetroit Red Wings Yzerman Chaisson Kozlov\nEdmonton Oilers Manson Buchberger Mellanby\nHartford Whalers Sanderson Cassells Corriveau\nLos Angeles Kings Robitaille Donnelly Hrudey\nMinnesota North Stars Modano Tinordi(not expected back) Broten\nMontreal Canadiens Muller Lebeau Savard\nNew Jersey Devils Stevens Semak MacLean\nNew York Islanders Turgeon King(finally) Marois\nNew York Rangers Messier Kovalev Bourque\nOttawa Senators MacIver Baker Jelinek\nPhiladelphia Flyers Lindros\/Recchi Fedyk\/Galley Eklund\nPittsburgh Penguins Lemieux Tocchet(even for him) Jagr\nQuebec Nordiques Sakic\/Ricci Kovalenko Pearson\nSan Jose Sharks Kisio Gaudreau Maley\nSt Louis Blues Shanahan C.Joseph Ron Sutter\nTampa Bay Lightening Bradley Bradley Creighton\/Kasper\nToronto Maple Leafs Gilmour Potvin Ellett\/Anderson\nVancouver Canucks Bure Nedved(finally) Momesso\nWashington Capitals Hatcher Bondra\/Cote Elynuik\nWinnipeg Jets Selanne Selanne Druce\n----------------------------------------------------------------------\n \nAs I mentioned up top, these are my *impressions* from where I sit. I\nwould welcome any opinions from those fans nearer their teams (in other\nwords, *anywhere* away from a Toronto newspaper!)\n \nBryan\n\n###\n\n","output":" hockey"} +{"input":"Subject: Travesty at the Joe Louis\nFrom: caldwell8102@mtroyal.ab.ca\nOrganization: Mount Royal College, Calgary, Alberta\nLines: 17\n\n(Detroit, April 19)\n\nIn a development that shocked most knowledgable observers, the Detroit Redwings\nscored no less than six goals against the best goaltender in the world en\nroute to a 6-3 win over the best team in the NHL, the Toronto Maple Leafs. \n\nThe Leafs could not be faulted, as they completely dominated the inferior\nDetroit squad and clearly deserved to win. Only the biased officiating of\nAndy Van Hellemond and the idiots that insisted upon throwing an octopus on\nthe ice at every stoppage in an obvious attempt to distract the superior \nvisiting side prevented an all-out massacre of the Wings by the league's best \nteam. \n\n \t\t\t\t\t\t\t Alan\n\nP.S. This is sweet, Roger. So sweet. I look forward to the next installment on\nWednesday night. I trust you do, too.\n\n###\n\n","output":" hockey"} +{"input":"From: rickert@NeXTwork.Rose-Hulman.Edu (John H. Rickert)\nSubject: Re: Players Rushed to Majors\nOrganization: Computer Science Department at Rose-Hulman\nLines: 13\nReply-To: rickert@NeXTwork.Rose-Hulman.Edu (John H. Rickert)\nNNTP-Posting-Host: g215a-1.nextwork.rose-hulman.edu\n\nIn article <93122@hydra.gatech.EDU> re4@prism.gatech.EDU (RUSSELL EARNEST) \nwrites:\n> This brings back the long suffering memories of pre-chop Braves fans who\n> kept being promised the Bob Horner - Dale Murphy back to back power slam. \n> Who could stop that? Guess we'll never know.\n\nWhy not? Horner played 130 games in 1985 and hit 27 HR.\nMurphy played 162 and hit 37.\nIn 1986 Horner hit 27 in 141 games and Murphy hit 29 in 160 games.\n(and the Braves lost 96 and 89 games).\n\njohn rickert\nrickert@nextwork.rose-hulman.edu\n\n###\n\n","output":" baseball"} +{"input":"From: ring@poseidon (Sue Rankin)\nSubject: Camden Yards\nOrganization: Athena Design, Inc.\nLines: 13\nNNTP-Posting-Host: poseidon.athena.com\n\nI am fortunate enough to have tickets for an Orioles-Red Sox game in \nBaltimore on Saturday, July 31st. I haven't been to the new park,\nand I was wondering if anyone out there can give me pointers or good tips \nor anything helpful about the place so that I can enjoy every moment spent\nthere.\nFor instance, what time do the gates open? Do we see the Orioles take BP?\nWhen will the Red Sox take BP? Anything you can tell me would be \nappreciated. Thank you in advance. \nPlease respond to my e-mail address.\nI know it's still three-and-a-half months away, but I'm psyched!\n\n\nSue\n\n###\n\n","output":" baseball"} +{"input":"From: lli+@cs.cmu.edu (Lori Iannamico)\nSubject: Pens box score 4\/14\nNntp-Posting-Host: lli.mach.cs.cmu.edu\nOrganization: School of Computer Science, Carnegie Mellon\nLines: 44\n\nPens-6 NJ Devils-6\n\nFIRST PERIOD: SCORING: 1, Pittsburgh, Daniels(Needham, Tippett)4:14.\n2, NJ Devils, C. Lemieux(Semak, Driver)10:19. 3, Pittsburgh, Stevens\n(Tocchet, Murphy)12:40ppg. 4, NJ Devils, Zelepukin(Driver, Niedermayer)\n17:26. PENALTIES: PGH, Stevens(roughing)1:30. NJD, Pellerin-double\nminor(cross-checking)1:30. NJD, Zelepukin(tripping)7:21. NJD,\nStasny(holding)11:15. PGH, Taglianetti(roughing)13:51. NJD, Lemieux\n(roughing)13:51. PGH, Jagr(tripping)15:23.\n\nSECOND PERIOD: SCORING: 5, Pittsburgh, Lemieux(Murphy, Tocchet)1:42.\n6, NJ Devils, Semak(Lemieux, Zelepukin)2:27. 7, Pittsburgh, McEachern\n(Jagr, Barrasso)4:24. 8, NJD, Stevens(Guerin, Pellerin)5:45. 9,\nPittsburgh, Lemieux(unassisted)12:40shg. 10, NJ Devils, Richer\n(Nicholls)15:53. 11, NJ Devils, Lemieux(Zelepukin)17:40. PENALTIES:\nPGH, Stevens(roughing)3:06. NJD, McKay(roughing)3:06. PGH, Mullen\n(hooking)10:42. PGH, Tocchet(roughing)12:06. NJD, Stevens(slashing)\n12:06. NJD, Lemieux(unsportsmanlike conduct)12:40. PGH, U.\nSamuelsson(cross checking)20:00. PGH, Barrasso-double minor(spearing)\nserved by McEachern, 20:00. NJD, Holik(cross checking)20:00. NJD,\nLemieux(roughing)20:00.\n\nTHIRD PERIOD: SCORING: 12, Pittsburgh, Mullen(Jagr, Lemieux)18:54.\nPENALTIES: NJD, Daneyko(interference)3:37. PGH, Stevens(roughing)\n9:18. NJD, Holik(roughing)9:18. PGH, match penalty-game misconduct,9:50.\nNJD, Zelepukin(tripping)12:01. PGH, Stevens(roughing)18:41. NJD,\nDaneyko(roughing)18:41.\n\nOVERTIME: SCORING: No scoring. PENALTIES: No penalties.\n\nSHOTS ON GOAL:\nPittsburgh: 9-11-8-2=30\nNJ Devils: 12-15-9-3=39\n\nGOALIES:\nBarrasso(39 shots, 33 saves. 43-14-5)\nBillington(30 shots, 24 saves)\n\nREF: Devorski Linesmen: Gauthier, Vines\n\nLori\nContact for the Penguins\nlli+@cs.cmu.edu\n\n###\n\n","output":" hockey"} +{"input":"From: maynard@ramsey.cs.laurentian.ca (Roger Maynard)\nSubject: Re: If You Were Pat Burns ...\nKeywords: Leaf Wings\nOrganization: Dept. of Computer Science, Laurentian University, Sudbury, ON\nLines: 24\n\nIn <1993Apr20.181549.11414@alchemy.chem.utoronto.ca> golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy) writes:\n\n>Pray for the Wings to become lazy and overconfident...the Wings\n>can only lose the series...Toronto cannot win it. Take away\n>Doug Gilmour and the Leafs are an old Tampa Bay.\n\nRight Gerald. And take away Bob Probert and the Wings are dead Octopuses.\n\n>The Leafs deserve a lot of credit for their diligent effort\n>during the regular season...but if Detroit puts in a reasonable\n>effort, this is not a contest.\n\nLet's wait for the body to get cold before we start in with the eulogies\nhm? They have only lost ONE game. The game was in Detroit after all and\nPotvin did not have his best evening. Nobody that I saw thought that the\nLeafs would sweep the Wings. It looks like it might go six. The Leafs\nwill take the Wings home advantage away in the next game.\n\n\n-- \n\ncordially, as always, maynard@ramsey.cs.laurentian.ca \n \"So many morons...\nrm ...and so little time.\"\n\n###\n\n","output":" hockey"} +{"input":"From: jfp001@acad.drake.edu\nSubject: Re: Goalie Mask Update\nLines: 41\nNntp-Posting-Host: acad.drake.edu\nOrganization: Drake University, Des Moines, Iowa, USA\n\nIn article <93289@hydra.gatech.EDU>, gtd597a@prism.gatech.EDU (Hrivnak) writes:\n> \n> \tHere are the results after three days of voting. Remember 3pts for \n> 1st, 2 for 2nd, and 1 for 3rd. Also, you can still turn in votes! And.. if\n> the guy isn't a regular goalie or he is retired, please include the team! \n> Thanks for your time, and keep on sending in those votes!\n> \n> Player Team Pts Votes\n> -----------------------------------------------------------\n> 1. Brian Hayward San Jose 15 6\n> Andy Moog Boston 15 6\n> 3. Curtis Joseph St. Louis 11 5\n> 4. Ed Belfour Chicago 10 5\n> 5. Gerry Cheevers Boston (retired) 5 3 \n> Manon Rheaume Atlanta (IHL) 5 2\n> Ron Hextall Quebec 5 2\n> 8. Don Beaupre Washington 4 2\n> -----------------------------------------------------------\n> Others receiving 1 vote: Artus Irbe (SJ), Tim Cheveldae (Det),\n> Clint Malarchuck (Buf\/SD,IHL), Grant Fuhr (Buf), Rick Wamsley \n> (Tor,ret), Jon Casey (Minn), John Vanbiesbrouck (NYR),\n> Ken Dryden (Mon,ret), Bob Essensa (Win), Mike Vernon (Cal),\n> Glenn Healy (NYI), Tommy Soderstron (???), Ray LeBlanc (USA).\n> \n\nC'mon, Tommy Soderstrom is having a fine rookie (I think he's a rookie)\nseason with the Flyers. I'm sure most of you knew that already, but just\nin case. \n\nJohn P.\njfp001@acad.drake.edu\nA longtime, but realistic Ranger fan who's willing to admit that the Rangers\nsucked big-time this year. They don't even deserve the luxury of a nice\ngolf course with a warm breeze. God, talk about underachievers!\nMike Keenan - we're waiting for you!\n> \n> -- \n> GO SKINS! ||\"Now for the next question... Does emotional music have quite\n> GO BRAVES! || an effect on you?\" - Mike Patton, Faith No More \n> GO HORNETS! ||\n> GO CAPITALS! ||Mike Friedman (Hrivnak fan!) Internet: gtd597a@prism.gatech.edu\n\n###\n\n","output":" hockey"} +{"input":"From: gld@cunixb.cc.columbia.edu (Gary L Dare)\nSubject: Stan Fischler, 4\/16 (Keenan stuff!)\nSummary: prior to Devils at Islanders Pregame\nNntp-Posting-Host: cunixb.cc.columbia.edu\nReply-To: gld@cunixb.cc.columbia.edu (Gary L Dare)\nOrganization: PhDs In The Hall\nLines: 30\n\n\n* The Keenan hiring is precipitated by the loss of an anticipated $5M\nin playoff revenue and fears of losing season ticket-holders (!), plus\nParamount chief Stan Jaffe's chip against the Flyers over l'Affaire\nLindros last autumn. Add to this that Neilsen might return as an\nassistant coach [Gerald, what'd I say earlier today??], and Roger\nconferred with Jaffe on the hiring. This hiring by Jaffe went over\nthe head of MSG, Inc. (Par. subsidiary) head Bob Gutkowski and over\nthe head and the protests of Pres.\/GM Neil Smith.\n\n* MSG is making the announcement on Saturday to get back at the\nIslanders for making the playoffs (i.e., steal the press).\n\n* Flyers owner Ed Snyder is livid and beside himself over this.\n\n* Keenan will make up to $900,000\/yr.\n\n* Gary Bettman has appointed an independent consul to look at\nGil Stein's admission into the Hall of Fame.\n\n* New crease colours, rather than blue?\n\n* The Oilers will charge to eat in the Press Room next year.\n\ngld\n--\n~~~~~~~~~~~~~~~~~~~~~~~~ Je me souviens ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGary L. Dare\n> gld@columbia.EDU \t\t\tGO Winnipeg Jets GO!!!\n> gld@cunixc.BITNET\t\t\tSelanne + Domi ==> Stanley\n\n###\n\n","output":" hockey"} +{"input":"From: damelio@progress.COM (Stephen D'Amelio)\nSubject: Re: What was Ray doing?\nNntp-Posting-Host: elba\nOrganization: Progress Software Corp.\nLines: 22\n\ndaveb@thewho.East.Sun.COM (Dave Brewer) writes:\n\n>In yesterday's fracus between Rob Ray and Brent Hughes, was it the camera angle or was\n>Ray actually punching Hughes where it appeared he was punching him? (For those that didn't\n>see the game - it was several inches below the belt and he punched him there quite a few\n>times.) Dreadful.\n\n>Also, why did Poulin get four minutes?\n\n\nI've been watching & playing hockey for a good long time now, and\nI've seen players with questionable tactics, but never have I seen\nwhat Ray did on Sunday. This guy gets my all time loser award. It's\none thing to repeatedly cross check someone to the back of the neck\nwhen they are down, it's another thing to have a fist fight with\nsomeones balls. Ray should be thrown out of the league, what an\na**hole.\n\n-Steve\n\n###\n\n","output":" hockey"} +{"input":"From: tjrad@iastate.edu (Thomas J Radosevich)\nSubject: Brewers injuries \nOrganization: Iowa State University, Ames IA\nLines: 21\n\n\n\nHi all,\n\nI've been locked in a small closet chained to a lab bench for the last week or\ntwo without access to really important information. I saw the 3.5 million\nshoulder back on the DL--How long is he out for (i.e. How many millions\/inning\nwill he get this year?) Nothing personal against Higuera mind you, just\nwondering how Bud can keep coffing up money for him when he lets current\nbig producers go over a relative pittance. (Please realize the term \n\"relative pittance\" can only be used with sarcasm when discussing baseball\nsalaries.)\n\nAdditional questions: I did'nt get to see Bones pitch this spring--how is\nhe looking and where is he going to fit in the rotation?\n\nHow is Surhoff shaping up defensively at third?\n\nAre they going to build a new stadium? When?\n\nTom\n\n###\n\n","output":" baseball"} diff --git a/internal/service/bedrock/testdata/validation_data.jsonl b/internal/service/bedrock/testdata/validation_data.jsonl new file mode 100644 index 00000000000..6e346f5672d --- /dev/null +++ b/internal/service/bedrock/testdata/validation_data.jsonl @@ -0,0 +1,25 @@ +{"input":"From: gld@cunixb.cc.columbia.edu (Gary L Dare)\nSubject: Re: Flames Truly Brutal in Loss\nNntp-Posting-Host: cunixb.cc.columbia.edu\nReply-To: gld@cunixb.cc.columbia.edu (Gary L Dare)\nOrganization: PhDs In The Hall\nDistribution: na\nLines: 13\n\n\nThis game would have been great as part of a double-header on ABC or\nESPN; the league would have been able to push back-to-back wins by\nLe Magnifique and The Great One. Unfortunately, the only network\nthat would have done that was SCA, seen in few areas and hard to\njustify as a pay channel. )-;\n\ngld\n--\n~~~~~~~~~~~~~~~~~~~~~~~~ Je me souviens ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGary L. Dare\n> gld@columbia.EDU \t\t\tGO Winnipeg Jets GO!!!\n> gld@cunixc.BITNET\t\t\tSelanne + Domi ==> Stanley\n\n###\n\n","output":" hockey"} +{"input":"From: smorris@venus.lerc.nasa.gov (Ron Morris )\nSubject: Murray as GM (was: Wings will win\nOrganization: NASA Lewis Research Center\nLines: 37\nDistribution: world\nNNTP-Posting-Host: venus.lerc.nasa.gov\nNews-Software: VAX\/VMS VNEWS 1.41 \n\nIn article <1993Apr19.204348.8254@sol.UVic.CA>, gballent@hudson.UVic.CA writes...\n> \n>In article 735249453@vela.acs.oakland.edu, ragraca@vela.acs.oakland.edu (Randy A. Graca) writes:\n> \n>>are predicting). Although I think Bryan Murray is probably the best GM\n>>I have ever seen in hockey\n> \n>How do you figure that?? When Bryan Murray took over the Wings they were\n>a pretty good team that was contending for the Stanley Cup but looked\n>unlikely to win it. Now they are a pretty good team that is contending for\n>the Stanley Cup but looks unlikely to win it. A truly great GM would\n>have been able to make the moves to push the team to the upper echelon\n>of the NHL and maybe win the Stanley Cup. A good GM (like Murray) can\n\nI think Murray has done a great job. He's picked up Ciccarelli,\nSheppard, Ysebaert, Howe, Coffey, and Riendeau (plus some depth players) \nwithout giving up anything the Wings needed or any of his top prospects.\nAll of this in three years. Has anyone done better?\n\nThe year before he took over, the Wings didn't even make the playoffs.\nThere was about a year and a half during Demers' stint that the Wings\ndid OK, but that was due to Demers' motavational skills and clutch\nand grab style. They didn't have much talent.\n\nGerald, Murray wasn't responsible for Primeau (although I'm not\nready to admit that's a horrible pick). They hired him after the\ndraft (which has never made sense to me). His first pick was\nLapointe.\n\nRon \n\n**********\n\"And one of my major goals is to leave the next president a new set\nof things to worry about. I'm getting bored reading the same problems\nin the paper, decade after decade. I want people to have to deal\nwith new problems.\"\n ... President Bill Clinton 2-4-93\n\n###\n\n","output":" hockey"} +{"input":"From: golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy)\nSubject: Re: Too Many Europeans in NHL\nArticle-I.D.: alchemy.1993Apr6.142037.9246\nOrganization: University of Toronto Chemistry Department\nLines: 14\n\nIn article <1993Apr6.044323.22829@pasteur.Berkeley.EDU> daniell@cory.Berkeley.EDU (Daniel Lyddy) writes:\n>\n>You know, you're absolutely right. I think we should round up all those\n>players of European descent and ship 'em back to where they came from. Let's\n>see, with whom should we start? I dunno, Lemieux? Hmmm...sounds like he\n>has *French* blood in him!!! Hey! France is part of Europe! Send that\n>Euro-blooded boy back!!!\n>\n\nDon't you Americans study history...the French settled in North America\nas early or before the British...Lemieux can probably trace back his\nNorth American heritage back a lot further than most of us.\n\nGerald\n\n###\n\n","output":" hockey"} +{"input":"From: krattige@hpcc01.corp.hp.com (Kim Krattiger)\nSubject: Re: Kevin Rogers\nOrganization: the HP Corporate notes server\nLines: 14\n\n>\/ hpcc01:rec.sport.baseball \/ pjtier01@ulkyvx.louisville.edu \/ 12:23 pm Apr 14, 1993 \/\n>\n>What's up with Kevin Rogers of San Francisco?? I thought he was slated to be\n>the fifth starter, but he's only gotten a few relief appearences. Are they\n>going with four starters for now, or is someone else the fifth?\n>\n> Thanks,\n> P. Tierney\n>----------\n>\nGiant's have a five man rotation of John Burkett, Trevor Wilson,\nBill Swift, Jeff Brantley, and Bud Black\/Dave Burba. Black has\nbeen put on the 15 day disables and Dave Burba will take his starts.\n\n###\n\n","output":" baseball"} +{"input":"From: warped@cs.montana.edu (Doug Dolven)\nSubject: Mel Hall\nOrganization: CS\nLines: 9\n\n\nHas anyone heard anything about Mel Hall this season? I'd heard he wasn't\nwith the Yankees any more. What happened to him?\n\n\t\t\t\tDoug Dolven\n-- \nDoug Dolven\nwarped@cs.montana.edu\ngdd7548@trex.oscs.montana.edu\n\n###\n\n","output":" baseball"} +{"input":"From: jerry@sheldev.shel.isc-br.com (Gerald Lanza)\nSubject: Re: '61 Orioles Trivia\nOrganization: Olivetti North America (Shelton, CT)\nLines: 20\n\nIn article <1993Apr14.190432.1706@hpcvaac.cv.hp.com> paula@koufax.cv.hp.com (Paul Andresen) writes:\n>In article <1993Apr13.151809.1286@galileo.cc.rochester.edu>, sparky@balsa.lle.rochester.edu (Michael Mueller) writes:\n>|> Hi All,\n>|> \n>|> Does anyone know who were the 4 pitchers for the 1961 Orioles \n>|> that were referred to as the \"Kiddy Corp\" because they were so young?\n>\n>Steve Barber 22 18-12\n>Chuck Estrada 23 15-9\n>Jack Fisher 22 10-13\n>Milt Pappas 22 13-9\n>\n\n\tThis list brings to mind possible the worst trade since Babe for\n\tNONO NANNETTE, i.e., Milt Pappas for Frank Robinson, I think in\n\t1965 ?. Robinson proceeded to win the triple crown in 1966 and\n\tmay have beaten out Yaz in '67 but was injured on a slide into \n\tsecond when he collided with the mighty Al Weis (Chisox). \n\n\t\t\t\t\tjerry\n\n###\n\n","output":" baseball"} +{"input":"From: kime@mongoose.torolab.ibm.com (Edward Kim)\nSubject: Re: Ind. Source Picks Baerga Over Alomar: Case Closed \nIn-Reply-To: tedward@cs.cornell.edu's message of Fri, 16 Apr 1993 19:07:35 GMT\nDistribution: na\nLines: 8\n\t<1993Apr16.190735.13322@cs.cornell.edu>\nOrganization: IBM Toronto Lab\n\n> That's a joke! (Alomar might not be a gold-glover, but he's certainly\n> no worse than Baerga defensively.)\nActually Alomar is a two-time gold-glover (91-92).\n\n> \n> -Valentine\n\nEdk\n\n###\n\n","output":" baseball"} +{"input":"From: cmk@athena.mit.edu (Charles M Kozierok)\nSubject: Re: Best Homeruns\nOrganization: Massachusetts Institute of Technology\nLines: 22\nNNTP-Posting-Host: electric-monk.mit.edu\n\nIn article <1993Apr16.172502.2301@osf.org> dswartz@osf.org (Dan Swartzendruber) writes:\n} In article <4200419@hpcc01.corp.hp.com> boell@hpcc01.corp.hp.com (Donald P Boell) writes:\n} >I'd have to say the most impressive HRs I've ever see came from Dave Kingman\n} >and his infamous moon-raker drives...\n} \n} I remember one he hit circa 1976 at Wrigley Field that went across\n} the street (in dead center field) and hit a house on the roof. He\n} whiffed a lot, but when he *did* connect, watch out!\n\nthe best home run i have *ever* seen came off, believe it or not,\nRoger Clemens (sorry, Val) a couple of years ago. he threw a ball to\nIncaviglia which was literally at Inky's neck, and he absolutely \nhammered the crap out of it. after the swing, Clemens nonchalantly\nmotioned for a new ball--he didn't even turn around to look, or\neven get upset. the ball hit the lights in the left-field standard,\nsome 70 or so feet about the Green Monster (over 100 feet above the\nground total!)\n\ntruly an amazing shot.\n\n-*-\ncharles\n\n###\n\n","output":" baseball"} +{"input":"From: pkortela@snakemail.hut.fi (Petteri Kortelainen)\nSubject: Re: Helsinki\/Stockholm & NHL expansion?\nOrganization: Helsinki University of Technology, Finland\nLines: 20\nDistribution: inet\n\t <1993Apr15.095653.17514@abo.fi>\nNNTP-Posting-Host: lk-hp-17.hut.fi\nIn-reply-to: MLINDROOS@FINABO.ABO.FI's message of Thu, 15 Apr 1993 09:56:53 GMT\n\nIn article <1993Apr15.095653.17514@abo.fi> MLINDROOS@FINABO.ABO.FI (Marcus Lindroos INF) writes:\n\n>In franti@polaris.utu.fi writes:\n\n\n>Not too low perhaps, but surely not as high as that of an European NHL\n>division. The Finnish team, for example, would contain all players currently \n on\n>the national team plus a top-class foreigner or two. They would be in an\n>entirely different league than TPS or Jokerit, both of whom have perhaps a\n>dozen players of international class - if even that. Why settle for a minor\n>league when you could have the best?\n\nHow many players of international class an average NHL team has. 6-10?\nTop players just play more in smaller rinks. Is the quality of European hockey\nreally poor, then recent years only few north-american (usually good farm \nplayers) players have got place in Finnish league or Elitserien, while most \nhave been shipped back. \n\nPetteri Kortelainen\n\n###\n\n","output":" hockey"} +{"input":"From: gak@wrs.com (Richard Stueven)\nSubject: Re: Octopus in Detroit?\nReply-To: gak@wrs.com\nOrganization: Wind River Systems, Inc.\nLines: 10\nNntp-Posting-Host: gakbox\n\nIt's in the FAQ.\n\nhave fun\ngak\n\n---\nRichard Stueven AHA# 22584 |----------| He has erected a multitude of new\nInternet: gak@wrs.com |----GO----| offices, and sent hither swarms\nATTMAIL: ...!attmail!gakhaus!gak |---SHARX--| of officers to harass our people,\nCow Palace: 107\/H\/3-4 |----------| and eat out their substance.\n\n###\n\n","output":" hockey"} +{"input":"From: fester@island.COM (Mike Fester)\nSubject: Re: Notes on Jays vs. Indians Series\nOrganization: \/usr\/local\/rn\/organization\nDistribution: na\nLines: 38\n\nIn article <1993Apr13.221704.4291@midway.uchicago.edu> thf2@midway.uchicago.edu writes:\n>In article rudy@netcom.com (Rudy Wade) writes:\n>>In article <1993Apr13.195301.22652@CSD-NewsHost.Stanford.EDU> nlu@Xenon.Stanford.EDU (Nelson Lu) writes:\n>>>Guess which line is which:\n>>>\tBA\tOBP\tSLG\tAB\tH\t2B\t3B\tHR\tBB\n>>>X\t.310\t.405\t.427\t571\t177\t27\t8\t8\t87\n>>>Y\t.312\t.354\t.455\t657\t205\t32\t1\t20\t35\n>>\n>>>The walks should give it away. OBP's, in general, somewhat more valuable than\n>>>slugging, and Alomar's edge in OBP was quite a bit larger than Baerga's edge\n>>>in slugging.\n>>\n>>I'm no SDCN, but what's more valuable:\n>>\n>>28 hits w\/5 more doubles, 12 more HRs OR\n>>7 more triples and 52 BBs? (Let's not forget the 39 extra SBs. How many CS?)\n>\n>Alomar had 9 CS. Baerga had 2.\n>\n>Don't forget the 59 more outs Baerga had (his GIDP balances out his CS, and\n>he had one more sacrifice than Alomar). A replacement level second baseman\n>could have had 17 hits, 5 walks, and a couple of XBH for the additional\n>outs Baerga had. A triple is little different than a home run. We're talking\n>exchanging almost 60 walks for six or seven home runs and four doubles. I \n>would say the almost-60 walks are more valuable.\n\nAlso, Alomar got a FAR greater boost from his home park than Baerga did from \nhis. And \"six or seven home runs\"? Hmm.\n\nSo, if you wanted to pick a second baseman to play in Toronto, you'd take \nAlomar. Anywhere else, and you'd probably take Baerga.\n\nMike\n-- \nDisclaimer - These opiini^H^H damn! ^H^H ^Q ^[ .... :w :q :wq :wq! ^d ^X ^?\nexit X Q ^C ^? :quitbye CtrlAltDel ~~q :~q logout save\/quit :!QUIT\n^[zz ^[ZZZZZZ ^vi man vi ^@ ^L ^[c ^# ^E ^X ^I ^T ? help helpquit ^D ^d !!\nman help ^C ^c :e! help exit ?Quit ?q CtrlShftDel \"Hey, what does Stop L1A d...\"\n\n###\n\n","output":" baseball"} +{"input":"From: brifre1@ac.dal.ca\nSubject: Yet more crazy predictions\nOrganization: Dalhousie University, Halifax, Nova Scotia, Canada\nLines: 36\n\n\nWell here it goes...my crazy predictions (which never come true, but hey..)\n\nAdams\n\tBos vs. Buf - Bos in 5 (cakewalk for the hot Bruins)\n\tQue vs. Mon - Que in 6 (best series of the first round)\n\nPatrick\n\tPit vs. NYI - Pit in 5 (NYI wins fourth game)\n\tWas vs. NJD - NJD in 7 (a grueling upset, possibly OT in game 7)\n\nNorris\n\tChi vs. StL - Chi in 5 (StL is no match for Keenan's Krew)\n\tDet vs. Tor - Tor in 6 (Clark steps it up in playoffs this year)\n\nSmythe (who cares?)\n\tVan vs. Win - Win in 7 (so I'm caught up in Teemu-mania, sue me!)\n\tCal vs. LAK - Cal in 5 (LA sucks!!!!!!!!! IMO)\n\nDivision finals\n\tBos vs. Que - Bos in 7 (killer games, watch for Cam to shine)\n\tPit vs. NJD - Pit in 6 (NJD go insane, kill all on ice, but Pit wins)\n\tChi vs. Tor - Tor in 7 (Tor defense finally get it together)\n\tCal vs. Win - Cal in 6 (Win too tired after 1st series)\n\nConference finals\n\tPit vs. Bos - Bos in 6 (Pit too beat up by NJD to play (I hope))\n\tCal vs. Tor - Tor in 6 (Vernon turns into a sieve)\n\nStanley Cup\n\tBos vs. Tor - Tor in 7 (Two totally different teams, who knows? Dreams\n\t\t\t\tcan come true, pig might one day evolve wings)\n\nFeel free to laugh at my predictions, I always do!\n\nBarfly\n\n###\n\n","output":" hockey"} +{"input":"From: drw3l@delmarva.evsc.Virginia.EDU (David Robert Walker)\nSubject: Re: Braves Pitching UpdateDIR\nOrganization: University of Virginia\nLines: 34\n\nIn article <8994@blue.cis.pitt.edu> traven@pitt.edu (Neal Traven) writes:\n>\n>One of the chapters in Palmer and Thorn's 'Hidden Game' is titled\n>'Pitching is 44% of Baseball,' implying that fielding is 6%. How do\n>they determine that? Beats me -- it's been a long, long time since I\n>read it.\n\nThis was (my opinion) the stupidest thing in the Hidden Game. The\nargument was\n\n1) Defense, or runs allowed, is 50% of the game.\n2) Unearned runs amount to 12% of the runs allowed; earned runs, 88%.\n\n3) Since unearned runs are the result of fielding, not pitching, and\nearned runs are the product of pitching, not fielding, fielding is 12%\nof defense and pitching is 88% of defense.\n4) Caombining with #1, pitching is 44% of the game, fielding 6%.\n\nPete is usually sharper than that. My own feel is that fielding is in\nthe 25-33% of defense range; call it 30-70 between fielding and\npitching.\n\n>One also has to separate offense into batting and baserunning, with the\n>split probably somewhere around 49.5% and 0.5%.\n\nI'd give baserunning a little more credit than that, maybe 45-5, or\neven 40-10. Give a team of Roberto Alomar and a team of John Oleruds\nidentical batting stats (which wouldn't be that unreasonable), and\neven if you don't let Roberto steal a single base, they'll score a lot\nmore than the Oleruds by going first-to-third more often. (No offense,\nGordon).\n\nClay D.\n\n###\n\n","output":" baseball"} +{"input":"From: stamber@rainbow.ecn.purdue.edu (Kevin L. Stamber)\nSubject: Re: How difficult is it to get Penguin tickets?\nOrganization: Purdue University Engineering Computer Network\nLines: 27\n\nIn article <1993Apr18.201811.28965@magnus.acs.ohio-state.edu>, dmoney@magnus.acs.ohio-state.edu (Dean R Money) writes:\n> The subject line says it all. Is it terribly difficult to get tickets\n> to Penguins games, especially now that they are in the playoffs? Would\n> it be easy to find scalpers outside of the Igloo selling tickets?\n> \n> Dean Money\n> dmoney@magnus.acs.ohio-state.edu\n\n Here is my traditional experience with tickets, playoffs and otherwise,\nat the Civic Arena.\n\n Scalping is illegal but nonetheless present outside the Arena. Best \nstrategy, given that you don't mind missing the Anthem (which is OK if B.E.\nTaylor decides to come back ever again :) ) is to wait until 7:40 or 7:45,\nwhen the game is rolling; the scalpers are at this point desperate to sell\nand will reduce to near or at face value to get rid of their tickets.\n\n Playoffs are a little different in that good seats will go early on; \nwhat's left at 7:45 may be nosebleed material (D, E sections).\n\nOthers can add on their opinions as well.\n\nKevin L. Stamber\nPurdue University\nPENGUINS 6 DEVILS 3 -- Pens lead series 1 game to none\n\n###\n\n","output":" hockey"} +{"input":"From: holger.ohlwein@ap.mchp.sni.de (Holger Ohlwein)\nSubject: Re: Canada 3 Sweden 1 at the World Champioships\nReply-To: holger.ohlwein@ap.mchp.sni.de (Holger Ohlwein)\nOrganization: Siemens Nixdorf Informationssysteme AG\nLines: 16\nNNTP-Posting-Host: 139.21.16.6\n\nIn article <20APR199319243244@venus.cc.hollandc.pe.ca>, white@venus.cc.hollandc.pe.ca (Take me Baby!) writes:\n> \n> \tToday at the World Championships in Munich, Canada scored an \n> impressive 3-1 victory over the defending World Champs, Sweden. \n \nIn the game *I* have seen yesterday in the Olympiahalle of Munich\nCanada won 4-1 against Sweden! The last goal for Canada was at 19:59 in\nthe 3rd period. Maybe you shouldn't go and get you another beer \nbefore the game is over and then post imaginary results...\n\nHolger\n\n-- \nS I E M E N S Holger Ohlwein AP153 Otto-Hahn-Ring 6 8000 Muenchen 83\n------------- Tel: + 49 (89) 636-3746 Email: holger.ohlwein@ap.mchp.sni.de\nN I X D O R F Never put off till tomorrow what you can avoid all together.\n\n###\n\n","output":" hockey"} +{"input":"From: steph@pegasus.cs.uiuc.edu (Dale Stephenson)\nSubject: Hits Stolen -- Second Base 1992\nSummary: Stolen Hits for all second basemen\nKeywords: second defense\nOrganization: University of Illinois, Dept. of Comp. Sci., Urbana, IL\nLines: 117\n\nDisclaimer -- This is for fun.\n\nIn my computerized baseball game, I keep track of a category called\n\"stolen hits\", defined as a play made that \"an average fielder would not\nmake with average effort.\" Using the 1992 Defensive Averages posted\nby Sherri Nichols (Thanks Sherri!), I've figured out some defensive stats\nfor the second basemen. Hits Stolen have been redefined as \"Plays Kurt\nStillwell would not have made.\"\n\nOK, I realize that's unfair. Kurt's probably the victim of pitching staff,\nfluke shots, and a monster park factor. But let's put it this way: If we\nreplaced every second baseman in the NL with someone with Kurt's 57.6% out\nmaking ability, how many extra hits would go by?\n\nTo try and correlate it to reality a little more, I've calculated Net\nHits Stolen, based on the number of outs made compared to what a league\naverage fielder would make. By the same method I've calculated Net Double\nPlays, and Net Extra Bases (doubles and triples let by).\n\nFinally, I throw all this into a a formula I call Defensive Contribution, or\nDCON :->. Basically, it represents the defensive contribution of a player.\nI add this number to OPS to get DOPS (Defense + Onbase Plus Slug), which\nshould represent the player's total contribution to the team. So don't\ntake it too seriously. The formula for DCON appears at the end of this\narticle.\n\nThe short version -- definition of terms\nHS -- Hits Stolen -- Extra outs compared to Kurt Stillwell\nNHS -- Net Hits Stolen -- Extra outs compared to average fielder\nNDP -- Net Double Plays -- Extra double plays turned compared to avg fielder\nNEB -- Net Extra Bases -- Extra bases prevented compared to avg. fielder\nDCON -- Defensive Contribution -- bases and hits prevented, as a rate.\nDOPS -- DCON + OPS -- quick & dirty measure of player's total contribution.\n\nNational League\n\nname HS NHS NDP NEB DCON DOPS\nAlicea, L. 50 21 2 -1 .160 .865\nSandberg, R. 108 42 1 1 .134 1.015\nThompson, R. 65 20 5 -1 .104 .852\nLind, J. 66 8 -2 1 .027 .571\nDoran, B. 31 -1 4 0 .014 .705\nDeShields, D. 51 1 -2 1 -.002 .755\nHarris, L. 25 -4 0 1 -.019 .602\nLemke, M. 43 -1 -5 -5 -.038 .573\nMorandini, M. 37 -9 -6 0 -.069 .580\nRandolph, W. 13 -16 3 -1 -.088 .582\nBiggio, C. 34 -26 -4 0 -.091 .656\nStillwell, K. 0 -43 -3 -1 -.236 .336\n\nOrdered by DOPS\n\n1.015 Sandberg\n .865 Alicea\n .852 Thompson\n .755 DeShields\n .705 Doran\n .678 *NL Average*\n .656 Biggio\n .602 Harris\n .582 Randolph\n .580 Morandini\n .573 Lemke\n .571 Lind\n .336 Stillwell\n\nAmerican League\n---------------\n\nname HS NHS NDP NEB DCON DOPS\nFletcher, S. 59 18 5 1 .116 .811\nReed, J. 83 17 3 1 .071 .708\nRipken, B. 56 9 -1 -1 .044 .631\nBaerga, C. 67 0 10 0 .029 .838\nBlankenship, L. 34 2 2 1 .023 .757\nMiller, K. 34 -4 1 -1 -.016 .725\nAlomar, R. 62 4 -9 -2 -.020 .812\nKnoblauch, C. 50 -13 7 -3 -.024 .718\nBordick, M. 37 -4 -2 -1 -.025 .704\nKelly, P. 42 -1 -5 -1 -.039 .636\nWhitaker, L. 40 -8 -1 -2 -.041 .806\nReynolds, H. 47 -6 -5 1 -.043 .603\nSax, S. 56 -6 -9 -1 -.052 .555\nSojo, L. 28 -11 -3 0 -.075 .602\n\nOrder by DOPS\n\n.838 Baerga\n.812 Alomar\n.811 Fletcher\n.806 Whitaker\n.757 Blankenship\n.725 Miller\n.718 Knoblauch\n.708 Reed\n.704 Bordick\n.691 *AL Average*\n.636 Kelly\n.631 Ripken\n.603 Reynolds\n.602 Sojo\n.555 Sax\n\nMore discussion --\n\nDCON formula: ((NHS + NDP)\/PA) + ((NHS + NDP + NEB)\/AB)\nWhy such a bizzare formula? Basically, it's designed to be added into the\nOPS, with the idea that \"a run prevented is as important as a run scored\".\nThe extra outs are factored into OBP, while the extra bases removed are \nfactored into SLG. That's why I used PA and AB as the divisors.\n\nFor more discussion see the post on Hits Stolen -- First Base 1992\n-- \nDale J. Stephenson |*| (steph@cs.uiuc.edu) |*| Baseball fanatic\n\n \"It is considered good to look wise, especially when not \n overburdened with information\" -- J. Golden Kimball\n\n###\n\n","output":" baseball"} +{"input":"From: genetic+@pitt.edu (David M. Tate)\nSubject: Re: Young Catchers\nArticle-I.D.: blue.7977\nOrganization: Department of Industrial Engineering\nLines: 65\n\nmss@netcom.com (Mark Singer) said:\n>In article <7862@blue.cis.pitt.edu> genetic+@pitt.edu (David M. Tate) writes:\n>\n>Well, perhaps if the Braves had no one else worth playing this year it\n>would be Lopez in there. But they do have others worth playing, at\n>least in *their* opinion. \n\nCatcher is their weakest position, with the possible exception of second base.\nThey have a chance to simultaneously replace their biggest offensive problem\nspot with a well-above-average offensive player *and* acclimate a highly\npromising potential star with no pressure on him to carry the team, and they\nwant to play *Olson* and *Berryhill* instead?!\n\n>>I disagree, in that I don't think it *is* a _tangible_ skill, any more than\n>>leadership is. I don't deny that it is a *real* skill, and that some catchers\n>>may be much better than others at it, but I really don't see any way that we\n>>could ever know who they are. Nichols's Law of Catcher Defense is eerily\n>>accurate far too often for me to take defensive assessments of catchers very\n>>seriously.\n>\n>Sorry. New. Don't know Nichols' Law. \n\n\"A catcher's defensive reputation will be inversely proportional to his\n recent offensive level of performance.\" Thus, Mickey Tettleton goes (in\n the media) from being a no-hit defensive whiz to a slugging thumb-finger\n in two short years. The rule doesn't apply to perceived \"superstars\", who\n get the Gold Glove Offensive Transfer effect instead. Greg Olson is probably\n considered to be a good defensive catcher precisely because he can't hit.\n\n\n>Don't believe in catchers'\n>era. But I am interested in pitchers' eras with different catchers.\n\nAren't they the same thing?\n\n>In other words, we know more than they do, so the only logic behind \n>a different decision than we would make must be financial. \n\nEither that or just stupidity.\n\n>I presume\n>we feel this way about other franchises than Atlanta, no?\n\nOf course.\n\n>>Is it fair to the young players? No. Does it make organizational sense? \n>>I think it does.\n>\n>Well if it does make organizational sense, one can hardly fault them\n>for their decisions. I mean, please don't tell me how to run my\n>business. Especially when I'm being successful.\n\nOne could make the same sort of argument in other cases. Pete Rose, in\npursuing Ty Cobb's record, was a huge gate attraction (and national media\nmagnet). The Reds made a lot of money off that; they also wasted the prime\nof Eric Davis. That may be \"good business\", but that doesn't mean I don't\nloathe them for it.\n\n\n\n-- \n David M. Tate | (i do not know what it is about you that closes\n posing as: | and opens; only something in me understands\n e e (can | the pocket of your glove is deeper than Pete Rose's)\n dy) cummings | nobody, not even Tim Raines, has such soft hands\n\n###\n\n","output":" baseball"} +{"input":"From: fmsalvat@eos.ncsu.edu (FRANK MICHAE SALVATORE)\nSubject: Re: Get Real. Caps have no chance\nOriginator: fmsalvat@c00532-106ps.eos.ncsu.edu\nReply-To: fmsalvat@eos.ncsu.edu (FRANK MICHAE SALVATORE)\nOrganization: North Carolina State University, Project Eos\nLines: 15\n\n\nIn article <1993Apr15.162719@staff.dccs.upenn.edu>, filinuk@staff.dccs.upenn.edu (Geoff Filinuk) writes:\n] \tAnyone who really believes that the Caps can beat\n> the Pens are kidding themselves. The Pens may not loose\n> one game in the playoffs.\n\n\nLet's be honest. The Pens may not 'loose' one game as you\nput it, but they will definitely lose one game. Remember,\nthe regular season doesn't mean much when it comes to \nplayoff time. The Caps have a shot at least - the Flyers\nsure don't\n\nFrank Salvatore\nfmsalvat@eos.ncsu.edu\n\n###\n\n","output":" hockey"} +{"input":"From: tedward@cs.cornell.edu (Edward [Ted] Fischer)\nSubject: Re: Rickey Henderson\nOrganization: Cornell Univ. CS Dept, Ithaca NY 14853\nDistribution: usa\nLines: 12\n\nIn article <1993Apr5.173500.26383@ra.msstate.edu> js1@Isis.MsState.Edu (Jiann-ming Su) writes:\n>I say buy out Henderson's contract and let him go bag groceries. Next \n>season, you'll be able to sign him for nothing. That goes for any bitching\n>ball player.\n\nI doubt Henderson would clear waivers. And if he did, he would\ninstantly be signed for the major league minimum, with Oakland picking\nup the remaining $3 million tab.\n\nSome GMs value on-field performance too...\n\n-Valentine\n\n###\n\n","output":" baseball"} +{"input":"From: dxf12@po.CWRU.Edu (Douglas Fowler)\nSubject: Re: Jack Morris\nOrganization: Case Western Reserve University, Cleveland, OH (USA)\nLines: 60\nReply-To: dxf12@po.CWRU.Edu (Douglas Fowler)\nNNTP-Posting-Host: slc12.ins.cwru.edu\n\n\nIn a previous article, tedward@cs.cornell.edu (Edward [Ted] Fischer) says:\n\n>In article <1qr05cINNpel@skeena.ucs.ubc.ca> stlouis@unixg.ubc.ca (Phill St. Louis) writes:\n>>Jack Morris' starts have been like his playoff starts. He has an ERA of\n>>17.18 in his 3 starts.\n>>\n>>What does luck have to do with a 17.18 ERA? He was lucky to get 21 wins\n>>last year, but he had an ERA of 4.04 with a team that scored a lot of\n>>runs. I would be happy if he could still pitch with an ERA of 4.04, but\n>>he seems to be suffering from a total callapse. \n>\n>Bad pitchers are more prone to this total collapse than good pitchers.\n>They are closer to the chasm of mediocrity. The smallest push and\n>they completely lose their grip.\n>\n But good ones can collapse somewhat, then come back the next year.\nBurleigh Grimes went from 20+ wins and an ERA of 3 or so in '24 to 13-19 and\nan ERA around 4 in '25. He pitched well for several more years. Carlton\nwon 13 and lost 20 the year after his 27-10 record. (Source: Bill James\nHistorical Baseball Abstract.)\n And let's not forget John Tudor, who started 1-5 and finished 21-6 in\n1985. He had a pretty bad ERA when you take Busch Stadium into account at\nthe start of the season.\n\n>>He gave up early runs\n>>in his '92 games and would get stronger as the game went on, thus giving\n>>up few runs in the last going. He stays in the game and gets the win.\n>>How else would he have pitched so many innings?\n>\n>Yup. He used to dig himself a hole, then get it together and stick in\n>until the run support eventually came through. This year he just\n>hasn't gotten it together.\n\n If I recall, he had a 4.50 ERA in the 1st half and a 3.50 ERA in the\n2nd half of last year. \n Hmmm, 21 runs in 11 innings. Suppose he starts 30 more games, and winds\nup w\/200 innings pitched. If he allows 4 runs a game in the next 189\ninnings, he'll have a 4.75 ERA or so at the end of the year. (I think I have\nhis totals right.) This is going to be hard to come back from.\n\n>>Jack may be finished. It is time to retire or be released, if he does\n>>not return to his form from last year.\n>\n>His $5 million contract is an awful lot to eat!\n\n My 1st hunch is that Morris is very gutsy, and that he may be pitching\nthrough an injury and not telling anyone. My 2nd guess is that he will be\nbanished to the bullpen the remainder of the season after a few more starts.\n(Perhaps when Stewart comes off the DL? Or will Danny Cox, who went 3 or 4\nscoreless innings against the Tribe today, start for Morris? He looks like\na really good one. Gaston is scrambling to find starters, I'd imagine.\nLuckily, the Jays have a very good offense.)\n I don't think they would dare release him before the end of the year.\nHe'll just be replaced by Stewart or Cox.\n-- \nDoug Fowler: dxf12@po.CWRU.edu : Me, age 4 & now: \"Mommys and Daddys & other\n Ever wonder if, after Casey : relatives have to give lots of hugs & love\nmissed the 3rd strike in the poem: & support, 'cause Heaven is just a great\nhe ran to first and made it? : big hug that lasts forever and ever!!!\"\n\n###\n\n","output":" baseball"} +{"input":"From: steph@cs.uiuc.edu (Dale Stephenson)\nSubject: Re: Notes on Jays vs. Indians Series\nOrganization: University of Illinois, Dept. of Comp. Sci., Urbana, IL\nDistribution: na\nLines: 38\n\nIn klopfens@andy.bgsu.edu (Bruce Klopfenstein) writes:\n\n>kime@mongoose.torolab.ibm.com (Edward Kim) writes:\n[...]\n>> \n>> I would tend to call the offensive contributions even, but Alomar wins hands\n>> down in defensive capabilities. I'm not just talking about the number of \n>> errors; nobody (including Lind!) has the range and athleticism at second base.\n>> I can't recall in the recent past anyone turning the double play better\n>> than Alomar. \n\n>Well, why don't you look up those stats? Baerga may not be the best defensive\n>second baseman in the league, but he's damn good. Check the stats for DPs\n>last year and see for yourself.\n\nAccording to the Defensive Average stats posted by Sherri, Baerga had the\nhighest percentage of DPs turned in the league, while Alomar had the worst.\nHowever, Alomar had a higher Defensive Average. So who would be better?\n\nUsing Alomar's opportunities (469 groundballs, 73 possible double plays)\nAlomar had 332 groundouts and turned 18 DPs.\nBaerga would have had (with same DA & DP%) 328 groundouts and 35 DPs.\n\nUsing Baerga's opportunites (545 groundballs, 99 possible double plays).\nAlomar would have had (with the same DA & DP%) 386 groundouts and 25 DPs.\nBaerga had 381 groundouts and 47 DPs.\n\nBaerga looks better, though it's possible his DP% would be lower with a \ndifferent SS.\n\nWill Baerga consistently turn twice as many double plays, however? Alomar\nhas established a high level of defense, Baerga has not. I would bet on\nAlomar to be better next year, but last year Baerga was just as good overall.\n-- \nDale J. Stephenson |*| (steph@cs.uiuc.edu) |*| Grad Student At Large\n\n \"It is considered good to look wise, especially when not \n overburdened with information\" -- J. Golden Kimball\n\n###\n\n","output":" baseball"} +{"input":"From: scott@asd.com (Scott Barman)\nSubject: Re: Jewish Baseball Players?\nOrganization: American Software Development Corp., West Babylon, NY\nLines: 18\n\nIn article <15APR93.14691229.0062@lafibm.lafayette.edu> VB30@lafibm.lafayette.edu (VB30) writes:\n>Just wondering. A friend and I were talking the other day, and\n>we were (for some reason) trying to come up with names of Jewish\n>baseball players, past and present. We weren't able to come up\n>with much, except for Sandy Koufax, (somebody) Stankowitz, and\n>maybe John Lowenstein. Can anyone come up with any more. I know\n>it sounds pretty lame to be racking our brains over this, but\n>humor us. Thanks for your help.\n>\n\nOh... I forgot... Art Shamsky, former Red and Mets player. Batted .301\nbetween injuries in 1969 (fell short of qualifying for Top 10 because of\ninjuries and platoon with Ron Swoboda; no Swobo wasn't Jewish).\n-- \nscott barman | Mets Mailing List (feed the following into your shell):\nscott@asd.com | mail mets-request@asd.com <\nSubject: Don Cherry - help me out, here\nOrganization: Administrative Computing & Info Services, Carnegie Mellon, Pittsburgh, PA\nLines: 12\nNNTP-Posting-Host: andrew.cmu.edu\n\n\n As a person who has rarely even SEEN Don Cherry and doesn't know\nanything about him, I don't know whether it is just this area\n(Pittsburgh) of the USA that is \"deprived\" of his broadcasts or whether\nhe's a Canadian thing altogether. Seriously, what is he all about? I\nknow he was a coach at one time, and from the volume of posts about him,\nSOMEONE surely is getting a steady diet of him somehow, but my question\nis, what is the deal with him? Secondly, are the comments of his that I\nread about on the net merely flame bait, or do people actually take him\nseriously? I gotta tell you, from what I see, he really sounds like an\nass. Let me know - maybe I'm missing something.\n\n###\n\n","output":" hockey"} +{"input":"From: Young-Soo Che \nSubject: Re: NHLPA poll (partial stats\/results)\nOrganization: Freshman, H&SS general, Carnegie Mellon, Pittsburgh, PA\nLines: 6\nNNTP-Posting-Host: andrew.cmu.edu\nIn-Reply-To: <1800@muller.loria.fr>\n\nAll these people who send in their polls should take a closer look at\nNJD, they are a very deep team, with two very capable goalies, and\nexcellent forwards and defensemen. Shooter in Richer, an all around do\nit all in Todd, chef Stasny-master of a thousand dishes, power play\ncaptain-Stevens. Take a look at the numbers, or play with them and see\nfor yourselves.\n\n###\n\n","output":" hockey"} +{"input":"From: mjones@fenway.aix.kingston.ibm.com (Mike Jones)\nSubject: Two stooges\nReply-To: mjones@donald.aix.kingston.ibm.com\nOrganization: IBM AIX\/ESA Development, Kingston NY\nLines: 9\n\nWell, the Red Sox have apparenly resigned Herm Winningham to a AAA contract.\nTed \"Larry\" Simmons signed him to a AAA contract then released him from\nBuffalo, allowing Lou \"Curly\" Gorman to circumvent the rule about not\nresigning free agents until May 1. Clearly, neither of these guys is bright\nenough to be Moe.\n\n Mike Jones | AIX High-End Development | mjones@donald.aix.kingston.ibm.com\n\nMake it right before you make it faster.\n\n###\n\n","output":" baseball"} From 51ceeb8546fa35baac9a7ca8137a0ab0210e9fb9 Mon Sep 17 00:00:00 2001 From: Richard Weerasinghe Date: Wed, 8 Nov 2023 22:29:59 +1300 Subject: [PATCH 04/62] terrafmt fixes --- internal/service/bedrock/custom_model_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index 42587473759..331680edf53 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -23,11 +23,11 @@ func TestAccBedrockCustomModel_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccCustomModelConfig_basic(rName), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr(customModelResourceName, "custom_model_name", rName), - resource.TestCheckResourceAttr(customModelResourceName, "job_name", rName), - resource.TestCheckResourceAttr(customModelResourceName, "base_model_id", "amazon.titan-text-express-v1"), - resource.TestCheckResourceAttr(customModelResourceName, "tags.%", "0"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(customModelResourceName, "custom_model_name", rName), + resource.TestCheckResourceAttr(customModelResourceName, "job_name", rName), + resource.TestCheckResourceAttr(customModelResourceName, "base_model_id", "amazon.titan-text-express-v1"), + resource.TestCheckResourceAttr(customModelResourceName, "tags.%", "0"), ), }, { From 416bf280278b9d0fdccd7da2d24fe61c5c0661a0 Mon Sep 17 00:00:00 2001 From: Richard Weerasinghe Date: Wed, 8 Nov 2023 22:53:19 +1300 Subject: [PATCH 05/62] add docs --- .../docs/d/bedrock_custom_model.html.markdown | 43 ++++ .../d/bedrock_custom_models.html.markdown | 44 ++++ .../docs/r/bedrock_custom_model.html.markdown | 206 ++++++++++++++++++ 3 files changed, 293 insertions(+) create mode 100644 website/docs/d/bedrock_custom_model.html.markdown create mode 100644 website/docs/d/bedrock_custom_models.html.markdown create mode 100644 website/docs/r/bedrock_custom_model.html.markdown diff --git a/website/docs/d/bedrock_custom_model.html.markdown b/website/docs/d/bedrock_custom_model.html.markdown new file mode 100644 index 00000000000..c84a468bb36 --- /dev/null +++ b/website/docs/d/bedrock_custom_model.html.markdown @@ -0,0 +1,43 @@ +--- +subcategory: "Amazon Bedrock" +layout: "aws" +page_title: "AWS: aws_bedrock_custom_model" +description: |- + Get the properties associated with a Bedrock custom model that you have created +--- + +# Data Source: aws_bedrock_custom_model + +Get the properties associated with a Bedrock custom model that you have created. + +## Example Usage + +```terraform +data "aws_bedrock_custom_model" "test" { + model_arn = "" +} +``` + +## Argument Reference + +* `model_arn` – (Required) Name or ARN of the custom model. + +## Attribute Reference + +This data source exports the following attributes in addition to the arguments above: + +* `base_model_arn` - ARN of the base model. +* `creation_time` - Creation time of the model. +* `hyper_parameters` - Hyperparameter values associated with this model. +* `job_arn` - Job ARN associated with this model. +* `job_name` - Job name associated with this model. +* `model_kms_key_arn` - The custom model is encrypted at rest using this key. +* `model_name` - Model name associated with this model. +* `output_data_config` - Output data configuration associated with this custom model. +* `training_data_config` - Information about the training dataset. +* `training_metrics` - The training metrics from the job creation. +* `validation_data_config` - Array of up to 10 validators. +* `validation_metrics` - The validation metrics from the job creation. +* `job_tags` - Key-value mapping of tags for the fine-tuning job. +* `tags` - Key-value mapping of resource tags. + \ No newline at end of file diff --git a/website/docs/d/bedrock_custom_models.html.markdown b/website/docs/d/bedrock_custom_models.html.markdown new file mode 100644 index 00000000000..4ec554d3262 --- /dev/null +++ b/website/docs/d/bedrock_custom_models.html.markdown @@ -0,0 +1,44 @@ +--- +subcategory: "Amazon Bedrock" +layout: "aws" +page_title: "AWS: aws_bedrock_custom_models" +description: |- + Returns a list of the custom models that you have created with the CreateModelCustomizationJob operation. +--- + +# Data Source: aws_bedrock_custom_models + +Returns a list of the custom models that you have created with the CreateModelCustomizationJob operation. + +## Example Usage + +```terraform +data "aws_bedrock_custom_models" "test" {} +``` + +## Argument Reference + +None + +## Attribute Reference + +This data source exports the following attributes in addition to the arguments above: + +* `model_summaries` - array of CustomModelSummary objects + +### CustomModelSummary + +Attributes of the CustomModelSummary object. + +* `base_model_arn` - The base model ARN. +* `base_model_name` - The base model name. +* `creation_time` - Creation time of the model. +* `model_arn` - The ARN of the custom model. +* `model_name` - The name of the custom model. +* `model_kms_key_arn` - The custom model is encrypted at rest using this key. +* `model_name` - Model name associated with this model. +* `output_data_config` - Output data configuration associated with this custom model. +* `training_data_config` - Information about the training dataset. +* `training_metrics` - The training metrics from the job creation. +* `validation_data_config` - Array of up to 10 validators. +* `validation_metrics` - The validation metrics from the job creation. diff --git a/website/docs/r/bedrock_custom_model.html.markdown b/website/docs/r/bedrock_custom_model.html.markdown new file mode 100644 index 00000000000..627c57b9ba1 --- /dev/null +++ b/website/docs/r/bedrock_custom_model.html.markdown @@ -0,0 +1,206 @@ +--- +subcategory: "Amazon Bedrock" +layout: "aws" +page_title: "AWS: aws_bedrock_custom_model" +description: |- + Manages a Bedrock custom model +--- + +# Resource: aws_bedrock_custom_model + +Manages a Bedrock custom model. + +## Example Usage + +```terraform +resource "random_id" "id" { + byte_length = 8 +} + +data aws_caller_identity current {} + +resource aws_s3_bucket training_data { + bucket = "bedrock-training-data-${random_id.id.hex}" +} + +resource aws_s3_bucket validation_data { + bucket = "bedrock-validation-data-${random_id.id.hex}" +} + +resource aws_s3_bucket output_data { + bucket = "bedrock-output-data-${random_id.id.hex}" +} + +resource "aws_s3_bucket_object" "training_data" { + bucket = aws_s3_bucket.training_data.id + key = "myfolder/training_data.jsonl" + source = "./testdata/training_data.jsonl" + etag = filemd5("./testdata/training_data.jsonl") +} + +resource "aws_s3_bucket_object" "validation_data" { + bucket = aws_s3_bucket.validation_data.id + key = "myfolder/validation_data.jsonl" + source = "./testdata/validation_data.jsonl" + etag = filemd5("./testdata/validation_data.jsonl") +} + +resource "aws_iam_role" "bedrock_fine_tuning" { + name = "bedrock-fine-tuning-${random_id.id.hex}" + + assume_role_policy = < Date: Wed, 8 Nov 2023 23:03:03 +1300 Subject: [PATCH 06/62] make semall fixes --- internal/service/bedrock/custom_model.go | 2 +- internal/service/bedrock/structures.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 369dc59e60e..a4cf5116bc1 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -213,7 +213,7 @@ func (r *resourceCustomModel) Create(ctx context.Context, req resource.CreateReq if resp.Diagnostics.HasError() { return } - vpcConfig := expandVpcConfig(ctx, vpcConfigs) + vpcConfig := expandVPCConfig(ctx, vpcConfigs) if len(vpcConfigs) > 0 { input.VpcConfig = &vpcConfig[0] } diff --git a/internal/service/bedrock/structures.go b/internal/service/bedrock/structures.go index 549f80b3549..45193b26fc3 100644 --- a/internal/service/bedrock/structures.go +++ b/internal/service/bedrock/structures.go @@ -28,7 +28,7 @@ type validationMetrics struct { ValidationLoss types.Float64 `tfsdk:"validation_loss"` } -func expandVpcConfig(ctx context.Context, tfList []vpcConfig) []bedrock_types.VpcConfig { +func expandVPCConfig(ctx context.Context, tfList []vpcConfig) []bedrock_types.VpcConfig { if len(tfList) == 0 { return nil } From 579d6630685264c11b09100b4c8d602b329b5056 Mon Sep 17 00:00:00 2001 From: Richard Weerasinghe Date: Thu, 9 Nov 2023 18:17:32 +1300 Subject: [PATCH 07/62] linting fixes --- .../bedrock/custom_model_data_source.go | 11 +--- .../bedrock/custom_models_data_source.go | 60 +++++++++---------- internal/service/bedrock/structures.go | 3 +- 3 files changed, 34 insertions(+), 40 deletions(-) diff --git a/internal/service/bedrock/custom_model_data_source.go b/internal/service/bedrock/custom_model_data_source.go index 6684c592aee..aa8fd682436 100644 --- a/internal/service/bedrock/custom_model_data_source.go +++ b/internal/service/bedrock/custom_model_data_source.go @@ -10,7 +10,6 @@ import ( "github.com/aws/aws-sdk-go-v2/service/bedrock" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-aws/internal/framework" "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" @@ -135,7 +134,7 @@ func (d *dataSourceCustomModel) Read(ctx context.Context, request datasource.Rea } data.JobTags = flex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) - response.Diagnostics.Append(data.refreshFromOutput(ctx, model)...) + data.refreshFromOutput(ctx, model) response.Diagnostics.Append(response.State.Set(ctx, &data)...) } @@ -159,11 +158,9 @@ type customModel struct { Tags types.Map `tfsdk:"tags"` } -func (data *customModel) refreshFromOutput(ctx context.Context, model *bedrock.GetCustomModelOutput) diag.Diagnostics { - var diags diag.Diagnostics - +func (data *customModel) refreshFromOutput(ctx context.Context, model *bedrock.GetCustomModelOutput) { if model == nil { - return diags + return } data.ID = flex.StringToFramework(ctx, model.ModelArn) @@ -179,6 +176,4 @@ func (data *customModel) refreshFromOutput(ctx context.Context, model *bedrock.G data.TrainingMetrics = flattenTrainingMetrics(ctx, model.TrainingMetrics) data.ValidationMetrics = flattenValidationMetrics(ctx, model.ValidationMetrics) data.OutputDataConfig = flex.StringToFramework(ctx, model.OutputDataConfig.S3Uri) - - return diags } diff --git a/internal/service/bedrock/custom_models_data_source.go b/internal/service/bedrock/custom_models_data_source.go index 075517c7ac4..960a7f463af 100644 --- a/internal/service/bedrock/custom_models_data_source.go +++ b/internal/service/bedrock/custom_models_data_source.go @@ -5,14 +5,17 @@ package bedrock import ( "context" + "time" "github.com/aws/aws-sdk-go-v2/service/bedrock" + bedrock_types "github.com/aws/aws-sdk-go-v2/service/bedrock/types" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-aws/internal/framework" "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" ) // @FrameworkDataSource @@ -84,7 +87,7 @@ func (d *dataSourceCustomModels) Read(ctx context.Context, request datasource.Re } data.ID = flex.StringToFramework(ctx, &d.Meta().Region) - response.Diagnostics.Append(data.refreshFromOutput(ctx, models)...) + data.refreshFromOutput(ctx, models) response.Diagnostics.Append(response.State.Set(ctx, &data)...) } @@ -93,37 +96,32 @@ type customModels struct { ModelSummaries types.List `tfsdk:"model_summaries"` } -func (cms *customModels) refreshFromOutput(ctx context.Context, out *bedrock.ListCustomModelsOutput) diag.Diagnostics { - var diags diag.Diagnostics - +func (cms *customModels) refreshFromOutput(ctx context.Context, out *bedrock.ListCustomModelsOutput) { if out == nil { - return diags + return } + cms.ModelSummaries = flattenCustomModelSummaries(ctx, out.ModelSummaries) +} - // cms.ModelSummaries = flattenCustomModelSummaries(ctx, out.ModelSummaries) +func flattenCustomModelSummaries(ctx context.Context, models []bedrock_types.CustomModelSummary) types.List { + attributeTypes := fwtypes.AttributeTypesMust[customModels](ctx) + elemType := types.ObjectType{AttrTypes: attributeTypes} - return diags -} + if models == nil { + return types.ListNull(elemType) + } + + attrs := make([]attr.Value, 0, len(models)) + for _, model := range models { + attr := map[string]attr.Value{} + attr["base_model_arn"] = flex.StringToFramework(ctx, model.BaseModelArn) + attr["base_model_name"] = flex.StringToFramework(ctx, model.BaseModelName) + attr["model_arn"] = flex.StringToFramework(ctx, model.ModelArn) + attr["model_name"] = flex.StringToFramework(ctx, model.ModelName) + attr["creation_time"] = flex.StringValueToFramework[string](ctx, model.CreationTime.Format(time.RFC3339)) + val := types.ObjectValueMust(attributeTypes, attr) + attrs = append(attrs, val) + } -// func flattenCustomModelSummaries(ctx context.Context, models []bedrock_types.CustomModelSummary) types.List { -// attributeTypes := flex.AttributeTypesMust[customModels](ctx) -// elemType := types.ObjectType{AttrTypes: attributeTypes} - -// if models == nil { -// return types.ListNull(elemType) -// } - -// attrs := make([]attr.Value, 0, len(models)) -// for _, model := range models { -// attr := map[string]attr.Value{} -// attr["base_model_arn"] = flex.StringToFramework(ctx, model.BaseModelArn) -// attr["base_model_name"] = flex.StringToFramework(ctx, model.BaseModelName) -// attr["model_arn"] = flex.StringToFramework(ctx, model.ModelArn) -// attr["model_name"] = flex.StringToFramework(ctx, model.ModelName) -// attr["creation_time"] = flex.StringValueToFramework[string](ctx, model.CreationTime.Format(time.RFC3339)) -// val := types.ObjectValueMust(attributeTypes, attr) -// attrs = append(attrs, val) -// } - -// return types.ListValueMust(elemType, attrs) -// } + return types.ListValueMust(elemType, attrs) +} diff --git a/internal/service/bedrock/structures.go b/internal/service/bedrock/structures.go index 45193b26fc3..68f60fc7a32 100644 --- a/internal/service/bedrock/structures.go +++ b/internal/service/bedrock/structures.go @@ -52,8 +52,9 @@ func expandValidationDataConfig(ctx context.Context, model *validationDataConfig apiObject := &bedrock_types.ValidationDataConfig{} for _, validator := range flex.ExpandFrameworkStringValueSet(ctx, model.Validators) { + s3uri := validator apiObject.Validators = append(apiObject.Validators, bedrock_types.Validator{ - S3Uri: &validator, + S3Uri: &s3uri, }) } From e1b689520ffb6b94564228465f2716d4baab778c Mon Sep 17 00:00:00 2001 From: Richard Weerasinghe Date: Mon, 11 Dec 2023 18:36:29 +1300 Subject: [PATCH 08/62] fix custom model resource --- internal/service/bedrock/custom_model.go | 83 ++++++++++--------- .../bedrock/custom_model_data_source.go | 2 +- internal/service/bedrock/custom_model_test.go | 46 ++++++++++ internal/service/bedrock/structures.go | 50 ++++++++--- 4 files changed, 129 insertions(+), 52 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index a4cf5116bc1..5f9b00d6a26 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -12,6 +12,7 @@ import ( bedrock_types "github.com/aws/aws-sdk-go-v2/service/bedrock/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -114,16 +115,14 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), }, Blocks: map[string]schema.Block{ - "validation_data_config": schema.ListNestedBlock{ - Validators: []validator.List{ - listvalidator.SizeBetween(0, 10), - }, - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "validators": schema.SetAttribute{ - ElementType: types.StringType, - Optional: true, + "validation_data_config": schema.SingleNestedBlock{ + Attributes: map[string]schema.Attribute{ + "validators": schema.SetAttribute{ + Validators: []validator.Set{ + setvalidator.SizeBetween(0, 10), }, + ElementType: types.StringType, + Optional: true, }, }, }, @@ -145,10 +144,15 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, }, }, - "training_metrics": schema.SingleNestedBlock{ - Attributes: map[string]schema.Attribute{ - "training_loss": schema.Float64Attribute{ - Computed: true, + "training_metrics": schema.ListNestedBlock{ + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "training_loss": schema.Float64Attribute{ + Computed: true, + }, }, }, }, @@ -192,7 +196,7 @@ func (r *resourceCustomModel) Create(ctx context.Context, req resource.CreateReq S3Uri: data.OutputDataConfig.ValueStringPointer(), }, CustomModelTags: getTagsIn(ctx), - ValidationDataConfig: expandValidationDataConfig(ctx, data.ValidationDataConfig), + ValidationDataConfig: expandValidationDataConfig(ctx, data.ValidationDataConfig, diag.Diagnostics{}), } var hp map[string]string @@ -242,6 +246,9 @@ func (r *resourceCustomModel) Create(ctx context.Context, req resource.CreateReq } // Successfully started job. Save the id now + // data.ID = flex.StringValueToFramework(ctx, "tf-acc-test-1531621220222582981") + // data.JobArn = flex.StringValueToFramework(ctx, "arn:aws:bedrock:us-east-1:219858395663:model-customization-job/amazon.titan-text-express-v1:0:8k/pc2v9cmxjzlq") + data.ID = data.CustomModelName // Also save job arn into state now incase we need to cancel and destroy. data.JobArn = flex.StringToFramework(ctx, jobStart.JobArn) @@ -317,30 +324,30 @@ func waitForModelCustomizationJob(ctx context.Context, conn *bedrock.Client, job } type resourceCustomModelModel struct { - ID types.String `tfsdk:"id"` - BaseModelId types.String `tfsdk:"base_model_id"` - ClientRequestToken types.String `tfsdk:"client_request_token"` - CustomModelKmsKeyId types.String `tfsdk:"custom_model_kms_key_id"` - CustomModelName types.String `tfsdk:"custom_model_name"` - HyperParameters types.Map `tfsdk:"hyper_parameters"` - JobName types.String `tfsdk:"job_name"` - JobTags types.Map `tfsdk:"job_tags"` - OutputDataConfig types.String `tfsdk:"output_data_config"` - RoleArn types.String `tfsdk:"role_arn"` - TrainingDataConfig types.String `tfsdk:"training_data_config"` - BaseModelArn types.String `tfsdk:"base_model_arn"` - CreationTime types.String `tfsdk:"creation_time"` - JobArn types.String `tfsdk:"job_arn"` - ModelArn types.String `tfsdk:"model_arn"` - ModelKmsKeyArn types.String `tfsdk:"model_kms_key_arn"` - ModelName types.String `tfsdk:"model_name"` - ValidationDataConfig *validationDataConfig `tfsdk:"validation_data_config"` - VpcConfig types.List `tfsdk:"vpc_config"` - TrainingMetrics *trainingMetrics `tfsdk:"training_metrics"` - ValidationMetrics []validationMetrics `tfsdk:"validation_metrics"` - Tags types.Map `tfsdk:"tags"` - TagsAll types.Map `tfsdk:"tags_all"` - Timeouts timeouts.Value `tfsdk:"timeouts"` + ID types.String `tfsdk:"id"` + BaseModelId types.String `tfsdk:"base_model_id"` + ClientRequestToken types.String `tfsdk:"client_request_token"` + CustomModelKmsKeyId types.String `tfsdk:"custom_model_kms_key_id"` + CustomModelName types.String `tfsdk:"custom_model_name"` + HyperParameters types.Map `tfsdk:"hyper_parameters"` + JobName types.String `tfsdk:"job_name"` + JobTags types.Map `tfsdk:"job_tags"` + OutputDataConfig types.String `tfsdk:"output_data_config"` + RoleArn types.String `tfsdk:"role_arn"` + TrainingDataConfig types.String `tfsdk:"training_data_config"` + BaseModelArn types.String `tfsdk:"base_model_arn"` + CreationTime types.String `tfsdk:"creation_time"` + JobArn types.String `tfsdk:"job_arn"` + ModelArn types.String `tfsdk:"model_arn"` + ModelKmsKeyArn types.String `tfsdk:"model_kms_key_arn"` + ModelName types.String `tfsdk:"model_name"` + ValidationDataConfig types.Object `tfsdk:"validation_data_config"` + VpcConfig types.List `tfsdk:"vpc_config"` + TrainingMetrics types.List `tfsdk:"training_metrics"` + ValidationMetrics []validationMetrics `tfsdk:"validation_metrics"` + Tags types.Map `tfsdk:"tags"` + TagsAll types.Map `tfsdk:"tags_all"` + Timeouts timeouts.Value `tfsdk:"timeouts"` } func (data *resourceCustomModelModel) refresh(ctx context.Context, conn *bedrock.Client) diag.Diagnostics { diff --git a/internal/service/bedrock/custom_model_data_source.go b/internal/service/bedrock/custom_model_data_source.go index aa8fd682436..ece9a83ae51 100644 --- a/internal/service/bedrock/custom_model_data_source.go +++ b/internal/service/bedrock/custom_model_data_source.go @@ -150,7 +150,7 @@ type customModel struct { ModelKmsKeyArn types.String `tfsdk:"model_kms_key_arn"` HyperParameters types.Map `tfsdk:"hyper_parameters"` TrainingDataConfig types.String `tfsdk:"training_data_config"` - TrainingMetrics *trainingMetrics `tfsdk:"training_metrics"` + TrainingMetrics types.List `tfsdk:"training_metrics"` ValidationDataConfig *validationDataConfig `tfsdk:"validation_data_config"` ValidationMetrics []validationMetrics `tfsdk:"validation_metrics"` OutputDataConfig types.String `tfsdk:"output_data_config"` diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index 331680edf53..654275939a8 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -39,6 +39,33 @@ func TestAccBedrockCustomModel_basic(t *testing.T) { }) } +// func TestAccBedrockCustomModel_basic(t *testing.T) { +// ctx := acctest.Context(t) +// rName := "tf-acc-test-1531621220222582981" // sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) +// customModelResourceName := "aws_bedrock_custom_model.test" + +// resource.ParallelTest(t, resource.TestCase{ +// PreCheck: func() { acctest.PreCheck(ctx, t) }, +// ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, +// Steps: []resource.TestStep{ +// { +// Config: testAccCustomModelConfig_basic2(rName), +// Check: resource.ComposeAggregateTestCheckFunc( +// resource.TestCheckResourceAttr(customModelResourceName, "custom_model_name", rName), +// resource.TestCheckResourceAttr(customModelResourceName, "job_name", rName), +// resource.TestCheckResourceAttr(customModelResourceName, "base_model_id", "amazon.titan-text-express-v1"), +// resource.TestCheckResourceAttr(customModelResourceName, "tags.%", "0"), +// ), +// }, +// { +// ResourceName: customModelResourceName, +// ImportState: true, +// ImportStateVerify: true, +// }, +// }, +// }) +// } + func testAccCustomModelConfig_basic(rName string) string { return fmt.Sprintf(` data "aws_caller_identity" "current" {} @@ -178,3 +205,22 @@ resource "aws_bedrock_custom_model" "test" { } `, rName) } + +// func testAccCustomModelConfig_basic2(rName string) string { +// return fmt.Sprintf(` +// resource "aws_bedrock_custom_model" "test" { +// custom_model_name = %[1]q +// job_name = %[1]q +// base_model_id = "amazon.titan-text-express-v1" +// role_arn = "arn:aws:iam::219858395663:role/bedrock-fine-tuning-tf-acc-test-1531621220222582981" +// hyper_parameters = { +// "epochCount" = "1" +// "batchSize" = "1" +// "learningRate" = "0.005" +// "learningRateWarmupSteps" = "0" +// } +// output_data_config = "s3://bedrock-output-data-tf-acc-test-1531621220222582981/myfolder/" +// training_data_config = "s3://bedrock-training-data-tf-acc-test-1531621220222582981/myfolder/training_data.jsonl" +// } +// `, rName) +// } diff --git a/internal/service/bedrock/structures.go b/internal/service/bedrock/structures.go index 68f60fc7a32..ce51af33788 100644 --- a/internal/service/bedrock/structures.go +++ b/internal/service/bedrock/structures.go @@ -7,8 +7,12 @@ import ( "context" bedrock_types "github.com/aws/aws-sdk-go-v2/service/bedrock/types" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" ) type vpcConfig struct { @@ -45,8 +49,14 @@ func expandVPCConfig(ctx context.Context, tfList []vpcConfig) []bedrock_types.Vp return vpcConfigs } -func expandValidationDataConfig(ctx context.Context, model *validationDataConfig) *bedrock_types.ValidationDataConfig { - if model == nil { +func expandValidationDataConfig(ctx context.Context, object types.Object, diags diag.Diagnostics) *bedrock_types.ValidationDataConfig { + if object.IsNull() { + return nil + } + + var model validationDataConfig + diags.Append(object.As(ctx, &model, basetypes.ObjectAsOptions{})...) + if diags.HasError() { return nil } @@ -61,19 +71,26 @@ func expandValidationDataConfig(ctx context.Context, model *validationDataConfig return apiObject } -func flattenTrainingMetrics(ctx context.Context, apiObject *bedrock_types.TrainingMetrics) *trainingMetrics { - model := &trainingMetrics{} +func flattenTrainingMetrics(ctx context.Context, apiObject *bedrock_types.TrainingMetrics) types.List { + attributeTypes := fwtypes.AttributeTypesMust[trainingMetrics](ctx) + elemType := types.ObjectType{AttrTypes: attributeTypes} - if apiObject != nil { - trainingLoss := float64(*apiObject.TrainingLoss) - model.TrainingLoss = flex.Float64ToFramework(ctx, &trainingLoss) + if apiObject == nil { + return types.ListNull(elemType) } - return model + attrs := make([]attr.Value, 0, 1) + attr := map[string]attr.Value{} + trainingLoss := float64(*apiObject.TrainingLoss) + attr["training_loss"] = flex.Float64ToFramework(ctx, &trainingLoss) + val := types.ObjectValueMust(attributeTypes, attr) + attrs = append(attrs, val) + + return types.ListValueMust(elemType, attrs) } func flattenValidationMetrics(ctx context.Context, apiObjects []bedrock_types.ValidatorMetric) []validationMetrics { - if apiObjects != nil { + if apiObjects == nil { return nil } @@ -88,16 +105,23 @@ func flattenValidationMetrics(ctx context.Context, apiObjects []bedrock_types.Va return model } -func flattenValidationDataConfig(ctx context.Context, apiObject *bedrock_types.ValidationDataConfig) *validationDataConfig { - model := &validationDataConfig{} +func flattenValidationDataConfig(ctx context.Context, apiObject *bedrock_types.ValidationDataConfig) types.Object { + attributeTypes := fwtypes.AttributeTypesMust[validationDataConfig](ctx) + attributeTypes["validators"] = types.SetType{ElemType: types.StringType} + + if apiObject == nil { + return types.ObjectNull(attributeTypes) + } validators := []*string{} if apiObject != nil { for _, validator := range apiObject.Validators { validators = append(validators, validator.S3Uri) } - model.Validators = flex.FlattenFrameworkStringSet(ctx, validators) + } + attrs := map[string]attr.Value{ + "validators": flex.FlattenFrameworkStringSet(ctx, validators), } - return model + return types.ObjectValueMust(attributeTypes, attrs) } From afa16cd4cd5179cfdba3a6b0506824baf914c5ec Mon Sep 17 00:00:00 2001 From: Richard Weerasinghe Date: Tue, 12 Dec 2023 08:02:05 +1300 Subject: [PATCH 09/62] make gen --- internal/service/bedrock/service_package_gen.go | 8 ++++---- internal/service/bedrock/tags_gen.go | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/internal/service/bedrock/service_package_gen.go b/internal/service/bedrock/service_package_gen.go index 6a9915792b6..8441d022103 100644 --- a/internal/service/bedrock/service_package_gen.go +++ b/internal/service/bedrock/service_package_gen.go @@ -38,16 +38,16 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.Serv func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.ServicePackageFrameworkResource { return []*types.ServicePackageFrameworkResource{ - { - Factory: newResourceModelInvocationLoggingConfiguration, - Name: "Model Invocation Logging Configuration", - }, { Factory: newResourceCustomModel, Tags: &types.ServicePackageResourceTags{ IdentifierAttribute: "model_arn", }, }, + { + Factory: newResourceModelInvocationLoggingConfiguration, + Name: "Model Invocation Logging Configuration", + }, } } diff --git a/internal/service/bedrock/tags_gen.go b/internal/service/bedrock/tags_gen.go index 301519e1e8d..a3a8ca70ea7 100644 --- a/internal/service/bedrock/tags_gen.go +++ b/internal/service/bedrock/tags_gen.go @@ -19,12 +19,12 @@ import ( // listTags lists bedrock service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. -func listTags(ctx context.Context, conn *bedrock.Client, identifier string) (tftags.KeyValueTags, error) { +func listTags(ctx context.Context, conn *bedrock.Client, identifier string, optFns ...func(*bedrock.Options)) (tftags.KeyValueTags, error) { input := &bedrock.ListTagsForResourceInput{ ResourceARN: aws.String(identifier), } - output, err := conn.ListTagsForResource(ctx, input) + output, err := conn.ListTagsForResource(ctx, input, optFns...) if err != nil { return tftags.New(ctx, nil), err @@ -100,7 +100,7 @@ func setTagsOut(ctx context.Context, tags []awstypes.Tag) { // updateTags updates bedrock service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. -func updateTags(ctx context.Context, conn *bedrock.Client, identifier string, oldTagsMap, newTagsMap any) error { +func updateTags(ctx context.Context, conn *bedrock.Client, identifier string, oldTagsMap, newTagsMap any, optFns ...func(*bedrock.Options)) error { oldTags := tftags.New(ctx, oldTagsMap) newTags := tftags.New(ctx, newTagsMap) @@ -114,7 +114,7 @@ func updateTags(ctx context.Context, conn *bedrock.Client, identifier string, ol TagKeys: removedTags.Keys(), } - _, err := conn.UntagResource(ctx, input) + _, err := conn.UntagResource(ctx, input, optFns...) if err != nil { return fmt.Errorf("untagging resource (%s): %w", identifier, err) @@ -129,7 +129,7 @@ func updateTags(ctx context.Context, conn *bedrock.Client, identifier string, ol Tags: Tags(updatedTags), } - _, err := conn.TagResource(ctx, input) + _, err := conn.TagResource(ctx, input, optFns...) if err != nil { return fmt.Errorf("tagging resource (%s): %w", identifier, err) From 561a5408cdc119db000bddd0c3b098b87b4d9817 Mon Sep 17 00:00:00 2001 From: Tyler Lynch Date: Wed, 13 Dec 2023 09:45:33 -0500 Subject: [PATCH 10/62] attributes, customization type --- internal/service/bedrock/custom_model.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 5f9b00d6a26..6caf84d2941 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -9,7 +9,7 @@ import ( "time" "github.com/aws/aws-sdk-go-v2/service/bedrock" - bedrock_types "github.com/aws/aws-sdk-go-v2/service/bedrock/types" + awstypes "github.com/aws/aws-sdk-go-v2/service/bedrock/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" @@ -17,10 +17,13 @@ import ( "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/framework" "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" @@ -47,15 +50,18 @@ func (r *resourceCustomModel) Metadata(_ context.Context, request resource.Metad func (r *resourceCustomModel) Schema(ctx context.Context, request resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - "id": framework.IDAttribute(), - "base_model_id": schema.StringAttribute{ + "base_model_identifier": schema.StringAttribute{ Required: true, // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^(arn:aws(-[^:]+)?:bedrock:[a-z0-9-]{1,20}:(([0-9]{12}:custom-model/[a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}/[a-z0-9]{12})|(:foundation-model/[a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}([a-z0-9-]{1,63}[.]){0,2}[a-z0-9-]{1,63}([:][a-z0-9-]{1,63}){0,2})))|([a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}([.]?[a-z0-9-]{1,63})([:][a-z0-9-]{1,63}){0,2})|(([0-9a-zA-Z][_-]?)+)$`), "minimum length of 1. Maximum length of 2048."), }, - "client_request_token": schema.StringAttribute{ + "customization_type": schema.StringAttribute{ Optional: true, - // ForceNew: true, - // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^[a-zA-Z0-9](-*[a-zA-Z0-9])*$`), "minimum length of 1. Maximum length of 256."), + Validators: []validator.String{ + enum.FrameworkValidate[awstypes.CustomizationType](), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "custom_model_kms_key_id": schema.StringAttribute{ Optional: true, @@ -73,6 +79,7 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem // ForceNew: true, // Elem: &schema.Schema{Type: schema.TypeString}, }, + "id": framework.IDAttribute(), "job_name": schema.StringAttribute{ Required: true, // ForceNew: true, From 744183a83d4901489e54118ab1f18ffa2e7c3d0b Mon Sep 17 00:00:00 2001 From: Tyler Lynch Date: Wed, 13 Dec 2023 09:50:32 -0500 Subject: [PATCH 11/62] atrributes arn --- internal/service/bedrock/custom_model.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 6caf84d2941..ca2326d65eb 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -50,6 +50,12 @@ func (r *resourceCustomModel) Metadata(_ context.Context, request resource.Metad func (r *resourceCustomModel) Schema(ctx context.Context, request resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ + "arn": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, "base_model_identifier": schema.StringAttribute{ Required: true, // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^(arn:aws(-[^:]+)?:bedrock:[a-z0-9-]{1,20}:(([0-9]{12}:custom-model/[a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}/[a-z0-9]{12})|(:foundation-model/[a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}([a-z0-9-]{1,63}[.]){0,2}[a-z0-9-]{1,63}([:][a-z0-9-]{1,63}){0,2})))|([a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}([.]?[a-z0-9-]{1,63})([:][a-z0-9-]{1,63}){0,2})|(([0-9a-zA-Z][_-]?)+)$`), "minimum length of 1. Maximum length of 2048."), From 59f38f5214ba727e0828d27f513f65f132569039 Mon Sep 17 00:00:00 2001 From: Tyler Lynch Date: Thu, 14 Dec 2023 08:48:26 -0500 Subject: [PATCH 12/62] attrtibutes base_model_identifier --- internal/service/bedrock/custom_model.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index ca2326d65eb..595fb7e3c13 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -26,6 +27,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/framework" "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -57,8 +59,11 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, }, "base_model_identifier": schema.StringAttribute{ - Required: true, - // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^(arn:aws(-[^:]+)?:bedrock:[a-z0-9-]{1,20}:(([0-9]{12}:custom-model/[a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}/[a-z0-9]{12})|(:foundation-model/[a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}([a-z0-9-]{1,63}[.]){0,2}[a-z0-9-]{1,63}([:][a-z0-9-]{1,63}){0,2})))|([a-z0-9-]{1,63}[.]{1}[a-z0-9-]{1,63}([.]?[a-z0-9-]{1,63})([:][a-z0-9-]{1,63}){0,2})|(([0-9a-zA-Z][_-]?)+)$`), "minimum length of 1. Maximum length of 2048."), + CustomType: fwtypes.ARNType, + Required: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 2048), + }, }, "customization_type": schema.StringAttribute{ Optional: true, From 076160641b03c063d3ebcf9df356f40bfdc0aa6f Mon Sep 17 00:00:00 2001 From: Tyler Lynch Date: Thu, 14 Dec 2023 08:49:53 -0500 Subject: [PATCH 13/62] attribute ordering --- internal/service/bedrock/custom_model.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 595fb7e3c13..9de615b068f 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -67,12 +67,12 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, "customization_type": schema.StringAttribute{ Optional: true, - Validators: []validator.String{ - enum.FrameworkValidate[awstypes.CustomizationType](), - }, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, + Validators: []validator.String{ + enum.FrameworkValidate[awstypes.CustomizationType](), + }, }, "custom_model_kms_key_id": schema.StringAttribute{ Optional: true, From 2d5bda2c875d67fb86b6b384c39665212f3b181e Mon Sep 17 00:00:00 2001 From: Tyler Lynch Date: Thu, 14 Dec 2023 09:15:18 -0500 Subject: [PATCH 14/62] attributes custom model --- internal/service/bedrock/custom_model.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 9de615b068f..b0976d59cbb 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -68,6 +68,7 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem "customization_type": schema.StringAttribute{ Optional: true, PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), stringplanmodifier.UseStateForUnknown(), }, Validators: []validator.String{ @@ -75,9 +76,14 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, }, "custom_model_kms_key_id": schema.StringAttribute{ - Optional: true, - // ForceNew: true, - // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^arn:aws(-[^:]+)?:kms:[a-zA-Z0-9-]*:[0-9]{12}:((key/[a-zA-Z0-9-]{36})|(alias/[a-zA-Z0-9-_/]+))$`), "minimum length of 1. Maximum length of 2048."), + CustomType: fwtypes.ARNType, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 2048), + }, }, "custom_model_name": schema.StringAttribute{ Required: true, From 418d5daebb3a6419ef6d3ee646064642bb87faeb Mon Sep 17 00:00:00 2001 From: Tyler Lynch Date: Thu, 14 Dec 2023 09:23:40 -0500 Subject: [PATCH 15/62] attri custom model name --- internal/service/bedrock/custom_model.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index b0976d59cbb..6acab187599 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -87,6 +87,9 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, "custom_model_name": schema.StringAttribute{ Required: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 63), + }, // ForceNew: true, // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^([0-9a-zA-Z][_-]?)+$`), "minimum length of 1. Maximum length of 63."), }, From 9dc48cd67e3926cf9f161d633c4eb2d74c289c95 Mon Sep 17 00:00:00 2001 From: Tyler Lynch Date: Tue, 19 Dec 2023 10:30:29 -0500 Subject: [PATCH 16/62] schema alignment --- internal/service/bedrock/custom_model.go | 183 ++++++++++++++--------- 1 file changed, 111 insertions(+), 72 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 6acab187599..67500435d74 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -8,6 +8,7 @@ import ( "fmt" "time" + "github.com/YakDriver/regexache" "github.com/aws/aws-sdk-go-v2/service/bedrock" awstypes "github.com/aws/aws-sdk-go-v2/service/bedrock/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" @@ -24,6 +25,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/framework" "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" @@ -49,18 +51,20 @@ func (r *resourceCustomModel) Metadata(_ context.Context, request resource.Metad resp.TypeName = "aws_bedrock_custom_model" } +// This resource is a composition of the following APIs. These APIs do not have consitently named attributes, so we will normalize them here. +// - CreateModelCustomizationJob +// - GetModelCustomizationJob +// - GetCustomModel func (r *resourceCustomModel) Schema(ctx context.Context, request resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - "arn": schema.StringAttribute{ - Computed: true, + "arn": framework.ARNAttributeComputedOnly(), + "base_model_arn": schema.StringAttribute{ + Required: true, + CustomType: fwtypes.ARNType, PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), + stringplanmodifier.RequiresReplace(), }, - }, - "base_model_identifier": schema.StringAttribute{ - CustomType: fwtypes.ARNType, - Required: true, Validators: []validator.String{ stringvalidator.LengthBetween(1, 2048), }, @@ -75,85 +79,62 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem enum.FrameworkValidate[awstypes.CustomizationType](), }, }, - "custom_model_kms_key_id": schema.StringAttribute{ - CustomType: fwtypes.ARNType, - Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - Validators: []validator.String{ - stringvalidator.LengthBetween(1, 2048), - }, - }, - "custom_model_name": schema.StringAttribute{ - Required: true, - Validators: []validator.String{ - stringvalidator.LengthBetween(1, 63), - }, - // ForceNew: true, - // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^([0-9a-zA-Z][_-]?)+$`), "minimum length of 1. Maximum length of 63."), - }, "hyper_parameters": schema.MapAttribute{ Required: true, ElementType: types.StringType, - // ForceNew: true, - // Elem: &schema.Schema{Type: schema.TypeString}, }, - "id": framework.IDAttribute(), + "job_arn": schema.StringAttribute{ + Computed: true, + }, "job_name": schema.StringAttribute{ Required: true, - // ForceNew: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 63), + stringvalidator.RegexMatches(regexache.MustCompile(`^[a-zA-Z0-9](-*[a-zA-Z0-9\+\-\.])*$`), + "must be up to 63 letters (uppercase and lowercase), numbers, plus sign, dashes, and dots, and must start with an alphanumeric"), + }, }, "job_tags": tftags.TagsAttribute(), - "output_data_config": schema.StringAttribute{ - Required: true, - // ForceNew: true, - // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^s3://[a-z0-9][\.\-a-z0-9]{1,61}[a-z0-9](/.*)?$`), "minimum length of 1. Maximum length of 1024."), - }, - "role_arn": schema.StringAttribute{ + "job_role_arn": schema.StringAttribute{ Required: true, - // ForceNew: true, - // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^arn:aws(-[^:]+)?:iam::([0-9]{12})?:role/.+$`), "minimum length of 1. Maximum length of 2048."), - }, - "training_data_config": schema.StringAttribute{ - Required: true, - // ForceNew: true, - // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^s3://[a-z0-9][\.\-a-z0-9]{1,61}[a-z0-9](/.*)?$`), "minimum length of 1. Maximum length of 1024."), - }, - "base_model_arn": schema.StringAttribute{ - Computed: true, - }, - "creation_time": schema.StringAttribute{ - Computed: true, - }, - "job_arn": schema.StringAttribute{ - Computed: true, + CustomType: fwtypes.ARNType, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 2048), + }, }, - "model_arn": schema.StringAttribute{ + "job_status": schema.StringAttribute{ Computed: true, }, - "model_kms_key_arn": schema.StringAttribute{ - Computed: true, + "kms_key_arn": schema.StringAttribute{ + Optional: true, + CustomType: fwtypes.ARNType, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 2048), + }, }, - "model_name": schema.StringAttribute{ - Computed: true, + "name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 63), + }, }, names.AttrTags: tftags.TagsAttribute(), names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), }, Blocks: map[string]schema.Block{ - "validation_data_config": schema.SingleNestedBlock{ - Attributes: map[string]schema.Attribute{ - "validators": schema.SetAttribute{ - Validators: []validator.Set{ - setvalidator.SizeBetween(0, 10), - }, - ElementType: types.StringType, - Optional: true, - }, - }, - }, - "vpc_config": schema.ListNestedBlock{ + "job_vpc_config": schema.ListNestedBlock{ Validators: []validator.List{ listvalidator.SizeAtMost(1), }, @@ -166,7 +147,42 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem "subnet_ids": schema.SetAttribute{ ElementType: types.StringType, Required: true, - // ValidateFunc: validation.StringMatch(regexache.MustCompile(`^[-0-9a-zA-Z]+$`), "minimum length of 1. Maximum length of 32."), + }, + }, + }, + }, + "output_data_config": schema.ListNestedBlock{ + Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "s3_uri": schema.StringAttribute{ + ElementType: types.StringType, + Required: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 1024), + stringvalidator.RegexMatches(regexache.MustCompile(`^s3://`), "minimum length of 1. Maximum length of 1024. Must be an S3 URI") + }, + }, + }, + }, + }, + "training_data_config": schema.ListNestedBlock{ + Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "s3_uri": schema.StringAttribute{ + ElementType: types.StringType, + Required: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 1024), + stringvalidator.RegexMatches(regexache.MustCompile(`^s3://`), "minimum length of 1. Maximum length of 1024. Must be an S3 URI") + }, }, }, }, @@ -183,6 +199,32 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, }, }, + "validation_data_config": schema.SetNestedBlock{ + Validators: []validator.Set{ + setvalidator.SizeAtMost(10), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "validator": schema.SetNestedBlock{ + Validators: []validator.Set{ + setvalidator.IsRequired(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "s3_uri": schema.StringAttribute{ + ElementType: types.StringType, + Required: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 1024), + stringvalidator.RegexMatches(regexache.MustCompile(`^s3://`), "minimum length of 1. Maximum length of 1024. Must be an S3 URI") + }, + }, + }, + }, + }, + }, + }, + }, "validation_metrics": schema.ListNestedBlock{ NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ @@ -192,9 +234,6 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, }, }, - "timeouts": timeouts.Block(ctx, timeouts.Opts{ - Create: true, - }), }, } } From fdddecd50ccf2c0fa469d8a72db262a7701d69c7 Mon Sep 17 00:00:00 2001 From: Tyler Lynch Date: Thu, 21 Dec 2023 14:53:01 -0500 Subject: [PATCH 17/62] schemas and expand --- internal/framework/flex/float.go | 14 ++ internal/framework/flex/float_test.go | 40 +++ internal/service/bedrock/custom_model.go | 306 +++++++++++------------ internal/service/bedrock/structures.go | 142 ++++++++--- 4 files changed, 313 insertions(+), 189 deletions(-) diff --git a/internal/framework/flex/float.go b/internal/framework/flex/float.go index d7f7250561b..2760a18d399 100644 --- a/internal/framework/flex/float.go +++ b/internal/framework/flex/float.go @@ -10,6 +10,20 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) +// Float32FromFrameworkFloat64 converts a Framework Float64 value to a float64 pointer. +func Float32FromFrameworkFloat64(ctx context.Context, v types.Float64) *float32 { + if v.IsNull() || v.IsUnknown() { + return nil + } + + f := v.ValueFloat64() + if f == 0 { + return nil + } + + return aws.Float32(float32(f)) +} + // Float64ToFramework converts a float64 pointer to a Framework Float64 value. // A nil float64 pointer is converted to a null Float64. func Float64ToFramework(ctx context.Context, v *float64) types.Float64 { diff --git a/internal/framework/flex/float_test.go b/internal/framework/flex/float_test.go index 167f33dd0e4..176d751acda 100644 --- a/internal/framework/flex/float_test.go +++ b/internal/framework/flex/float_test.go @@ -13,6 +13,46 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" ) +func TestFloat32FromFrameworkFloat64(t *testing.T) { + t.Parallel() + + type testCase struct { + input types.Float64 + expected *float32 + } + tests := map[string]testCase{ + "valid float64": { + input: types.Float64Value(42.1), + expected: aws.Float32(42.1), + }, + "valid float64Small": { + input: types.Float64Value(.3), + expected: aws.Float32(.3), + }, + "zero float64": { + input: types.Float64Value(0), + expected: nil, + }, + "nil float64": { + input: types.Float64Null(), + expected: nil, + }, + } + + for name, test := range tests { + name, test := name, test + t.Run(name, func(t *testing.T) { + t.Parallel() + + got := flex.Float32FromFrameworkFloat64(context.Background(), test.input) + + if diff := cmp.Diff(got, test.expected); diff != "" { + t.Errorf("unexpected diff (+wanted, -got): %s", diff) + } + }) + } +} + func TestFloat64ToFramework(t *testing.T) { t.Parallel() diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 67500435d74..4e3603d958b 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -13,7 +13,6 @@ import ( awstypes "github.com/aws/aws-sdk-go-v2/service/bedrock/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" - "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" @@ -25,7 +24,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/framework" "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" @@ -99,7 +98,7 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, "job_tags": tftags.TagsAttribute(), "job_role_arn": schema.StringAttribute{ - Required: true, + Required: true, CustomType: fwtypes.ARNType, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), @@ -138,6 +137,7 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem Validators: []validator.List{ listvalidator.SizeAtMost(1), }, + CustomType: fwtypes.NewListNestedObjectTypeOf[vpcConfig](ctx), NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "security_group_ids": schema.SetAttribute{ @@ -156,32 +156,36 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem listvalidator.IsRequired(), listvalidator.SizeAtMost(1), }, + CustomType: fwtypes.NewListNestedObjectTypeOf[outputDataConfig](ctx), NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "s3_uri": schema.StringAttribute{ - ElementType: types.StringType, - Required: true, + Required: true, Validators: []validator.String{ stringvalidator.LengthBetween(1, 1024), - stringvalidator.RegexMatches(regexache.MustCompile(`^s3://`), "minimum length of 1. Maximum length of 1024. Must be an S3 URI") + stringvalidator.RegexMatches(regexache.MustCompile(`^s3://`), "minimum length of 1. Maximum length of 1024. Must be an S3 URI"), }, }, }, }, }, + "timeouts": timeouts.Block(ctx, timeouts.Opts{ + Create: true, + Delete: true, + }), "training_data_config": schema.ListNestedBlock{ Validators: []validator.List{ listvalidator.IsRequired(), listvalidator.SizeAtMost(1), }, + CustomType: fwtypes.NewListNestedObjectTypeOf[trainingDataConfig](ctx), NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "s3_uri": schema.StringAttribute{ - ElementType: types.StringType, - Required: true, + Required: true, Validators: []validator.String{ stringvalidator.LengthBetween(1, 1024), - stringvalidator.RegexMatches(regexache.MustCompile(`^s3://`), "minimum length of 1. Maximum length of 1024. Must be an S3 URI") + stringvalidator.RegexMatches(regexache.MustCompile(`^s3://`), "minimum length of 1. Maximum length of 1024. Must be an S3 URI"), }, }, }, @@ -191,6 +195,7 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem Validators: []validator.List{ listvalidator.SizeAtMost(1), }, + CustomType: fwtypes.NewListNestedObjectTypeOf[trainingMetrics](ctx), NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "training_loss": schema.Float64Attribute{ @@ -199,24 +204,26 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, }, }, - "validation_data_config": schema.SetNestedBlock{ - Validators: []validator.Set{ - setvalidator.SizeAtMost(10), + "validation_data_config": schema.ListNestedBlock{ + Validators: []validator.List{ + listvalidator.SizeAtMost(1), }, + CustomType: fwtypes.NewListNestedObjectTypeOf[validationDataConfig](ctx), NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "validator": schema.SetNestedBlock{ - Validators: []validator.Set{ - setvalidator.IsRequired(), + Blocks: map[string]schema.Block{ + "validator": schema.ListNestedBlock{ + Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtMost(10), }, + CustomType: fwtypes.NewListNestedObjectTypeOf[validatorConfig](ctx), NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "s3_uri": schema.StringAttribute{ - ElementType: types.StringType, - Required: true, + Required: true, Validators: []validator.String{ stringvalidator.LengthBetween(1, 1024), - stringvalidator.RegexMatches(regexache.MustCompile(`^s3://`), "minimum length of 1. Maximum length of 1024. Must be an S3 URI") + stringvalidator.RegexMatches(regexache.MustCompile(`^s3://`), "minimum length of 1. Maximum length of 1024. Must be an S3 URI"), }, }, }, @@ -226,6 +233,7 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, }, "validation_metrics": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[validationMetrics](ctx), NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "validation_loss": schema.Float64Attribute{ @@ -238,76 +246,69 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem } } -func (r *resourceCustomModel) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - var data resourceCustomModelModel +func (r *resourceCustomModel) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + conn := r.Meta().BedrockClient(ctx) - resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) - if resp.Diagnostics.HasError() { + var data resourceCustomModelData + response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) + if response.Diagnostics.HasError() { return } - conn := r.Meta().BedrockClient(ctx) - defaultTagsConfig := r.Meta().DefaultTagsConfig - job_tags := defaultTagsConfig.MergeTags(tftags.New(ctx, data.JobTags)) + var outputData []outputDataConfig + response.Diagnostics.Append(data.OutputDataConfig.ElementsAs(ctx, &outputData, false)...) + if response.Diagnostics.HasError() { + return + } + var trainingData []trainingDataConfig + response.Diagnostics.Append(data.TrainingDataConfig.ElementsAs(ctx, &trainingData, false)...) + if response.Diagnostics.HasError() { + return + } input := &bedrock.CreateModelCustomizationJobInput{ - BaseModelIdentifier: data.BaseModelId.ValueStringPointer(), - CustomModelName: data.CustomModelName.ValueStringPointer(), + BaseModelIdentifier: data.BaseModelArn.ValueStringPointer(), + CustomModelName: data.Name.ValueStringPointer(), + CustomModelTags: getTagsIn(ctx), + HyperParameters: flex.ExpandFrameworkStringValueMap(ctx, data.HyperParameters), JobName: data.JobName.ValueStringPointer(), - RoleArn: data.RoleArn.ValueStringPointer(), - TrainingDataConfig: &bedrock_types.TrainingDataConfig{ - S3Uri: data.TrainingDataConfig.ValueStringPointer(), - }, - OutputDataConfig: &bedrock_types.OutputDataConfig{ - S3Uri: data.OutputDataConfig.ValueStringPointer(), - }, - CustomModelTags: getTagsIn(ctx), - ValidationDataConfig: expandValidationDataConfig(ctx, data.ValidationDataConfig, diag.Diagnostics{}), + OutputDataConfig: expandOutputDataConfig(ctx, outputData), + TrainingDataConfig: expandTrainingDataConfig(ctx, trainingData), + RoleArn: data.JobRoleArn.ValueStringPointer(), } - var hp map[string]string - resp.Diagnostics.Append(data.HyperParameters.ElementsAs(ctx, &hp, false)...) - if resp.Diagnostics.HasError() { - return - } - input.HyperParameters = hp - - if !data.ClientRequestToken.IsNull() { - input.ClientRequestToken = data.ClientRequestToken.ValueStringPointer() + if !data.CustomizationType.IsNull() { + input.CustomModelName = data.CustomizationType.ValueStringPointer() } - if !data.CustomModelKmsKeyId.IsNull() { - input.CustomModelKmsKeyId = data.CustomModelKmsKeyId.ValueStringPointer() + if !data.KmsKeyArn.IsNull() { + input.CustomModelKmsKeyId = data.KmsKeyArn.ValueStringPointer() } - var vpcConfigs []vpcConfig - resp.Diagnostics.Append(data.VpcConfig.ElementsAs(ctx, &vpcConfigs, false)...) - if resp.Diagnostics.HasError() { - return + if !data.JobTags.IsNull() { + input.JobTags = Tags(tftags.New(ctx, data.JobTags)) } - vpcConfig := expandVPCConfig(ctx, vpcConfigs) - if len(vpcConfigs) > 0 { - input.VpcConfig = &vpcConfig[0] + if !data.JobVpcConfig.IsNull() { + var vpcData []vpcConfig + response.Diagnostics.Append(data.JobVpcConfig.ElementsAs(ctx, &vpcData, false)...) + if response.Diagnostics.HasError() { + return + } + input.VpcConfig = expandVPCConfig(ctx, vpcData) } - - if len(job_tags) > 0 { - input.JobTags = Tags(tftags.New(ctx, job_tags.IgnoreAWS())) + if !data.ValidationDataConfig.IsNull() { + var validationData []validationDataConfig + response.Diagnostics.Append(data.ValidationDataConfig.ElementsAs(ctx, &validationData, false)...) + if response.Diagnostics.HasError() { + return + } + input.ValidationDataConfig = expandValidationDataConfig(ctx, validationData, diag.Diagnostics{}) } - tflog.Info(ctx, "CreateModelCustomizationJobInput:", map[string]any{ - "BaseModelIdentifier": input.BaseModelIdentifier, - "ClientRequestToken": input.ClientRequestToken, - "CustomModelName": input.CustomModelName, - "CustomModelKmsKeyId": input.CustomModelKmsKeyId, - "JobName": input.JobName, - "RoleArn": input.RoleArn, - "OutputDataConfig": input.OutputDataConfig.S3Uri, - "TrainingDataConfig": input.TrainingDataConfig.S3Uri, - "ValidationDataConfig": input.ValidationDataConfig, - "VpcConfig": input.VpcConfig, - }) - - jobStart, err := conn.CreateModelCustomizationJob(ctx, input) + job, err := conn.CreateModelCustomizationJob(ctx, input) if err != nil { - resp.Diagnostics.AddError("creating Bedrock Custom Model Customization Job", err.Error()) + response.Diagnostics.AddError( + create.ProblemStandardMessage(names.Bedrock, create.ErrActionCreating, "ModelCustomizationJob", data.JobName.ValueString(), nil), + err.Error(), + ) return } @@ -315,54 +316,45 @@ func (r *resourceCustomModel) Create(ctx context.Context, req resource.CreateReq // data.ID = flex.StringValueToFramework(ctx, "tf-acc-test-1531621220222582981") // data.JobArn = flex.StringValueToFramework(ctx, "arn:aws:bedrock:us-east-1:219858395663:model-customization-job/amazon.titan-text-express-v1:0:8k/pc2v9cmxjzlq") - data.ID = data.CustomModelName // Also save job arn into state now incase we need to cancel and destroy. - data.JobArn = flex.StringToFramework(ctx, jobStart.JobArn) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) - if resp.Diagnostics.HasError() { - return - } + data.JobArn = flex.StringToFramework(ctx, job.JobArn) - createTimeout := r.CreateTimeout(ctx, data.Timeouts) - err = waitForModelCustomizationJob(ctx, conn, *jobStart.JobArn, createTimeout) - if err != nil { - resp.Diagnostics.AddError("failed to complete model customisation job", err.Error()) + response.Diagnostics.Append(data.refresh(ctx, conn)...) + if response.Diagnostics.HasError() { return } - - resp.Diagnostics.Append(data.refresh(ctx, conn)...) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + response.Diagnostics.Append(response.State.Set(ctx, &data)...) } -func (r *resourceCustomModel) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var data resourceCustomModelModel - resp.Diagnostics.Append(req.State.Get(ctx, &data)...) - if resp.Diagnostics.HasError() { +func (r *resourceCustomModel) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + var data resourceCustomModelData + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + if response.Diagnostics.HasError() { return } conn := r.Meta().BedrockClient(ctx) - resp.Diagnostics.Append(data.refresh(ctx, conn)...) - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) + response.Diagnostics.Append(data.refresh(ctx, conn)...) + response.Diagnostics.Append(response.State.Set(ctx, &data)...) } -func (r *resourceCustomModel) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { +func (r *resourceCustomModel) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { tflog.Trace(ctx, "Update not supported.") } -func (r *resourceCustomModel) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { +func (r *resourceCustomModel) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { conn := r.Meta().BedrockClient(ctx) _, err := conn.DeleteModelInvocationLoggingConfiguration(ctx, &bedrock.DeleteModelInvocationLoggingConfigurationInput{}) if err != nil { - resp.Diagnostics.AddError("failed to delete model invocation logging configuration", err.Error()) + response.Diagnostics.AddError("failed to delete model invocation logging configuration", err.Error()) return } } -func (r *resourceCustomModel) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) +func (r *resourceCustomModel) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("id"), request, response) } func waitForModelCustomizationJob(ctx context.Context, conn *bedrock.Client, jobArn string, timeout time.Duration) error { @@ -389,70 +381,68 @@ func waitForModelCustomizationJob(ctx context.Context, conn *bedrock.Client, job }) } -type resourceCustomModelModel struct { - ID types.String `tfsdk:"id"` - BaseModelId types.String `tfsdk:"base_model_id"` - ClientRequestToken types.String `tfsdk:"client_request_token"` - CustomModelKmsKeyId types.String `tfsdk:"custom_model_kms_key_id"` - CustomModelName types.String `tfsdk:"custom_model_name"` - HyperParameters types.Map `tfsdk:"hyper_parameters"` - JobName types.String `tfsdk:"job_name"` - JobTags types.Map `tfsdk:"job_tags"` - OutputDataConfig types.String `tfsdk:"output_data_config"` - RoleArn types.String `tfsdk:"role_arn"` - TrainingDataConfig types.String `tfsdk:"training_data_config"` - BaseModelArn types.String `tfsdk:"base_model_arn"` - CreationTime types.String `tfsdk:"creation_time"` - JobArn types.String `tfsdk:"job_arn"` - ModelArn types.String `tfsdk:"model_arn"` - ModelKmsKeyArn types.String `tfsdk:"model_kms_key_arn"` - ModelName types.String `tfsdk:"model_name"` - ValidationDataConfig types.Object `tfsdk:"validation_data_config"` - VpcConfig types.List `tfsdk:"vpc_config"` - TrainingMetrics types.List `tfsdk:"training_metrics"` - ValidationMetrics []validationMetrics `tfsdk:"validation_metrics"` - Tags types.Map `tfsdk:"tags"` - TagsAll types.Map `tfsdk:"tags_all"` - Timeouts timeouts.Value `tfsdk:"timeouts"` +type resourceCustomModelData struct { + Arn types.String `tfsdk:"arn"` + BaseModelArn types.String `tfsdk:"base_model_arn"` + CustomizationType types.String `tfsdk:"customization_type"` + HyperParameters types.Map `tfsdk:"hyper_parameters"` + Id types.String `tfsdk:"id"` + JobArn types.String `tfsdk:"job_arn"` + JobName types.String `tfsdk:"job_name"` + JobTags types.Map `tfsdk:"job_tags"` + JobRoleArn types.String `tfsdk:"job_role_arn"` + JobStatus types.String `tfsdk:"job_status"` + JobVpcConfig fwtypes.ListNestedObjectValueOf[vpcConfig] `tfsdk:"job_vpc_config"` + KmsKeyArn types.String `tfsdk:"kms_key_arn"` + Name types.String `tfsdk:"name"` + OutputDataConfig fwtypes.ListNestedObjectValueOf[outputDataConfig] `tfsdk:"output_data_config"` + TrainingDataConfig fwtypes.ListNestedObjectValueOf[trainingDataConfig] `tfsdk:"training_data_config"` + TrainingMetrics fwtypes.ListNestedObjectValueOf[trainingMetrics] `tfsdk:"training_metrics"` + ValidationDataConfig fwtypes.ListNestedObjectValueOf[validationDataConfig] `tfsdk:"validation_data_config"` + ValidationMetrics fwtypes.ListNestedObjectValueOf[validationMetrics] `tfsdk:"validation_metrics"` + Tags types.Map `tfsdk:"tags"` + TagsAll types.Map `tfsdk:"tags_all"` + Timeouts timeouts.Value `tfsdk:"timeouts"` } -func (data *resourceCustomModelModel) refresh(ctx context.Context, conn *bedrock.Client) diag.Diagnostics { +func (data *resourceCustomModelData) refresh(ctx context.Context, conn *bedrock.Client) diag.Diagnostics { var diags diag.Diagnostics - modelId := data.ID - input := &bedrock.GetCustomModelInput{ - ModelIdentifier: modelId.ValueStringPointer(), - } - output, err := conn.GetCustomModel(ctx, input) - if err != nil { - // If we got here, the state has the model name and the job arn. - // Should we check for tainted state instead? - tflog.Info(ctx, "resourceCustomModelRead: Error reading Bedrock Custom Model. Ignoring to allow destroy to attempt to cleanup.") - return diags - } - - data.BaseModelArn = flex.StringToFramework(ctx, output.BaseModelArn) - data.CreationTime = flex.StringValueToFramework(ctx, output.CreationTime.Format((time.RFC3339))) - data.HyperParameters = flex.FlattenFrameworkStringValueMap(ctx, output.HyperParameters) - data.JobArn = flex.StringToFramework(ctx, output.JobArn) - // This is nil in the model object - could be a bug - // However this is already in state so we can skip setting this here and avoid a forced update due to value change. - // d.Set("job_name", model.JobName) - data.ModelArn = flex.StringToFramework(ctx, output.ModelArn) - data.ModelKmsKeyArn = flex.StringToFramework(ctx, output.ModelKmsKeyArn) - data.ModelName = flex.StringToFramework(ctx, output.ModelName) - data.OutputDataConfig = flex.StringToFramework(ctx, output.OutputDataConfig.S3Uri) - data.TrainingDataConfig = flex.StringToFramework(ctx, output.TrainingDataConfig.S3Uri) - data.TrainingMetrics = flattenTrainingMetrics(ctx, output.TrainingMetrics) - data.ValidationDataConfig = flattenValidationDataConfig(ctx, output.ValidationDataConfig) - data.ValidationMetrics = flattenValidationMetrics(ctx, output.ValidationMetrics) - - jobTags, err := listTags(ctx, conn, *output.JobArn) - if err != nil { - diags.AddError("reading Tags for Job", err.Error()) - return diags - } - data.JobTags = flex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) - + /* modelId := data.ID + input := &bedrock.GetCustomModelInput{ + ModelIdentifier: modelId.ValueStringPointer(), + } + output, err := conn.GetCustomModel(ctx, input) + + if err != nil { + // If we got here, the state has the model name and the job arn. + // Should we check for tainted state instead? + tflog.Info(ctx, "resourceCustomModelRead: Error reading Bedrock Custom Model. Ignoring to allow destroy to attempt to cleanup.") + return diags + } + + data.BaseModelArn = flex.StringToFramework(ctx, output.BaseModelArn) + data.CreationTime = flex.StringValueToFramework(ctx, output.CreationTime.Format((time.RFC3339))) + data.HyperParameters = flex.FlattenFrameworkStringValueMap(ctx, output.HyperParameters) + data.JobArn = flex.StringToFramework(ctx, output.JobArn) + // This is nil in the model object - could be a bug + // However this is already in state so we can skip setting this here and avoid a forced update due to value change. + // d.Set("job_name", model.JobName) + data.ModelArn = flex.StringToFramework(ctx, output.ModelArn) + data.ModelKmsKeyArn = flex.StringToFramework(ctx, output.ModelKmsKeyArn) + data.ModelName = flex.StringToFramework(ctx, output.ModelName) + data.OutputDataConfig = flex.StringToFramework(ctx, output.OutputDataConfig.S3Uri) + data.TrainingDataConfig = flex.StringToFramework(ctx, output.TrainingDataConfig.S3Uri) + data.TrainingMetrics = flattenTrainingMetrics(ctx, output.TrainingMetrics) + data.ValidationDataConfig = flattenValidationDataConfig(ctx, output.ValidationDataConfig) + data.ValidationMetrics = flattenValidationMetrics(ctx, output.ValidationMetrics) + + jobTags, err := listTags(ctx, conn, *output.JobArn) + if err != nil { + diags.AddError("reading Tags for Job", err.Error()) + return diags + } + data.JobTags = flex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) + */ return diags } diff --git a/internal/service/bedrock/structures.go b/internal/service/bedrock/structures.go index ce51af33788..bc1dba4c052 100644 --- a/internal/service/bedrock/structures.go +++ b/internal/service/bedrock/structures.go @@ -6,11 +6,10 @@ package bedrock import ( "context" - bedrock_types "github.com/aws/aws-sdk-go-v2/service/bedrock/types" + awstypes "github.com/aws/aws-sdk-go-v2/service/bedrock/types" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" ) @@ -20,58 +19,139 @@ type vpcConfig struct { SubnetIds types.Set `tfsdk:"subnet_ids"` } -type validationDataConfig struct { - Validators types.Set `tfsdk:"validators"` +func expandVPCConfig(ctx context.Context, l []vpcConfig) *awstypes.VpcConfig { + if len(l) == 0 { + return nil + } + vpcConfigs := make([]*awstypes.VpcConfig, len(l)) + for i, item := range l { + vpcConfigs[i] = item.expand(ctx) + } + return vpcConfigs[0] // return single object, not list +} + +func (v vpcConfig) expand(ctx context.Context) *awstypes.VpcConfig { + return &awstypes.VpcConfig{ + SecurityGroupIds: flex.ExpandFrameworkStringValueSet(ctx, v.SecurityGroupIds), + SubnetIds: flex.ExpandFrameworkStringValueSet(ctx, v.SubnetIds), + } +} + +type outputDataConfig struct { + S3Uri types.String `tfsdk:"s3_uri"` +} + +func expandOutputDataConfig(ctx context.Context, l []outputDataConfig) *awstypes.OutputDataConfig { + if len(l) == 0 { + return nil + } + outputDataConfigs := make([]*awstypes.OutputDataConfig, len(l)) + for i, item := range l { + outputDataConfigs[i] = item.expand(ctx) + } + return outputDataConfigs[0] // return single object, not list +} + +func (o outputDataConfig) expand(ctx context.Context) *awstypes.OutputDataConfig { + return &awstypes.OutputDataConfig{ + S3Uri: flex.StringFromFramework(ctx, o.S3Uri), + } +} + +type trainingDataConfig struct { + S3Uri types.String `tfsdk:"s3_uri"` +} + +func expandTrainingDataConfig(ctx context.Context, l []trainingDataConfig) *awstypes.TrainingDataConfig { + if len(l) == 0 { + return nil + } + trainingDataConfigs := make([]*awstypes.TrainingDataConfig, len(l)) + for i, item := range l { + trainingDataConfigs[i] = item.expand(ctx) + } + return trainingDataConfigs[0] // return single object, not list +} + +func (t trainingDataConfig) expand(ctx context.Context) *awstypes.TrainingDataConfig { + return &awstypes.TrainingDataConfig{ + S3Uri: flex.StringFromFramework(ctx, t.S3Uri), + } } type trainingMetrics struct { TrainingLoss types.Float64 `tfsdk:"training_loss"` } -type validationMetrics struct { - ValidationLoss types.Float64 `tfsdk:"validation_loss"` +func expandTrainingMetrics(ctx context.Context, l []trainingMetrics) *awstypes.TrainingMetrics { + if len(l) == 0 { + return nil + } + trainingMetricsObject := make([]*awstypes.TrainingMetrics, len(l)) + for i, item := range l { + trainingMetricsObject[i] = item.expand(ctx) + } + return trainingMetricsObject[0] // return single object, not list } -func expandVPCConfig(ctx context.Context, tfList []vpcConfig) []bedrock_types.VpcConfig { - if len(tfList) == 0 { +func (t trainingMetrics) expand(ctx context.Context) *awstypes.TrainingMetrics { + if t.TrainingLoss.IsNull() || t.TrainingLoss.IsUnknown() { return nil } - var vpcConfigs []bedrock_types.VpcConfig - - for _, item := range tfList { - vpcConfig := bedrock_types.VpcConfig{ - SecurityGroupIds: flex.ExpandFrameworkStringValueSet(ctx, item.SecurityGroupIds), - SubnetIds: flex.ExpandFrameworkStringValueSet(ctx, item.SubnetIds), - } - vpcConfigs = append(vpcConfigs, vpcConfig) + return &awstypes.TrainingMetrics{ + TrainingLoss: flex.Float32FromFrameworkFloat64(ctx, t.TrainingLoss), } +} - return vpcConfigs +type validationDataConfig struct { + Validators types.Set `tfsdk:"validator"` } -func expandValidationDataConfig(ctx context.Context, object types.Object, diags diag.Diagnostics) *bedrock_types.ValidationDataConfig { - if object.IsNull() { +func expandValidationDataConfig(ctx context.Context, l []validationDataConfig, diags diag.Diagnostics) *awstypes.ValidationDataConfig { + if len(l) == 0 { return nil } + validationDataConfigs := make([]*awstypes.ValidationDataConfig, len(l)) + for i, item := range l { + validationDataConfigs[i] = item.expand(ctx, diags) + } + return validationDataConfigs[0] // return single object, not list +} - var model validationDataConfig - diags.Append(object.As(ctx, &model, basetypes.ObjectAsOptions{})...) +func (v validationDataConfig) expand(ctx context.Context, diags diag.Diagnostics) *awstypes.ValidationDataConfig { + var validators []validatorConfig + diags.Append(v.Validators.ElementsAs(ctx, &validators, false)...) if diags.HasError() { return nil } + return &awstypes.ValidationDataConfig{ + Validators: expandValidators(ctx, validators), + } +} - apiObject := &bedrock_types.ValidationDataConfig{} - for _, validator := range flex.ExpandFrameworkStringValueSet(ctx, model.Validators) { - s3uri := validator - apiObject.Validators = append(apiObject.Validators, bedrock_types.Validator{ - S3Uri: &s3uri, - }) +type validatorConfig struct { + S3Uri types.String `tfsdk:"s3_uri"` +} + +func expandValidators(ctx context.Context, l []validatorConfig) []awstypes.Validator { + validators := make([]awstypes.Validator, len(l)) + for i, item := range l { + validators[i] = item.expand(ctx) } + return validators +} + +func (v validatorConfig) expand(ctx context.Context) awstypes.Validator { + return awstypes.Validator{ + S3Uri: flex.StringFromFramework(ctx, v.S3Uri), + } +} - return apiObject +type validationMetrics struct { + ValidationLoss types.Float64 `tfsdk:"validation_loss"` } -func flattenTrainingMetrics(ctx context.Context, apiObject *bedrock_types.TrainingMetrics) types.List { +func flattenTrainingMetrics(ctx context.Context, apiObject *awstypes.TrainingMetrics) types.List { attributeTypes := fwtypes.AttributeTypesMust[trainingMetrics](ctx) elemType := types.ObjectType{AttrTypes: attributeTypes} @@ -89,7 +169,7 @@ func flattenTrainingMetrics(ctx context.Context, apiObject *bedrock_types.Traini return types.ListValueMust(elemType, attrs) } -func flattenValidationMetrics(ctx context.Context, apiObjects []bedrock_types.ValidatorMetric) []validationMetrics { +func flattenValidationMetrics(ctx context.Context, apiObjects []awstypes.ValidatorMetric) []validationMetrics { if apiObjects == nil { return nil } @@ -105,7 +185,7 @@ func flattenValidationMetrics(ctx context.Context, apiObjects []bedrock_types.Va return model } -func flattenValidationDataConfig(ctx context.Context, apiObject *bedrock_types.ValidationDataConfig) types.Object { +func flattenValidationDataConfig(ctx context.Context, apiObject *awstypes.ValidationDataConfig) types.Object { attributeTypes := fwtypes.AttributeTypesMust[validationDataConfig](ctx) attributeTypes["validators"] = types.SetType{ElemType: types.StringType} From a712fc46f27001ccb03568ccd5eabb8650409c00 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 28 Jan 2024 16:23:18 -0500 Subject: [PATCH 18/62] d/aws_bedrock_foundation_models: Use AutoFlEx. --- .../bedrock/foundation_models_data_source.go | 190 ++++++------------ .../service/bedrock/service_package_gen.go | 2 +- 2 files changed, 63 insertions(+), 129 deletions(-) diff --git a/internal/service/bedrock/foundation_models_data_source.go b/internal/service/bedrock/foundation_models_data_source.go index dde7968db33..1d0867e4d94 100644 --- a/internal/service/bedrock/foundation_models_data_source.go +++ b/internal/service/bedrock/foundation_models_data_source.go @@ -7,7 +7,6 @@ import ( "context" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/bedrock" awstypes "github.com/aws/aws-sdk-go-v2/service/bedrock/types" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" @@ -16,39 +15,39 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/framework" - "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" "github.com/hashicorp/terraform-provider-aws/names" ) -const DSNameFoundationModels = "Foundation Models Data Source" - // @FrameworkDataSource(name="Foundation Models") -func newDataSourceFoundationModels(context.Context) (datasource.DataSourceWithConfigure, error) { - return &dataSourceFoundationModels{}, nil +func newFoundationModelsDataSource(context.Context) (datasource.DataSourceWithConfigure, error) { + return &foundationModelsDataSource{}, nil } -type dataSourceFoundationModels struct { +type foundationModelsDataSource struct { framework.DataSourceWithConfigure } -func (d *dataSourceFoundationModels) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { +func (d *foundationModelsDataSource) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { response.TypeName = "aws_bedrock_foundation_models" } -func (d *dataSourceFoundationModels) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { - resp.Schema = schema.Schema{ +func (d *foundationModelsDataSource) Schema(ctx context.Context, request datasource.SchemaRequest, response *datasource.SchemaResponse) { + response.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ "by_customization_type": schema.StringAttribute{ - Optional: true, + CustomType: fwtypes.StringEnumType[awstypes.ModelCustomization](), + Optional: true, }, "by_inference_type": schema.StringAttribute{ - Optional: true, + CustomType: fwtypes.StringEnumType[awstypes.InferenceType](), + Optional: true, }, "by_output_modality": schema.StringAttribute{ - Optional: true, + CustomType: fwtypes.StringEnumType[awstypes.ModelModality](), + Optional: true, }, "by_provider": schema.StringAttribute{ Optional: true, @@ -56,45 +55,21 @@ func (d *dataSourceFoundationModels) Schema(ctx context.Context, req datasource. stringvalidator.RegexMatches(regexache.MustCompile(`^[a-z0-9-]{1,63}$`), ""), }, }, - "id": schema.StringAttribute{ - Computed: true, - }, - }, - Blocks: map[string]schema.Block{ - "model_summaries": schema.ListNestedBlock{ - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "customizations_supported": schema.SetAttribute{ - ElementType: types.StringType, - Computed: true, - }, - "inference_types_supported": schema.SetAttribute{ - ElementType: types.StringType, - Computed: true, - }, - "input_modalities": schema.SetAttribute{ - ElementType: types.StringType, - Computed: true, - }, - "model_arn": schema.StringAttribute{ - Computed: true, - }, - "model_id": schema.StringAttribute{ - Computed: true, - }, - "model_name": schema.StringAttribute{ - Computed: true, - }, - "output_modalities": schema.SetAttribute{ - ElementType: types.StringType, - Computed: true, - }, - "provider_name": schema.StringAttribute{ - Computed: true, - }, - "response_streaming_supported": schema.BoolAttribute{ - Computed: true, - }, + names.AttrID: framework.IDAttribute(), + "model_summaries": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[foundationModelSummaryModel](ctx), + Computed: true, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "customizations_supported": types.SetType{ElemType: types.StringType}, + "inference_types_supported": types.SetType{ElemType: types.StringType}, + "input_modalities": types.SetType{ElemType: types.StringType}, + "model_arn": types.StringType, + "model_id": types.StringType, + "model_name": types.StringType, + "output_modalities": types.SetType{ElemType: types.StringType}, + "provider_name": types.StringType, + "response_streaming_supported": types.BoolType, }, }, }, @@ -102,97 +77,56 @@ func (d *dataSourceFoundationModels) Schema(ctx context.Context, req datasource. } } -func (d *dataSourceFoundationModels) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { - conn := d.Meta().BedrockClient(ctx) - - var data foundationModels +func (d *foundationModelsDataSource) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { + var data foundationModelsDataSourceModel response.Diagnostics.Append(request.Config.Get(ctx, &data)...) if response.Diagnostics.HasError() { return } - data.ID = types.StringValue(d.Meta().Region) + + conn := d.Meta().BedrockClient(ctx) input := &bedrock.ListFoundationModelsInput{} - if !data.ByCustomizationType.IsNull() { - input.ByCustomizationType = awstypes.ModelCustomization(data.ByCustomizationType.ValueString()) - } - if !data.ByInferenceType.IsNull() { - input.ByInferenceType = awstypes.InferenceType(data.ByInferenceType.ValueString()) - } - if !data.ByOutputModality.IsNull() { - input.ByOutputModality = awstypes.ModelModality(data.ByOutputModality.ValueString()) - } - if !data.ByProvider.IsNull() { - input.ByProvider = aws.String(data.ByProvider.ValueString()) + response.Diagnostics.Append(fwflex.Expand(ctx, data, input)...) + if response.Diagnostics.HasError() { + return } - models, err := conn.ListFoundationModels(ctx, input) + output, err := conn.ListFoundationModels(ctx, input) + if err != nil { - response.Diagnostics.AddError( - create.ProblemStandardMessage(names.Bedrock, create.ErrActionReading, DSNameFoundationModels, data.ID.String(), err), - err.Error(), - ) + response.Diagnostics.AddError("listing Bedrock Foundation Models", err.Error()) + return } - data.ModelSummaries = flattenFoundationModelSummaries(ctx, models.ModelSummaries) + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + if response.Diagnostics.HasError() { + return + } - response.Diagnostics.Append(response.State.Set(ctx, &data)...) -} + data.ID = types.StringValue(d.Meta().Region) -type foundationModels struct { - ByCustomizationType types.String `tfsdk:"by_customization_type"` - ByInferenceType types.String `tfsdk:"by_inference_type"` - ByOutputModality types.String `tfsdk:"by_output_modality"` - ByProvider types.String `tfsdk:"by_provider"` - ID types.String `tfsdk:"id"` - ModelSummaries types.List `tfsdk:"model_summaries"` + response.Diagnostics.Append(response.State.Set(ctx, &data)...) } -type foundationModelSummary struct { - CustomizationsSupported types.Set `tfsdk:"customizations_supported"` - InferenceTypesSupported types.Set `tfsdk:"inference_types_supported"` - InputModalities types.Set `tfsdk:"input_modalities"` - ModelID types.String `tfsdk:"model_id"` - ModelArn types.String `tfsdk:"model_arn"` - ModelName types.String `tfsdk:"model_name"` - OutputModalities types.Set `tfsdk:"output_modalities"` - ProviderName types.String `tfsdk:"provider_name"` - ResponseStreamingSupported types.Bool `tfsdk:"response_streaming_supported"` +type foundationModelsDataSourceModel struct { + ByCustomizationType fwtypes.StringEnum[awstypes.ModelCustomization] `tfsdk:"by_customization_type"` + ByInferenceType fwtypes.StringEnum[awstypes.InferenceType] `tfsdk:"by_inference_type"` + ByOutputModality fwtypes.StringEnum[awstypes.ModelModality] `tfsdk:"by_output_modality"` + ByProvider types.String `tfsdk:"by_provider"` + ID types.String `tfsdk:"id"` + ModelSummaries fwtypes.ListNestedObjectValueOf[foundationModelSummaryModel] `tfsdk:"model_summaries"` } -func flattenFoundationModelSummaries(ctx context.Context, models []awstypes.FoundationModelSummary) types.List { - attributeTypes := fwtypes.AttributeTypesMust[foundationModelSummary](ctx) - - // HACK: Reflection used above to build the attributeTypes cannot determine the ElemType - attributeTypes["customizations_supported"] = types.SetType{ElemType: types.StringType} - attributeTypes["inference_types_supported"] = types.SetType{ElemType: types.StringType} - attributeTypes["input_modalities"] = types.SetType{ElemType: types.StringType} - attributeTypes["output_modalities"] = types.SetType{ElemType: types.StringType} - - elemType := types.ObjectType{AttrTypes: attributeTypes} - - if models == nil { - return types.ListNull(elemType) - } - - attrs := make([]attr.Value, 0, len(models)) - for _, model := range models { - attr := map[string]attr.Value{} - attr["model_arn"] = flex.StringToFramework(ctx, model.ModelArn) - attr["model_id"] = flex.StringToFramework(ctx, model.ModelId) - attr["model_name"] = flex.StringToFramework(ctx, model.ModelName) - attr["provider_name"] = flex.StringToFramework(ctx, model.ProviderName) - - attr["customizations_supported"] = flex.FlattenFrameworkStringValueSet(ctx, model.CustomizationsSupported) - attr["inference_types_supported"] = flex.FlattenFrameworkStringValueSet(ctx, model.InferenceTypesSupported) - attr["input_modalities"] = flex.FlattenFrameworkStringValueSet(ctx, model.InputModalities) - attr["output_modalities"] = flex.FlattenFrameworkStringValueSet(ctx, model.OutputModalities) - attr["response_streaming_supported"] = flex.BoolToFramework(ctx, model.ResponseStreamingSupported) - - val := types.ObjectValueMust(attributeTypes, attr) - attrs = append(attrs, val) - } - - return types.ListValueMust(elemType, attrs) +type foundationModelSummaryModel struct { + CustomizationsSupported fwtypes.SetValueOf[types.String] `tfsdk:"customizations_supported"` + InferenceTypesSupported fwtypes.SetValueOf[types.String] `tfsdk:"inference_types_supported"` + InputModalities fwtypes.SetValueOf[types.String] `tfsdk:"input_modalities"` + ModelARN types.String `tfsdk:"model_arn"` + ModelID types.String `tfsdk:"model_id"` + ModelName types.String `tfsdk:"model_name"` + OutputModalities fwtypes.SetValueOf[types.String] `tfsdk:"output_modalities"` + ProviderName types.String `tfsdk:"provider_name"` + ResponseStreamingSupported types.Bool `tfsdk:"response_streaming_supported"` } diff --git a/internal/service/bedrock/service_package_gen.go b/internal/service/bedrock/service_package_gen.go index 8441d022103..1620d097954 100644 --- a/internal/service/bedrock/service_package_gen.go +++ b/internal/service/bedrock/service_package_gen.go @@ -30,7 +30,7 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.Serv Name: "Foundation Model", }, { - Factory: newDataSourceFoundationModels, + Factory: newFoundationModelsDataSource, Name: "Foundation Models", }, } From bdbca571995af0f3a8f52d6dd9733b5da8fa1ecd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 28 Jan 2024 16:23:33 -0500 Subject: [PATCH 19/62] Acceptance test output: % make testacc TESTARGS='-run=TestAccBedrockFoundationModelsDataSource_basic' PKG=bedrock ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/bedrock/... -v -count 1 -parallel 20 -run=TestAccBedrockFoundationModelsDataSource_basic -timeout 360m === RUN TestAccBedrockFoundationModelsDataSource_basic === PAUSE TestAccBedrockFoundationModelsDataSource_basic === CONT TestAccBedrockFoundationModelsDataSource_basic --- PASS: TestAccBedrockFoundationModelsDataSource_basic (12.04s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrock 21.790s From cf35f5371ed0b289d3a70623115c191da9f8aec8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 28 Jan 2024 16:59:36 -0500 Subject: [PATCH 20/62] d/aws_bedrock_custom_models: Use AutoFlEx. --- .../bedrock/custom_models_data_source.go | 121 +++++++----------- .../bedrock/custom_models_data_source_test.go | 5 +- .../foundation_models_data_source_test.go | 20 +-- .../service/bedrock/service_package_gen.go | 7 +- 4 files changed, 66 insertions(+), 87 deletions(-) diff --git a/internal/service/bedrock/custom_models_data_source.go b/internal/service/bedrock/custom_models_data_source.go index 960a7f463af..41d52b43c66 100644 --- a/internal/service/bedrock/custom_models_data_source.go +++ b/internal/service/bedrock/custom_models_data_source.go @@ -5,61 +5,45 @@ package bedrock import ( "context" - "time" "github.com/aws/aws-sdk-go-v2/service/bedrock" - bedrock_types "github.com/aws/aws-sdk-go-v2/service/bedrock/types" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-aws/internal/framework" - "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + "github.com/hashicorp/terraform-provider-aws/names" ) -// @FrameworkDataSource -func newDataSourceCustomModels(context.Context) (datasource.DataSourceWithConfigure, error) { - return &dataSourceCustomModels{}, nil +// @FrameworkDataSource(name="Custom Models") +func newCustomModelsDataSource(context.Context) (datasource.DataSourceWithConfigure, error) { + return &customModelsDataSource{}, nil } -type dataSourceCustomModels struct { +type customModelsDataSource struct { framework.DataSourceWithConfigure } -// Metadata should return the full name of the data source, such as -// examplecloud_thing. -func (d *dataSourceCustomModels) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { +func (d *customModelsDataSource) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { response.TypeName = "aws_bedrock_custom_models" } -// Schema returns the schema for this data source. -func (d *dataSourceCustomModels) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { - resp.Schema = schema.Schema{ +func (d *customModelsDataSource) Schema(ctx context.Context, request datasource.SchemaRequest, response *datasource.SchemaResponse) { + response.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - }, - }, - Blocks: map[string]schema.Block{ - "model_summaries": schema.ListNestedBlock{ - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "base_model_arn": schema.StringAttribute{ - Computed: true, - }, - "base_model_name": schema.StringAttribute{ - Computed: true, - }, - "model_arn": schema.StringAttribute{ - Computed: true, - }, - "model_name": schema.StringAttribute{ - Computed: true, - }, - "creation_time": schema.StringAttribute{ - Computed: true, - }, + names.AttrID: framework.IDAttribute(), + "model_summaries": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelSummaryModel](ctx), + Computed: true, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "base_model_arn": types.StringType, + "base_model_name": types.StringType, + "creation_time": types.StringType, + "model_arn": types.StringType, + "model_name": types.StringType, }, }, }, @@ -67,61 +51,48 @@ func (d *dataSourceCustomModels) Schema(ctx context.Context, req datasource.Sche } } -// Read is called when the provider must read data source values in order to update state. -// Config values should be read from the ReadRequest and new state values set on the ReadResponse. -func (d *dataSourceCustomModels) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { - var data customModels - +func (d *customModelsDataSource) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { + var data customModelsDataSourceModel response.Diagnostics.Append(request.Config.Get(ctx, &data)...) - if response.Diagnostics.HasError() { return } conn := d.Meta().BedrockClient(ctx) - models, err := conn.ListCustomModels(ctx, nil) - if err != nil { - response.Diagnostics.AddError("reading Bedrock Custom Models", err.Error()) + input := &bedrock.ListCustomModelsInput{} + response.Diagnostics.Append(fwflex.Expand(ctx, data, input)...) + if response.Diagnostics.HasError() { return } - data.ID = flex.StringToFramework(ctx, &d.Meta().Region) - data.refreshFromOutput(ctx, models) - response.Diagnostics.Append(response.State.Set(ctx, &data)...) -} + output, err := conn.ListCustomModels(ctx, input) -type customModels struct { - ID types.String `tfsdk:"id"` - ModelSummaries types.List `tfsdk:"model_summaries"` -} + if err != nil { + response.Diagnostics.AddError("listing Bedrock Custom Models", err.Error()) -func (cms *customModels) refreshFromOutput(ctx context.Context, out *bedrock.ListCustomModelsOutput) { - if out == nil { return } - cms.ModelSummaries = flattenCustomModelSummaries(ctx, out.ModelSummaries) -} - -func flattenCustomModelSummaries(ctx context.Context, models []bedrock_types.CustomModelSummary) types.List { - attributeTypes := fwtypes.AttributeTypesMust[customModels](ctx) - elemType := types.ObjectType{AttrTypes: attributeTypes} - if models == nil { - return types.ListNull(elemType) + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + if response.Diagnostics.HasError() { + return } - attrs := make([]attr.Value, 0, len(models)) - for _, model := range models { - attr := map[string]attr.Value{} - attr["base_model_arn"] = flex.StringToFramework(ctx, model.BaseModelArn) - attr["base_model_name"] = flex.StringToFramework(ctx, model.BaseModelName) - attr["model_arn"] = flex.StringToFramework(ctx, model.ModelArn) - attr["model_name"] = flex.StringToFramework(ctx, model.ModelName) - attr["creation_time"] = flex.StringValueToFramework[string](ctx, model.CreationTime.Format(time.RFC3339)) - val := types.ObjectValueMust(attributeTypes, attr) - attrs = append(attrs, val) - } + data.ID = types.StringValue(d.Meta().Region) + + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +type customModelsDataSourceModel struct { + ID types.String `tfsdk:"id"` + ModelSummaries fwtypes.ListNestedObjectValueOf[customModelSummaryModel] `tfsdk:"model_summaries"` +} - return types.ListValueMust(elemType, attrs) +type customModelSummaryModel struct { + BaseModelARN types.String `tfsdk:"base_model_arn"` + BaseModelName types.String `tfsdk:"base_model_name"` + CreationTime types.String `tfsdk:"creation_time"` + ModelARN types.String `tfsdk:"model_arn"` + ModelName types.String `tfsdk:"model_name"` } diff --git a/internal/service/bedrock/custom_models_data_source_test.go b/internal/service/bedrock/custom_models_data_source_test.go index 7f76fe1508f..f5c12bee1fc 100644 --- a/internal/service/bedrock/custom_models_data_source_test.go +++ b/internal/service/bedrock/custom_models_data_source_test.go @@ -16,6 +16,7 @@ import ( func TestAccBedrockCustomModelsDataSource_basic(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + datasourceName := "data.aws_bedrock_custom_models.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -25,13 +26,15 @@ func TestAccBedrockCustomModelsDataSource_basic(t *testing.T) { { Config: testAccCustomModelsDataSourceConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.aws_bedrock_custom_models.test", "id"), + resource.TestCheckResourceAttrSet(datasourceName, "id"), + acctest.CheckResourceAttrGreaterThanValue(datasourceName, "model_summaries.#", 0), ), }, }, }) } +// TODO Shared config with resource? func testAccCustomModelsDataSourceConfig_basic(rName string) string { return fmt.Sprintf(` data "aws_caller_identity" "current" {} diff --git a/internal/service/bedrock/foundation_models_data_source_test.go b/internal/service/bedrock/foundation_models_data_source_test.go index e3e4bbba763..7dd42073d79 100644 --- a/internal/service/bedrock/foundation_models_data_source_test.go +++ b/internal/service/bedrock/foundation_models_data_source_test.go @@ -14,6 +14,7 @@ import ( func TestAccBedrockFoundationModelsDataSource_basic(t *testing.T) { ctx := acctest.Context(t) + datasourceName := "aws_bedrock_foundation_models.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -22,8 +23,8 @@ func TestAccBedrockFoundationModelsDataSource_basic(t *testing.T) { { Config: testAccFoundationModelsDataSourceConfig_basic(), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.aws_bedrock_foundation_models.test", "id"), - acctest.CheckResourceAttrGreaterThanValue("data.aws_bedrock_foundation_models.test", "model_summaries.#", 0), + resource.TestCheckResourceAttrSet(datasourceName, "id"), + acctest.CheckResourceAttrGreaterThanValue(datasourceName, "model_summaries.#", 0), ), }, }, @@ -32,6 +33,7 @@ func TestAccBedrockFoundationModelsDataSource_basic(t *testing.T) { func TestAccBedrockFoundationModelsDataSource_byCustomizationType(t *testing.T) { ctx := acctest.Context(t) + datasourceName := "aws_bedrock_foundation_models.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -40,8 +42,8 @@ func TestAccBedrockFoundationModelsDataSource_byCustomizationType(t *testing.T) { Config: testAccFoundationModelsDataSourceConfig_byCustomizationType(string(types.ModelCustomizationFineTuning)), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.aws_bedrock_foundation_models.test", "id"), - acctest.CheckResourceAttrGreaterThanValue("data.aws_bedrock_foundation_models.test", "model_summaries.#", 0), + resource.TestCheckResourceAttrSet(datasourceName, "id"), + acctest.CheckResourceAttrGreaterThanValue(datasourceName, "model_summaries.#", 0), ), }, }, @@ -50,6 +52,7 @@ func TestAccBedrockFoundationModelsDataSource_byCustomizationType(t *testing.T) func TestAccBedrockFoundationModelsDataSource_byInferenceType(t *testing.T) { ctx := acctest.Context(t) + datasourceName := "aws_bedrock_foundation_models.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -58,8 +61,8 @@ func TestAccBedrockFoundationModelsDataSource_byInferenceType(t *testing.T) { { Config: testAccFoundationModelsDataSourceConfig_byInferenceType(string(types.InferenceTypeOnDemand)), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.aws_bedrock_foundation_models.test", "id"), - acctest.CheckResourceAttrGreaterThanValue("data.aws_bedrock_foundation_models.test", "model_summaries.#", 0), + resource.TestCheckResourceAttrSet(datasourceName, "id"), + acctest.CheckResourceAttrGreaterThanValue(datasourceName, "model_summaries.#", 0), ), }, }, @@ -68,6 +71,7 @@ func TestAccBedrockFoundationModelsDataSource_byInferenceType(t *testing.T) { func TestAccBedrockFoundationModelsDataSource_byOutputModality(t *testing.T) { ctx := acctest.Context(t) + datasourceName := "aws_bedrock_foundation_models.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -76,8 +80,8 @@ func TestAccBedrockFoundationModelsDataSource_byOutputModality(t *testing.T) { { Config: testAccFoundationModelsDataSourceConfig_byOutputModality(string(types.ModelModalityText)), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.aws_bedrock_foundation_models.test", "id"), - acctest.CheckResourceAttrGreaterThanValue("data.aws_bedrock_foundation_models.test", "model_summaries.#", 0), + resource.TestCheckResourceAttrSet(datasourceName, "id"), + acctest.CheckResourceAttrGreaterThanValue(datasourceName, "model_summaries.#", 0), ), }, }, diff --git a/internal/service/bedrock/service_package_gen.go b/internal/service/bedrock/service_package_gen.go index 1620d097954..2d0a4d01736 100644 --- a/internal/service/bedrock/service_package_gen.go +++ b/internal/service/bedrock/service_package_gen.go @@ -16,15 +16,16 @@ type servicePackage struct{} func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.ServicePackageFrameworkDataSource { return []*types.ServicePackageFrameworkDataSource{ + { + Factory: newCustomModelsDataSource, + Name: "Custom Models", + }, { Factory: newDataSourceCustomModel, Tags: &types.ServicePackageResourceTags{ IdentifierAttribute: "model_arn", }, }, - { - Factory: newDataSourceCustomModels, - }, { Factory: newDataSourceFoundationModel, Name: "Foundation Model", From 9e2cd12355d3f660a642264fc1f3639b7a9b9898 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 28 Jan 2024 17:13:08 -0500 Subject: [PATCH 21/62] d/aws_bedrock_foundation_model: Use AutoFlEx. --- .../bedrock/foundation_model_data_source.go | 71 ++++++++----------- .../foundation_model_data_source_test.go | 14 +++- .../service/bedrock/service_package_gen.go | 2 +- 3 files changed, 40 insertions(+), 47 deletions(-) diff --git a/internal/service/bedrock/foundation_model_data_source.go b/internal/service/bedrock/foundation_model_data_source.go index d6721a1293d..a1b1a28183b 100644 --- a/internal/service/bedrock/foundation_model_data_source.go +++ b/internal/service/bedrock/foundation_model_data_source.go @@ -5,42 +5,38 @@ package bedrock import ( "context" + "fmt" "github.com/aws/aws-sdk-go-v2/service/bedrock" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/framework" - "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" "github.com/hashicorp/terraform-provider-aws/names" ) -const DSNameFoundationModel = "Foundation Model Data Source" - // @FrameworkDataSource(name="Foundation Model") -func newDataSourceFoundationModel(context.Context) (datasource.DataSourceWithConfigure, error) { - return &dataSourceFoundationModel{}, nil +func newFoundationModelDataSource(context.Context) (datasource.DataSourceWithConfigure, error) { + return &foundationModelDataSource{}, nil } -type dataSourceFoundationModel struct { +type foundationModelDataSource struct { framework.DataSourceWithConfigure } -func (d *dataSourceFoundationModel) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { +func (d *foundationModelDataSource) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { response.TypeName = "aws_bedrock_foundation_model" } -func (d *dataSourceFoundationModel) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { - resp.Schema = schema.Schema{ +func (d *foundationModelDataSource) Schema(ctx context.Context, request datasource.SchemaRequest, response *datasource.SchemaResponse) { + response.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ "customizations_supported": schema.SetAttribute{ ElementType: types.StringType, Computed: true, }, - "id": schema.StringAttribute{ - Computed: true, - }, + names.AttrID: framework.IDAttribute(), "inference_types_supported": schema.SetAttribute{ ElementType: types.StringType, Computed: true, @@ -72,57 +68,46 @@ func (d *dataSourceFoundationModel) Schema(ctx context.Context, req datasource.S } } -func (d *dataSourceFoundationModel) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { - conn := d.Meta().BedrockClient(ctx) - - var data foundationModel +func (d *foundationModelDataSource) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { + var data foundationModelDataSourceModel response.Diagnostics.Append(request.Config.Get(ctx, &data)...) if response.Diagnostics.HasError() { return } + conn := d.Meta().BedrockClient(ctx) + input := &bedrock.GetFoundationModelInput{ - ModelIdentifier: data.ModelID.ValueStringPointer(), + ModelIdentifier: fwflex.StringFromFramework(ctx, data.ModelID), } - model, err := conn.GetFoundationModel(ctx, input) + + output, err := conn.GetFoundationModel(ctx, input) + if err != nil { - response.Diagnostics.AddError( - create.ProblemStandardMessage(names.Bedrock, create.ErrActionReading, DSNameFoundationModel, data.ModelID.String(), err), - err.Error(), - ) + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Foundation Model (%s)", data.ModelID.ValueString()), err.Error()) + return } - data.refreshFromOutput(ctx, model) + response.Diagnostics.Append(fwflex.Flatten(ctx, output.ModelDetails, &data)...) + if response.Diagnostics.HasError() { + return + } + + data.ID = data.ModelID + response.Diagnostics.Append(response.State.Set(ctx, &data)...) } -type foundationModel struct { +type foundationModelDataSourceModel struct { CustomizationsSupported types.Set `tfsdk:"customizations_supported"` ID types.String `tfsdk:"id"` InferenceTypesSupported types.Set `tfsdk:"inference_types_supported"` InputModalities types.Set `tfsdk:"input_modalities"` - ModelArn types.String `tfsdk:"model_arn"` + ModelARN types.String `tfsdk:"model_arn"` ModelID types.String `tfsdk:"model_id"` ModelName types.String `tfsdk:"model_name"` OutputModalities types.Set `tfsdk:"output_modalities"` ProviderName types.String `tfsdk:"provider_name"` ResponseStreamingSupported types.Bool `tfsdk:"response_streaming_supported"` } - -func (data *foundationModel) refreshFromOutput(ctx context.Context, model *bedrock.GetFoundationModelOutput) { - if model == nil { - return - } - - data.ID = flex.StringToFramework(ctx, model.ModelDetails.ModelId) - data.ModelArn = flex.StringToFramework(ctx, model.ModelDetails.ModelArn) - data.ModelID = flex.StringToFramework(ctx, model.ModelDetails.ModelId) - data.ModelName = flex.StringToFramework(ctx, model.ModelDetails.ModelName) - data.ProviderName = flex.StringToFramework(ctx, model.ModelDetails.ProviderName) - data.CustomizationsSupported = flex.FlattenFrameworkStringValueSet(ctx, model.ModelDetails.CustomizationsSupported) - data.InferenceTypesSupported = flex.FlattenFrameworkStringValueSet(ctx, model.ModelDetails.InferenceTypesSupported) - data.InputModalities = flex.FlattenFrameworkStringValueSet(ctx, model.ModelDetails.InputModalities) - data.OutputModalities = flex.FlattenFrameworkStringValueSet(ctx, model.ModelDetails.OutputModalities) - data.ResponseStreamingSupported = flex.BoolToFramework(ctx, model.ModelDetails.ResponseStreamingSupported) -} diff --git a/internal/service/bedrock/foundation_model_data_source_test.go b/internal/service/bedrock/foundation_model_data_source_test.go index 13eabe82efa..355ca16fca3 100644 --- a/internal/service/bedrock/foundation_model_data_source_test.go +++ b/internal/service/bedrock/foundation_model_data_source_test.go @@ -12,6 +12,7 @@ import ( func TestAccBedrockFoundationModelDataSource_basic(t *testing.T) { ctx := acctest.Context(t) + datasourceName := "data.aws_bedrock_foundation_model.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -19,9 +20,16 @@ func TestAccBedrockFoundationModelDataSource_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccFoundationModelDataSourceConfig_basic(), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.aws_bedrock_foundation_model.test", "id"), - resource.TestCheckResourceAttrSet("data.aws_bedrock_foundation_model.test", "model_id"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(datasourceName, "customizations_supported.#"), + resource.TestCheckResourceAttrSet(datasourceName, "id"), + resource.TestCheckResourceAttrSet(datasourceName, "inference_types_supported.#"), + resource.TestCheckResourceAttrSet(datasourceName, "input_modalities.#"), + resource.TestCheckResourceAttrSet(datasourceName, "model_arn"), + resource.TestCheckResourceAttrSet(datasourceName, "model_name"), + resource.TestCheckResourceAttrSet(datasourceName, "output_modalities.#"), + resource.TestCheckResourceAttrSet(datasourceName, "provider_name"), + resource.TestCheckResourceAttrSet(datasourceName, "response_streaming_supported"), ), }, }, diff --git a/internal/service/bedrock/service_package_gen.go b/internal/service/bedrock/service_package_gen.go index 2d0a4d01736..fd48e422166 100644 --- a/internal/service/bedrock/service_package_gen.go +++ b/internal/service/bedrock/service_package_gen.go @@ -27,7 +27,7 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.Serv }, }, { - Factory: newDataSourceFoundationModel, + Factory: newFoundationModelDataSource, Name: "Foundation Model", }, { From 34ebc2b63385b89c87606ce1af6b112bb4c0e5c0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 28 Jan 2024 17:13:22 -0500 Subject: [PATCH 22/62] Acceptance test output: % make testacc TESTARGS='-run=TestAccBedrockFoundationModelDataSource_basic' PKG=bedrock ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/bedrock/... -v -count 1 -parallel 20 -run=TestAccBedrockFoundationModelDataSource_basic -timeout 360m === RUN TestAccBedrockFoundationModelDataSource_basic === PAUSE TestAccBedrockFoundationModelDataSource_basic === CONT TestAccBedrockFoundationModelDataSource_basic --- PASS: TestAccBedrockFoundationModelDataSource_basic (12.31s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrock 21.983s From 9d13c518d6b7b79057b6b8688a55f3953dd340d9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 28 Jan 2024 17:39:34 -0500 Subject: [PATCH 23/62] d/aws_bedrock_custom_model: Use AutoFlEx. --- .../bedrock/custom_model_data_source.go | 169 +++++++++--------- .../bedrock/custom_model_data_source_test.go | 33 ++-- .../bedrock/foundation_model_data_source.go | 25 +-- .../service/bedrock/service_package_gen.go | 11 +- 4 files changed, 123 insertions(+), 115 deletions(-) diff --git a/internal/service/bedrock/custom_model_data_source.go b/internal/service/bedrock/custom_model_data_source.go index ece9a83ae51..ba3ca636023 100644 --- a/internal/service/bedrock/custom_model_data_source.go +++ b/internal/service/bedrock/custom_model_data_source.go @@ -5,44 +5,40 @@ package bedrock import ( "context" - "time" + "fmt" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/bedrock" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-aws/internal/framework" "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/names" ) -// @FrameworkDataSource +// @FrameworkDataSource(name="Custom Model") // @Tags(identifierAttribute="model_arn") -func newDataSourceCustomModel(context.Context) (datasource.DataSourceWithConfigure, error) { - return &dataSourceCustomModel{}, nil +func newCustomModelDataSource(context.Context) (datasource.DataSourceWithConfigure, error) { + return &customModelDataSource{}, nil } -type dataSourceCustomModel struct { +type customModelDataSource struct { framework.DataSourceWithConfigure } -// Metadata should return the full name of the data source, such as -// examplecloud_thing. -func (d *dataSourceCustomModel) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { +func (d *customModelDataSource) Metadata(_ context.Context, request datasource.MetadataRequest, response *datasource.MetadataResponse) { response.TypeName = "aws_bedrock_custom_model" } // Schema returns the schema for this data source. -func (d *dataSourceCustomModel) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { - resp.Schema = schema.Schema{ +func (d *customModelDataSource) Schema(ctx context.Context, request datasource.SchemaRequest, response *datasource.SchemaResponse) { + response.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{ - Computed: true, - }, - "model_id": schema.StringAttribute{ - Required: true, - }, "base_model_arn": schema.StringAttribute{ Computed: true, }, @@ -53,6 +49,7 @@ func (d *dataSourceCustomModel) Schema(ctx context.Context, req datasource.Schem ElementType: types.StringType, Computed: true, }, + names.AttrID: framework.IDAttribute(), "job_arn": schema.StringAttribute{ Computed: true, }, @@ -63,42 +60,44 @@ func (d *dataSourceCustomModel) Schema(ctx context.Context, req datasource.Schem "model_arn": schema.StringAttribute{ Computed: true, }, + "model_id": schema.StringAttribute{ + Required: true, + }, "model_kms_key_arn": schema.StringAttribute{ Computed: true, }, "model_name": schema.StringAttribute{ Computed: true, }, - "training_data_config": schema.StringAttribute{ - Computed: true, - }, "output_data_config": schema.StringAttribute{ Computed: true, }, names.AttrTags: tftags.TagsAttributeComputedOnly(), - }, - Blocks: map[string]schema.Block{ - "training_metrics": schema.SingleNestedBlock{ - Attributes: map[string]schema.Attribute{ - "training_loss": schema.Float64Attribute{ - Computed: true, + "training_data_config": schema.StringAttribute{ + Computed: true, + }, + "training_metrics": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelTrainingMetricsModel](ctx), + Computed: true, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "training_loss": types.Float64Type, }, }, }, - "validation_data_config": schema.SingleNestedBlock{ - Attributes: map[string]schema.Attribute{ - "validators": schema.ListAttribute{ - ElementType: types.StringType, - Computed: true, - }, + "validation_data_config": schema.ObjectAttribute{ + CustomType: fwtypes.NewObjectTypeOf[customModelValidationDataConfigModel](ctx), + Computed: true, + AttributeTypes: map[string]attr.Type{ + "validators": types.ListType{ElemType: types.StringType}, }, }, - "validation_metrics": schema.ListNestedBlock{ - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "validation_loss": schema.Float64Attribute{ - Computed: true, - }, + "validation_metrics": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelValidationMetricsModel](ctx), + Computed: true, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "validation_loss": types.Float64Type, }, }, }, @@ -106,13 +105,9 @@ func (d *dataSourceCustomModel) Schema(ctx context.Context, req datasource.Schem } } -// Read is called when the provider must read data source values in order to update state. -// Config values should be read from the ReadRequest and new state values set on the ReadResponse. -func (d *dataSourceCustomModel) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { - var data customModel - +func (d *customModelDataSource) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { + var data customModelDataSourceModel response.Diagnostics.Append(request.Config.Get(ctx, &data)...) - if response.Diagnostics.HasError() { return } @@ -120,60 +115,66 @@ func (d *dataSourceCustomModel) Read(ctx context.Context, request datasource.Rea conn := d.Meta().BedrockClient(ctx) input := &bedrock.GetCustomModelInput{ - ModelIdentifier: data.ModelID.ValueStringPointer(), + ModelIdentifier: fwflex.StringFromFramework(ctx, data.ModelID), } - model, err := conn.GetCustomModel(ctx, input) + + output, err := conn.GetCustomModel(ctx, input) + if err != nil { - response.Diagnostics.AddError("reading Bedrock Custom Model", err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s)", data.ModelID.ValueString()), err.Error()) + return } - jobTags, err := listTags(ctx, conn, *model.JobArn) + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + if response.Diagnostics.HasError() { + return + } + + data.ID = data.ModelID + + jobARN := aws.ToString(output.JobArn) + jobTags, err := listTags(ctx, conn, jobARN) + if err != nil { - response.Diagnostics.AddError("reading Tags for Job", err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model Job (%s) tags", jobARN), err.Error()) + + return } + data.JobTags = flex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) - data.refreshFromOutput(ctx, model) response.Diagnostics.Append(response.State.Set(ctx, &data)...) } -type customModel struct { - ID types.String `tfsdk:"id"` - ModelID types.String `tfsdk:"model_id"` - BaseModelArn types.String `tfsdk:"base_model_arn"` - CreationTime types.String `tfsdk:"creation_time"` - JobArn types.String `tfsdk:"job_arn"` - ModelArn types.String `tfsdk:"model_arn"` - ModelName types.String `tfsdk:"model_name"` - JobName types.String `tfsdk:"job_name"` - ModelKmsKeyArn types.String `tfsdk:"model_kms_key_arn"` - HyperParameters types.Map `tfsdk:"hyper_parameters"` - TrainingDataConfig types.String `tfsdk:"training_data_config"` - TrainingMetrics types.List `tfsdk:"training_metrics"` - ValidationDataConfig *validationDataConfig `tfsdk:"validation_data_config"` - ValidationMetrics []validationMetrics `tfsdk:"validation_metrics"` - OutputDataConfig types.String `tfsdk:"output_data_config"` - JobTags types.Map `tfsdk:"job_tags"` - Tags types.Map `tfsdk:"tags"` +type customModelDataSourceModel struct { + BaseModelARN types.String `tfsdk:"base_model_arn"` + CreationTime types.String `tfsdk:"creation_time"` + HyperParameters types.Map `tfsdk:"hyper_parameters"` + ID types.String `tfsdk:"id"` + JobARN types.String `tfsdk:"job_arn"` + JobName types.String `tfsdk:"job_name"` + JobTags types.Map `tfsdk:"job_tags"` + ModelARN types.String `tfsdk:"model_arn"` + ModelID types.String `tfsdk:"model_id"` + ModelKMSKeyARN types.String `tfsdk:"model_kms_key_arn"` + ModelName types.String `tfsdk:"model_name"` + OutputDataConfig types.String `tfsdk:"output_data_config"` + Tags types.Map `tfsdk:"tags"` + TrainingDataConfig types.String `tfsdk:"training_data_config"` + TrainingMetrics fwtypes.ListNestedObjectValueOf[customModelTrainingMetricsModel] `tfsdk:"training_metrics"` + ValidationDataConfig fwtypes.ObjectValueOf[customModelValidationDataConfigModel] `tfsdk:"validation_data_config"` + ValidationMetrics fwtypes.ListNestedObjectValueOf[customModelValidationMetricsModel] `tfsdk:"validation_metrics"` } -func (data *customModel) refreshFromOutput(ctx context.Context, model *bedrock.GetCustomModelOutput) { - if model == nil { - return - } +type customModelTrainingMetricsModel struct { + TrainingLoss types.Float64 `tfsdk:"training_loss"` +} + +type customModelValidationDataConfigModel struct { + Validators fwtypes.ListValueOf[types.String] `tfsdk:"validators"` +} - data.ID = flex.StringToFramework(ctx, model.ModelArn) - data.BaseModelArn = flex.StringToFramework(ctx, model.BaseModelArn) - data.CreationTime = flex.StringValueToFramework[string](ctx, model.CreationTime.Format(time.RFC3339)) - data.JobArn = flex.StringToFramework(ctx, model.JobArn) - data.ModelArn = flex.StringToFramework(ctx, model.ModelArn) - data.ModelName = flex.StringToFramework(ctx, model.ModelName) - data.JobName = flex.StringToFramework(ctx, model.JobName) - data.ModelKmsKeyArn = flex.StringToFramework(ctx, model.ModelKmsKeyArn) - data.HyperParameters = flex.FlattenFrameworkStringValueMap(ctx, model.HyperParameters) - data.TrainingDataConfig = flex.StringToFramework(ctx, model.TrainingDataConfig.S3Uri) - data.TrainingMetrics = flattenTrainingMetrics(ctx, model.TrainingMetrics) - data.ValidationMetrics = flattenValidationMetrics(ctx, model.ValidationMetrics) - data.OutputDataConfig = flex.StringToFramework(ctx, model.OutputDataConfig.S3Uri) +type customModelValidationMetricsModel struct { + ValidationLoss types.Float64 `tfsdk:"validation_loss"` } diff --git a/internal/service/bedrock/custom_model_data_source_test.go b/internal/service/bedrock/custom_model_data_source_test.go index 6e56689c4ff..bab02d015d4 100644 --- a/internal/service/bedrock/custom_model_data_source_test.go +++ b/internal/service/bedrock/custom_model_data_source_test.go @@ -16,7 +16,7 @@ func TestAccBedrockCustomModelDataSource_basic(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrock_custom_model.test" - dataSourceResourceName := "data.aws_bedrock_custom_model.test" + datasourceName := "data.aws_bedrock_custom_model.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -25,27 +25,28 @@ func TestAccBedrockCustomModelDataSource_basic(t *testing.T) { { Config: testAccCustomModelDataSourceConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(dataSourceResourceName, "id"), - resource.TestCheckResourceAttrPair(resourceName, "base_model_arn", dataSourceResourceName, "base_model_arn"), - resource.TestCheckResourceAttrPair(resourceName, "creation_time", dataSourceResourceName, "creation_time"), - resource.TestCheckResourceAttrPair(resourceName, "hyper_parameters", dataSourceResourceName, "hyper_parameters"), - resource.TestCheckResourceAttrPair(resourceName, "job_arn", dataSourceResourceName, "job_arn"), - resource.TestCheckResourceAttrPair(resourceName, "job_name", dataSourceResourceName, "job_name"), - resource.TestCheckResourceAttrPair(resourceName, "job_tags", dataSourceResourceName, "job_tags"), - resource.TestCheckResourceAttrPair(resourceName, "model_arn", dataSourceResourceName, "model_arn"), - resource.TestCheckResourceAttrPair(resourceName, "model_kms_key_arn", dataSourceResourceName, "model_kms_key_arn"), - resource.TestCheckResourceAttrPair(resourceName, "model_name", dataSourceResourceName, "model_name"), - resource.TestCheckResourceAttrPair(resourceName, "output_data_config", dataSourceResourceName, "output_data_config"), - resource.TestCheckResourceAttrPair(resourceName, "training_data_config", dataSourceResourceName, "training_data_config"), - resource.TestCheckResourceAttrPair(resourceName, "training_metrics", dataSourceResourceName, "training_metrics"), - resource.TestCheckResourceAttrPair(resourceName, "validation_data_config", dataSourceResourceName, "validation_data_config"), - resource.TestCheckResourceAttrPair(resourceName, "validation_metrics", dataSourceResourceName, "validation_metrics"), + resource.TestCheckResourceAttrSet(datasourceName, "id"), + resource.TestCheckResourceAttrPair(resourceName, "base_model_arn", datasourceName, "base_model_arn"), + resource.TestCheckResourceAttrPair(resourceName, "creation_time", datasourceName, "creation_time"), + resource.TestCheckResourceAttrPair(resourceName, "hyper_parameters", datasourceName, "hyper_parameters"), + resource.TestCheckResourceAttrPair(resourceName, "job_arn", datasourceName, "job_arn"), + resource.TestCheckResourceAttrPair(resourceName, "job_name", datasourceName, "job_name"), + resource.TestCheckResourceAttrPair(resourceName, "job_tags", datasourceName, "job_tags"), + resource.TestCheckResourceAttrPair(resourceName, "model_arn", datasourceName, "model_arn"), + resource.TestCheckResourceAttrPair(resourceName, "model_kms_key_arn", datasourceName, "model_kms_key_arn"), + resource.TestCheckResourceAttrPair(resourceName, "model_name", datasourceName, "model_name"), + resource.TestCheckResourceAttrPair(resourceName, "output_data_config", datasourceName, "output_data_config"), + resource.TestCheckResourceAttrPair(resourceName, "training_data_config", datasourceName, "training_data_config"), + resource.TestCheckResourceAttrPair(resourceName, "training_metrics", datasourceName, "training_metrics"), + resource.TestCheckResourceAttrPair(resourceName, "validation_data_config", datasourceName, "validation_data_config"), + resource.TestCheckResourceAttrPair(resourceName, "validation_metrics", datasourceName, "validation_metrics"), ), }, }, }) } +// TODO Shared config with resource? func testAccCustomModelDataSourceConfig_basic(rName string) string { return fmt.Sprintf(` data "aws_caller_identity" "current" {} diff --git a/internal/service/bedrock/foundation_model_data_source.go b/internal/service/bedrock/foundation_model_data_source.go index a1b1a28183b..4a74e287649 100644 --- a/internal/service/bedrock/foundation_model_data_source.go +++ b/internal/service/bedrock/foundation_model_data_source.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-aws/internal/framework" fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -33,15 +34,18 @@ func (d *foundationModelDataSource) Schema(ctx context.Context, request datasour response.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ "customizations_supported": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, ElementType: types.StringType, Computed: true, }, names.AttrID: framework.IDAttribute(), "inference_types_supported": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, ElementType: types.StringType, Computed: true, }, "input_modalities": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, ElementType: types.StringType, Computed: true, }, @@ -55,6 +59,7 @@ func (d *foundationModelDataSource) Schema(ctx context.Context, request datasour Computed: true, }, "output_modalities": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, ElementType: types.StringType, Computed: true, }, @@ -100,14 +105,14 @@ func (d *foundationModelDataSource) Read(ctx context.Context, request datasource } type foundationModelDataSourceModel struct { - CustomizationsSupported types.Set `tfsdk:"customizations_supported"` - ID types.String `tfsdk:"id"` - InferenceTypesSupported types.Set `tfsdk:"inference_types_supported"` - InputModalities types.Set `tfsdk:"input_modalities"` - ModelARN types.String `tfsdk:"model_arn"` - ModelID types.String `tfsdk:"model_id"` - ModelName types.String `tfsdk:"model_name"` - OutputModalities types.Set `tfsdk:"output_modalities"` - ProviderName types.String `tfsdk:"provider_name"` - ResponseStreamingSupported types.Bool `tfsdk:"response_streaming_supported"` + CustomizationsSupported fwtypes.SetValueOf[types.String] `tfsdk:"customizations_supported"` + ID types.String `tfsdk:"id"` + InferenceTypesSupported fwtypes.SetValueOf[types.String] `tfsdk:"inference_types_supported"` + InputModalities fwtypes.SetValueOf[types.String] `tfsdk:"input_modalities"` + ModelARN types.String `tfsdk:"model_arn"` + ModelID types.String `tfsdk:"model_id"` + ModelName types.String `tfsdk:"model_name"` + OutputModalities fwtypes.SetValueOf[types.String] `tfsdk:"output_modalities"` + ProviderName types.String `tfsdk:"provider_name"` + ResponseStreamingSupported types.Bool `tfsdk:"response_streaming_supported"` } diff --git a/internal/service/bedrock/service_package_gen.go b/internal/service/bedrock/service_package_gen.go index fd48e422166..c48ed068071 100644 --- a/internal/service/bedrock/service_package_gen.go +++ b/internal/service/bedrock/service_package_gen.go @@ -17,15 +17,16 @@ type servicePackage struct{} func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.ServicePackageFrameworkDataSource { return []*types.ServicePackageFrameworkDataSource{ { - Factory: newCustomModelsDataSource, - Name: "Custom Models", - }, - { - Factory: newDataSourceCustomModel, + Factory: newCustomModelDataSource, + Name: "Custom Model", Tags: &types.ServicePackageResourceTags{ IdentifierAttribute: "model_arn", }, }, + { + Factory: newCustomModelsDataSource, + Name: "Custom Models", + }, { Factory: newFoundationModelDataSource, Name: "Foundation Model", From 72ed7d28de2ac661d4812b0bb9ac363fa27b234c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sun, 28 Jan 2024 17:41:40 -0500 Subject: [PATCH 24/62] Add CHANGELOG entry. --- .changelog/34310.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changelog/34310.txt diff --git a/.changelog/34310.txt b/.changelog/34310.txt new file mode 100644 index 00000000000..3efcda23b86 --- /dev/null +++ b/.changelog/34310.txt @@ -0,0 +1,11 @@ +```release-note:new-data-source +aws_bedrock_custom_model +``` + +```release-note:new-data-source +aws_bedrock_custom_models +``` + +```release-note:resource +aws_bedrock_custom_model +``` \ No newline at end of file From 6de445a83d746dc04a9e9117a3f807583d0335e7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 29 Jan 2024 08:42:34 -0500 Subject: [PATCH 25/62] Add 'MapOfStringType'. --- internal/framework/types/mapof.go | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/internal/framework/types/mapof.go b/internal/framework/types/mapof.go index 8269c131f8e..eccd2ac7885 100644 --- a/internal/framework/types/mapof.go +++ b/internal/framework/types/mapof.go @@ -16,22 +16,26 @@ import ( ) var ( - _ basetypes.MapTypable = MapTypeOf[basetypes.StringValue]{} + _ basetypes.MapTypable = mapTypeOf[basetypes.StringValue]{} _ basetypes.MapValuable = MapValueOf[basetypes.StringValue]{} ) -// MapTypeOf is the attribute type of a MapValueOf. -type MapTypeOf[T attr.Value] struct { +var ( + // MapOfStringType is a custom type used for defining a Map of strings. + MapOfStringType = mapTypeOf[basetypes.StringValue]{basetypes.MapType{ElemType: basetypes.StringType{}}} +) + +type mapTypeOf[T attr.Value] struct { basetypes.MapType } -func NewMapTypeOf[T attr.Value](ctx context.Context) MapTypeOf[T] { +func NewMapTypeOf[T attr.Value](ctx context.Context) mapTypeOf[T] { var zero T - return MapTypeOf[T]{basetypes.MapType{ElemType: zero.Type(ctx)}} + return mapTypeOf[T]{basetypes.MapType{ElemType: zero.Type(ctx)}} } -func (t MapTypeOf[T]) Equal(o attr.Type) bool { - other, ok := o.(MapTypeOf[T]) +func (t mapTypeOf[T]) Equal(o attr.Type) bool { + other, ok := o.(mapTypeOf[T]) if !ok { return false @@ -40,18 +44,19 @@ func (t MapTypeOf[T]) Equal(o attr.Type) bool { return t.MapType.Equal(other.MapType) } -func (t MapTypeOf[T]) String() string { +func (t mapTypeOf[T]) String() string { var zero T return fmt.Sprintf("%T", zero) } -func (t MapTypeOf[T]) ValueFromMap(ctx context.Context, in basetypes.MapValue) (basetypes.MapValuable, diag.Diagnostics) { +func (t mapTypeOf[T]) ValueFromMap(ctx context.Context, in basetypes.MapValue) (basetypes.MapValuable, diag.Diagnostics) { var diags diag.Diagnostics var zero T if in.IsNull() { return NewMapValueOfNull[T](ctx), diags } + if in.IsUnknown() { return NewMapValueOfUnknown[T](ctx), diags } @@ -73,7 +78,7 @@ func (t MapTypeOf[T]) ValueFromMap(ctx context.Context, in basetypes.MapValue) ( return value, diags } -func (t MapTypeOf[T]) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { +func (t mapTypeOf[T]) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { attrValue, err := t.MapType.ValueFromTerraform(ctx, in) if err != nil { @@ -93,11 +98,11 @@ func (t MapTypeOf[T]) ValueFromTerraform(ctx context.Context, in tftypes.Value) return mapValuable, nil } -func (t MapTypeOf[T]) ValueType(ctx context.Context) attr.Value { +func (t mapTypeOf[T]) ValueType(ctx context.Context) attr.Value { return MapValueOf[T]{} } -// MapValueOf represents a Terraform Plugin Framework Map value whose elements are of type MapTypeOf. +// MapValueOf represents a Terraform Plugin Framework Map value whose elements are of type mapTypeOf. type MapValueOf[T attr.Value] struct { basetypes.MapValue } From 2a4578ab116cd63b3ffd1b32e488976d43801dea Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 29 Jan 2024 10:28:04 -0500 Subject: [PATCH 26/62] Add 'framework.validators.S3URI'. --- internal/framework/validators/s3_uri.go | 48 ++++++++++++ internal/framework/validators/s3_uri_test.go | 77 ++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 internal/framework/validators/s3_uri.go create mode 100644 internal/framework/validators/s3_uri_test.go diff --git a/internal/framework/validators/s3_uri.go b/internal/framework/validators/s3_uri.go new file mode 100644 index 00000000000..6a762cf9332 --- /dev/null +++ b/internal/framework/validators/s3_uri.go @@ -0,0 +1,48 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validators + +import ( + "context" + + "github.com/YakDriver/regexache" + "github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" +) + +// s3URIValidator validates that a string Attribute's value is a valid S3 URI. +type s3URIValidator struct{} + +func (validator s3URIValidator) Description(_ context.Context) string { + return "value must be a valid S3 URI" +} + +func (validator s3URIValidator) MarkdownDescription(ctx context.Context) string { + return validator.Description(ctx) +} + +func (validator s3URIValidator) ValidateString(ctx context.Context, request validator.StringRequest, response *validator.StringResponse) { + if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() { + return + } + + if !regexache.MustCompile(`^s3://[a-z0-9][\.\-a-z0-9]{1,61}[a-z0-9](/.*)?$`).MatchString(request.ConfigValue.ValueString()) { + response.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic( + request.Path, + validator.Description(ctx), + request.ConfigValue.ValueString(), + )) + return + } +} + +// S3URI returns a string validator which ensures that any configured +// attribute value: +// +// - Is a string, which represents a valid S3 URI (s3://bucket[/key]). +// +// Null (unconfigured) and unknown (known after apply) values are skipped. +func S3URI() validator.String { + return s3URIValidator{} +} diff --git a/internal/framework/validators/s3_uri_test.go b/internal/framework/validators/s3_uri_test.go new file mode 100644 index 00000000000..b8b9212224b --- /dev/null +++ b/internal/framework/validators/s3_uri_test.go @@ -0,0 +1,77 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package validators_test + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + fwvalidators "github.com/hashicorp/terraform-provider-aws/internal/framework/validators" +) + +func TestS3URIValidator(t *testing.T) { + t.Parallel() + + type testCase struct { + val types.String + expectedDiagnostics diag.Diagnostics + } + tests := map[string]testCase{ + "unknown String": { + val: types.StringUnknown(), + }, + "null String": { + val: types.StringNull(), + }, + "invalid String": { + val: types.StringValue("test-value"), + expectedDiagnostics: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic( + path.Root("test"), + "Invalid Attribute Value", + `Attribute test value must be a valid S3 URI, got: test-value`, + ), + }, + }, + "valid S3 URI": { + val: types.StringValue("s3://bucket/path/to/key"), + }, + "invalid characters": { + val: types.StringValue("s3://asbcdefg--#/key"), + expectedDiagnostics: diag.Diagnostics{ + diag.NewAttributeErrorDiagnostic( + path.Root("test"), + "Invalid Attribute Value", + `Attribute test value must be a valid S3 URI, got: s3://asbcdefg--#/key`, + ), + }, + }, + } + + for name, test := range tests { + name, test := name, test + t.Run(name, func(t *testing.T) { + t.Parallel() + + ctx := context.Background() + + request := validator.StringRequest{ + Path: path.Root("test"), + PathExpression: path.MatchRoot("test"), + ConfigValue: test.val, + } + response := validator.StringResponse{} + fwvalidators.S3URI().ValidateString(ctx, request, &response) + + if diff := cmp.Diff(response.Diagnostics, test.expectedDiagnostics); diff != "" { + t.Errorf("unexpected diagnostics difference: %s", diff) + } + }) + } +} From 524f453a56a0cce3574a56d3281da6dd215e1c19 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 29 Jan 2024 12:17:19 -0500 Subject: [PATCH 27/62] r/aws_bedrock_custom_model: Use AutoFlEx. --- internal/service/bedrock/custom_model.go | 436 ++++++++++-------- .../bedrock/custom_model_data_source.go | 59 ++- .../service/bedrock/service_package_gen.go | 3 +- internal/service/bedrock/structures.go | 207 --------- 4 files changed, 285 insertions(+), 420 deletions(-) delete mode 100644 internal/service/bedrock/structures.go diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 4e3603d958b..31e7c2ec020 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -5,17 +5,18 @@ package bedrock import ( "context" + "errors" "fmt" "time" "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/bedrock" awstypes "github.com/aws/aws-sdk-go-v2/service/bedrock/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" @@ -23,62 +24,66 @@ import ( "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" - "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" "github.com/hashicorp/terraform-provider-aws/internal/framework" - "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + fwvalidators "github.com/hashicorp/terraform-provider-aws/internal/framework/validators" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) -// @FrameworkResource +// @FrameworkResource(name="Custom Model") // @Tags(identifierAttribute="model_arn") -func newResourceCustomModel(context.Context) (resource.ResourceWithConfigure, error) { - r := &resourceCustomModel{} +func newCustomModelResource(context.Context) (resource.ResourceWithConfigure, error) { + r := &customModelResource{} + r.SetDefaultCreateTimeout(120 * time.Minute) + return r, nil } -type resourceCustomModel struct { +type customModelResource struct { framework.ResourceWithConfigure + framework.WithNoOpUpdate + framework.WithImportByID framework.WithTimeouts } -func (r *resourceCustomModel) Metadata(_ context.Context, request resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *customModelResource) Metadata(_ context.Context, request resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = "aws_bedrock_custom_model" } -// This resource is a composition of the following APIs. These APIs do not have consitently named attributes, so we will normalize them here. -// - CreateModelCustomizationJob -// - GetModelCustomizationJob -// - GetCustomModel -func (r *resourceCustomModel) Schema(ctx context.Context, request resource.SchemaRequest, resp *resource.SchemaResponse) { - resp.Schema = schema.Schema{ +func (r *customModelResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { + // This resource is a composition of the following APIs. These APIs do not have consitently named attributes, so we will normalize them here. + // - CreateModelCustomizationJob + // - GetModelCustomizationJob + // - GetCustomModel + response.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - "arn": framework.ARNAttributeComputedOnly(), + names.AttrARN: framework.ARNAttributeComputedOnly(), "base_model_arn": schema.StringAttribute{ - Required: true, CustomType: fwtypes.ARNType, + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, - Validators: []validator.String{ - stringvalidator.LengthBetween(1, 2048), - }, }, "customization_type": schema.StringAttribute{ - Optional: true, + CustomType: fwtypes.StringEnumType[awstypes.CustomizationType](), + Optional: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), stringplanmodifier.UseStateForUnknown(), }, - Validators: []validator.String{ - enum.FrameworkValidate[awstypes.CustomizationType](), - }, }, "hyper_parameters": schema.MapAttribute{ + CustomType: fwtypes.MapOfStringType, Required: true, ElementType: types.StringType, }, @@ -98,14 +103,11 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, "job_tags": tftags.TagsAttribute(), "job_role_arn": schema.StringAttribute{ - Required: true, CustomType: fwtypes.ARNType, + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, - Validators: []validator.String{ - stringvalidator.LengthBetween(1, 2048), - }, }, "job_status": schema.StringAttribute{ Computed: true, @@ -116,9 +118,6 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, - Validators: []validator.String{ - stringvalidator.LengthBetween(1, 2048), - }, }, "name": schema.StringAttribute{ Required: true, @@ -131,20 +130,38 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, names.AttrTags: tftags.TagsAttribute(), names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + "training_metrics": schema.ObjectAttribute{ + CustomType: fwtypes.NewObjectTypeOf[customModelTrainingMetricsModel](ctx), + Computed: true, + AttributeTypes: map[string]attr.Type{ + "training_loss": types.Float64Type, + }, + }, + "validation_metrics": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelValidationMetricsModel](ctx), + Computed: true, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "validation_loss": types.Float64Type, + }, + }, + }, }, Blocks: map[string]schema.Block{ "job_vpc_config": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelVPCConfigModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), }, - CustomType: fwtypes.NewListNestedObjectTypeOf[vpcConfig](ctx), NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "security_group_ids": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, ElementType: types.StringType, Required: true, }, "subnet_ids": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, ElementType: types.StringType, Required: true, }, @@ -152,18 +169,18 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, }, "output_data_config": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelOutputDataConfigModel](ctx), Validators: []validator.List{ listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), listvalidator.SizeAtMost(1), }, - CustomType: fwtypes.NewListNestedObjectTypeOf[outputDataConfig](ctx), NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "s3_uri": schema.StringAttribute{ Required: true, Validators: []validator.String{ - stringvalidator.LengthBetween(1, 1024), - stringvalidator.RegexMatches(regexache.MustCompile(`^s3://`), "minimum length of 1. Maximum length of 1024. Must be an S3 URI"), + fwvalidators.S3URI(), }, }, }, @@ -174,57 +191,43 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem Delete: true, }), "training_data_config": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelTrainingDataConfigModel](ctx), Validators: []validator.List{ listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), listvalidator.SizeAtMost(1), }, - CustomType: fwtypes.NewListNestedObjectTypeOf[trainingDataConfig](ctx), NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "s3_uri": schema.StringAttribute{ Required: true, Validators: []validator.String{ - stringvalidator.LengthBetween(1, 1024), - stringvalidator.RegexMatches(regexache.MustCompile(`^s3://`), "minimum length of 1. Maximum length of 1024. Must be an S3 URI"), + fwvalidators.S3URI(), }, }, }, }, }, - "training_metrics": schema.ListNestedBlock{ - Validators: []validator.List{ - listvalidator.SizeAtMost(1), - }, - CustomType: fwtypes.NewListNestedObjectTypeOf[trainingMetrics](ctx), - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "training_loss": schema.Float64Attribute{ - Computed: true, - }, - }, - }, - }, "validation_data_config": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelValidationDataConfigModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), }, - CustomType: fwtypes.NewListNestedObjectTypeOf[validationDataConfig](ctx), NestedObject: schema.NestedBlockObject{ Blocks: map[string]schema.Block{ "validator": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelValidatorConfigModel](ctx), Validators: []validator.List{ listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), listvalidator.SizeAtMost(10), }, - CustomType: fwtypes.NewListNestedObjectTypeOf[validatorConfig](ctx), NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "s3_uri": schema.StringAttribute{ Required: true, Validators: []validator.String{ - stringvalidator.LengthBetween(1, 1024), - stringvalidator.RegexMatches(regexache.MustCompile(`^s3://`), "minimum length of 1. Maximum length of 1024. Must be an S3 URI"), - }, + fwvalidators.S3URI()}, }, }, }, @@ -232,101 +235,102 @@ func (r *resourceCustomModel) Schema(ctx context.Context, request resource.Schem }, }, }, - "validation_metrics": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[validationMetrics](ctx), - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "validation_loss": schema.Float64Attribute{ - Computed: true, - }, - }, - }, - }, }, } } -func (r *resourceCustomModel) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { - conn := r.Meta().BedrockClient(ctx) - +func (r *customModelResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { var data resourceCustomModelData response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) if response.Diagnostics.HasError() { return } - var outputData []outputDataConfig - response.Diagnostics.Append(data.OutputDataConfig.ElementsAs(ctx, &outputData, false)...) + conn := r.Meta().BedrockClient(ctx) + + input := &bedrock.CreateModelCustomizationJobInput{} + response.Diagnostics.Append(fwflex.Expand(ctx, data, input)...) if response.Diagnostics.HasError() { return } - var trainingData []trainingDataConfig - response.Diagnostics.Append(data.TrainingDataConfig.ElementsAs(ctx, &trainingData, false)...) - if response.Diagnostics.HasError() { + + input.BaseModelIdentifier = fwflex.StringFromFramework(ctx, data.BaseModelARN) + input.ClientRequestToken = aws.String(id.UniqueId()) + input.CustomModelTags = getTagsIn(ctx) + input.JobTags = getTagsIn(ctx) + + output, err := conn.CreateModelCustomizationJob(ctx, input) + + if err != nil { + response.Diagnostics.AddError("creating Bedrock Custom Model customization job", err.Error()) + return } - input := &bedrock.CreateModelCustomizationJobInput{ - BaseModelIdentifier: data.BaseModelArn.ValueStringPointer(), - CustomModelName: data.Name.ValueStringPointer(), - CustomModelTags: getTagsIn(ctx), - HyperParameters: flex.ExpandFrameworkStringValueMap(ctx, data.HyperParameters), - JobName: data.JobName.ValueStringPointer(), - OutputDataConfig: expandOutputDataConfig(ctx, outputData), - TrainingDataConfig: expandTrainingDataConfig(ctx, trainingData), - RoleArn: data.JobRoleArn.ValueStringPointer(), - } + jobARN := aws.ToString(output.JobArn) - if !data.CustomizationType.IsNull() { - input.CustomModelName = data.CustomizationType.ValueStringPointer() - } - if !data.KmsKeyArn.IsNull() { - input.CustomModelKmsKeyId = data.KmsKeyArn.ValueStringPointer() + _, err = waitModelCustomizationJobCompleted(ctx, conn, jobARN, r.CreateTimeout(ctx, data.Timeouts)) + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for Bedrock Custom Model customization job (%s) complete", jobARN), err.Error()) + + return } - if !data.JobTags.IsNull() { - input.JobTags = Tags(tftags.New(ctx, data.JobTags)) + + // Set values for unknowns. + + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +func (r *customModelResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + var data resourceCustomModelData + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + if response.Diagnostics.HasError() { + return } - if !data.JobVpcConfig.IsNull() { - var vpcData []vpcConfig - response.Diagnostics.Append(data.JobVpcConfig.ElementsAs(ctx, &vpcData, false)...) - if response.Diagnostics.HasError() { - return - } - input.VpcConfig = expandVPCConfig(ctx, vpcData) + + if err := data.InitFromID(); err != nil { + response.Diagnostics.AddError("parsing resource ID", err.Error()) + + return } - if !data.ValidationDataConfig.IsNull() { - var validationData []validationDataConfig - response.Diagnostics.Append(data.ValidationDataConfig.ElementsAs(ctx, &validationData, false)...) - if response.Diagnostics.HasError() { - return - } - input.ValidationDataConfig = expandValidationDataConfig(ctx, validationData, diag.Diagnostics{}) + + conn := r.Meta().BedrockClient(ctx) + + output, err := findCustomModelByID(ctx, conn, data.ARN.ValueString()) + + if tfresource.NotFound(err) { + response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) + response.State.RemoveResource(ctx) + + return } - job, err := conn.CreateModelCustomizationJob(ctx, input) if err != nil { - response.Diagnostics.AddError( - create.ProblemStandardMessage(names.Bedrock, create.ErrActionCreating, "ModelCustomizationJob", data.JobName.ValueString(), nil), - err.Error(), - ) + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s)", data.ID.ValueString()), err.Error()) + return } - // Successfully started job. Save the id now - // data.ID = flex.StringValueToFramework(ctx, "tf-acc-test-1531621220222582981") - // data.JobArn = flex.StringValueToFramework(ctx, "arn:aws:bedrock:us-east-1:219858395663:model-customization-job/amazon.titan-text-express-v1:0:8k/pc2v9cmxjzlq") + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + if response.Diagnostics.HasError() { + return + } - // Also save job arn into state now incase we need to cancel and destroy. - data.JobArn = flex.StringToFramework(ctx, job.JobArn) + jobARN := aws.ToString(output.JobArn) + jobTags, err := listTags(ctx, conn, jobARN) + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model Job (%s) tags", jobARN), err.Error()) - response.Diagnostics.Append(data.refresh(ctx, conn)...) - if response.Diagnostics.HasError() { return } + + data.JobTags = fwflex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) + response.Diagnostics.Append(response.State.Set(ctx, &data)...) } - -func (r *resourceCustomModel) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { +func (r *customModelResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { var data resourceCustomModelData response.Diagnostics.Append(request.State.Get(ctx, &data)...) if response.Diagnostics.HasError() { @@ -335,26 +339,108 @@ func (r *resourceCustomModel) Read(ctx context.Context, request resource.ReadReq conn := r.Meta().BedrockClient(ctx) - response.Diagnostics.Append(data.refresh(ctx, conn)...) - response.Diagnostics.Append(response.State.Set(ctx, &data)...) + _, err := conn.DeleteCustomModel(ctx, &bedrock.DeleteCustomModelInput{ + ModelIdentifier: fwflex.StringFromFramework(ctx, data.ARN), + }) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("deleting Bedrock Custom Model (%s)", data.ID.ValueString()), err.Error()) + + return + } } -func (r *resourceCustomModel) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { - tflog.Trace(ctx, "Update not supported.") +func (r *customModelResource) ModifyPlan(ctx context.Context, request resource.ModifyPlanRequest, response *resource.ModifyPlanResponse) { + r.SetTagsAll(ctx, request, response) } -func (r *resourceCustomModel) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { - conn := r.Meta().BedrockClient(ctx) +func findCustomModelByID(ctx context.Context, conn *bedrock.Client, id string) (*bedrock.GetCustomModelOutput, error) { + input := &bedrock.GetCustomModelInput{ + ModelIdentifier: aws.String(id), + } + + output, err := conn.GetCustomModel(ctx, input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } - _, err := conn.DeleteModelInvocationLoggingConfiguration(ctx, &bedrock.DeleteModelInvocationLoggingConfigurationInput{}) if err != nil { - response.Diagnostics.AddError("failed to delete model invocation logging configuration", err.Error()) - return + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) } + + return output, nil } -func (r *resourceCustomModel) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root("id"), request, response) +func findModelCustomizationJobByID(ctx context.Context, conn *bedrock.Client, id string) (*bedrock.GetModelCustomizationJobOutput, error) { + input := &bedrock.GetModelCustomizationJobInput{ + JobIdentifier: aws.String(id), + } + + output, err := conn.GetModelCustomizationJob(ctx, input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} + +func statusModelCustomizationJob(ctx context.Context, conn *bedrock.Client, id string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := findModelCustomizationJobByID(ctx, conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, string(output.Status), nil + } +} + +func waitModelCustomizationJobCompleted(ctx context.Context, conn *bedrock.Client, id string, timeout time.Duration) (*bedrock.GetModelCustomizationJobOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(awstypes.ModelCustomizationJobStatusInProgress), + Target: enum.Slice(awstypes.ModelCustomizationJobStatusCompleted), + Refresh: statusModelCustomizationJob(ctx, conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*bedrock.GetModelCustomizationJobOutput); ok { + tfresource.SetLastError(err, errors.New(aws.ToString(output.FailureMessage))) + + return output, err + } + + return nil, err } func waitForModelCustomizationJob(ctx context.Context, conn *bedrock.Client, jobArn string, timeout time.Duration) error { @@ -382,67 +468,35 @@ func waitForModelCustomizationJob(ctx context.Context, conn *bedrock.Client, job } type resourceCustomModelData struct { - Arn types.String `tfsdk:"arn"` - BaseModelArn types.String `tfsdk:"base_model_arn"` - CustomizationType types.String `tfsdk:"customization_type"` - HyperParameters types.Map `tfsdk:"hyper_parameters"` - Id types.String `tfsdk:"id"` - JobArn types.String `tfsdk:"job_arn"` - JobName types.String `tfsdk:"job_name"` - JobTags types.Map `tfsdk:"job_tags"` - JobRoleArn types.String `tfsdk:"job_role_arn"` - JobStatus types.String `tfsdk:"job_status"` - JobVpcConfig fwtypes.ListNestedObjectValueOf[vpcConfig] `tfsdk:"job_vpc_config"` - KmsKeyArn types.String `tfsdk:"kms_key_arn"` - Name types.String `tfsdk:"name"` - OutputDataConfig fwtypes.ListNestedObjectValueOf[outputDataConfig] `tfsdk:"output_data_config"` - TrainingDataConfig fwtypes.ListNestedObjectValueOf[trainingDataConfig] `tfsdk:"training_data_config"` - TrainingMetrics fwtypes.ListNestedObjectValueOf[trainingMetrics] `tfsdk:"training_metrics"` - ValidationDataConfig fwtypes.ListNestedObjectValueOf[validationDataConfig] `tfsdk:"validation_data_config"` - ValidationMetrics fwtypes.ListNestedObjectValueOf[validationMetrics] `tfsdk:"validation_metrics"` - Tags types.Map `tfsdk:"tags"` - TagsAll types.Map `tfsdk:"tags_all"` - Timeouts timeouts.Value `tfsdk:"timeouts"` + ARN types.String `tfsdk:"arn"` + BaseModelARN fwtypes.ARN `tfsdk:"base_model_arn"` + CustomizationType fwtypes.StringEnum[awstypes.CustomizationType] `tfsdk:"customization_type"` + HyperParameters fwtypes.MapValueOf[types.String] `tfsdk:"hyper_parameters"` + ID types.String `tfsdk:"id"` + JobARN types.String `tfsdk:"job_arn"` + JobName types.String `tfsdk:"job_name"` + JobRoleARN fwtypes.ARN `tfsdk:"job_role_arn"` + JobStatus types.String `tfsdk:"job_status"` + JobTags types.Map `tfsdk:"job_tags"` + JobVPCConfig fwtypes.ListNestedObjectValueOf[customModelVPCConfigModel] `tfsdk:"job_vpc_config"` + KmsKeyARN fwtypes.ARN `tfsdk:"kms_key_arn"` + Name types.String `tfsdk:"name"` + OutputDataConfig fwtypes.ListNestedObjectValueOf[customModelOutputDataConfigModel] `tfsdk:"output_data_config"` + Tags types.Map `tfsdk:"tags"` + TagsAll types.Map `tfsdk:"tags_all"` + Timeouts timeouts.Value `tfsdk:"timeouts"` + TrainingDataConfig fwtypes.ListNestedObjectValueOf[customModelTrainingDataConfigModel] `tfsdk:"training_data_config"` + TrainingMetrics fwtypes.ObjectValueOf[customModelTrainingMetricsModel] `tfsdk:"training_metrics"` + ValidationDataConfig fwtypes.ListNestedObjectValueOf[customModelValidationDataConfigModel] `tfsdk:"validation_data_config"` + ValidationMetrics fwtypes.ListNestedObjectValueOf[customModelValidationMetricsModel] `tfsdk:"validation_metrics"` +} + +func (data *resourceCustomModelData) InitFromID() error { + data.ARN = data.ID + + return nil } -func (data *resourceCustomModelData) refresh(ctx context.Context, conn *bedrock.Client) diag.Diagnostics { - var diags diag.Diagnostics - - /* modelId := data.ID - input := &bedrock.GetCustomModelInput{ - ModelIdentifier: modelId.ValueStringPointer(), - } - output, err := conn.GetCustomModel(ctx, input) - - if err != nil { - // If we got here, the state has the model name and the job arn. - // Should we check for tainted state instead? - tflog.Info(ctx, "resourceCustomModelRead: Error reading Bedrock Custom Model. Ignoring to allow destroy to attempt to cleanup.") - return diags - } - - data.BaseModelArn = flex.StringToFramework(ctx, output.BaseModelArn) - data.CreationTime = flex.StringValueToFramework(ctx, output.CreationTime.Format((time.RFC3339))) - data.HyperParameters = flex.FlattenFrameworkStringValueMap(ctx, output.HyperParameters) - data.JobArn = flex.StringToFramework(ctx, output.JobArn) - // This is nil in the model object - could be a bug - // However this is already in state so we can skip setting this here and avoid a forced update due to value change. - // d.Set("job_name", model.JobName) - data.ModelArn = flex.StringToFramework(ctx, output.ModelArn) - data.ModelKmsKeyArn = flex.StringToFramework(ctx, output.ModelKmsKeyArn) - data.ModelName = flex.StringToFramework(ctx, output.ModelName) - data.OutputDataConfig = flex.StringToFramework(ctx, output.OutputDataConfig.S3Uri) - data.TrainingDataConfig = flex.StringToFramework(ctx, output.TrainingDataConfig.S3Uri) - data.TrainingMetrics = flattenTrainingMetrics(ctx, output.TrainingMetrics) - data.ValidationDataConfig = flattenValidationDataConfig(ctx, output.ValidationDataConfig) - data.ValidationMetrics = flattenValidationMetrics(ctx, output.ValidationMetrics) - - jobTags, err := listTags(ctx, conn, *output.JobArn) - if err != nil { - diags.AddError("reading Tags for Job", err.Error()) - return diags - } - data.JobTags = flex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) - */ - return diags +func (data *resourceCustomModelData) setID() { + data.ID = data.ARN } diff --git a/internal/service/bedrock/custom_model_data_source.go b/internal/service/bedrock/custom_model_data_source.go index ba3ca636023..57ad416c290 100644 --- a/internal/service/bedrock/custom_model_data_source.go +++ b/internal/service/bedrock/custom_model_data_source.go @@ -8,13 +8,11 @@ import ( "fmt" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go-v2/service/bedrock" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-aws/internal/framework" - "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" @@ -46,8 +44,8 @@ func (d *customModelDataSource) Schema(ctx context.Context, request datasource.S Computed: true, }, "hyper_parameters": schema.MapAttribute{ - ElementType: types.StringType, Computed: true, + ElementType: types.StringType, }, names.AttrID: framework.IDAttribute(), "job_arn": schema.StringAttribute{ @@ -69,27 +67,33 @@ func (d *customModelDataSource) Schema(ctx context.Context, request datasource.S "model_name": schema.StringAttribute{ Computed: true, }, - "output_data_config": schema.StringAttribute{ - Computed: true, + "output_data_config": schema.ObjectAttribute{ + CustomType: fwtypes.NewObjectTypeOf[customModelOutputDataConfigModel](ctx), + Computed: true, + AttributeTypes: map[string]attr.Type{ + "s3_uri": types.StringType, + }, }, names.AttrTags: tftags.TagsAttributeComputedOnly(), - "training_data_config": schema.StringAttribute{ - Computed: true, + "training_data_config": schema.ObjectAttribute{ + CustomType: fwtypes.NewObjectTypeOf[customModelTrainingDataConfigModel](ctx), + Computed: true, + AttributeTypes: map[string]attr.Type{ + "s3_uri": types.StringType, + }, }, - "training_metrics": schema.ListAttribute{ - CustomType: fwtypes.NewListNestedObjectTypeOf[customModelTrainingMetricsModel](ctx), + "training_metrics": schema.ObjectAttribute{ + CustomType: fwtypes.NewObjectTypeOf[customModelTrainingMetricsModel](ctx), Computed: true, - ElementType: types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "training_loss": types.Float64Type, - }, + AttributeTypes: map[string]attr.Type{ + "training_loss": types.Float64Type, }, }, "validation_data_config": schema.ObjectAttribute{ CustomType: fwtypes.NewObjectTypeOf[customModelValidationDataConfigModel](ctx), Computed: true, AttributeTypes: map[string]attr.Type{ - "validators": types.ListType{ElemType: types.StringType}, + "validators": types.ListType{ElemType: fwtypes.NewObjectTypeOf[customModelValidatorConfigModel](ctx)}, }, }, "validation_metrics": schema.ListAttribute{ @@ -114,11 +118,7 @@ func (d *customModelDataSource) Read(ctx context.Context, request datasource.Rea conn := d.Meta().BedrockClient(ctx) - input := &bedrock.GetCustomModelInput{ - ModelIdentifier: fwflex.StringFromFramework(ctx, data.ModelID), - } - - output, err := conn.GetCustomModel(ctx, input) + output, err := findCustomModelByID(ctx, conn, data.ModelID.ValueString()) if err != nil { response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s)", data.ModelID.ValueString()), err.Error()) @@ -142,7 +142,7 @@ func (d *customModelDataSource) Read(ctx context.Context, request datasource.Rea return } - data.JobTags = flex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) + data.JobTags = fwflex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) response.Diagnostics.Append(response.State.Set(ctx, &data)...) } @@ -150,7 +150,7 @@ func (d *customModelDataSource) Read(ctx context.Context, request datasource.Rea type customModelDataSourceModel struct { BaseModelARN types.String `tfsdk:"base_model_arn"` CreationTime types.String `tfsdk:"creation_time"` - HyperParameters types.Map `tfsdk:"hyper_parameters"` + HyperParameters fwtypes.MapValueOf[types.String] `tfsdk:"hyper_parameters"` ID types.String `tfsdk:"id"` JobARN types.String `tfsdk:"job_arn"` JobName types.String `tfsdk:"job_name"` @@ -167,6 +167,14 @@ type customModelDataSourceModel struct { ValidationMetrics fwtypes.ListNestedObjectValueOf[customModelValidationMetricsModel] `tfsdk:"validation_metrics"` } +type customModelOutputDataConfigModel struct { + S3URI types.String `tfsdk:"s3_uri"` +} + +type customModelTrainingDataConfigModel struct { + S3URI types.String `tfsdk:"s3_uri"` +} + type customModelTrainingMetricsModel struct { TrainingLoss types.Float64 `tfsdk:"training_loss"` } @@ -178,3 +186,12 @@ type customModelValidationDataConfigModel struct { type customModelValidationMetricsModel struct { ValidationLoss types.Float64 `tfsdk:"validation_loss"` } + +type customModelValidatorConfigModel struct { + S3URI types.String `tfsdk:"s3_uri"` +} + +type customModelVPCConfigModel struct { + SecurityGroupIDs fwtypes.SetValueOf[types.String] `tfsdk:"security_group_ids"` + SubnetIDs fwtypes.SetValueOf[types.String] `tfsdk:"subnet_ids"` +} diff --git a/internal/service/bedrock/service_package_gen.go b/internal/service/bedrock/service_package_gen.go index c48ed068071..68572243440 100644 --- a/internal/service/bedrock/service_package_gen.go +++ b/internal/service/bedrock/service_package_gen.go @@ -41,7 +41,8 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.Serv func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.ServicePackageFrameworkResource { return []*types.ServicePackageFrameworkResource{ { - Factory: newResourceCustomModel, + Factory: newCustomModelResource, + Name: "Custom Model", Tags: &types.ServicePackageResourceTags{ IdentifierAttribute: "model_arn", }, diff --git a/internal/service/bedrock/structures.go b/internal/service/bedrock/structures.go deleted file mode 100644 index bc1dba4c052..00000000000 --- a/internal/service/bedrock/structures.go +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package bedrock - -import ( - "context" - - awstypes "github.com/aws/aws-sdk-go-v2/service/bedrock/types" - "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" - fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" -) - -type vpcConfig struct { - SecurityGroupIds types.Set `tfsdk:"security_group_ids"` - SubnetIds types.Set `tfsdk:"subnet_ids"` -} - -func expandVPCConfig(ctx context.Context, l []vpcConfig) *awstypes.VpcConfig { - if len(l) == 0 { - return nil - } - vpcConfigs := make([]*awstypes.VpcConfig, len(l)) - for i, item := range l { - vpcConfigs[i] = item.expand(ctx) - } - return vpcConfigs[0] // return single object, not list -} - -func (v vpcConfig) expand(ctx context.Context) *awstypes.VpcConfig { - return &awstypes.VpcConfig{ - SecurityGroupIds: flex.ExpandFrameworkStringValueSet(ctx, v.SecurityGroupIds), - SubnetIds: flex.ExpandFrameworkStringValueSet(ctx, v.SubnetIds), - } -} - -type outputDataConfig struct { - S3Uri types.String `tfsdk:"s3_uri"` -} - -func expandOutputDataConfig(ctx context.Context, l []outputDataConfig) *awstypes.OutputDataConfig { - if len(l) == 0 { - return nil - } - outputDataConfigs := make([]*awstypes.OutputDataConfig, len(l)) - for i, item := range l { - outputDataConfigs[i] = item.expand(ctx) - } - return outputDataConfigs[0] // return single object, not list -} - -func (o outputDataConfig) expand(ctx context.Context) *awstypes.OutputDataConfig { - return &awstypes.OutputDataConfig{ - S3Uri: flex.StringFromFramework(ctx, o.S3Uri), - } -} - -type trainingDataConfig struct { - S3Uri types.String `tfsdk:"s3_uri"` -} - -func expandTrainingDataConfig(ctx context.Context, l []trainingDataConfig) *awstypes.TrainingDataConfig { - if len(l) == 0 { - return nil - } - trainingDataConfigs := make([]*awstypes.TrainingDataConfig, len(l)) - for i, item := range l { - trainingDataConfigs[i] = item.expand(ctx) - } - return trainingDataConfigs[0] // return single object, not list -} - -func (t trainingDataConfig) expand(ctx context.Context) *awstypes.TrainingDataConfig { - return &awstypes.TrainingDataConfig{ - S3Uri: flex.StringFromFramework(ctx, t.S3Uri), - } -} - -type trainingMetrics struct { - TrainingLoss types.Float64 `tfsdk:"training_loss"` -} - -func expandTrainingMetrics(ctx context.Context, l []trainingMetrics) *awstypes.TrainingMetrics { - if len(l) == 0 { - return nil - } - trainingMetricsObject := make([]*awstypes.TrainingMetrics, len(l)) - for i, item := range l { - trainingMetricsObject[i] = item.expand(ctx) - } - return trainingMetricsObject[0] // return single object, not list -} - -func (t trainingMetrics) expand(ctx context.Context) *awstypes.TrainingMetrics { - if t.TrainingLoss.IsNull() || t.TrainingLoss.IsUnknown() { - return nil - } - return &awstypes.TrainingMetrics{ - TrainingLoss: flex.Float32FromFrameworkFloat64(ctx, t.TrainingLoss), - } -} - -type validationDataConfig struct { - Validators types.Set `tfsdk:"validator"` -} - -func expandValidationDataConfig(ctx context.Context, l []validationDataConfig, diags diag.Diagnostics) *awstypes.ValidationDataConfig { - if len(l) == 0 { - return nil - } - validationDataConfigs := make([]*awstypes.ValidationDataConfig, len(l)) - for i, item := range l { - validationDataConfigs[i] = item.expand(ctx, diags) - } - return validationDataConfigs[0] // return single object, not list -} - -func (v validationDataConfig) expand(ctx context.Context, diags diag.Diagnostics) *awstypes.ValidationDataConfig { - var validators []validatorConfig - diags.Append(v.Validators.ElementsAs(ctx, &validators, false)...) - if diags.HasError() { - return nil - } - return &awstypes.ValidationDataConfig{ - Validators: expandValidators(ctx, validators), - } -} - -type validatorConfig struct { - S3Uri types.String `tfsdk:"s3_uri"` -} - -func expandValidators(ctx context.Context, l []validatorConfig) []awstypes.Validator { - validators := make([]awstypes.Validator, len(l)) - for i, item := range l { - validators[i] = item.expand(ctx) - } - return validators -} - -func (v validatorConfig) expand(ctx context.Context) awstypes.Validator { - return awstypes.Validator{ - S3Uri: flex.StringFromFramework(ctx, v.S3Uri), - } -} - -type validationMetrics struct { - ValidationLoss types.Float64 `tfsdk:"validation_loss"` -} - -func flattenTrainingMetrics(ctx context.Context, apiObject *awstypes.TrainingMetrics) types.List { - attributeTypes := fwtypes.AttributeTypesMust[trainingMetrics](ctx) - elemType := types.ObjectType{AttrTypes: attributeTypes} - - if apiObject == nil { - return types.ListNull(elemType) - } - - attrs := make([]attr.Value, 0, 1) - attr := map[string]attr.Value{} - trainingLoss := float64(*apiObject.TrainingLoss) - attr["training_loss"] = flex.Float64ToFramework(ctx, &trainingLoss) - val := types.ObjectValueMust(attributeTypes, attr) - attrs = append(attrs, val) - - return types.ListValueMust(elemType, attrs) -} - -func flattenValidationMetrics(ctx context.Context, apiObjects []awstypes.ValidatorMetric) []validationMetrics { - if apiObjects == nil { - return nil - } - - var model []validationMetrics - for _, validationMetric := range apiObjects { - validationLoss := float64(*validationMetric.ValidationLoss) - model = append(model, validationMetrics{ - ValidationLoss: flex.Float64ToFramework(ctx, &validationLoss), - }) - } - - return model -} - -func flattenValidationDataConfig(ctx context.Context, apiObject *awstypes.ValidationDataConfig) types.Object { - attributeTypes := fwtypes.AttributeTypesMust[validationDataConfig](ctx) - attributeTypes["validators"] = types.SetType{ElemType: types.StringType} - - if apiObject == nil { - return types.ObjectNull(attributeTypes) - } - - validators := []*string{} - if apiObject != nil { - for _, validator := range apiObject.Validators { - validators = append(validators, validator.S3Uri) - } - } - attrs := map[string]attr.Value{ - "validators": flex.FlattenFrameworkStringSet(ctx, validators), - } - - return types.ObjectValueMust(attributeTypes, attrs) -} From 4ba5e6ce2770e985f187d491b4ee6393980e98f9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 29 Jan 2024 13:51:43 -0500 Subject: [PATCH 28/62] r/aws_bedrock_custom_model: Ensure everything is ForceNew. --- internal/service/bedrock/custom_model.go | 111 ++++++++++++++--------- 1 file changed, 67 insertions(+), 44 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 31e7c2ec020..5631f1cbf55 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -19,11 +19,13 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/mapplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-provider-aws/internal/enum" @@ -86,6 +88,9 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem CustomType: fwtypes.MapOfStringType, Required: true, ElementType: types.StringType, + PlanModifiers: []planmodifier.Map{ + mapplanmodifier.RequiresReplace(), + }, }, "job_arn": schema.StringAttribute{ Computed: true, @@ -101,7 +106,13 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem "must be up to 63 letters (uppercase and lowercase), numbers, plus sign, dashes, and dots, and must start with an alphanumeric"), }, }, - "job_tags": tftags.TagsAttribute(), + "job_tags": schema.MapAttribute{ + Optional: true, + ElementType: types.StringType, + PlanModifiers: []planmodifier.Map{ + mapplanmodifier.RequiresReplace(), + }, + }, "job_role_arn": schema.StringAttribute{ CustomType: fwtypes.ARNType, Required: true, @@ -109,9 +120,6 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem stringplanmodifier.RequiresReplace(), }, }, - "job_status": schema.StringAttribute{ - Computed: true, - }, "kms_key_arn": schema.StringAttribute{ Optional: true, CustomType: fwtypes.ARNType, @@ -150,6 +158,9 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem Blocks: map[string]schema.Block{ "job_vpc_config": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[customModelVPCConfigModel](ctx), + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, Validators: []validator.List{ listvalidator.SizeAtMost(1), }, @@ -157,19 +168,28 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem Attributes: map[string]schema.Attribute{ "security_group_ids": schema.SetAttribute{ CustomType: fwtypes.SetOfStringType, - ElementType: types.StringType, Required: true, + ElementType: types.StringType, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.RequiresReplace(), + }, }, "subnet_ids": schema.SetAttribute{ CustomType: fwtypes.SetOfStringType, - ElementType: types.StringType, Required: true, + ElementType: types.StringType, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.RequiresReplace(), + }, }, }, }, }, "output_data_config": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[customModelOutputDataConfigModel](ctx), + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, Validators: []validator.List{ listvalidator.IsRequired(), listvalidator.SizeAtLeast(1), @@ -179,6 +199,9 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem Attributes: map[string]schema.Attribute{ "s3_uri": schema.StringAttribute{ Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, Validators: []validator.String{ fwvalidators.S3URI(), }, @@ -192,6 +215,9 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem }), "training_data_config": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[customModelTrainingDataConfigModel](ctx), + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, Validators: []validator.List{ listvalidator.IsRequired(), listvalidator.SizeAtLeast(1), @@ -201,6 +227,9 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem Attributes: map[string]schema.Attribute{ "s3_uri": schema.StringAttribute{ Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, Validators: []validator.String{ fwvalidators.S3URI(), }, @@ -210,6 +239,9 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem }, "validation_data_config": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[customModelValidationDataConfigModel](ctx), + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, Validators: []validator.List{ listvalidator.SizeAtMost(1), }, @@ -217,6 +249,9 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem Blocks: map[string]schema.Block{ "validator": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[customModelValidatorConfigModel](ctx), + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, Validators: []validator.List{ listvalidator.IsRequired(), listvalidator.SizeAtLeast(1), @@ -226,6 +261,9 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem Attributes: map[string]schema.Attribute{ "s3_uri": schema.StringAttribute{ Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, Validators: []validator.String{ fwvalidators.S3URI()}, }, @@ -254,12 +292,15 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat return } + // Some fields for CreateModelCustomizationJobInput don't match those from GetCustomModelOutput, so we need to set them manually. input.BaseModelIdentifier = fwflex.StringFromFramework(ctx, data.BaseModelARN) input.ClientRequestToken = aws.String(id.UniqueId()) + input.CustomModelKmsKeyId = fwflex.StringFromFramework(ctx, data.ModelKmsKeyARN) + input.CustomModelName = fwflex.StringFromFramework(ctx, data.ModelName) input.CustomModelTags = getTagsIn(ctx) input.JobTags = getTagsIn(ctx) - output, err := conn.CreateModelCustomizationJob(ctx, input) + outputC, err := conn.CreateModelCustomizationJob(ctx, input) if err != nil { response.Diagnostics.AddError("creating Bedrock Custom Model customization job", err.Error()) @@ -267,9 +308,8 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat return } - jobARN := aws.ToString(output.JobArn) - - _, err = waitModelCustomizationJobCompleted(ctx, conn, jobARN, r.CreateTimeout(ctx, data.Timeouts)) + jobARN := aws.ToString(outputC.JobArn) + outputG, err := waitModelCustomizationJobCompleted(ctx, conn, jobARN, r.CreateTimeout(ctx, data.Timeouts)) if err != nil { response.Diagnostics.AddError(fmt.Sprintf("waiting for Bedrock Custom Model customization job (%s) complete", jobARN), err.Error()) @@ -278,6 +318,14 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat } // Set values for unknowns. + response.Diagnostics.Append(fwflex.Flatten(ctx, outputG, &data)...) + if response.Diagnostics.HasError() { + return + } + + // Some fields for GetModelCustomizationJobOutput don't match those from GetCustomModelOutput, so we need to set them manually. + data.ModelARN = fwflex.StringToFramework(ctx, outputG.OutputModelArn) + data.setID() response.Diagnostics.Append(response.State.Set(ctx, &data)...) } @@ -297,7 +345,7 @@ func (r *customModelResource) Read(ctx context.Context, request resource.ReadReq conn := r.Meta().BedrockClient(ctx) - output, err := findCustomModelByID(ctx, conn, data.ARN.ValueString()) + output, err := findCustomModelByID(ctx, conn, data.ModelARN.ValueString()) if tfresource.NotFound(err) { response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) @@ -340,7 +388,7 @@ func (r *customModelResource) Delete(ctx context.Context, request resource.Delet conn := r.Meta().BedrockClient(ctx) _, err := conn.DeleteCustomModel(ctx, &bedrock.DeleteCustomModelInput{ - ModelIdentifier: fwflex.StringFromFramework(ctx, data.ARN), + ModelIdentifier: fwflex.StringFromFramework(ctx, data.ModelARN), }) if errs.IsA[*awstypes.ResourceNotFoundException](err) { @@ -443,45 +491,20 @@ func waitModelCustomizationJobCompleted(ctx context.Context, conn *bedrock.Clien return nil, err } -func waitForModelCustomizationJob(ctx context.Context, conn *bedrock.Client, jobArn string, timeout time.Duration) error { - return retry.RetryContext(ctx, timeout, func() *retry.RetryError { - jobEnd, err := conn.GetModelCustomizationJob(ctx, &bedrock.GetModelCustomizationJobInput{ - JobIdentifier: &jobArn, - }) - if err != nil { - return retry.NonRetryableError(fmt.Errorf("getting model customization job: %s", err)) - } - - tflog.Info(ctx, "GetModelCustomizationJobOuput:", map[string]any{ - "Status": jobEnd.Status, - }) - - switch jobEnd.Status { - case "InProgress": - return retry.RetryableError(fmt.Errorf("expected instance to be Completed but was in state %s", jobEnd.Status)) - case "Completed": - return nil - default: - return retry.NonRetryableError(fmt.Errorf(*jobEnd.FailureMessage)) - } - }) -} - type resourceCustomModelData struct { - ARN types.String `tfsdk:"arn"` BaseModelARN fwtypes.ARN `tfsdk:"base_model_arn"` CustomizationType fwtypes.StringEnum[awstypes.CustomizationType] `tfsdk:"customization_type"` HyperParameters fwtypes.MapValueOf[types.String] `tfsdk:"hyper_parameters"` ID types.String `tfsdk:"id"` JobARN types.String `tfsdk:"job_arn"` JobName types.String `tfsdk:"job_name"` - JobRoleARN fwtypes.ARN `tfsdk:"job_role_arn"` - JobStatus types.String `tfsdk:"job_status"` JobTags types.Map `tfsdk:"job_tags"` JobVPCConfig fwtypes.ListNestedObjectValueOf[customModelVPCConfigModel] `tfsdk:"job_vpc_config"` - KmsKeyARN fwtypes.ARN `tfsdk:"kms_key_arn"` - Name types.String `tfsdk:"name"` + ModelARN types.String `tfsdk:"arn"` + ModelKmsKeyARN fwtypes.ARN `tfsdk:"kms_key_arn"` + ModelName types.String `tfsdk:"name"` OutputDataConfig fwtypes.ListNestedObjectValueOf[customModelOutputDataConfigModel] `tfsdk:"output_data_config"` + RoleARN fwtypes.ARN `tfsdk:"job_role_arn"` Tags types.Map `tfsdk:"tags"` TagsAll types.Map `tfsdk:"tags_all"` Timeouts timeouts.Value `tfsdk:"timeouts"` @@ -492,11 +515,11 @@ type resourceCustomModelData struct { } func (data *resourceCustomModelData) InitFromID() error { - data.ARN = data.ID + data.ModelARN = data.ID return nil } func (data *resourceCustomModelData) setID() { - data.ID = data.ARN + data.ID = data.ModelARN } From 7bfdb155cc2de21d73de9fbe4306bf4ff6c8a004 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 30 Jan 2024 07:42:00 -0500 Subject: [PATCH 29/62] r/aws_bedrock_custom_model: Some fixes. --- internal/service/bedrock/custom_model.go | 31 +++++++++++++------ .../service/bedrock/service_package_gen.go | 2 +- .../service/bedrock/test-fixtures/train.jsonl | 1 + .../training_data.jsonl | 0 .../bedrock/test-fixtures/validate.jsonl | 1 + .../validation_data.jsonl | 0 6 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 internal/service/bedrock/test-fixtures/train.jsonl rename internal/service/bedrock/{testdata => test-fixtures}/training_data.jsonl (100%) create mode 100644 internal/service/bedrock/test-fixtures/validate.jsonl rename internal/service/bedrock/{testdata => test-fixtures}/validation_data.jsonl (100%) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 5631f1cbf55..2c38d300b93 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -41,7 +41,7 @@ import ( ) // @FrameworkResource(name="Custom Model") -// @Tags(identifierAttribute="model_arn") +// @Tags(identifierAttribute="arn") func newCustomModelResource(context.Context) (resource.ResourceWithConfigure, error) { r := &customModelResource{} @@ -79,6 +79,7 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem "customization_type": schema.StringAttribute{ CustomType: fwtypes.StringEnumType[awstypes.CustomizationType](), Optional: true, + Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), stringplanmodifier.UseStateForUnknown(), @@ -92,6 +93,7 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem mapplanmodifier.RequiresReplace(), }, }, + names.AttrID: framework.IDAttribute(), "job_arn": schema.StringAttribute{ Computed: true, }, @@ -292,7 +294,7 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat return } - // Some fields for CreateModelCustomizationJobInput don't match those from GetCustomModelOutput, so we need to set them manually. + // Some fields from CreateModelCustomizationJobInput don't match those from GetCustomModelOutput, so we need to set them manually. input.BaseModelIdentifier = fwflex.StringFromFramework(ctx, data.BaseModelARN) input.ClientRequestToken = aws.String(id.UniqueId()) input.CustomModelKmsKeyId = fwflex.StringFromFramework(ctx, data.ModelKmsKeyARN) @@ -300,7 +302,7 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat input.CustomModelTags = getTagsIn(ctx) input.JobTags = getTagsIn(ctx) - outputC, err := conn.CreateModelCustomizationJob(ctx, input) + outputCJ, err := conn.CreateModelCustomizationJob(ctx, input) if err != nil { response.Diagnostics.AddError("creating Bedrock Custom Model customization job", err.Error()) @@ -308,8 +310,8 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat return } - jobARN := aws.ToString(outputC.JobArn) - outputG, err := waitModelCustomizationJobCompleted(ctx, conn, jobARN, r.CreateTimeout(ctx, data.Timeouts)) + jobARN := aws.ToString(outputCJ.JobArn) + outputGJ, err := waitModelCustomizationJobCompleted(ctx, conn, jobARN, r.CreateTimeout(ctx, data.Timeouts)) if err != nil { response.Diagnostics.AddError(fmt.Sprintf("waiting for Bedrock Custom Model customization job (%s) complete", jobARN), err.Error()) @@ -317,15 +319,24 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat return } + data.ModelARN = fwflex.StringToFramework(ctx, outputGJ.OutputModelArn) + data.setID() + // Set values for unknowns. - response.Diagnostics.Append(fwflex.Flatten(ctx, outputG, &data)...) - if response.Diagnostics.HasError() { + // We need to read the model as not all fields are returned by GetModelCustomizationJob. + outputGM, err := findCustomModelByID(ctx, conn, data.ModelARN.ValueString()) + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s)", data.ID.ValueString()), err.Error()) + return } - // Some fields for GetModelCustomizationJobOutput don't match those from GetCustomModelOutput, so we need to set them manually. - data.ModelARN = fwflex.StringToFramework(ctx, outputG.OutputModelArn) - data.setID() + // Set values for unknowns. + response.Diagnostics.Append(fwflex.Flatten(ctx, outputGM, &data)...) + if response.Diagnostics.HasError() { + return + } response.Diagnostics.Append(response.State.Set(ctx, &data)...) } diff --git a/internal/service/bedrock/service_package_gen.go b/internal/service/bedrock/service_package_gen.go index 68572243440..7261d1ebcd5 100644 --- a/internal/service/bedrock/service_package_gen.go +++ b/internal/service/bedrock/service_package_gen.go @@ -44,7 +44,7 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic Factory: newCustomModelResource, Name: "Custom Model", Tags: &types.ServicePackageResourceTags{ - IdentifierAttribute: "model_arn", + IdentifierAttribute: "arn", }, }, { diff --git a/internal/service/bedrock/test-fixtures/train.jsonl b/internal/service/bedrock/test-fixtures/train.jsonl new file mode 100644 index 00000000000..edbb920603f --- /dev/null +++ b/internal/service/bedrock/test-fixtures/train.jsonl @@ -0,0 +1 @@ +{"prompt": "what is AWS", "completion": "it's Amazon Web Services"} \ No newline at end of file diff --git a/internal/service/bedrock/testdata/training_data.jsonl b/internal/service/bedrock/test-fixtures/training_data.jsonl similarity index 100% rename from internal/service/bedrock/testdata/training_data.jsonl rename to internal/service/bedrock/test-fixtures/training_data.jsonl diff --git a/internal/service/bedrock/test-fixtures/validate.jsonl b/internal/service/bedrock/test-fixtures/validate.jsonl new file mode 100644 index 00000000000..edbb920603f --- /dev/null +++ b/internal/service/bedrock/test-fixtures/validate.jsonl @@ -0,0 +1 @@ +{"prompt": "what is AWS", "completion": "it's Amazon Web Services"} \ No newline at end of file diff --git a/internal/service/bedrock/testdata/validation_data.jsonl b/internal/service/bedrock/test-fixtures/validation_data.jsonl similarity index 100% rename from internal/service/bedrock/testdata/validation_data.jsonl rename to internal/service/bedrock/test-fixtures/validation_data.jsonl From 5b67d649fb612a945510a297976d1d60e8f8a18b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 30 Jan 2024 09:21:02 -0500 Subject: [PATCH 30/62] r/aws_bedrock_custom_models: Use 'fwtypes.Timestamp' for 'creation_time'. --- .../service/bedrock/custom_models_data_source.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/service/bedrock/custom_models_data_source.go b/internal/service/bedrock/custom_models_data_source.go index 41d52b43c66..6f8d4405581 100644 --- a/internal/service/bedrock/custom_models_data_source.go +++ b/internal/service/bedrock/custom_models_data_source.go @@ -41,7 +41,7 @@ func (d *customModelsDataSource) Schema(ctx context.Context, request datasource. AttrTypes: map[string]attr.Type{ "base_model_arn": types.StringType, "base_model_name": types.StringType, - "creation_time": types.StringType, + "creation_time": fwtypes.TimestampType, "model_arn": types.StringType, "model_name": types.StringType, }, @@ -90,9 +90,9 @@ type customModelsDataSourceModel struct { } type customModelSummaryModel struct { - BaseModelARN types.String `tfsdk:"base_model_arn"` - BaseModelName types.String `tfsdk:"base_model_name"` - CreationTime types.String `tfsdk:"creation_time"` - ModelARN types.String `tfsdk:"model_arn"` - ModelName types.String `tfsdk:"model_name"` + BaseModelARN types.String `tfsdk:"base_model_arn"` + BaseModelName types.String `tfsdk:"base_model_name"` + CreationTime fwtypes.Timestamp `tfsdk:"creation_time"` + ModelARN types.String `tfsdk:"model_arn"` + ModelName types.String `tfsdk:"model_name"` } From 4c958ffb9fa712c7664b77b543520f258044be77 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 30 Jan 2024 09:22:26 -0500 Subject: [PATCH 31/62] d/aws_bedrock_custom_model: Use list-of-object for 'Computed blocks', not object. --- .../bedrock/custom_model_data_source.go | 80 +++++++++++-------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/internal/service/bedrock/custom_model_data_source.go b/internal/service/bedrock/custom_model_data_source.go index 57ad416c290..4d9afd0eac7 100644 --- a/internal/service/bedrock/custom_model_data_source.go +++ b/internal/service/bedrock/custom_model_data_source.go @@ -41,9 +41,11 @@ func (d *customModelDataSource) Schema(ctx context.Context, request datasource.S Computed: true, }, "creation_time": schema.StringAttribute{ - Computed: true, + CustomType: fwtypes.TimestampType, + Computed: true, }, "hyper_parameters": schema.MapAttribute{ + CustomType: fwtypes.MapOfStringType, Computed: true, ElementType: types.StringType, }, @@ -67,33 +69,41 @@ func (d *customModelDataSource) Schema(ctx context.Context, request datasource.S "model_name": schema.StringAttribute{ Computed: true, }, - "output_data_config": schema.ObjectAttribute{ - CustomType: fwtypes.NewObjectTypeOf[customModelOutputDataConfigModel](ctx), + "output_data_config": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelOutputDataConfigModel](ctx), Computed: true, - AttributeTypes: map[string]attr.Type{ - "s3_uri": types.StringType, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "s3_uri": types.StringType, + }, }, }, names.AttrTags: tftags.TagsAttributeComputedOnly(), - "training_data_config": schema.ObjectAttribute{ - CustomType: fwtypes.NewObjectTypeOf[customModelTrainingDataConfigModel](ctx), + "training_data_config": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelTrainingDataConfigModel](ctx), Computed: true, - AttributeTypes: map[string]attr.Type{ - "s3_uri": types.StringType, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "s3_uri": types.StringType, + }, }, }, - "training_metrics": schema.ObjectAttribute{ - CustomType: fwtypes.NewObjectTypeOf[customModelTrainingMetricsModel](ctx), + "training_metrics": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelTrainingMetricsModel](ctx), Computed: true, - AttributeTypes: map[string]attr.Type{ - "training_loss": types.Float64Type, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "training_loss": types.Float64Type, + }, }, }, - "validation_data_config": schema.ObjectAttribute{ - CustomType: fwtypes.NewObjectTypeOf[customModelValidationDataConfigModel](ctx), + "validation_data_config": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelValidationDataConfigModel](ctx), Computed: true, - AttributeTypes: map[string]attr.Type{ - "validators": types.ListType{ElemType: fwtypes.NewObjectTypeOf[customModelValidatorConfigModel](ctx)}, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "validators": fwtypes.NewListNestedObjectTypeOf[customModelValidatorConfigModel](ctx), + }, }, }, "validation_metrics": schema.ListAttribute{ @@ -148,23 +158,23 @@ func (d *customModelDataSource) Read(ctx context.Context, request datasource.Rea } type customModelDataSourceModel struct { - BaseModelARN types.String `tfsdk:"base_model_arn"` - CreationTime types.String `tfsdk:"creation_time"` - HyperParameters fwtypes.MapValueOf[types.String] `tfsdk:"hyper_parameters"` - ID types.String `tfsdk:"id"` - JobARN types.String `tfsdk:"job_arn"` - JobName types.String `tfsdk:"job_name"` - JobTags types.Map `tfsdk:"job_tags"` - ModelARN types.String `tfsdk:"model_arn"` - ModelID types.String `tfsdk:"model_id"` - ModelKMSKeyARN types.String `tfsdk:"model_kms_key_arn"` - ModelName types.String `tfsdk:"model_name"` - OutputDataConfig types.String `tfsdk:"output_data_config"` - Tags types.Map `tfsdk:"tags"` - TrainingDataConfig types.String `tfsdk:"training_data_config"` - TrainingMetrics fwtypes.ListNestedObjectValueOf[customModelTrainingMetricsModel] `tfsdk:"training_metrics"` - ValidationDataConfig fwtypes.ObjectValueOf[customModelValidationDataConfigModel] `tfsdk:"validation_data_config"` - ValidationMetrics fwtypes.ListNestedObjectValueOf[customModelValidationMetricsModel] `tfsdk:"validation_metrics"` + BaseModelARN types.String `tfsdk:"base_model_arn"` + CreationTime fwtypes.Timestamp `tfsdk:"creation_time"` + HyperParameters fwtypes.MapValueOf[types.String] `tfsdk:"hyper_parameters"` + ID types.String `tfsdk:"id"` + JobARN types.String `tfsdk:"job_arn"` + JobName types.String `tfsdk:"job_name"` + JobTags types.Map `tfsdk:"job_tags"` + ModelARN types.String `tfsdk:"model_arn"` + ModelID types.String `tfsdk:"model_id"` + ModelKMSKeyARN types.String `tfsdk:"model_kms_key_arn"` + ModelName types.String `tfsdk:"model_name"` + OutputDataConfig fwtypes.ListNestedObjectValueOf[customModelOutputDataConfigModel] `tfsdk:"output_data_config"` + Tags types.Map `tfsdk:"tags"` + TrainingDataConfig fwtypes.ListNestedObjectValueOf[customModelTrainingDataConfigModel] `tfsdk:"training_data_config"` + TrainingMetrics fwtypes.ListNestedObjectValueOf[customModelTrainingMetricsModel] `tfsdk:"training_metrics"` + ValidationDataConfig fwtypes.ListNestedObjectValueOf[customModelValidationDataConfigModel] `tfsdk:"validation_data_config"` + ValidationMetrics fwtypes.ListNestedObjectValueOf[customModelValidationMetricsModel] `tfsdk:"validation_metrics"` } type customModelOutputDataConfigModel struct { @@ -180,7 +190,7 @@ type customModelTrainingMetricsModel struct { } type customModelValidationDataConfigModel struct { - Validators fwtypes.ListValueOf[types.String] `tfsdk:"validators"` + Validators fwtypes.ListNestedObjectValueOf[customModelValidatorConfigModel] `tfsdk:"validators"` } type customModelValidationMetricsModel struct { From 1082c3cac06345d54553b0a858785fbc953271be Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 30 Jan 2024 09:27:10 -0500 Subject: [PATCH 32/62] r/aws_bedrock_custom_model: Use list-of-object for 'Computed blocks', not object. --- internal/service/bedrock/custom_model.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 2c38d300b93..24ce9974cdd 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -140,11 +140,13 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem }, names.AttrTags: tftags.TagsAttribute(), names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), - "training_metrics": schema.ObjectAttribute{ - CustomType: fwtypes.NewObjectTypeOf[customModelTrainingMetricsModel](ctx), + "training_metrics": schema.ListAttribute{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelTrainingMetricsModel](ctx), Computed: true, - AttributeTypes: map[string]attr.Type{ - "training_loss": types.Float64Type, + ElementType: types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "training_loss": types.Float64Type, + }, }, }, "validation_metrics": schema.ListAttribute{ @@ -520,7 +522,7 @@ type resourceCustomModelData struct { TagsAll types.Map `tfsdk:"tags_all"` Timeouts timeouts.Value `tfsdk:"timeouts"` TrainingDataConfig fwtypes.ListNestedObjectValueOf[customModelTrainingDataConfigModel] `tfsdk:"training_data_config"` - TrainingMetrics fwtypes.ObjectValueOf[customModelTrainingMetricsModel] `tfsdk:"training_metrics"` + TrainingMetrics fwtypes.ListNestedObjectValueOf[customModelTrainingMetricsModel] `tfsdk:"training_metrics"` ValidationDataConfig fwtypes.ListNestedObjectValueOf[customModelValidationDataConfigModel] `tfsdk:"validation_data_config"` ValidationMetrics fwtypes.ListNestedObjectValueOf[customModelValidationMetricsModel] `tfsdk:"validation_metrics"` } From 89fd2bd61412e1a8a1af49e932dc32550714f520 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 30 Jan 2024 09:39:47 -0500 Subject: [PATCH 33/62] r/aws_bedrock_custom_model: We need to read both the job and the model as not all fields are returned by GetModelCustomizationJob. --- internal/service/bedrock/custom_model.go | 27 +++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 24ce9974cdd..ebd1728db98 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -358,7 +358,23 @@ func (r *customModelResource) Read(ctx context.Context, request resource.ReadReq conn := r.Meta().BedrockClient(ctx) - output, err := findCustomModelByID(ctx, conn, data.ModelARN.ValueString()) + // We need to read both the job and the model as not all fields are returned by GetModelCustomizationJob. + outputGJ, err := findModelCustomizationJobByID(ctx, conn, data.JobARN.ValueString()) + + if tfresource.NotFound(err) { + response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) + response.State.RemoveResource(ctx) + + return + } + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model customization job (%s)", data.JobARN.ValueString()), err.Error()) + + return + } + + outputGM, err := findCustomModelByID(ctx, conn, data.ModelARN.ValueString()) if tfresource.NotFound(err) { response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) @@ -373,12 +389,17 @@ func (r *customModelResource) Read(ctx context.Context, request resource.ReadReq return } - response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + response.Diagnostics.Append(fwflex.Flatten(ctx, outputGJ, &data)...) + if response.Diagnostics.HasError() { + return + } + + response.Diagnostics.Append(fwflex.Flatten(ctx, outputGM, &data)...) if response.Diagnostics.HasError() { return } - jobARN := aws.ToString(output.JobArn) + jobARN := aws.ToString(outputGM.JobArn) jobTags, err := listTags(ctx, conn, jobARN) if err != nil { From a0797caf4056211f572c626baf8a4e5f49b339fc Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 30 Jan 2024 16:57:53 -0500 Subject: [PATCH 34/62] r/aws_bedrock_custom_model: Get Read working. --- internal/service/bedrock/custom_model.go | 41 ++++++++++++++++++------ 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index ebd1728db98..c506e81cd40 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -7,10 +7,12 @@ import ( "context" "errors" "fmt" + "strings" "time" "github.com/YakDriver/regexache" "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" "github.com/aws/aws-sdk-go-v2/service/bedrock" awstypes "github.com/aws/aws-sdk-go-v2/service/bedrock/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" @@ -321,10 +323,12 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat return } + // Set values for unknowns. + data.CustomizationType = fwtypes.StringEnumValue(outputGJ.CustomizationType) + data.JobARN = fwflex.StringToFramework(ctx, outputCJ.JobArn) data.ModelARN = fwflex.StringToFramework(ctx, outputGJ.OutputModelArn) data.setID() - // Set values for unknowns. // We need to read the model as not all fields are returned by GetModelCustomizationJob. outputGM, err := findCustomModelByID(ctx, conn, data.ModelARN.ValueString()) @@ -334,12 +338,15 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat return } - // Set values for unknowns. - response.Diagnostics.Append(fwflex.Flatten(ctx, outputGM, &data)...) + var new resourceCustomModelData + response.Diagnostics.Append(fwflex.Flatten(ctx, outputGM, &new)...) if response.Diagnostics.HasError() { return } + data.TrainingMetrics = new.TrainingMetrics + data.ValidationMetrics = new.ValidationMetrics + response.Diagnostics.Append(response.State.Set(ctx, &data)...) } @@ -358,8 +365,7 @@ func (r *customModelResource) Read(ctx context.Context, request resource.ReadReq conn := r.Meta().BedrockClient(ctx) - // We need to read both the job and the model as not all fields are returned by GetModelCustomizationJob. - outputGJ, err := findModelCustomizationJobByID(ctx, conn, data.JobARN.ValueString()) + outputGM, err := findCustomModelByID(ctx, conn, data.ModelARN.ValueString()) if tfresource.NotFound(err) { response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) @@ -369,12 +375,16 @@ func (r *customModelResource) Read(ctx context.Context, request resource.ReadReq } if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model customization job (%s)", data.JobARN.ValueString()), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s)", data.ID.ValueString()), err.Error()) return } - outputGM, err := findCustomModelByID(ctx, conn, data.ModelARN.ValueString()) + baseModelARN := fwflex.StringFromFramework(ctx, data.BaseModelARN) + + // We need to read both the job and the model as not all fields are returned by GetModelCustomizationJob. + jobARN := aws.ToString(outputGM.JobArn) + outputGJ, err := findModelCustomizationJobByID(ctx, conn, jobARN) if tfresource.NotFound(err) { response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) @@ -384,7 +394,7 @@ func (r *customModelResource) Read(ctx context.Context, request resource.ReadReq } if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s)", data.ID.ValueString()), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model customization job (%s)", jobARN), err.Error()) return } @@ -399,7 +409,20 @@ func (r *customModelResource) Read(ctx context.Context, request resource.ReadReq return } - jobARN := aws.ToString(outputGM.JobArn) + data.JobName = fwflex.StringToFramework(ctx, outputGJ.JobName) // Null in GetCustomModelOutput. + if baseModelARN != nil { + // Value in GetCustomModelOutput can contain the model version and parameter count. + if old, err := arn.Parse(aws.ToString(baseModelARN)); err == nil { + if new, err := arn.Parse(aws.ToString(outputGM.BaseModelArn)); err == nil { + if len(strings.SplitN(old.Resource, ":", 2)) == 1 { + // Old ARN doesn't contain the model version and parameter count. + new.Resource = strings.SplitN(new.Resource, ":", 2)[0] + data.BaseModelARN = fwtypes.ARNValue(new.String()) + } + } + } + } + jobTags, err := listTags(ctx, conn, jobARN) if err != nil { From aa17dce9afc56a081a87267ce2b224874c684137 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 31 Jan 2024 09:15:07 -0500 Subject: [PATCH 35/62] r/aws_bedrock_custom_model: Start to update documentation to reflect new behaviors. --- website/docs/r/bedrock_custom_model.html.markdown | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/website/docs/r/bedrock_custom_model.html.markdown b/website/docs/r/bedrock_custom_model.html.markdown index 627c57b9ba1..ca813d2af97 100644 --- a/website/docs/r/bedrock_custom_model.html.markdown +++ b/website/docs/r/bedrock_custom_model.html.markdown @@ -3,12 +3,23 @@ subcategory: "Amazon Bedrock" layout: "aws" page_title: "AWS: aws_bedrock_custom_model" description: |- - Manages a Bedrock custom model + Manages an Amazon Bedrock custom model. --- # Resource: aws_bedrock_custom_model -Manages a Bedrock custom model. +Manages an Amazon Bedrock custom model. +Model customization is the process of providing training data to a base model in order to improve its performance for specific use-cases. + +This Terraform resource interacts with two Amazon Bedrock entities: +1. A Fine-tuning or Continued Pre-training job which is started when the Terraform resource is created. The customization job can take several hours to run to completion. The duration of the job depends on the size of the training data (number of records, input tokens, and output tokens), and [hyperparameters](https://docs.aws.amazon.com/bedrock/latest/userguide/custom-models-hp.html) (number of epochs, and batch size). +2. The custom model produced on successful completion of the customization job. + +This resource's [behaviors](https://developer.hashicorp.com/terraform/language/resources/behavior) correspond to operations on these Amazon Bedrock entities: +* [_Create_](https://developer.hashicorp.com/terraform/plugin/framework/resources/create) starts the customization job and immediately returns. +* [_Read_](https://developer.hashicorp.com/terraform/plugin/framework/resources/read) returns the status and results of the customization job. If the customization job has completed, the custom model's properties are returned. +* [_Update_](https://developer.hashicorp.com/terraform/plugin/framework/resources/update) updates the customization job's [tags](https://docs.aws.amazon.com/bedrock/latest/userguide/tagging.html), and the tags on any custom model produced by the job. +* [_Delete_](https://developer.hashicorp.com/terraform/plugin/framework/resources/delete) stops the customization job if it is still active. If the customization job has completed, the custom model produced by the job is deleted. ## Example Usage From 43fe7440df0659bc9cafdd5852148896fba21eef Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 31 Jan 2024 09:16:31 -0500 Subject: [PATCH 36/62] Documentation tweaks from Tyler. --- website/docs/r/bedrock_custom_model.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/bedrock_custom_model.html.markdown b/website/docs/r/bedrock_custom_model.html.markdown index ca813d2af97..26ef56e4920 100644 --- a/website/docs/r/bedrock_custom_model.html.markdown +++ b/website/docs/r/bedrock_custom_model.html.markdown @@ -12,7 +12,7 @@ Manages an Amazon Bedrock custom model. Model customization is the process of providing training data to a base model in order to improve its performance for specific use-cases. This Terraform resource interacts with two Amazon Bedrock entities: -1. A Fine-tuning or Continued Pre-training job which is started when the Terraform resource is created. The customization job can take several hours to run to completion. The duration of the job depends on the size of the training data (number of records, input tokens, and output tokens), and [hyperparameters](https://docs.aws.amazon.com/bedrock/latest/userguide/custom-models-hp.html) (number of epochs, and batch size). +1. A Continued Pre-training or Fine-tuning job which is started when the Terraform resource is created. The customization job can take several hours to run to completion. The duration of the job depends on the size of the training data (number of records, input tokens, and output tokens), and [hyperparameters](https://docs.aws.amazon.com/bedrock/latest/userguide/custom-models-hp.html) (number of epochs, and batch size). 2. The custom model produced on successful completion of the customization job. This resource's [behaviors](https://developer.hashicorp.com/terraform/language/resources/behavior) correspond to operations on these Amazon Bedrock entities: From ff6c31f8afc7d82f637a124c2330b8fd44d0485d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 31 Jan 2024 11:24:20 -0500 Subject: [PATCH 37/62] r/aws_bedrock_custom_model: Update documentation to reflect new behaviors. --- .../docs/r/bedrock_custom_model.html.markdown | 206 ++++-------------- 1 file changed, 38 insertions(+), 168 deletions(-) diff --git a/website/docs/r/bedrock_custom_model.html.markdown b/website/docs/r/bedrock_custom_model.html.markdown index 26ef56e4920..bfa547012da 100644 --- a/website/docs/r/bedrock_custom_model.html.markdown +++ b/website/docs/r/bedrock_custom_model.html.markdown @@ -13,205 +13,75 @@ Model customization is the process of providing training data to a base model in This Terraform resource interacts with two Amazon Bedrock entities: 1. A Continued Pre-training or Fine-tuning job which is started when the Terraform resource is created. The customization job can take several hours to run to completion. The duration of the job depends on the size of the training data (number of records, input tokens, and output tokens), and [hyperparameters](https://docs.aws.amazon.com/bedrock/latest/userguide/custom-models-hp.html) (number of epochs, and batch size). -2. The custom model produced on successful completion of the customization job. +2. The custom model output on successful completion of the customization job. This resource's [behaviors](https://developer.hashicorp.com/terraform/language/resources/behavior) correspond to operations on these Amazon Bedrock entities: * [_Create_](https://developer.hashicorp.com/terraform/plugin/framework/resources/create) starts the customization job and immediately returns. -* [_Read_](https://developer.hashicorp.com/terraform/plugin/framework/resources/read) returns the status and results of the customization job. If the customization job has completed, the custom model's properties are returned. -* [_Update_](https://developer.hashicorp.com/terraform/plugin/framework/resources/update) updates the customization job's [tags](https://docs.aws.amazon.com/bedrock/latest/userguide/tagging.html), and the tags on any custom model produced by the job. -* [_Delete_](https://developer.hashicorp.com/terraform/plugin/framework/resources/delete) stops the customization job if it is still active. If the customization job has completed, the custom model produced by the job is deleted. +* [_Read_](https://developer.hashicorp.com/terraform/plugin/framework/resources/read) returns the status and results of the customization job. If the customization job has completed, the output model's properties are returned. +* [_Update_](https://developer.hashicorp.com/terraform/plugin/framework/resources/update) updates the customization job's [tags](https://docs.aws.amazon.com/bedrock/latest/userguide/tagging.html). +* [_Delete_](https://developer.hashicorp.com/terraform/plugin/framework/resources/delete) stops the customization job if it is still active. If the customization job has completed, the custom model output by the job is deleted. ## Example Usage ```terraform -resource "random_id" "id" { - byte_length = 8 -} - -data aws_caller_identity current {} - -resource aws_s3_bucket training_data { - bucket = "bedrock-training-data-${random_id.id.hex}" -} - -resource aws_s3_bucket validation_data { - bucket = "bedrock-validation-data-${random_id.id.hex}" -} - -resource aws_s3_bucket output_data { - bucket = "bedrock-output-data-${random_id.id.hex}" -} - -resource "aws_s3_bucket_object" "training_data" { - bucket = aws_s3_bucket.training_data.id - key = "myfolder/training_data.jsonl" - source = "./testdata/training_data.jsonl" - etag = filemd5("./testdata/training_data.jsonl") -} - -resource "aws_s3_bucket_object" "validation_data" { - bucket = aws_s3_bucket.validation_data.id - key = "myfolder/validation_data.jsonl" - source = "./testdata/validation_data.jsonl" - etag = filemd5("./testdata/validation_data.jsonl") -} - -resource "aws_iam_role" "bedrock_fine_tuning" { - name = "bedrock-fine-tuning-${random_id.id.hex}" - - assume_role_policy = < Date: Wed, 31 Jan 2024 14:56:51 -0500 Subject: [PATCH 38/62] r/aws_bedrock_custom_model: New lifecycle. --- internal/framework/base.go | 23 +- internal/framework/types/string_enum.go | 6 - internal/service/bedrock/custom_model.go | 320 ++++++++++-------- .../service/bedrock/service_package_gen.go | 2 +- .../delegation_signer_record.go | 2 +- .../docs/r/bedrock_custom_model.html.markdown | 2 +- 6 files changed, 204 insertions(+), 151 deletions(-) diff --git a/internal/framework/base.go b/internal/framework/base.go index e8b29c9440c..94dbf5e792f 100644 --- a/internal/framework/base.go +++ b/internal/framework/base.go @@ -10,6 +10,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws/arn" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/types" @@ -107,10 +108,26 @@ func (w *WithImportByID) ImportState(ctx context.Context, request resource.Impor resource.ImportStatePassthroughID(ctx, path.Root(names.AttrID), request, response) } -// WithNoOpUpdate is intended to be embedded in resources which have no need of an Update method. -type WithNoOpUpdate struct{} +// WithNoUpdate is intended to be embedded in resources which cannot be updated. +type WithNoUpdate struct{} -func (w *WithNoOpUpdate) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { +func (w *WithNoUpdate) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { + response.Diagnostics.Append(diag.NewErrorDiagnostic("not supported", "This resource's Update method should not have been called")) +} + +// WithNoOpUpdate is intended to be embedded in resources which have no need of a custom Update method. +// For example, resources where only `tags` can be updated and that is handled via transparent tagging. +type WithNoOpUpdate[T any] struct{} + +func (w *WithNoOpUpdate[T]) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { + var t T + + response.Diagnostics.Append(request.Plan.Get(ctx, &t)...) + if response.Diagnostics.HasError() { + return + } + + response.Diagnostics.Append(response.State.Set(ctx, &t)...) } // DataSourceWithConfigure is a structure to be embedded within a DataSource that implements the DataSourceWithConfigure interface. diff --git a/internal/framework/types/string_enum.go b/internal/framework/types/string_enum.go index 146d0c165e9..41d52518eb6 100644 --- a/internal/framework/types/string_enum.go +++ b/internal/framework/types/string_enum.go @@ -174,9 +174,3 @@ func (v StringEnum[T]) Type(context.Context) attr.Type { func (v StringEnum[T]) ValueEnum() T { return T(v.ValueString()) } - -// StringEnumValue is useful if you have a zero value StringEnum but need a -// way to get a non-zero value such as when flattening. -func (v StringEnum[T]) StringEnumValue(value string) StringEnum[T] { - return StringEnum[T]{StringValue: basetypes.NewStringValue(value)} -} diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index c506e81cd40..e8a9ab1b084 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -43,18 +43,17 @@ import ( ) // @FrameworkResource(name="Custom Model") -// @Tags(identifierAttribute="arn") +// @Tags(identifierAttribute="job_arn") func newCustomModelResource(context.Context) (resource.ResourceWithConfigure, error) { r := &customModelResource{} - r.SetDefaultCreateTimeout(120 * time.Minute) + r.SetDefaultDeleteTimeout(120 * time.Minute) return r, nil } type customModelResource struct { framework.ResourceWithConfigure - framework.WithNoOpUpdate framework.WithImportByID framework.WithTimeouts } @@ -70,14 +69,32 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem // - GetCustomModel response.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - names.AttrARN: framework.ARNAttributeComputedOnly(), - "base_model_arn": schema.StringAttribute{ + "base_model_identifier": schema.StringAttribute{ CustomType: fwtypes.ARNType, Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, + "custom_model_arn": schema.StringAttribute{ + Computed: true, + }, + "custom_model_kms_key_id": schema.StringAttribute{ + Optional: true, + CustomType: fwtypes.ARNType, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "custom_model_name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 63), + }, + }, "customization_type": schema.StringAttribute{ CustomType: fwtypes.StringEnumType[awstypes.CustomizationType](), Optional: true, @@ -87,7 +104,7 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem stringplanmodifier.UseStateForUnknown(), }, }, - "hyper_parameters": schema.MapAttribute{ + "hyperparameters": schema.MapAttribute{ CustomType: fwtypes.MapOfStringType, Required: true, ElementType: types.StringType, @@ -96,9 +113,7 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem }, }, names.AttrID: framework.IDAttribute(), - "job_arn": schema.StringAttribute{ - Computed: true, - }, + "job_arn": framework.ARNAttributeComputedOnly(), "job_name": schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ @@ -110,36 +125,17 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem "must be up to 63 letters (uppercase and lowercase), numbers, plus sign, dashes, and dots, and must start with an alphanumeric"), }, }, - "job_tags": schema.MapAttribute{ - Optional: true, - ElementType: types.StringType, - PlanModifiers: []planmodifier.Map{ - mapplanmodifier.RequiresReplace(), - }, + "job_status": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.ModelCustomizationJobStatus](), + Computed: true, }, - "job_role_arn": schema.StringAttribute{ + "role_arn": schema.StringAttribute{ CustomType: fwtypes.ARNType, Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, - "kms_key_arn": schema.StringAttribute{ - Optional: true, - CustomType: fwtypes.ARNType, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - }, - "name": schema.StringAttribute{ - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - Validators: []validator.String{ - stringvalidator.LengthBetween(1, 63), - }, - }, names.AttrTags: tftags.TagsAttribute(), names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), "training_metrics": schema.ListAttribute{ @@ -162,35 +158,6 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem }, }, Blocks: map[string]schema.Block{ - "job_vpc_config": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[customModelVPCConfigModel](ctx), - PlanModifiers: []planmodifier.List{ - listplanmodifier.RequiresReplace(), - }, - Validators: []validator.List{ - listvalidator.SizeAtMost(1), - }, - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "security_group_ids": schema.SetAttribute{ - CustomType: fwtypes.SetOfStringType, - Required: true, - ElementType: types.StringType, - PlanModifiers: []planmodifier.Set{ - setplanmodifier.RequiresReplace(), - }, - }, - "subnet_ids": schema.SetAttribute{ - CustomType: fwtypes.SetOfStringType, - Required: true, - ElementType: types.StringType, - PlanModifiers: []planmodifier.Set{ - setplanmodifier.RequiresReplace(), - }, - }, - }, - }, - }, "output_data_config": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[customModelOutputDataConfigModel](ctx), PlanModifiers: []planmodifier.List{ @@ -279,6 +246,35 @@ func (r *customModelResource) Schema(ctx context.Context, request resource.Schem }, }, }, + "vpc_config": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[customModelVPCConfigModel](ctx), + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "security_group_ids": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, + Required: true, + ElementType: types.StringType, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.RequiresReplace(), + }, + }, + "subnet_ids": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, + Required: true, + ElementType: types.StringType, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.RequiresReplace(), + }, + }, + }, + }, + }, }, } } @@ -298,11 +294,8 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat return } - // Some fields from CreateModelCustomizationJobInput don't match those from GetCustomModelOutput, so we need to set them manually. - input.BaseModelIdentifier = fwflex.StringFromFramework(ctx, data.BaseModelARN) + // Additional fields. input.ClientRequestToken = aws.String(id.UniqueId()) - input.CustomModelKmsKeyId = fwflex.StringFromFramework(ctx, data.ModelKmsKeyARN) - input.CustomModelName = fwflex.StringFromFramework(ctx, data.ModelName) input.CustomModelTags = getTagsIn(ctx) input.JobTags = getTagsIn(ctx) @@ -315,38 +308,23 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat } jobARN := aws.ToString(outputCJ.JobArn) - outputGJ, err := waitModelCustomizationJobCompleted(ctx, conn, jobARN, r.CreateTimeout(ctx, data.Timeouts)) + job, err := findModelCustomizationJobByID(ctx, conn, jobARN) if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("waiting for Bedrock Custom Model customization job (%s) complete", jobARN), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model customization job (%s)", jobARN), err.Error()) return } // Set values for unknowns. - data.CustomizationType = fwtypes.StringEnumValue(outputGJ.CustomizationType) - data.JobARN = fwflex.StringToFramework(ctx, outputCJ.JobArn) - data.ModelARN = fwflex.StringToFramework(ctx, outputGJ.OutputModelArn) + data.CustomizationType = fwtypes.StringEnumValue(job.CustomizationType) + data.CustomModelARN = fwflex.StringToFramework(ctx, job.OutputModelArn) + data.JobARN = fwflex.StringToFramework(ctx, job.JobArn) + data.JobStatus = fwtypes.StringEnumValue(job.Status) + data.TrainingMetrics = fwtypes.NewListNestedObjectValueOfNull[customModelTrainingMetricsModel](ctx) + data.ValidationMetrics = fwtypes.NewListNestedObjectValueOfNull[customModelValidationMetricsModel](ctx) data.setID() - // We need to read the model as not all fields are returned by GetModelCustomizationJob. - outputGM, err := findCustomModelByID(ctx, conn, data.ModelARN.ValueString()) - - if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s)", data.ID.ValueString()), err.Error()) - - return - } - - var new resourceCustomModelData - response.Diagnostics.Append(fwflex.Flatten(ctx, outputGM, &new)...) - if response.Diagnostics.HasError() { - return - } - - data.TrainingMetrics = new.TrainingMetrics - data.ValidationMetrics = new.ValidationMetrics - response.Diagnostics.Append(response.State.Set(ctx, &data)...) } @@ -365,25 +343,7 @@ func (r *customModelResource) Read(ctx context.Context, request resource.ReadReq conn := r.Meta().BedrockClient(ctx) - outputGM, err := findCustomModelByID(ctx, conn, data.ModelARN.ValueString()) - - if tfresource.NotFound(err) { - response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) - response.State.RemoveResource(ctx) - - return - } - - if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s)", data.ID.ValueString()), err.Error()) - - return - } - - baseModelARN := fwflex.StringFromFramework(ctx, data.BaseModelARN) - - // We need to read both the job and the model as not all fields are returned by GetModelCustomizationJob. - jobARN := aws.ToString(outputGM.JobArn) + jobARN := data.JobARN.ValueString() outputGJ, err := findModelCustomizationJobByID(ctx, conn, jobARN) if tfresource.NotFound(err) { @@ -404,37 +364,77 @@ func (r *customModelResource) Read(ctx context.Context, request resource.ReadReq return } - response.Diagnostics.Append(fwflex.Flatten(ctx, outputGM, &data)...) - if response.Diagnostics.HasError() { - return - } - - data.JobName = fwflex.StringToFramework(ctx, outputGJ.JobName) // Null in GetCustomModelOutput. + // Some fields in GetModelCustomizationJobOutput have different names than in CreateModelCustomizationJobInput. + data.CustomModelKmsKeyID = fwflex.StringToFrameworkARN(ctx, outputGJ.OutputModelKmsKeyArn) + data.CustomModelName = fwflex.StringToFramework(ctx, outputGJ.OutputModelName) + data.JobStatus = fwtypes.StringEnumValue(outputGJ.Status) + // The base model ARN in GetCustomModelOutput can contain the model version and parameter count. + baseModelARN := fwflex.StringFromFramework(ctx, data.BaseModelIdentifier) + data.BaseModelIdentifier = fwflex.StringToFrameworkARN(ctx, outputGJ.BaseModelArn) if baseModelARN != nil { - // Value in GetCustomModelOutput can contain the model version and parameter count. if old, err := arn.Parse(aws.ToString(baseModelARN)); err == nil { - if new, err := arn.Parse(aws.ToString(outputGM.BaseModelArn)); err == nil { + if new, err := arn.Parse(aws.ToString(outputGJ.BaseModelArn)); err == nil { if len(strings.SplitN(old.Resource, ":", 2)) == 1 { // Old ARN doesn't contain the model version and parameter count. new.Resource = strings.SplitN(new.Resource, ":", 2)[0] - data.BaseModelARN = fwtypes.ARNValue(new.String()) + data.BaseModelIdentifier = fwtypes.ARNValue(new.String()) } } } } - jobTags, err := listTags(ctx, conn, jobARN) + if outputGJ.OutputModelArn != nil { + customModelARN := aws.ToString(outputGJ.OutputModelArn) + outputGM, err := findCustomModelByID(ctx, conn, customModelARN) - if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model Job (%s) tags", jobARN), err.Error()) + if tfresource.NotFound(err) { + response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) + response.State.RemoveResource(ctx) + + return + } + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s)", customModelARN), err.Error()) + + return + } + + var customModelData resourceCustomModelData + response.Diagnostics.Append(fwflex.Flatten(ctx, outputGM, &customModelData)...) + if response.Diagnostics.HasError() { + return + } + data.CustomModelARN = fwflex.StringToFramework(ctx, outputGM.ModelArn) + data.TrainingMetrics = customModelData.TrainingMetrics + data.ValidationMetrics = customModelData.ValidationMetrics + } + + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +func (r *customModelResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { + var old, new resourceCustomModelData + response.Diagnostics.Append(request.State.Get(ctx, &old)...) + if response.Diagnostics.HasError() { + return + } + response.Diagnostics.Append(request.Plan.Get(ctx, &new)...) + if response.Diagnostics.HasError() { return } - data.JobTags = fwflex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) + // Update is only called when `tags` are updated. + // Set unknowns to the old (in state) values. + new.CustomModelARN = old.CustomModelARN + new.JobStatus = old.JobStatus + new.TrainingMetrics = old.TrainingMetrics + new.ValidationMetrics = old.ValidationMetrics - response.Diagnostics.Append(response.State.Set(ctx, &data)...) + response.Diagnostics.Append(response.State.Set(ctx, &new)...) } + func (r *customModelResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { var data resourceCustomModelData response.Diagnostics.Append(request.State.Get(ctx, &data)...) @@ -444,18 +444,41 @@ func (r *customModelResource) Delete(ctx context.Context, request resource.Delet conn := r.Meta().BedrockClient(ctx) - _, err := conn.DeleteCustomModel(ctx, &bedrock.DeleteCustomModelInput{ - ModelIdentifier: fwflex.StringFromFramework(ctx, data.ModelARN), - }) + if data.JobStatus.ValueEnum() == awstypes.ModelCustomizationJobStatusInProgress { + jobARN := data.JobARN.ValueString() + input := &bedrock.StopModelCustomizationJobInput{ + JobIdentifier: aws.String(jobARN), + } - if errs.IsA[*awstypes.ResourceNotFoundException](err) { - return + _, err := conn.StopModelCustomizationJob(ctx, input) + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("stopping Bedrock Custom Model customization job (%s)", jobARN), err.Error()) + + return + } + + if _, err := waitModelCustomizationJobStopped(ctx, conn, jobARN, r.DeleteTimeout(ctx, data.Timeouts)); err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for Bedrock Custom Model customization job (%s) stop", jobARN), err.Error()) + + return + } } - if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("deleting Bedrock Custom Model (%s)", data.ID.ValueString()), err.Error()) + if !data.CustomModelARN.IsNull() { + _, err := conn.DeleteCustomModel(ctx, &bedrock.DeleteCustomModelInput{ + ModelIdentifier: fwflex.StringFromFramework(ctx, data.CustomModelARN), + }) - return + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("deleting Bedrock Custom Model (%s)", data.ID.ValueString()), err.Error()) + + return + } } } @@ -548,20 +571,38 @@ func waitModelCustomizationJobCompleted(ctx context.Context, conn *bedrock.Clien return nil, err } +func waitModelCustomizationJobStopped(ctx context.Context, conn *bedrock.Client, id string, timeout time.Duration) (*bedrock.GetModelCustomizationJobOutput, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(awstypes.ModelCustomizationJobStatusStopping), + Target: enum.Slice(awstypes.ModelCustomizationJobStatusStopped), + Refresh: statusModelCustomizationJob(ctx, conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*bedrock.GetModelCustomizationJobOutput); ok { + tfresource.SetLastError(err, errors.New(aws.ToString(output.FailureMessage))) + + return output, err + } + + return nil, err +} + type resourceCustomModelData struct { - BaseModelARN fwtypes.ARN `tfsdk:"base_model_arn"` + BaseModelIdentifier fwtypes.ARN `tfsdk:"base_model_identifier"` + CustomModelARN types.String `tfsdk:"custom_model_arn"` + CustomModelKmsKeyID fwtypes.ARN `tfsdk:"custom_model_kms_key_id"` + CustomModelName types.String `tfsdk:"custom_model_name"` CustomizationType fwtypes.StringEnum[awstypes.CustomizationType] `tfsdk:"customization_type"` - HyperParameters fwtypes.MapValueOf[types.String] `tfsdk:"hyper_parameters"` + HyperParameters fwtypes.MapValueOf[types.String] `tfsdk:"hyperparameters"` ID types.String `tfsdk:"id"` JobARN types.String `tfsdk:"job_arn"` JobName types.String `tfsdk:"job_name"` - JobTags types.Map `tfsdk:"job_tags"` - JobVPCConfig fwtypes.ListNestedObjectValueOf[customModelVPCConfigModel] `tfsdk:"job_vpc_config"` - ModelARN types.String `tfsdk:"arn"` - ModelKmsKeyARN fwtypes.ARN `tfsdk:"kms_key_arn"` - ModelName types.String `tfsdk:"name"` + JobStatus fwtypes.StringEnum[awstypes.ModelCustomizationJobStatus] `tfsdk:"job_status"` OutputDataConfig fwtypes.ListNestedObjectValueOf[customModelOutputDataConfigModel] `tfsdk:"output_data_config"` - RoleARN fwtypes.ARN `tfsdk:"job_role_arn"` + RoleARN fwtypes.ARN `tfsdk:"role_arn"` Tags types.Map `tfsdk:"tags"` TagsAll types.Map `tfsdk:"tags_all"` Timeouts timeouts.Value `tfsdk:"timeouts"` @@ -569,14 +610,15 @@ type resourceCustomModelData struct { TrainingMetrics fwtypes.ListNestedObjectValueOf[customModelTrainingMetricsModel] `tfsdk:"training_metrics"` ValidationDataConfig fwtypes.ListNestedObjectValueOf[customModelValidationDataConfigModel] `tfsdk:"validation_data_config"` ValidationMetrics fwtypes.ListNestedObjectValueOf[customModelValidationMetricsModel] `tfsdk:"validation_metrics"` + VPCConfig fwtypes.ListNestedObjectValueOf[customModelVPCConfigModel] `tfsdk:"vpc_config"` } func (data *resourceCustomModelData) InitFromID() error { - data.ModelARN = data.ID + data.JobARN = data.ID return nil } func (data *resourceCustomModelData) setID() { - data.ID = data.ModelARN + data.ID = data.JobARN } diff --git a/internal/service/bedrock/service_package_gen.go b/internal/service/bedrock/service_package_gen.go index 7261d1ebcd5..c0b085318c3 100644 --- a/internal/service/bedrock/service_package_gen.go +++ b/internal/service/bedrock/service_package_gen.go @@ -44,7 +44,7 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic Factory: newCustomModelResource, Name: "Custom Model", Tags: &types.ServicePackageResourceTags{ - IdentifierAttribute: "arn", + IdentifierAttribute: "job_arn", }, }, { diff --git a/internal/service/route53domains/delegation_signer_record.go b/internal/service/route53domains/delegation_signer_record.go index b4758d99ed7..5196d05b617 100644 --- a/internal/service/route53domains/delegation_signer_record.go +++ b/internal/service/route53domains/delegation_signer_record.go @@ -42,7 +42,7 @@ func newDelegationSignerRecordResource(context.Context) (resource.ResourceWithCo type delegationSignerRecordResource struct { framework.ResourceWithConfigure - framework.WithNoOpUpdate + framework.WithNoUpdate framework.WithTimeouts framework.WithImportByID } diff --git a/website/docs/r/bedrock_custom_model.html.markdown b/website/docs/r/bedrock_custom_model.html.markdown index bfa547012da..091612e7691 100644 --- a/website/docs/r/bedrock_custom_model.html.markdown +++ b/website/docs/r/bedrock_custom_model.html.markdown @@ -32,7 +32,7 @@ TODO This resource supports the following arguments: * `base_model_identifier` - (Required) The Amazon Resource Name (ARN) of the base model. -* `custom_model_kms_key_id` - (Optional) The custom model is encrypted at rest using this key. +* `custom_model_kms_key_id` - (Optional) The custom model is encrypted at rest using this key. Specify the key ARN. * `custom_model_name` - (Required) Name for the custom model. * `customization_type` -(Optional) The customization type. Valid values: `FINE_TUNING`, `CONTINUED_PRE_TRAINING`. * `hyperparameters` - (Required) [Parameters](https://docs.aws.amazon.com/bedrock/latest/userguide/custom-models-hp.html) related to tuning the model. From 27ab71555271da206afe6fcc5a493d08bf03f7dd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 31 Jan 2024 15:42:53 -0500 Subject: [PATCH 39/62] r/aws_bedrock_custom_model: Better handling of Stopped jobs. --- internal/service/bedrock/custom_model.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index e8a9ab1b084..10b3c5206fc 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -452,6 +452,10 @@ func (r *customModelResource) Delete(ctx context.Context, request resource.Delet _, err := conn.StopModelCustomizationJob(ctx, input) + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + if err != nil { response.Diagnostics.AddError(fmt.Sprintf("stopping Bedrock Custom Model customization job (%s)", jobARN), err.Error()) @@ -533,6 +537,13 @@ func findModelCustomizationJobByID(ctx context.Context, conn *bedrock.Client, id return nil, tfresource.NewEmptyResultError(input) } + if status := output.Status; status == awstypes.ModelCustomizationJobStatusStopped { + return nil, &retry.NotFoundError{ + Message: string(status), + LastRequest: input, + } + } + return output, nil } From d6c6a8ff934e299553901545c02d58266a559ffb Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 31 Jan 2024 16:23:58 -0500 Subject: [PATCH 40/62] r/aws_bedrock_custom_model: Tidy up acceptance tests. --- internal/service/bedrock/custom_model.go | 29 ++- internal/service/bedrock/custom_model_test.go | 245 ++++++++++-------- internal/service/bedrock/exports_test.go | 3 + .../bedrock/test-fixtures/training_data.jsonl | 100 ------- .../test-fixtures/validation_data.jsonl | 25 -- .../docs/r/bedrock_custom_model.html.markdown | 26 +- 6 files changed, 192 insertions(+), 236 deletions(-) delete mode 100644 internal/service/bedrock/test-fixtures/training_data.jsonl delete mode 100644 internal/service/bedrock/test-fixtures/validation_data.jsonl diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 10b3c5206fc..b454148e83f 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -520,6 +520,23 @@ func findModelCustomizationJobByID(ctx context.Context, conn *bedrock.Client, id JobIdentifier: aws.String(id), } + output, err := findModelCustomizationJob(ctx, conn, input) + + if err != nil { + return nil, err + } + + if status := output.Status; status == awstypes.ModelCustomizationJobStatusStopped { + return nil, &retry.NotFoundError{ + Message: string(status), + LastRequest: input, + } + } + + return output, nil +} + +func findModelCustomizationJob(ctx context.Context, conn *bedrock.Client, input *bedrock.GetModelCustomizationJobInput) (*bedrock.GetModelCustomizationJobOutput, error) { output, err := conn.GetModelCustomizationJob(ctx, input) if errs.IsA[*awstypes.ResourceNotFoundException](err) { @@ -537,19 +554,15 @@ func findModelCustomizationJobByID(ctx context.Context, conn *bedrock.Client, id return nil, tfresource.NewEmptyResultError(input) } - if status := output.Status; status == awstypes.ModelCustomizationJobStatusStopped { - return nil, &retry.NotFoundError{ - Message: string(status), - LastRequest: input, - } - } - return output, nil } func statusModelCustomizationJob(ctx context.Context, conn *bedrock.Client, id string) retry.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := findModelCustomizationJobByID(ctx, conn, id) + input := &bedrock.GetModelCustomizationJobInput{ + JobIdentifier: aws.String(id), + } + output, err := findModelCustomizationJob(ctx, conn, input) if tfresource.NotFound(err) { return nil, "", nil diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index 654275939a8..e1689af2125 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -4,103 +4,152 @@ package bedrock_test import ( + "context" "fmt" "testing" + "github.com/aws/aws-sdk-go-v2/service/bedrock" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfbedrock "github.com/hashicorp/terraform-provider-aws/internal/service/bedrock" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" ) func TestAccBedrockCustomModel_basic(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - customModelResourceName := "aws_bedrock_custom_model.test" + resourceName := "aws_bedrock_custom_model.test" + var v bedrock.GetModelCustomizationJobOutput resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckCustomModelDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccCustomModelConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr(customModelResourceName, "custom_model_name", rName), - resource.TestCheckResourceAttr(customModelResourceName, "job_name", rName), - resource.TestCheckResourceAttr(customModelResourceName, "base_model_id", "amazon.titan-text-express-v1"), - resource.TestCheckResourceAttr(customModelResourceName, "tags.%", "0"), + testAccCheckCustomModelExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "base_model_identifier"), + resource.TestCheckNoResourceAttr(resourceName, "custom_model_arn"), + resource.TestCheckNoResourceAttr(resourceName, "custom_model_kms_key_id"), + resource.TestCheckResourceAttr(resourceName, "custom_model_name", rName), + resource.TestCheckResourceAttr(resourceName, "customization_type", "FINE_TUNING"), + resource.TestCheckResourceAttr(resourceName, "hyperparameters.%", "4"), + resource.TestCheckResourceAttr(resourceName, "hyperparameters.batchSize", "1"), + resource.TestCheckResourceAttr(resourceName, "hyperparameters.epochCount", "1"), + resource.TestCheckResourceAttr(resourceName, "hyperparameters.learningRate", "0.005"), + resource.TestCheckResourceAttr(resourceName, "hyperparameters.learningRateWarmupSteps", "0"), + resource.TestCheckResourceAttrSet(resourceName, "job_arn"), + resource.TestCheckResourceAttr(resourceName, "job_name", rName), + resource.TestCheckResourceAttr(resourceName, "job_status", "InProgress"), + resource.TestCheckResourceAttr(resourceName, "output_data_config.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "output_data_config.0.s3_uri"), + resource.TestCheckResourceAttrSet(resourceName, "role_arn"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "training_data_config.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "training_data_config.0.s3_uri"), + resource.TestCheckNoResourceAttr(resourceName, "training_metrics"), + resource.TestCheckResourceAttr(resourceName, "validation_data_config.#", "0"), + resource.TestCheckNoResourceAttr(resourceName, "validation_metrics"), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "0"), ), }, { - ResourceName: customModelResourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"base_model_identifier"}, }, }, }) } -// func TestAccBedrockCustomModel_basic(t *testing.T) { -// ctx := acctest.Context(t) -// rName := "tf-acc-test-1531621220222582981" // sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) -// customModelResourceName := "aws_bedrock_custom_model.test" - -// resource.ParallelTest(t, resource.TestCase{ -// PreCheck: func() { acctest.PreCheck(ctx, t) }, -// ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, -// Steps: []resource.TestStep{ -// { -// Config: testAccCustomModelConfig_basic2(rName), -// Check: resource.ComposeAggregateTestCheckFunc( -// resource.TestCheckResourceAttr(customModelResourceName, "custom_model_name", rName), -// resource.TestCheckResourceAttr(customModelResourceName, "job_name", rName), -// resource.TestCheckResourceAttr(customModelResourceName, "base_model_id", "amazon.titan-text-express-v1"), -// resource.TestCheckResourceAttr(customModelResourceName, "tags.%", "0"), -// ), -// }, -// { -// ResourceName: customModelResourceName, -// ImportState: true, -// ImportStateVerify: true, -// }, -// }, -// }) -// } +func testAccCheckCustomModelDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).BedrockClient(ctx) -func testAccCustomModelConfig_basic(rName string) string { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_bedrock_custom_model" { + continue + } + + _, err := tfbedrock.FindModelCustomizationJobByID(ctx, conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("Bedrock Custom Model %s still exists", rs.Primary.ID) + } + + return nil + } +} + +func testAccCheckCustomModelExists(ctx context.Context, n string, v *bedrock.GetModelCustomizationJobOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).BedrockClient(ctx) + + output, err := tfbedrock.FindModelCustomizationJobByID(ctx, conn, rs.Primary.ID) + + if err != nil { + return err + } + + *v = *output + + return nil + } +} + +func testAccCustomModelConfig_base(rName string) string { return fmt.Sprintf(` data "aws_caller_identity" "current" {} data "aws_region" "current" {} data "aws_partition" "current" {} -resource aws_s3_bucket training_data { - bucket = "bedrock-training-data-%[1]s" +resource "aws_s3_bucket" "training" { + bucket = "%[1]s-training" } -resource aws_s3_bucket validation_data { - bucket = "bedrock-validation-data-%[1]s" +resource "aws_s3_bucket" "validation" { + bucket = "%[1]s-validation" } -resource aws_s3_bucket output_data { - bucket = "bedrock-output-data-%[1]s" +resource "aws_s3_bucket" "output" { + bucket = "%[1]s-output" force_destroy = true } -resource "aws_s3_bucket_object" "training_data" { - bucket = aws_s3_bucket.training_data.id - key = "myfolder/training_data.jsonl" - source = "./testdata/training_data.jsonl" - etag = filemd5("./testdata/training_data.jsonl") +resource "aws_s3_object" "training" { + bucket = aws_s3_bucket.training.id + key = "data/train.jsonl" + source = "test-fixtures/train.jsonl" } -resource "aws_s3_bucket_object" "validation_data" { - bucket = aws_s3_bucket.validation_data.id - key = "myfolder/validation_data.jsonl" - source = "./testdata/validation_data.jsonl" - etag = filemd5("./testdata/validation_data.jsonl") +resource "aws_s3_object" "validation" { + bucket = aws_s3_bucket.validation.id + key = "data/validate.jsonl" + source = "test-fixtures/validate.jsonl" } -resource "aws_iam_role" "bedrock_fine_tuning" { - name = "bedrock-fine-tuning-%[1]s" +resource "aws_iam_role" "test" { + name = %[1]q assume_role_policy = <\nSubject: Did The Blues Pull It Out?\nLines: 10\n\nWhen I left, it was 4-3, Blues with 2:00 to go! As I predicted in\n\"@#$%! I was right in the first place!!!\" Blues in 6! YES!!!\n\nOf course it's only one game -- that could be the 'Hawks stab in the face to\nwake them up -- that's what playoffs are about, on any given day... :-)\n-------------------------------------------------------------------------\n** Robbie Po ** PGH PENGUINS!!! \"We do what comes naturally!\nPatrick Division Semi's '91 STANLEY CUP You see now, wait for the\nPENGUINS 6, Devils 3 '92 CHAMPIONS possibility, don't you see a\nPenguins lead, 1-0 12 STRAIGHT WINS! strong resemblance...\"-DG '89\n\n###\n\n","output":" hockey"} -{"input":"From: kkeller@mail.sas.upenn.edu (Keith Keller)\nSubject: Re: Sad day for hockey\nArticle-I.D.: netnews.118520\nOrganization: University of Pennsylvania, School of Arts and Sciences\nLines: 39\nNntp-Posting-Host: mail.sas.upenn.edu\n\nIn article <1pq50fINN15b@abyss.West.Sun.COM> dvb@ick (David Van Beveren) writes:\n>NO NO NO! since all the penalties fall into three classes, there should\n>only be three penalties:\n>\n>1. Foul (Any illegal contact with the other player or his stick with your\n> body or stick). If you get 5 you are out for the game.\n>\n>2. Unsportsmanlike contact. (An intentional foul). This inlcludes all the\n> current flavours of roughing, fighting and boarding. If you get two you\n> are thrown out of the game, and fined.\n>\n>3. Technical foul. Bad mouthing the ref, by player or coach. Penalty shot\n> is awarded. Two and you are thrown out of the game.\n>\n>Besides the penalty shot for one technical, if the team gets 5 penalties\n>in a period, the opposing team gets a penalty shot for every additional one,\n>until the end of the period. The victim gets two shots if he\/she was in\n>the act of shooting when the foul ocured.\n\nThese new rule changes are great! However, I think that your rules are\nMUCH too complicated. How will the normal average fan be able to count\nhow many fouls a player has? And then we would even have to remember the\nnames of the players, in order to determine who drew the foul! And, of\ncourse, there will have to be new \"sub-positions\", like the power center\nwho just sits in the slot until the (blue, of course) puck comes near him,\nand the \"shooting defenseman\" and the \"point defenseman\". Finally, we'll\nbe able to keep stats on the best and the worst penalty-shot takers. \nSince almost everyone on the ice will be getting fouled, we'll be able to\nsee Ulf Samuellson (sp?) and Tie Domi miss penalty shots like crazy. \n\n;-) ;-) ;-)\n\n--\n Keith Keller\t\t\t\tLET'S GO RANGERS!!!!!\n\t\t\t\t\t\tLET'S GO QUAKERS!!!!!\n\tkkeller@mail.sas.upenn.edu\t\tIVY LEAGUE CHAMPS!!!!\n\n\"Next time you go over my head, I'll have yours on a platter.\"\n\t\t\t\t\t\t-- Cmdr. Benjamin Sisko, 1993\n\n###\n\n","output":" hockey"} -{"input":"From: v103r4g8@ubvmsb.cc.buffalo.edu (We will NOT cave in....GODS OF WAR, Def Leppard)\nSubject: HELP HELP HELP\nOrganization: University at Buffalo\nLines: 11\nNews-Software: VAX\/VMS VNEWS 1.41\nNntp-Posting-Host: ubvmsb.cc.buffalo.edu\n\n\nDoes anyone have the NHL STANDINGS for March 28th? I need them IMMEDIATELY\nfor a project. Please post or email. THANKS.\n\n\n\n\n*************************************************************************\n Andy Hillery --- School Of Architecture\t \t\n State University of New York at Buffalo \n*************************************************************************\n\n###\n\n","output":" hockey"} -{"input":"From: etxonss@ufsa.ericsson.se (Staffan Axelsson)\nSubject: Sweden-Finland, April 15\nNntp-Posting-Host: uipc104.ericsson.se\nOrganization: Ericsson Telecom, Stockholm, Sweden\nLines: 119\n\n\n Played in Scandinavium, Gothenburg, April 15 1993:\n ==================================================\n\n SWEDEN - FINLAND 6-6 (1-2,3-1,2-3)\n\n 1st: SWE 1-0 Peter Popovic (Markus Naslund) 6:10\n FIN 1-1 Ville Siren (Keijo Sailynoja) 8:44 (pp)\n FIN 1-2 Juha Riihijarvi (Timo Saarikoski,Vesa Viitakoski) 13:12 (pp)\n 2nd: FIN 1-3 Jari Korpisalo (Kari Harila,Rauli Raitanen) 6:48\n SWE 2-3 Jan Larsson (Mikael Renberg,Stefan Nilsson) 7:25\n SWE 3-3 Hakan Ahlund (Thomas Rundqvist) 8:56\n SWE 4-3 Roger Akerstrom (Roger Hansson) 9:13\n 3rd: SWE 5-3 Stefan Nilsson (Patrik Juhlin,Charles Berglund) 2:20\n FIN 5-4 Keijo Sailynoja 9:23\n FIN 5-5 Keijo Sailynoja 9:44 (ps)\n SWE 6-5 Mikael Renberg (Hakan Ahlund,Thomas Rundqvist) 17:16\n FIN 6-6 Jari Korpisalo 17:44\n\n Shots on goal: Penalties: Attendance: Referee:\n Sweden 8 10 10 - 28 5*2min 6,799 Peter Andersson\n Finland 12 10 11 - 33 6*2min,1*10min (Sweden)\n\n-------------------------------------------------------------------------------\n\n Sweden opened the scoring as Markus Naslund made a drop pass at the Finnish\n blue line, Popovic picked it up and advanced towards the Finnish goal and\n shot a nice hard wrist shot in Ketterer's top corner. Ville Siren's slap\n shot from the blue line on power play made it 1-1, and Juha Riihijarvi\n scored a nice goal in another power play when he close in front of goal\n put the puck high over Aslin, 1-2 after the first period.\n The Finns started the second period with really good pressure. Korpisalo\n made it 1-3 with another goal from close range high over Aslin. Then,\n during the Finnish pressure, Sweden turned the game around in 1:47.\n Mikael Renberg worked hard behind the Finnish goal, and passed the puck to\n Jan Larsson in front, who backhanded the puck low, 2-3. Rundqvist entered\n the Finnish zone and passed to Ahlund, and the Finnish defense let Ahlund \n skate in and take a shot that Ketterer dropped into the goal, 3-3.\n Next, Roger Hansson -behind the goal- sent the puck back to the blue line\n where Roger Akerstrom took a slap shot and Ketterer didn't see the puck since\n there was traffic in front, 4-3.\n Third period started with a nice goal by Stefan \"the Shadow\" Nilsson. Stefan\n and Patrik Juhlin entered the Finnish zone, Patrik passed the puck back to\n Stefan who alone with Ketterer made no mistake, 5-3.\n Then, Keijo Sailynoja show started. He reduce and equalized the lead in only\n 21 seconds! First he scored the 5-4 goal, and after that he came in alone \n with Aslin but was tripped by Aslin to get a penalty shot. Sailynoja\n made a nice penalty shot, showed forehand and put in with a low backhand shot.\n The Swedes seemed to head for a win when Mikael Renberg scored the 6-5 goal\n late in the game on a nice power play combination. Renberg waited in the slot,\n showed that he wanted the puck on the backhand side, Ahlund passed the puck\n and Renberg took a turnaround shot low in Ketterer's goal's far side.\n But Jari Korpisalo had other plans as he only 28 seconds later scored the\n game's final goal to make it 6-6. Korpisalo took a slap shot from a narrow\n angle that -maybe- Aslin should have saved.\n\n All in all, a decent game where the defense wasn't the best.\n Both teams juggled around the lines a bit in the second and third period\n to try no combinations.\n\n Renberg and Rundqvist plays well together in the Swedish team. Larsson-\n Nilsson-Juhlin best line overall again, it seems to be a working WC line.\n Stillman good on defense.\n Some players aren't good enough for the WC though. Hakan Ahlund (faell ner\n hjaelmen och jobba!), Roger Hansson, Challe Berglund, Kenny Jonsson\n will likely have to leave for NHL pros.\n\n Two-goal scorers Jari Korpisalo and Keijo Sailynoja played well in the\n Finnish team. Markus Ketterer didn't have a very good game, we've seen him\n a lot better, so Lindfors is probably Finland's starting goalie in the WC.\n I heard that Esa Tikkanen will join the Finnish team. It would be inter-\n resting to know which other pros coach Matikainen counts on for the WC.\n \n-------------------------------------------------------------------------------\n\n Starting lines:\n\n \tSWEDEN\t\t\t\t\tFINLAND\n\n 35. Peter Aslin\t\t\t30. Markus Ketterer\n\n 8. Kenneth Kennholt\t\t\t 2. Mikko Haapakoski\n 14. Fredrik Stillman\t\t\t 3. Ville Siren\n\n 10. Hakan Ahlund\t\t\t28. Jarkko Varvio\n 9. Thomas Rundqvist\t\t\t40. Mika Nieminen\n 29. Mikael Renberg \t\t\t18. Keijo Sailynoja\n\n 27. Roger Akerstrom\t\t\t 4. Erik Hamalainen\n 7. Arto Blomsten\t\t\t 8. Kari Harila\n\n 20. Jan Larsson \t \t\t25. Rauli Raitanen\n 4. Stefan Nilsson \t\t\t26. Petri Varis\n 5. Patrik Juhlin\t\t\t14. Jari Korpisalo\n\n 3. Peter Popovic\t\t\t 5. Timo Jutila\n 32. Stefan Larsson\t\t\t44. Harri Laurila\n\n 11. Roger Hansson\t\t\t24. Juha Riihijarvi\n 33. Fredrik Nilsson\t\t\t22. Timo Saarikoski\n 24. Peter Ottosson\t\t\t11. Vesa Viitakoski\n\n\t\t\t\t\t 6. Pasi Sormunen\n\t\t\t\t\t12. Janne Laukkanen\n\n 19. Markus Naslund\t\t\t29. Juha Ylonen\n 21. Peter Forsberg\t\t\t27. Timo Peltomaa\n 18. Jonas Bergqvist\t\t\t17. Marko Palo\n\n Played parts of the game:\n 22. Charles Berglund\t\t\t15. Mika Alatalo\n 6. Kenny Jonsson\t\t\t16. Saku Koivu\n\t\t\t\t\t20. Marko Palo\n\n-------------------------------------------------------------------------------\n--\n ((\\\\ \/\/| Staffan Axelsson \n \\\\ \/\/|| etxonss@ufsa.ericsson.se \n\\\\_))\/\/-|| r.s.h. contact for Swedish hockey\n\n###\n\n","output":" hockey"} -{"input":"From: brucek@Ingres.COM (Bruce Kleinman)\nSubject: Re: When did Dodgers move from NY to LA?\nArticle-I.D.: pony.1993Apr6.195730.20277\nOrganization: Ingres Corporation, A subsidiary of The ASK Group, Inc.\nLines: 6\n\nIn article <1993Apr5.160030.2328@ncar.ucar.edu> tparker@music.scd.ucar.edu (Tom Parker) writes:\n>I have a bet with my buddy on when the Dodgers moved from NY to LA. Does\n>anyone know what year they moved?\n>\n\nThe Dodgers' first year in LA was 1958.\n\n###\n\n","output":" baseball"} -{"input":"From: epp@mala.bc.ca (Lorne Epp)\nSubject: Re: LA ON ABC IN CANADA\nOrganization: Malaspina College\nLines: 27\n\nIn article , boora@kits.sfu.ca (The GodFather) writes:\n> \tWas the ABC coverage of the Kings\/Flames game supposed to be the\n> way it was shown in BC with CBC overriding the ABC coverage? When I flipped\n> to ABC, it was the same commentators, same commercials even. My question\n> is: Was this the real ABC coverage or did CBC just \"black out\" the \n> ABC coverage for its own?\n> \n> \n\nHere in Nanaimo (on Vancouver Island, for you furriners out there) we\ngot the ABC coverage on KOMO. It probably depends on your cable company.\n\nI started off switching between the CBC and ABC broadcasts, but finally\nsettled on ABC. I can't stand Don Whitman, and Al Michaels was doing a\ndecent job. He followed the play pretty well, knew all the players'\nnames, and only made a couple of \"rookie\" mistakes that I noticed.\nOne thing that surprised me is that they never once attempted to explain\nthe offside rule.\n\nAm-I-paranoid-or-is-this-really-happening department:\nThere were no fights in the game, but there were a couple of occasions\nwhere it looked like a fight was about to start. Both times ABC cut\naway to show a closeup of a coach or McNall or something. Has ABC\ndecided to adopt the \"Spicer policy?\"\n\n----------------------------------------------------------------------\nLorne Epp epp@mala.bc.ca\n\n###\n\n","output":" hockey"} -{"input":"From: golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy)\nSubject: Re: WC 93: Results, April 18\nOrganization: University of Toronto Chemistry Department\nLines: 43\n\nIn article <1993Apr19.211406.22528@iscnvx.lmsc.lockheed.com> spiegel@sgi413.msd.lmsc.lockheed.com (Mark Spiegel) writes:\n>\tAccording to the SJ Murky News the Team USA roster is (names and\n>\tteams played for in 1992-93 listed):\n>\n>\t\tGoalies\n>\t\t-------\n........\n>\t\tForwards\n>\t\t--------\n>\tTony Amonte\tNew York Rangers\n>\tTed Drury\tHarvard Univ\n>\tRob Gaudreau\tSan Jose' Sharks\n>\tCraig Johnson\tUniv of Minnesota\n>\tJeff Lazaro\tOttawa Senators\n>\tMike Modano\tMinnesota North Stars\n>\tEd Olczyk\tNew York Rangers\n>\tDerek Plante\tUniv of Minnesota-Duluth\n>\tShion Podein\tEdmonton Oilers\n>\tDavid Sacco\tBoston University\n>\tDarren Turcotte New York Rangers\n>\tDoug Weight\tEdmonton Oilers\n>\n\nIt looks like the Edmonton Oilers just decided to take a European\nvacation this spring...\n\nRanford, Tugnutt, Benning, Manson, Smith, Buchberger, and Corson\nare playing for Canada.\n\nPodein and Weight are playing for the US.\n\nIs Kravchuk playing for the Russians...I know he had nagging\ninjuries late in the season.\n\nPodein is an interesting case...because he was eligible to\nplay in Cape Breton in the AHL playoffs like Kovalev, Zubov,\nand Andersson...obviously Sather and Pocklington are not\nthe total scrooges everyone makes them out to be...certainly\nin this case they've massively outclassed Paramount and the\nNew York Rangers.\n\nGerald\n\n###\n\n","output":" hockey"} -{"input":"From: gp2011@andy.bgsu.edu (George Pavlic)\nSubject: Re: Ron Francis\nOrganization: Bowling Green State University B.G., Oh.\nLines: 10\n\nNot to mention, Mr. Francis is an incredibly nice person. Over Christmas\nbreak, a friend of mine had a little Xmas gathering. The two of us drove\nto Ron's house. While I stayed in the car out of shyness, my friend went\nto the door and rang the bell. Ron answered and my friend introduced\nhimself. He then proceeded to invite Francis to the party. Ron declined\nbecause he \"had to watch his daughter.\" He then reached out and shook my\nfriend's hand! I know this isn't r.s.b., but I don't think Barry Bonds\nwould be this polite in this situation.\n\nGeorge\n\n###\n\n","output":" hockey"} -{"input":"From: gspira@nyx.cs.du.edu (Greg Spira)\nSubject: Re: Sandberg, Runs, RBIs (was: Re: Notes on Jays vs. Indians Series)\nOrganization: University of Denver, Dept. of Math & Comp. Sci.\nDistribution: na\nLines: 28\n\nbratt@crchh7a9.NoSubdomain.NoDomain (John Bratt) writes:\n\n>RBIs and Runs scored are the two most important offensive statistics.\n\nActually, they're pretty worthless, if you want to evaluate players\nwith stats. RBIs and Runs Scored should be banned; all they do is\nconfuse victims of mediot brainwashing like yourself. \n\n You\n>can talk about OBP and SLG% all you want, but the fact remains:\n\n>\tThe team that scores more runs wins the game!\n>\t---------------------------------------------\n\nUh, so?\n\nYou've just explained why we use OBP and SLG to evaluate players.\nPrecisely because the team that scores more runs wins the game.\nTraditional baseball stats have gotten way too far away from methods\nwhich enable fans to see who contributes to those runs scored - that's\nwhere OBP, SLG, Runs Created, Linear Weights, etc. come in. These\nsimplify matters so that we can more easily measure a player's\noffensive contribution to the team's runs scored.\n\nThank you for making our case. Have a nice day.\n\nGreg\n\n###\n\n","output":" baseball"} -{"input":"From: d_jaracz@oz.plymouth.edu (David R. Jaracz)\nSubject: Re: Octopus in Detroit?\nOrganization: Plymouth State College - Plymouth, NH.\nLines: 16\n\nIn article <93106.092246DLMQC@CUNYVM.BITNET> Harold Zazula writes:\n>I was watching the Detroit-Minnesota game last night and thought I saw an\n>octopus on the ice after Ysebaert scored to tie the game at two. What gives?\n\nNo no no!!! It's a squid! Keep the tradition alive! (Kinda like the\nfish at UNH games....)\n\n>(is there some custom to throw octopuses on the ice in Detroit?)\n>-------\n>Not Responsible -- Dain Bramaged!!\n>\n>Harold Zazula\n>dlmqc@cunyvm.cuny.edu\n>hzazula@alehouse.acc.qc.edu\n\n###\n\n","output":" hockey"} -{"input":"From: erics@netcom.com (Eric Smith)\nSubject: Re: Infield Fly Rule\nOrganization: NETCOM On-line Communication Services (408 241-9760 guest)\nLines: 31\n\njrogoff@scott.skidmore.edu (jay rogoff) writes:\n\n>One last infield fly question that has always puzzled me and hasn't\n>yet been addressed. I believe the rule also does *not* deal with this\n>situation:\n\n>If Infield Fly is declared and the ball is caught, runners can tag up\n>and advance at their own risk, as on any fly ball.\n\n>However, if the Infield Fly is *not* caught, at what point can a\n>runner legally leave his base w\/o fear of being doubled off for\n>advancing too early? When the\n>ball hits the ground? When a fielder first touches the ball after it\n>hits the ground?\n\n>Enlightenment would be appreciated.\n\nI'm not sure I understand this question. When the IF rule is invoked,\nthe batter is automatically out. This relieves the runners from being\nforced to advance to the next base if the ball is not caught. Other\nthan that, isn't it just the same as any situation in which a runner on\na base is not forced to the next base on a dropped fly ball? That is,\nif the ball is caught he can tag up and run (or decide to stay), and\nif the ball is dropped he can have left the base at any time.\n\n-----\nEric Smith\nerics@netcom.com\nerics@infoserv.com\nCI$: 70262,3610\n\n###\n\n","output":" baseball"} -{"input":"From: j3david@sms.business.uwo.ca (James David)\nSubject: Plus minus stat...\nOrganization: University of Western Ontario\nNntp-Posting-Host: sms.business.uwo.ca\nLines: 65\n\nRoger Maynard shares his views, with the masses, on Bob Gainey\nand life in general:\n \n>In <1993Apr15.160450.27799@sol.UVic.CA> gballent@hudson.UVic.CA\n>(Greg Ballentine) writes:\n \n>>The Selke candidate forwards main purpose on a shift is to\n>>prevent goals from being scored- not to score them. When\n>>Lemieux or Gilmour play their number one purpose is to score-\n>>defence is secondary- especially considering the line that\n>>plays against them is probably a defensive one. That is why\n>>they are not Selke candidates.\n>>Gainey is the best defensive forward ever. I stand by that\n>>assessment. He was a very good player who belongs in the hall\n>>of fame. Did you ever watch him play? He never made a\n>>technical error.\n \n>I watched him over his entire career. I have NEVER seen a\n>player, and that includes Russell Courtnall and Davie Keon,\n>screw up as many breakaways as Bob Gainey. And I will never\n>forget the time Denis Potvin caught Gainey with his head down. \n>You have been sold a bill of goods on Bob Gainey.\n \nIt was Bryan Trottier, not Denis Potvin. It was a vicious\n'boarding' from behind...Trottier was given a major.\n \nBut Roger, what the hell does this have to do with Gainey's skill\nas a hockey player? If Probert smashes Gilmour's head into the\nboards next week, will that diminish your assessment of Gilmour's\nskills?\n \n>Gainey was a plugger. And when the press runs out of things to\n>say about the stars on dynasties they start to hype the\n>pluggers. Grant Fuhr, Essa Tikkannen, Butch Goring, Bob\n>Nystrom, Bob Gainey, Doug Jarvis, Derek Sanderson, Wayne\n>Cashman, Bob Baun, Bob Pulford, Ralph Backstrom, Henri Richard,\n>Dick Duff...and so on...\n \nI would take Fuhr and Sanderson off of the latter.\n \nI think Gainey would be honoured to know that you've included him\non this list. I also think you have a relatively naive view\nabout what wins a hockey game...pluggers are an integral part of\nany team. The Selke is designed to acknowledge their\ncontribution...I think that most people understand that it's not\nthe Nobel Prize...so settle down.\n \n>cordially, as always,\n \n>rm\n \n>-- \n>Roger Maynard \n>maynard@ramsey.cs.laurentian.ca \n \ncongenially, as always,\n \njd\n \n--\nJames David\ndavid@student.business.uwo.ca\n\nj3david@sms.business.uwo.ca (James David)\nWestern Business School -- London, Ontario\n\n###\n\n","output":" hockey"} -{"input":"From: gspira@nyx.cs.du.edu (Greg Spira)\nSubject: Re: Notes on Jays vs. Indians Series\nOrganization: University of Denver, Dept. of Math & Comp. Sci.\nDistribution: na\nLines: 30\n\n\n>Something else to consider:\n\n>Alomar's H-R splits were .500-.363 SLG, .444-.369 OBP! Baerga's was .486-.424\n>and .392-.318. Pretty clearly, Alomar got a HUGE boost from his home park.\n\nNot necessarily. It could mean that, or it could mean that he just hit\na lot better at home than he did on the road (see Frank Thomas' home\/road\nsplits in '91 for an example). I would guess that some of Alomar's split\nis due to the Skydome, but most of it is probably due just to coincidence.\nThere's no way to be sure, of course, but the only hitters the Skydome\nseems to regularly help a lot are right handed home run hitters, and\nAlomar is not a home run hitter.\n\n>I'd say you could make a good for them being about equal right now. T&P\n>rated Baerga higher, actually.\n\nOnly because of t&P's bogus fielding stats, which rate Alomar as the worst\ndefensive second baseman in the league. On a career basis, I think T&P's\nfielding stats may mean something, but on a seasonal basis it comes up\nwith ridiculous results like this. Alomar may not be the god of fielding\nthe media says he is, but he sure isn't the worst in baseball.\n\nOffensively, T&P rate Alomar much higher last year.\n\nRegarding the A vs. B argument, I'll just say they're both very good players\nwith different strengths and a bright future.\n\n\nGreg\n\n###\n\n","output":" baseball"} -{"input":"From: rauser@fraser.sfu.ca (Richard John Rauser)\nSubject: Too Many Europeans in NHL\nOrganization: Simon Fraser University, Burnaby, B.C., Canada\nLines: 50\n\n\n\n Ten years ago, the number of Europeans in the NHL was roughly a quarter\nof what it is now. Going into the 1992\/93 season, the numbers of Euros on\nNHL teams have escalated to the following stats:\n\nCanadians: 400\nAmericans: 100\nEuropeans: 100\n\n Please note that these numbers are rounded off, and taken from the top\n25 players on each of the 24 teams. My source is the Vancouver Sun.\n\n Here's the point: there are far too many Europeans in the NHL. I am sick\nof watching a game between an American and a Canadian team (let's say, the\nRed Wings and the Canucks) and seeing names like \"Bure\" \"Konstantinov\" and\n\"Borshevshky\". Is this North America or isn't it? Toronto, Detriot, Quebec,\nand Edmonton are particularly annoying, but the numbers of Euros on other\nteams is getting worse as well. \n\n I live in Vancouver and if I hear one more word about \"Pavel Bure, the\nRussian Rocket\" I will completely throw up. As it is now, every time I see\nthe Canucks play I keep hoping someone will cross-check Bure into the plexiglassso hard they have to carry him out on a stretcher. (By the way, I'm not a\nCanucks fan to begin with ;-). \n\n Okay, the stretcher remark was a little carried away. But the point is that\nI resent NHL owners drafting all these Europeans INSTEAD of Canadians (and\nsome Americans). It denies young Canadians the opportunity to play in THEIR\nNORTH AMERICAN LEAGUE and instead gives it to Europeans, who aren't even\nbetter hockey players. It's all hype. This \"European mystique\" is sickening,\nbut until NHL owners get over it, Canadian and American players will continue\nto have to fight harder to get drafted into their own league.\n\n With the numbers of Euros in the NHL escalating, the problem is clearly\nonly getting worse.\n\n I'm all for the creation of a European Hockey League, and let the Bures\nand Selannes of the world play on their own continent.\n\n I just don't want them on mine.\n\n\n \n \n-- \nRichard J. Rauser \"You have no idea what you're doing.\"\nrauser@sfu.ca \"Oh, don't worry about that. We're professional\nWNI outlaws - we do this for a living.\"\n-----------------\n\"Remember, no matter where you go, there you are.\" -Dr.Banzai\n\n###\n\n","output":" hockey"} -{"input":"From: dchhabra@stpl.ists.ca (Deepak Chhabra)\nSubject: Re: hawks vs leafs lastnight\nNntp-Posting-Host: stpl.ists.ca\nOrganization: Solar Terresterial Physics Laboratory, ISTS\nDistribution: na\nLines: 18\n\nIn article <1993Apr18.153820.10118@alchemy.chem.utoronto.ca> golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy) writes:\n\n>>on all replays, joe murphy's goal shouldn't have counted ! \n>>the game would have ended in 2-2 tie !\n\n>I thought the red light went on...thus, in the review, the presumption\n>would be to find conclusive evidence that the puck did not go in the\n>net...from the replays I say, even from the rear, the evidence wasn't\n>conclusive that the puck was in or out...in my opinion...\n\nI was under the impression that the objective is to find conclusive\nevidence that the puck _did_ cross the line. And, the replays I saw showed \nfairly conclusively that the puck did _not_ cross the goal line at any\ntime anyway. Somebody screwed up. \n\n\ndchhabra@stpl.ists.ca\n\n###\n\n","output":" hockey"} -{"input":"From: iacs3650@Oswego.EDU (Kevin Mundstock)\nSubject: Re: Yogi-isms\nReply-To: iacs3650@oswego.Oswego.EDU (Kevin Mundstock)\nOrganization: Instructional Computing Center, SUNY at Oswego, Oswego, NY\nLines: 14\n\nIn article <1993Apr2.153725.17543@bsu-ucs> 00mbstultz@leo.bsuvc.bsu.edu writes:\n>\n>Here's an interesting quote from Bill Veek from _Get that Nigger off\n>the Field_:\n> \"Josh (Gibson) was, at minimum, two Yogi Berras.\"\n>Speaking of Yogi, anybody know any good Yogi-isms?\n>Mike \"Curious George\" Stultz\n\nHere's one I remember: (sort of)\nYogi's asleep in a hotel room late at night and gets a call from someone.\nAfter he answers the phone the person at the other end asks if he woke Yogi\nup. Yogi answered, \"No, the phone did.\"\n\nKevin\n\n###\n\n","output":" baseball"} -{"input":"From: marc@yogi.austin.ibm.com (Marc J. Stephenson)\nSubject: Re: Astros Are Back!!!!!!!!!!!!!!!!!!!\nDistribution: usa\nOrganization: IBM, Austin\nLines: 63\n\nIn article <15APR199311534452@rosie.uh.edu> st1rp@rosie.uh.edu (Schwam, David S.) writes:\n>In article , marc@yogi.austin.ibm.com (Marc J. Stephenson) writes...\n>> 2) Astros relief corps holding together. If Doug Jones keeps his changeup\n>> effective and Xavier Hernandez can be effective, then it's passable.\n>> There's no reasonable left-handed help, and the middle relief is iffy.\n>> Tom Edens was expected to take over the Joe Boever setup man role, but\n>> he's been injured, and he was an expansion team acquisition anyway. \n>> Houston thought that Boever would demand too much money, so they let him\n>> go. Doug Jones can lose his touch - he went from Cleveland's all-star\n>> closer to the minors in a pretty short span.\n>\n> From what I understand, Boever and Murphy were considered expendable by the\n ^^^^^^\n>club. Houston felt that their positions could be filled by a number of\n>players.. Art Doug Jones is the key to Houston's success. He must have\n>another great year for Houston to challenge in the NL West. \nNo argument at all with Murphy. He scared the hell out of me when he came in\nlast year. On the other hand, the club though enough of Boever to put him into\nan awful lot of games (he may have led the league in appearances - he did at\nleast at some point). He seemed to be a very viable setup guy - but I guess\nthat's not considered that crucial by the club. I can just remember two years\nago so well, though...\n...\n> The unsuspected strength of the lower part of the order has saved the\n> club so far. Biggio and Finley just aren't doing their job of getting\n> on base. Instead of filling his role as an RBI man, Bagwell has had to\n> assume Biggio and Finley's job. Biggio concerns me, since he usually\n> starts the season very strong.\n\nI'm not that concerned. Those guys have been relatively consistent over the\nyears and they have no good reasons to decline (no injuries, not old, ...).\nI expect them to come through just fine. It's those guys that have not\nbeen consistently good that are the worrisome part, even if they are coming\nthrough right now.\n> * * * * * *\n>\n> On a side note, are you at all concerned with the rumors concerning\n>next year's uniform? There is talk that their road uniform will be\n>(blech..) traditional grey, with the word \"HOUSTON\" written across the\n>chest. If I'm not mistaken, their home uniforms may totally eliminate\n>the color orange (shiver..). McLane's favorite color is red, so...\n\nThis sounds like their old road unis. Pretty dull. Buttons or pullovers?\nI'll check through my uniform book to see if they've always had some orange.\n\n> I'm really upset.. the current unforms are dull and the new ones sound\n>horrible. I'd like to see the uniform of the mid-1980s return. They\n>may not have been pretty, but Houston had established a long precident of\n>wearing the ugliest uniforms in baseball -- and I liked it.\n\nWell, we'll see. I've got a Astros pullover shirt with the \"Astros stripes\"\nacross the shoulders and I have trouble making myself wear it in public. i\ncan see why they might want that to change. Gee, if they eliminate the\norange, will they reupholster the seats in the Astros stripes section (what\nused to be the gold and yellow levels - I don't know those numbers they use\nnow).\n\nI saw a pinstripe version of an Astros cap and I actually thought it looked \ngood!\n-- \nMarc Stephenson\t IBM AWS (Advanced Workstations & Systems - Austin,TX)\nDISCLAIMER: The content of this posting is independent of official IBM position.\nINTERNET->marc@austin.ibm.com VNET: MARC at AUSVMQ IBM T\/L: 678-3189\n\n###\n\n","output":" baseball"} -{"input":"From: nittmo@camelot.bradley.edu (Christopher Taylor)\nSubject: When Is Melido Due Back?\nNntp-Posting-Host: camelot.bradley.edu\nOrganization: Bradley University\nDistribution: na\nLines: 6\n\nWhen are the Yankees planning on activating Melido Perez? His 15 days on\nthe DL are up today, but are they bringing him back this weekend? \n\nThanks for any info.\n\n###\n\n","output":" baseball"} -{"input":"From: hbrooks@uiatma.atmos.uiuc.edu (Harold_Brooks)\nSubject: Re: Spanky Released\nKeywords: WHY!?!\nOrganization: Colorado Needs the Huckabay Kiteball Campaign Committee\nLines: 45\n\nIn article <1993Apr12.130652.22090@sei.cmu.edu> wp@sei.cmu.edu (William Pollak) writes:\n[Deletions]\n>\n>Spanky isn't very good defensively anymore, he's an offensive liability, and,\n>judging from his outburst this winter after the Bucs failed to sign Drabek,\n>he's a jerk with his head in the sand. Tommy Prince, on the other hand, can't\n>hit. In the paper, Simmons was citing the case of Tom Pagnozzi, who never hit\n>in the minors or majors, but suddenly somehow learned how. \n\nGeez, Dal must have slipped something into Ted's drink sometime. Comparing\nPrince to Pagnozzi offensively is laughable. Prince has never hit well in\nthe minors and he's now 27 years old, I think. Pagnozzi was not a bad hitter\nin the minors. (I'll bring in the numbers tomorrow assuming I don't have\nanother brain cramp and forget.) He had a very good year at Louisville \nbefore coming up to the majors. As I recall, the hype on Pagnozzi coming up\nin the organization was good hit, decent fielding. When he got to the \nmajors and didn't hit as well as expected (not as much playing time?), he \nbecame Exhibit 312 in Nichols' Law of Catcher Defense and got the reputation \nas an outstanding defensive catcher. It's not clear he ever learned to\nhit. His four years with more than 100 AB--\n\nBorn 31 July 1962\nYear AB BA SLG OBA \n1988 195 .282 .320 .328\n1990 220 .277 .373 .321\n1991 459 .264 .351 .317\n1992 485 .249 .359 .290 \n\nNo power, less-than-league-average walks, peak year when he turned 28, \nnow declining. If Ted is going to invoke Pagnozzi as a model for Prince,\ngiven that Prince has underperformed Pagnozzi in the minors, it's not\na rosy picture.\n\nBTW, I'm still unhappy with moving Zeile, who had the same reputation \ncoming up in the Cardinal organization as Pagnozzi, except that he was\na much, much better hitter, to 3rd where he could be an average hitter\nand a below average fielder instead of a well-above average hitter\nas an average (or below average) fielding catcher.\n\nHarold\n-- \nHarold Brooks hbrooks@uiatma.atmos.uiuc.edu\nNational Severe Storms Laboratory (Norman, OK)\n\"I used to work for a brewery, too, but I didn't drink on the job.\"\n-P. Bavasi on Dal Maxvill's view that Florida can win the NL East in '93\n\n###\n\n","output":" baseball"} -{"input":"Subject: McRae is (Re: Torre: The worst manager?)\nFrom: scott@mccall.com (Scott D. Davis)\nReply-To: scott@mccall.com (Scott D. Davis)\nOrganization: The McCall Pattern Co., Manhattan, KS, USA\nNntp-Posting-Host: mis2\nNntp-Posting-User: scott\nLines: 18\n\n\nIn article <16BB1C589.DAK988S@vma.smsu.edu.Ext>, DAK988S@vma.smsu.edu writes:\n>gt7469a@prism.gatech.EDU (Brian R. Landmann) writes:\n>>Joe Torre has to be the worst manager in baseball.\n>>brian, a very distressed cardinal fan.\n>No....Hal McRae is the worst manager in baseball. I've never seen a guy who\n>can waste talent like he can. One of the best raw-talent staffs in the league,\n>and he's still finding a way to lose. I'll be surprised if he makes it through\n>the next 2 weeks, unless drastic improvement is made.\n> \nKC(?) news was doing a report on that. They said that McRae is\nreally a batting coach and not a manager. But for some reason\nhe took the job. Whatever the reason, the Royals need a new\nmanager now...while it is too late.\n--\nScott D. Davis The McCall Pattern Company\n(uucp: ...!widener!depot!mccall!scott)\t615 McCall Road\n(800)255-2762, in Kansas (913)776-4041 Manhattan, KS 66502, USA\n\n###\n\n","output":" baseball"} -{"input":"From: jason@studsys.mscs.mu.edu (Jason Hanson)\nSubject: Re: NHL team in Milwaukee\nOrganization: UTexas Mail-to-News Gateway\nLines: 42\nNNTP-Posting-Host: cs.utexas.edu\n\nNewsgroups: rec.sport.hockey\nSubject: Re: NHL team in Milwaukee\nSummary: \nExpires: \nSender: \nDistribution: \nOrganization: Marquette University - Department MSCS\nKeywords: \n\nIn article <1993Apr16.131843.24012@walter.cray.com> cbetz@radioman.cray.com (Charles Betz {x66442 CF\/ENG}) writes:\n>\n>Bradley Center in Milwaukee is home to the Milwaukee Admirals minor leauge\n>hockey team. The owner of the Admirals (sorry, I can't remember his name)\n>either owns or at least shelled out the majority of the funds to build the\n>Bradley Center.\n\nLloyd Pettit married into Allen-Bradley Corp. (ab.com) family and owns the\nAdmirals. He donated the Bradley Center and the new Pettit National Ice\nCenter.\n\n>Supposedly he was approached by the NHL about an expansion franchise, but \n>turned it down because he thought the franchise fee of $50 million was too\n>high.\n\nThis is not the way I have heard it. See, Lloyd (as he is affectionately\nreferred to by Milwaukeeans and Bob Uecker) bought the Bradley Center *TO* get\nthe NHL to come here.\n\n>Like I said, I don't know whether this story is true or just a rumor, but if\n>it's true, don't look for an NHL team in Milwaukee anytime soon. The Admirals\n>aren't going to be forced out of the building and you won't see an NHL club\n>and a minor league club in the same building, especially since the NBA's\n>Milwaukee Bucks play there as well.\n\nYeah, the Bucks, the Milwaukee Wave (soccer), the Admirals, the Marquette\nWarriors, concerts and a bunch of other things...\n-- \nJason Hanson | 915 W. Wisconsin Ave #1010 | (414) 288-2179\nMarquette University | Milwaukee, WI 53233-2373 | Ham Radio: N9LEA\/AE\n-- jason@studsys.mscs.mu.edu ==+== n9lea@n0ary.#nocal.ca.usa.na --\n\n###\n\n","output":" hockey"} -{"input":"From: luriem@alleg.edu(Michael Lurie) The Liberalizer\nSubject: Yankee fears.\nOrganization: Allegheny College\nLines: 9\n\n\nI'll tell youm all one thing. Steve howe and FARR are much better then the \nworst pitcher in yankee Pitching ___________________\n\n\nWHO do you think I am talking about. I'll post the answers if you e-mail \nto me. Use reply. or post you're answers, but e-mailing them to me meaqns \nthat I will post the final results. I have one particular horrid pitcher \nin mind.\n\n###\n\n","output":" baseball"} -{"input":"From: rja@mahogany126.cray.com (Russ Anderson)\nSubject: Re: A surfeit of offense?\nOriginator: rja@mahogany126\nLines: 35\nNntp-Posting-Host: mahogany126\nOrganization: The 1991 World Champion Minnesota Twins!\n\n\nIn article <1qi008INNphe@jhunix.hcf.jhu.edu>, pablo@jhunix.hcf.jhu.edu (Pablo A Iglesias) writes:\n> In article <1993Apr14.160447.17835@cs.cornell.edu> tedward@cs.cornell.edu (Edward [Ted] Fischer) writes:\n> >Last year the American League scored 9802 runs in 1134 games, for a\n> >total of 8.6 runs per game, with 1.0 HR\/game. Through Tuesday, the AL\n> >has 477 runs in 48 games, for a total of 9.9 runs per game, and a\n> >total of 1.7 HR\/game. In 1987 there were 9.8 runs per game, and 2.3\n> >HR\/game.\n> \n> >The big question: How significant is this? Have we returned to 1987?\n> >Or is this just a minor abberation?\n> >\n> >Some thoughts:\n> \n> >d) I thought offense was generally down in April, rising as the\n> >weather got warm and pitchers got tired. This may be a bigger\n> >abberation from the norm than it seems.\n> \n> 1. I don't get a feeling that the weather has been an issue this year. \n> There doesn't seem to be a really cold spell in North America which \n> does makes it harder to hit (not to mention making the ball carry less)\n\nYou obviously did not watch the Twins in Chicago.\n\nNo cold spell? It's been snowing most of the week in Minnesota.\n(5 inches in Duluth last weekend)\n\n> I would still put things under the too early to tell category. \n\nYup.\n\n-- \nRuss Anderson | Disclaimer: Any statements are my own and do not reflect\n------------------ upon my employer or anyone else. (c) 1993\nEX-Twins' Jack Morris, 10 innings pitched, 0 runs (World Series MVP!)\n\n###\n\n","output":" baseball"} -{"input":"From: fierkelab@bchm.biochem.duke.edu (Eric Roush)\nSubject: Re: Young Catchers\nArticle-I.D.: news.12799\nOrganization: Biochemistry\nLines: 139\nNntp-Posting-Host: bruchner.biochem.duke.edu\n\nSince I was the one responsible for these divergent threads of\napprox. 40+ posts (going back to: The Braves could be better off\nif an injury happens), I may as well inject a little more\nfuel to the flame!\n\n1) Back at the beginning of Spring Training, I though\nLopez would make the squad easily. Olson was still\nrecovering from his late-season injury (knee, I believe),\nand there were questions as to whether he would be\nable to play before June. And then Berryhill was dinged up.\n\nI was looking forward to this, because I believe that Lopez\ncan hit AND field the position. Before last season, he was\nthe Braves \"Defensive Catcher\" prospect, while Brian Deak was\nthe Braves \"Offensive Catcher\" prospect. Besides, Olson\nand Berryhill couldn't hit their way out of a wet cardboard\nbox, and don't walk enough to be useful.\n\nBut Olson recovered quickly, Berryhill recovered, and the Braves went\nwith the two vets. I still say that if one of those two had been down\nat the start of the season, he wouldn't have gotten his job back.\n\n2) There is a certain logic to keeping Olson and Berryhill around.\nAfter all, ML catchers are in short supply and suffer from wear and\ntear. There are teams out there without ONE average ML catcher\n(California and Seattle come to mind). Certainly, trying to\nmove Olson or Berryhill through waivers would be unlikely to work.\nPlus, you'd have to eat that salary, which isn't huge, but isn't\ntiddleywinks either (I think Olson's at about $800,000, Berryhill\nat $450,000, but that's only what I recall).\n\n3) Yes, I think arbitration-eligibility may have a role to\nplay in this also. What is it, that 5\/6 of the 2+year players\naren't eligible for arbitration? Only the 1\/6 that were on the roster\nthe longest are eligible? Of course, the system may change,\nbut the extent of that change is not yet known. From a business\nstandpoint, it may make sense to keep Lopez down until June\/the\nfirst time Olson\/Berryhill go on the DL.\n\n4) I am still disappointed that Lopez isn't on the team.\nI still prefer to think of myself as a fan when it comes to the Braves,\nand the truth is that I'd rather see our best team on the field,\nwhich, IMO, includes Lopez.\n\nOf course,today we play the Cubs. Hopefully, we won't need him. ;)\n\nAs for the Schuerholz\/Cox conversation, I imagine it went\nlike this: (Remember, they've BOTH been GM's)\n(the following is not meant to be read by the humor-impaired)\n\nCox: OK, we've sent Jones down. His fielding could be a\nlittle smoother. Besides, Blauser can hit OK and his fielding\nis better than it used to be.\n\nSchuerholz: Well, we'll have to send Nieves down too. Deion\njust won't sign that baseball only contract. We can't count\non him in October, so we have to keep Nixon around for the\ndefense. Besides, Gorman's not ready to give up on\nBilly Hatcher yet. Once Hatcher's gone AND Deion signs,\nwe can move Nixon for Frankie Rodriguez. That ought to\ngive us some pitching depth in 1995.\n\nCox: Yep, that'll be nice. Too bad Deion won't sign.\nOK, I'll look for Nieves when Justice starts having\nBerry-Berry...er, back problems again. Now, what about\nKlesko?\n\nSchuerholz: Well, we've still got to fork out another 1.5 mil\nfor Bream. If we keep Klesko, we either lose the money\nor Cabrera. I keep dangling Sid in front of Dal Maxwell,\nbut somehow he doesn't seem to be the same GM. First\nJeffries for Jose, and now Whiten for Clark! If he\ngets rid of Brian Jordan, then I'd HAVE to believe that he\nand Whitey Herzog switched bodies at the Winter Meetings!\n\nCox: OK, keep trying on Bream, and I'll wait til the trading\ndeadline for my Hunter\/Klesko platoon. Maybe I can get a few\nextra at-bats for Cabrera while we wait. Try California...\nif Snow starts slowly, maybe WhiteyDal will bite on Sid.\nAnd if that doesn't work, then perhaps Sid's knees\ncould be \"persuaded\" to act up. There's always the\n15-day DL! Mwa-ha-ha-ha-ha!\n\nSchuerholz: What about Caraballo?\n\nCox: Well, he's not that much better than Lemke. Maybe if he starts\nin Richmond, he'll start walking more. Besides, if he's going to be\narbitration-eligible, better to stretch him out so that we actually\nget some value from him before he makes the big bucks.\n\nSchuerholz: Now, let's see. That leaves Lopez.\n\nCox: NOOOOO! I gotta keep Lopez! Sure, I didn't think Olson\nwould recover this quickly. Maybe I can talk Caminiti into\nrunning into him again?\n\nSchuerholz: Nope, Lopez has gotta go. You know that he'll get\n$3 million in arbitration. May as well put it off that one\nextra year. Besides, until Olson's shown his stuff a little\nbit, I can't trade him. Besides, Berryhill's a left-handed\nhitter. You know how rare that is?\n\nCox: Don't you mean a left-handed whiffer? Pretty common,\nif you ask me. I mean, he made Pat Borders look good in\nthe World Series. PAT BORDERS!!!\n\nSchuerholz: Hey, you're the one who wouldn't write Lopez\ninto the lineup.\n\nCox: Well, you're the one who went out and got me Jeff\nReardon! Besides, I thought Lopez wouldn't be used\nto our pitching staff's stuff. He got some time with\nthem this spring...looked pretty good. Come on, surely\nwe only need to keep one stiff behind the plate?\n\nSchuerholz: Yeah, but which stiff? Whichever one we keep\nwill be hurt by May.\n\nCox: OK, OK, you made your point. Keep them both. Surely\none of them will be on the DL by June at the latest. Then I\ncan call up Lopez, and then we can win 110 games! The Pennant!\nTHE WORLD SERIES! I'll be up there with John McGraw! Casey\nStengel! Earl Weaver! Oh, they laughed at me in Toronto,\nbut have you ever had to deal with George Bell? I'll finally\nget my just reward! Mwa-ha-ha-ha!\n\nSchuerholz: Easy, Bobby. Have you been taking those\n\"happy pills\" left around by Chuck Tanner? Why'd you\never hire that guy anyhow?\n\nCox: Don't ask me; ask Ted.\n\n-------------------------------------------------------\nEric Roush\t\tfierkelab@\tbchm.biochem.duke.edu\n\"I am a Marxist, of the Groucho sort\"\nGrafitti, Paris, 1968\n\nTANSTAAFL! (although the Internet comes close.)\n--------------------------------------------------------\n\n###\n\n","output":" baseball"} -{"input":"From: str@maredsous.Eng.Sun.COM (Todd Rader)\nSubject: Re: Rickey Henderson\nOrganization: Sun\nLines: 6\nDistribution: usa\nNNTP-Posting-Host: maredsous\n\nIn article <1993Apr5.173500.26383@ra.msstate.edu> js1@Isis.MsState.Edu (Jiann-ming Su) writes:\n%I say buy out Henderson's contract and let him go bag groceries. Next \n%season, you'll be able to sign him for nothing. That goes for any bitching\n%ball player.\n\nStay in school. You have a lot to learn.\n\n###\n\n","output":" baseball"} -{"input":"From: umturne4@ccu.umanitoba.ca (Daryl Turner)\nSubject: Re: Pens Info needed\nNntp-Posting-Host: ccu.umanitoba.ca\nOrganization: University of Manitoba, Winnipeg, Manitoba, Canada\nLines: 19\n\nIn article <1993Apr15.140541.28465@ericsson.se> etxonss@ufsa.ericsson.se (Staffan Axelsson) writes:\n>\n> Actually, Swedish coach Curt Lundmark is thinking about leaving two\n> spots open for additions from eliminated NHLers. It is Mats Sundin and\n> Calle Johansson that Curt hopes can join the team, although in a late\n> stage of the tournament. Technically, I seem to recall that you can leave\n> spots open until 24 hrs before the WC final.\n>\nHmmm...I also heard through the grapevine that Team Finland might try and\nleave a spot open for at least one NHLer. (Some guy named Sel{nne, ever\nhear of him? :) They might have to be content with Kurri, though, I hope. :)\n\n\nDaryl Turner : r.s.h contact for the Winnipeg Jets \nInternet: umturne4@ccu.umanitoba.ca \nFidoNET: 1:348\/701 -or- 1:348\/4 (please route through 348\/700)\nTkachuk over to Zhamnov, up to Sel{nne, he shoots, he scores! \nThe Jets win the Cup! The Jets win the Cup!\nEssensa for Vezina! Housley for Norris! Sel{nne for Calder!\n\n###\n\n","output":" hockey"} -{"input":"From: rickert@NeXTwork.Rose-Hulman.Edu (John H. Rickert)\nSubject: mile high runs\nArticle-I.D.: master.1psq90INNh93\nReply-To: rickert@NeXTwork.Rose-Hulman.Edu (John H. Rickert)\nOrganization: Computer Science Department at Rose-Hulman\nLines: 35\nNNTP-Posting-Host: g215a-1.nextwork.rose-hulman.edu\n\nHow many runs will be scored in Denver?\nI don't know.\n\nbut some idea can be gotten by looking at the runs scored in \nMile High Stadium during the last few years of the Bears\/Zephyrs \ntenure in the American Association.\n\nHere's the total runs scored per game in Zephyrs games, \nall league games and the ratio. I found the same ratios for HR.\n\nYear rpg lea ratio hrpg lea ratio \n1992 10.22 9.10 1.12 1.65 1.58 1.04\n1991 9.53 8.87 1.07 1.41 1.26 1.12\n1990 10.71 8.72 1.23 1.49 1.24 1.20\n1989 9.07 8.34 1.09 1.27 1.11 1.14\n1988 9.90 8.37 1.18 1.29 1.08 1.19\n1987 12.55 10.70 1.17 2.39 1.92 1.24\n1986 9.45 9.33 1.01 1.35 1.38 .98\n1985 9.50 8.54 1.11 1.53 1.34 1.14\n1984 9.99 9.10 1.10 1.55 1.59 .97\n1983 10.60 9.99 1.06 2.03 1.74 1.17\n1982 11.29 10.35 1.09 2.24 1.91 1.17\n1981 10.29 9.25 1.11 1.43 1.49 .96\n1980 10.59 9.43 1.12 1.63 1.46 1.12\n 1446\/13-->1.11 1444\/13-->1.11\n\nIt seems pretty clear that Denver will have a large effect \non runs scored (I'll stick with my prediction from last year \nthat it'll be one of the top 3 in the NL this year) \nand a fairly large effect on Homeruns - though apparently not as large as \nAtlanta, Wrigley, Cincinnati and San Diego.\nStill it ought to be a pretty decent home run park.\n\njohn rickert\nrickert@nextwork.rose-hulman.edu\n\n###\n\n","output":" baseball"} -{"input":"From: jrmst8+@pitt.edu (Joseph R Mcdonald)\nSubject: Re: Wirtz is a weenie\nOrganization: University of Pittsburgh\nLines: 27\n\nIn article rp16+@andrew.cmu.edu (Robert Angelo Pleshar) writes:\n>In other TV news, the Penguins announced yesterday that they will have 3\n>fewer broadcast TV games, and will have 22(!) games on some sort of\n>subscription \/ pay-per-view system. Yuck.\n\nThis is incorrect. This year the Pens had 61 games on \"free\" TV and 6\ngames on PPV. Next year they will have 62 games on free TV and 22 on \na subscription basis. \n\nYou actually get 1 more free game than last year, and there will be no\nmore \"radio-only\" games.\n\nIts a good deal. Last year, everybody bitched about Baldwin \"breaking\nup the team\". Now, he goes out of his way to keep the nucleus of this\nteam together and that takes money. He comes up with a creative way\nto generate more revenue so he can afford this team, and people bitch\nsome more.\n\nEverybody wants something for nothing.\n\nDean\n\n-- \n-------------------------------------------------------------------------------\nDean J. Falcione \"Badges? What badges? We \n(using jrmst8 by permission Don't need no stinkin'\n of the owner, Joe McDonald) badges!\"\n\n###\n\n","output":" hockey"} -{"input":"From: georgeh@gjhsun (George H)\nSubject: Re: President Trophy winner missing playoffs ???\nOrganization: Michigan State University\nLines: 17\nNNTP-Posting-Host: gjhsun.cl.msu.edu\n\njstrangi@hora.seas.upenn.edu (Jim Strangio) writes:\n\n>In article <13APR93.17376172.0059@VM1.MCGILL.CA> CCDB@MUSICA.MCGILL.CA (CCDB000) writes:\n\n>When was the last time a President's Trophy winner fell to last place\n>the following year? A long time, I'd bet.\n>--\n\nWell I think it in 1969 the Montreal Canadians finished 1st (although\nthere was no President's cup in those days) and missed the playoffs \nin 1970. I do recall that the 1970 playoff picture wasn't decided until\nthe final day, when the NY Rangers defeated the RedWings. The tie-breaker was\nthe number of goals for (if I remember correctly), so the Rangers played\nwith an empty net for the entire game. Some Hab loyalists accused \nthe Wings of 'throwing' the game to keep them out, but as I recall, \nGordie and Delvecchio had the flu, so coach Sid Abel sat them out,\nand the Rangers swarmed the RedWings most of the night.\n\n###\n\n","output":" hockey"} -{"input":"From: John Michael Santore \nSubject: Re: NHL Team Captains\nOrganization: Sophomore, Mathematics, Carnegie Mellon, Pittsburgh, PA\nLines: 31\n\t<1993Apr19.022113.12134@ann-arbor.applicon.slb.com>\n\t\nNNTP-Posting-Host: po5.andrew.cmu.edu\nIn-Reply-To: \n\n>Michael Collingridge writes:\n> \n>>And, while we are on the subject, has a captain ever been traded, \n>>resigned, or been striped of his title during the season? Any other \n>>team captain trivia would be appreciated.\n> \n>Wasn't Ron Francis captain of the Whalers when he was traded to\n>Pittsburgh?\n>\n>Mom.\n\nRick Tocchet was captain of the Flyers for several years before he was\ntraded to the Pens...\n\n -John Santore\n\n\n=============================================================================\n ____________________ \n\/ \\ \"We break the surface tension \n\\_________ ____ \\ with our wild kinetic dreams\"\n\/ \/ \\ \\ -Rush, Grand Designs\n\\_______ \/ (*) ) )\n\/ \/ \/\\___\/ \/ Go Philadelphia Flyers!\n\\_____ \/ \/ \/\n\/ \/ \\_______\/ John Santore (jsbh@andrew.cmu.edu)\n\\________\/ \n \nRush-Yes-King Crimson-Emerson, Lake and Palmer-Marillion-Genesis (w\/ Gabriel)\n=============================================================================\n\n###\n\n","output":" hockey"} -{"input":"From: adavis@mcl.bdm.com (Arthur Davis)\nSubject: Re: Ron Francis\nOrganization: BDM International, Inc.\nLines: 17\nNNTP-Posting-Host: jupiter.mcl.bdm.com\n\nIn article <1993Apr19.171223.11311@Virginia.EDU> mjr4u@Virginia.EDU (\"Matthew J. Rush\") writes:\n> I forgot to ask: Is this the highest points total Francis has\n>had in a season? Has he ever had a 100 point season before,\n>either with the Pens or the Whalers?\n>\n\nFrancis got 101 in 89-90, his last full season with Hartford.\n\nIn agreement with your previous post, I think Francis is a tremendous and\ngenerally underrated complete player. I would LOVE to have him here in a\nCapitals uniform where he would certainly be the #1 center (even though\nPivonka is also a very good complete player who is generally underrated).\nFrancis impresses me in many ways as an \"ethical Dale Hunter\". Tons of\nheart and can-do attitude with a lot of different skills, but none of\nthe cheap shots and few penalty minutes. Not to mention nearly always\ncoming through when it's important.\n\n###\n\n","output":" hockey"} -{"input":"From: filinuk@staff.dccs.upenn.edu (Geoff Filinuk)\nSubject: Get Real. Caps have no chance\nReply-To: filinuk@staff.dccs.upenn.edu (Geoff Filinuk)\nOrganization: University of Pennsylvania\nLines: 7\nNntp-Posting-Host: staff.dccs.upenn.edu\n\n\n\tAnyone who really believes that the Caps can beat\nthe Pens are kidding themselves. The Pens may not loose\none game in the playoffs.\n\nGeoff Filinuk\nFlyers Fan\n\n###\n\n","output":" hockey"} -{"input":"From: ma_ind25@blurt.oswego.edu\nSubject: Re:Jewish Baseball Players?\nOrganization: SUNY College at Oswego, Oswego, NY\nLines: 3\n\nI believe that Rusty Staub was also a jewish ball-player\nAlso, Mordaci Brown back in the early 20th century. He was a pitcher whose\nnickname was \"3 fingers\" Brown....for obvious reasons....he had 3 fingers.\n\n###\n\n","output":" baseball"} -{"input":"From: jtchern@ocf.berkeley.edu (Joseph Hernandez)\nSubject: MLB Standings and Scores for Thu., Apr. 15th, 1993\nOrganization: JTC Enterprises Sports Division (Major League Baseball Dept.)\nLines: 73\nDistribution: world\nNNTP-Posting-Host: monsoon.berkeley.edu\n\n\n\t MLB Standings and Scores for Thursday, April 15th, 1993\n\t (including yesterday's games)\n\nNATIONAL WEST\t Won Lost Pct. GB Last 10 Streak Home Road\nHouston Astros 05 03 .625 -- 5-3 Won 5 00-03 05-00\nAtlanta Braves 06 04 .600 -- 6-4 Lost 1 03-03 03-01\nSan Francisco Giants 05 04 .556 0.5 5-4 Lost 1 02-01 03-03\nLos Angeles Dodgers 03 06 .333 2.5 3-6 Lost 3 00-02 03-04\nColorado Rockies 02 05 .286 2.5 2-5 Lost 3 02-03 00-02\nSan Diego Padres 02 06 .250 3.0 2-6 Lost 3 00-03 02-03\nCincinnati Reds 02 07 .222 3.5 2-7 Lost 3 01-02 01-05\n\nNATIONAL EAST\nPhiladelphia Phillies 08 01 .889 -- 8-1 Won 5 05-01 03-00\nPittsburgh Pirates 06 02 .750 1.5 6-2 Won 3 03-02 03-00\nSt. Louis Cardinals 06 02 .750 1.5 6-2 Won 2 04-02 02-00\nNew York Mets 04 03 .571 3.0 4-3 Won 2 02-03 02-00\nChicago Cubs 04 05 .444 4.0 4-5 Won 1 01-02 03-03\nMontreal Expos 03 05 .375 4.5 3-5 Lost 2 00-02 03-03\nFlorida Marlins 03 06 .333 5.0 3-6 Won 2 02-04 01-02\n\n\nAMERICAN WEST Won Lost Pct. GB Last 10 Streak Home Road\nTexas Rangers 06 02 .750 -- 6-2 Lost 1 04-02 02-00\nCalifornia Angels 05 02 .714 0.5 5-2 Won 3 03-02 02-00\nOakland Athletics 04 03 .571 1.5 4-3 Lost 1 04-02 00-01\nSeattle Mariners 04 03 .571 1.5 4-3 Won 1 03-02 01-01\nChicago White Sox 04 04 .500 2.0 4-4 Won 1 02-03 02-01\nMinnesota Twins 04 04 .500 2.0 4-4 Lost 1 01-02 03-02\nKansas City Royals 01 07 .125 5.0 1-7 Lost 2 01-05 00-02\n\nAMERICAN EAST\nBoston Red Sox 06 02 .750 -- 6-2 Won 2 02-00 04-02\nNew York Yankees 05 03 .625 1.0 5-3 Won 2 02-00 03-03\nToronto Blue Jays 04 03 .571 1.5 4-3 Lost 1 03-02 01-01\nDetroit Tigers 03 04 .429 2.5 3-4 Won 1 01-00 02-04\nCleveland Indians 03 05 .375 3.0 3-5 Lost 2 02-01 01-04\nMilwaukee Brewers 02 05 .286 3.5 2-5 Lost 4 00-02 02-03\nBaltimore Orioles 02 06 .250 4.0 2-6 Won 1 00-02 02-04\n\n\n\t\t\t YESTERDAY'S SCORES\n (IDLE teams listed in alphabetical order)\n\nNATIONAL LEAGUE\t\t\t\tAMERICAN LEAGUE\n\nHouston\t\t9\t\t\tBaltimore\t6\nMontreal\t5\t\t\tTexas\t\t5\n\nPittsburgh 11\t\t\tSeattle\t 10\nSan Diego\t7\t\t\tToronto\t\t9 (10)\n\nChicago\t\t6\t\t\tCleveland\t7\nAtlanta\t\t0\t\t\tBoston\t 12\n\nCincinnati\t2\t\t\tCalifornia 12\nPhiladelphia\t9\t\t\tMilwaukee 2\n\nNew York\t6\t\t\tKansas City\t5\nColorado\t3\t\t\tNew York\t6\n\nFlorida\t\t6\t\t\tMinnesota PPD\nSan Francisco\t4\t\t\tChicago RAIN\n\nSt. Louis\t2\t\t\tDetroit IDLE\nLos Angeles\t1 (15)\t\t\tOakland IDLE\n-- \n-------------------------------------------------------------------------------\nJoseph Hernandez | RAMS | | \/.\\ ******* _|_|_ \/ | LAKERS\njtchern@ocf.Berkeley.EDU | KINGS | |__ | | DODGERS _|_|_ | | RAIDERS\njtcent@soda.Berkeley.EDU | ANGELS |____||_|_| ******* | | |___| CLIPPERS\n-------------------------------------------------------------------------------\n\n###\n\n","output":" baseball"} -{"input":"From: golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy)\nSubject: Re: Too Many Europeans in NHL\nArticle-I.D.: alchemy.1993Apr6.195022.6362\nOrganization: University of Toronto Chemistry Department\nLines: 24\n\nIn article <1993Apr6.155743.18798@adobe.com> snichols@adobe.com (Sherri Nichols) writes:\n>In article <1993Apr6.141557.8864@alchemy.chem.utoronto.ca> golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy) writes:\n>>Anyways, crawl back into the hole you crawled out of...the NBA doesn't\n>>care where they get basketball players from, major league baseball\n>>doesn't give a damn where they get baseball players from (except Cuba,\n>>that is).\n>\n>MLB is perfectly willing to take players from Cuba. They just have to\n>defect first. \n>\n>Sort of like the situation used to be with Russian\/Czech\/etc hockey\n>players, until the political situation in those countries changed.\n>\n\nMajor league baseball has told the Blue Jays and the Expos not to\nsign Oscar Linares (I think that is his name)\n...Canada does not have the restrictions against\nCubans that the US has and other major league teams have told the\nCanadian teams that they would be very unhappy if the Expos or the\nBlue Jays would do this. Cubans players would not have to defect\nto play in Canada and could play the 81 home games for the Expos\nand Blue Jays without any trouble.\n\nGerald\n\n###\n\n","output":" hockey"} -{"input":"From: roger@crux.Princeton.EDU (Roger Lustig)\nSubject: Re: New Home for the Bosox!!!\nOriginator: news@nimaster\nNntp-Posting-Host: crux.princeton.edu\nReply-To: roger@astro.princeton.edu (Roger Lustig)\nOrganization: Princeton University\nLines: 30\n\nIn article <1993Apr15.132741.11322@scott.skidmore.edu> jrogoff@scott.skidmore.edu (jay rogoff) writes:\n\n>> I agree, though I'd also be happy with a stadium that looks\n>> like new Comiskey. The new park was also made for baseball.\n>> Unlike Three Rivers, the Vet, Riverfront, etc., it's not a\n>> football park in which they also play baseball.\n\n>While we're on the multipurpose subject, let's not forget Shea, which\n>was designed to accommodate both the Mets & Jets. It was the first\n>stadium (I think) to have the box seats on rollers so they could be\n>oriented at right angles for baseball & in parallel for football.\n\nNot the first. RFK, olim DC Stadium, was built 2 years earlier.\nNowadays they don't move the seats back for the few exhibition\ngames; but the 3rd-base\/LF lower deck used to move. It was all \nmetal, which was pretty noisy on Bat Day.\n\n>Of course, with the Jets gone to Jersey (and a truly good football\n>stadium), the Mets are saddled with a multipurpose stadium where,\n>because it's circular, the seats are almost always too far from the\n>action. The Mets announcers--Kiner & Murphy in particular--have\n>always hyped it as \"beautiful Shea\n>Stadium,\" a tipoff to how unbeautiful it truly is.\n\nIt's vastly better than it was before they fixed it, though. Back in\nthe late 70's it was a *dump*.\n\nRoger (don't you*like* jet noise?)\n\n###\n\n","output":" baseball"} -{"input":"Subject: Remarks by President Clinton to NCAA Division I Champion Hockey Team\nFrom: \"nigel allen\" \nReply-To: \"nigel allen\" \nDistribution: rec\nOrganization: Canada Remote Systems\nLines: 158\n\n\nHere is a press release from the White House.\n\n Remarks by President Clinton to NCAA Division I Champion Hockey Team\nApril 19; Q&A Following\n To: National Desk\n Contact: White House Office of the Press Secretary, 202-456-2100\n\n WASHINGTON, April 19 -- Following is a transcript\nof remarks by President Clinton to the University of Maine \"Black\nBears\" NCAA Division I hockey champions:\n\n The Rose Garden\n\n 9:58 A.M. EDT\n\n THE PRESIDENT: Good morning ladies and gentlemen. It's\nan honor for me to welcome the University of Maine Black Bears, the\nwinner of the NCAA Division I hockey national championship to the\nRose Garden and the White House. I understand from Senator Mitchell\nthat this is the first team from the University of Maine every to win\na national championship. And we're glad to have them here.\n\n I'm inspired not only by how the team pulled together to\nwin the championship, but how the entire state pulled together to\ncheer them onto victory.\n\n Coming from a state that is also relatively small in\nsize, but also filled with pride and tradition and community, I can\nunderstand how the people of Maine must feel about the Black Bears.\nIn our state people are still talking about the time we won the\nOrange Bowl over the number one ranked football team, and that was\nback in 1978. I'm sure that 15 years from now, the people of Maine\nwill as proud of this team as they are today.\n\n You know, in my state football is a slightly more\npopular sport than hockey. We don't have a lot of ice. (Laughter.)\nBut after spending three months getting banged around in this town, I\ncan understand a little more about hockey than I did before I came\nhere. Hockey is a tough game. It's a hard-hitting sport. It does\nhave one virtue though, there's a penalty for delay of game. I wish\nwe had that rule in the Senate. (Laughter.)\n\n In government as in hockey, leadership is important. In\nthe United States Senate, our team has a great captain, the Majority\nLeader and the senior Senator from Maine, George Mitchell; junior\nSenator -- Cohen looks so young, I can't imagine. (Laughter.) I'm\nactually bitter about Senator Cohen because he looks so much younger\nthan me.\n\n On your hockey team, the captain Jim Montgomery has done\na great job. He scored the winning goal late in the championship\ngame, leading you to a come-from-behind victory -- something else I\nknow a little bit about.\n\n Sport brings out the best in individuals and in teams\nand in communities. I share the pride that Senator Mitchell and\nSenator Cohen and Congressman Andrews and all the people of Maine\nmust feel for the Black Bears who have shown us all how to play as a\nteam, how to bring out the best in one another, and how to come from\nbehind.\n\n I think it's important, as I ask young people from\naround America who have achieved outstanding things in working\ntogether, to come here to the White House to be recognized and\nappreciated by their country, to remember that those kinds of values\nand those kinds of virtues need to be ingrained in all of us for all\nof our lives.\n\n We now have another role model, and I'm glad to have\nthem here today. (Applause.)\n\n (The President is presented with team jersey.)\n(Applause.)\n\n THE PRESIDENT: That's great. I love it. It's beautiful.\n(Applause.)\n\n (The President is presented with an autographed stick.)\n\n THE PRESIDENT: Thank you. That's great. (Applause.)\n\n * * * * * *\n\n Q Mr. President, did you authorize the move on Waco\nthis morning, sir?\n\n THE PRESIDENT: I was aware of it. I think the Attorney\nGeneral made the decision. And I think I should refer all questions\nto her and to the FBI.\n\n Q Did you have any instructions for her as to how it\nshould be executed?\n\n THE PRESIDENT: No, they made the tactical decisions.\nThat was their judgment, the FBI.\n\n Q Is this a raid?\n\n THE PRESIDENT: And I will -- I want to refer you to --\ntalk to the Attorney General and the FBI. I knew it was going to be\ndone, but the decisions were entirely theirs, all the tactical\ndecisions.\n\n Q What did you and Senator Mitchell talk about this\nmorning?\n\n Q Any chance for that stimulus package?\n\n THE PRESIDENT: Senator Mitchell ought to pay my\nquarter. (Laughter.) I was in there -- (laughter).\n\n SENATOR MITCHELL: You have to pay that quarter.\n\n THE PRESIDENT: I was ready. (Laughter.) Senator\nMitchell, he's worth a quarter any day.\n\n Q Any chance for your bill, sir?\n\n THE PRESIDENT: We talked about what was going to happen\nthis week in the Senate and about what other meetings we're going to\nhave for the rest of the week. We only had about five minutes to\ntalk. And we agreed we'd get back together later, around noon, and\ntalk some more.\n\n Q Senator Dole said over the weekend that your\ncompromise is no compromise.\n\n THE PRESIDENT: Well, I know he did, but, look, Senator\nDole and a lot of the other Republicans now in the Senate voted for\nthe same kind of thing for Ronald Reagan in 1983; and our research\nindicates that a majority of them over time voted for a total of 28\nemergency spending measures totalling over $100 billion when Reagan\nand Bush were President, in those administrations. And many of those\npurposes were not nearly as worthy as putting the American people\nback to work. I don't want to go back and revisit every one, but you\n\n\ncan do it. You can look at the research there. So this position\nthey're taking is not credible. We have a very tough five-year\ndeficit reduction plan. All these costs are covered during that time\nand then some. And the very people that are saying this has all got\nto be paid for don't have much of a history on which to base their\nposition. They've got 12 years of vote for stimulus measures of this\nkind that had very little to with putting the American people back to\nwork. So I think we've got a chance to work it out, and I'm hopeful.\nWe'll see what happens today and tomorrow. I'm feeling pretty good\nabout it.\n\n THE PRESS: Thank you\n\n END 10:10 A.M. EDT\n\n -30-\n\n--\nCanada Remote Systems - Toronto, Ontario\n416-629-7000\/629-7044\n\n###\n\n","output":" hockey"} -{"input":"From: maynard@ramsey.cs.laurentian.ca (Roger Maynard)\nSubject: Re: Jack Morris\nOrganization: Dept. of Computer Science, Laurentian University, Sudbury, ON\nLines: 33\n\nIn <1993Apr19.024222.11181@newshub.ariel.yorku.ca> cs902043@ariel.yorku.ca (SHAWN LUDDINGTON) writes:\n\n>Hey Valentine, I don't see Boston with any world series rings on their\n>fingers. Damn, Morris now has three and probably the Hall of Fame in his \n>future. Therefore, I would have to say Toronto easily made the best \n>signing. And don't tell me Boston will win this year. They won't \n>even be in the top 4 in the division, more like 6th.\n\nYeah Valentine, how many rings does Clemens have? \n\nNothin' like good old fashioned Canadian logic...\n\nBTW: The only good thing I can say about the Jay's rotation this year\nis that it could have been worse. Stewart might have stayed healthy.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n-- \n\ncordially, as always, maynard@ramsey.cs.laurentian.ca \n \"So many morons...\nrm ...and so little time.\"\n\n###\n\n","output":" baseball"} -{"input":"From: tedward@cs.cornell.edu (Edward [Ted] Fischer)\nSubject: Re: Best Homeruns\nOrganization: Cornell Univ. CS Dept, Ithaca NY 14853\nLines: 18\n\nIn article <1qn6tqINNmnf@senator-bedfellow.MIT.EDU> cmk@athena.mit.edu (Charles M Kozierok) writes:\n>\n>the best home run i have *ever* seen came off, believe it or not,\n>Roger Clemens (sorry, Val) a couple of years ago. he threw a ball to\n>Incaviglia which was literally at Inky's neck, and he absolutely \n>hammered the crap out of it. after the swing, Clemens nonchalantly\n>motioned for a new ball--he didn't even turn around to look, or\n>even get upset. the ball hit the lights in the left-field standard,\n>some 70 or so feet about the Green Monster (over 100 feet above the\n>ground total!)\n>\n>truly an amazing shot.\n\nI agree. Home runs off Clemens are always memorable. Kinda like\neclipses and hurricanes. They don't happen very often.\n\nCheers,\n-Valentine\n\n###\n\n","output":" baseball"} -{"input":"From: niguma@ug.cs.dal.ca (Gord Niguma)\nSubject: Re: Notes on Jays vs. Indians Series\nNntp-Posting-Host: ug.cs.dal.ca\nOrganization: Math, Stats & CS, Dalhousie University, Halifax, NS, Canada\nDistribution: na\nLines: 22\n\nIn klopfens@andy.bgsu.edu (Bruce Klopfenstein) writes:\n\n>cmk@athena.mit.edu (Charles M Kozierok) writes:\n>> In article <1993Apr13.195301.22652@CSD-NewsHost.Stanford.EDU> nlu@Xenon.Stanford.EDU (Nelson Lu) writes:\n>> } \n>> } Guess which line is which:\n>> } \tBA\tOBP\tSLG\tAB\tH\t2B\t3B\tHR\tBB\n>> } X\t.310\t.405\t.427\t571\t177\t27\t8\t8\t87\n>> } Y\t.312\t.354\t.455\t657\t205\t32\t1\t20\t35\n\n\n>I just love how the Alomar fans left RBIs off this list. Give me a break!\n\n Alomar fans left RBI fans and Runs off this list because they are dependant\non the team. (To a large extent). If Frank Thomas hit first, he'd lose a LOT\nof RBI's; and anyways how many 2nd place hitters have you known to drive\nin 100 runs? Doesn't happen that often.....very unlikely with Devon White's\n~.300 OBP in front of you...\n\n\t\t\t\t\t\tGord Niguma\n\t\t\t\t\t\t(fav player: John Olerud)\n\n###\n\n","output":" baseball"} -{"input":"From: tedward@cs.cornell.edu (Edward [Ted] Fischer)\nSubject: Re: Notes on Jays vs. Indians Series\nOrganization: Cornell Univ. CS Dept, Ithaca NY 14853\nDistribution: na\nLines: 21\n\nIn article <1993Apr15.212014.1782@news.acns.nwu.edu> edo@casbah.acns.nwu.edu (Edward Ouellette) writes:\n>\n>My point? RBI might not be a perfect stat but nothing is. And no stat (or lack\n>of) can tell me there are no clutch hitters. Maybe no stat CAN tell me,\n>either, but some people are... I just know it!!! 8)\n\nI was *hoping* somebody would mention clutch. Clutch? Baerga? The\ntwo words simply do not go together. With runners in scoring\nposition, Baerga batted .308\/.366\/.418 last year. This doesn't quite\n*suck*, but most batters hit *better* in this situation.\n\nAlomar? He hit .354\/.439\/.517 with runners in scoring position!\n\nThe difference? Alomar had 68 RBIs in 147 such AB. Baerga had 81\nRBIs in 182 such AB. Baerga got 25% more chances, yet succeeded only\n20% more times.\n\nFrankly, I don't believe in clutch. But if I did, my vote would\ngo to Alomar for MVP (let alone \"best 2B in the AL\").\n\n-Valentine\n\n###\n\n","output":" baseball"} -{"input":"From: pereira@CAM.ORG (Dean Pereira)\nSubject: Canadiens - another Stanley Cup???\nOrganization: Champlain Regional College, St-Lambert QC CANADA\nLines: 12\n\n\n\t\tWith the kind of team Montreal has now, they can take the\ncup easily. The only problem they have right now is that everyone is\ntrying to steal the show and play alone. They need some massive teamwork.\n\tThey are also in a little of a slump because long-time hockey\nMontreal Canadiens announcer Claude Mouton died last tuesday and it was\nrough on everybody because he has worked with the organization for 21\nyears. But I know that is no excuse. But if the Habs manage to get some\ngood teamwork and get into the spirit, they should have no problem\nwinning in May.\n\n\t\t\t\t\t\tDean\n\n###\n\n","output":" hockey"} -{"input":"From: golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy)\nSubject: Re: RUMOUR - Keenan signs with Rangers?\nOrganization: University of Toronto Chemistry Department\nLines: 22\n\nIn article <1993Apr16.171347.784@news.columbia.edu> gld@cunixb.cc.columbia.edu (Gary L Dare) writes:\n>\n>UPI Clarinet has just relayed a \"scoop\" from the Toronto Sun\n>(or was that Star? I like the Star myself ...) that Iron Mike\n>Keenan has come to an agreement with the New York Rangers for\n>next season. Interestingly, this comes the day after the Times\n>Sports had an editorial about how the Rangers need their own\n>Pat Riley ... who cares about what happens after next season?\n>\n\nThe rumour was basically everywhere in Toronto based on reports\nthat Keenan has told both San Jose and Philadelphia that he\nwas no longer interested in pursuing further negotiations with\neither team. \n\nThe Ranger announcement is supposed to happen tomorrow supposedly.\n\nThe Rangers have so many veterans that they had to get a coach\nwith \"weight\" and a proven record...and whom they know Messier respects.\n\nGerald\n\n###\n\n","output":" hockey"} -{"input":"From: darling@cellar.org (Thomas Darling)\nSubject: Re: WHERE ARE THE DOUBTERS NOW? HMM?\nOrganization: The Cellar BBS and public access system\nLines: 18\n\njason@studsys.mscs.mu.edu (Jason Hanson) writes:\n\n> In article <1993Apr4.051942.27095@ramsey.cs.laurentian.ca> maynard@ramsey.cs.\n> >\n> >And after the Leafs make cream cheese of the Philadelphia side tomorrow\n> >night the Leafs will be without equal.\n> \n> Then again, maybe not.\n\nTo put it mildly. As I watched the Flyers demolish Toronto last night, 4-0,\nI realized that no matter how good the Leafs' #1 line may be, they'll need\none or two more decent lines to go far in the playoffs. And, of course, a\nhealthy Felix Potvin.\n\n^~^~^~^~^~^~^~^~^\\\\\\^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^\nThomas A. Darling \\\\\\ The Cellar BBS & Public Access System: 215.539.3043\ndarling@cellar.org \\\\\\ GEnie: T.DARLING \\\\ FactHQ \"Truth Thru Technology\"\nv~v~v~v~v~v~v~v~v~v~\\\\\\~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v~v\n\n###\n\n","output":" hockey"} -{"input":"From: layfield@cpsc.ucalgary.ca (Colin Layfield)\nSubject: Re: Smiths birthday goal was LEAFS GO ALL THE WAY !!!\nOrganization: University of Calgary Computer Science\nLines: 23\n\nIn article mwm@aps.anl.gov writes:\n>In article 5KL@undergrad.math.uwaterloo.ca, kwk2chow@descartes.uwaterloo.ca (KEVIN C.) writes:\n>> (Thanks for the goals by Steve Smith) \n>I don't see why more people don't blame grant fuhr for the goal that smith \n>put in his own net, it's common to play the puck back to your own goalie when\n>deep in your own end and under little or no pressure from the offensive team.\n>If fuhr had been in position the puck would have never crossed the line.\n>\n>Mike McDowell\n\nI have to disagree with you on this one. It is anything BUT common. In the\n4 or 5 years I have been watching hockey I have NEVER seen this happen EVER.\n\nI am not sure what league you have been watching. :-)\n\nAnyone else agree with this?\n\n Colin Layfield | \"Religion and Sex are power plays,\n | Manipulate the people for the money they pay,\n The University of Calgary | Selling Skin, Selling God\n Computer Science | The numbers look the same on their CREDIT CARDS!\"\n layfield@cpsc.ucalgary.ca | - Queensryche\n\n###\n\n","output":" hockey"} -{"input":"From: dchhabra@stpl.ists.ca (Deepak Chhabra)\nSubject: Re: div. and conf. names\nNntp-Posting-Host: stpl.ists.ca\nOrganization: Solar Terresterial Physics Laboratory, ISTS\nDistribution: na\nLines: 56\n\nIn article <1993Apr19.003221.11964@ramsey.cs.laurentian.ca> maynard@ramsey.cs.laurentian.ca (Roger Maynard) writes:\n[Evan Pritchard writes:]\n\n>>\tI think that you are incorrect, Roger. Patrick,\n>>Smythe and Adams all played or coached in the league before becoming\n>>front office types. Hence, they did help build the league, although\n>>they were not great players themselves. \n>\n>Punch Imlach's contributions as a coach and GM were far greater than\n>those of the above combined. Should we name a division or trophy after\n>him? [owner vs. player contributions deleted...]\n>Are we going to honour those who contributed to the league's evolution\n>or are we going to honour those who contributed to the glory of the \n>sport itself? \n\n[stuff deleted...]\n\n>The money issue is irrelevant to the point that we would agree on, and\n>that is: \"it is the players that are what make the game great and not the\n>people who put them on the ice\"\n \nAs I recall, the author of the _original_ article that started the thread\nclaimed that he disliked the changing of the names for a variety of reasons. \nRoger, on one front you flamed him rather severely on the grounds that his\nwas a \"jingoistic rant\", but you also supported the name-changing on the\ngrounds that the current names are inappropriate because of the individuals\nthey represent. FWIW, I do not think the flaming was warranted, nor do I \nthink you enhanced what credibility you have with it at all. Just an \nobservation...\n\nHowever, that aside, the real question is whether you like the idea of\nchanging the names based on the reasons given for it (making it easier for\nthe 'casual fan'), or whether you like the idea of unique divisional names\nbased on individuals who do deserve the honour. IMO, the latter is a nice\nand unique touch that differs from other sports. In addition, I do not\nthink that changing divisional names will have an effect on the number of\npeople that are interested in hockey, so it's a pointless exercise anyway.\n\nIf the current names are inappropriate, then that is a separate issue, not \ncentral to the original article. Something to consider additionally is\nwhether or not players like Orr who 'contributed to the glory of the sport'\nwould have been able to do so _without_ an organized professional league to\nplay in. In this case, honouring builders of the _league_ as opposed to\nbuilders of the _sport_ becomes a chicken-and-egg type question. (although\nit was the chicken.....)\n\n>Exactly true. Naming divisions and trophies after Smythe and the bunch\n>is the same kind of nepotism that put Stein in the hall of fame. I have\n>always thought that this was nonsense.\n\nDunno if the Stein comparison is justifiable, since it doesn't look as though\nhis 'unanimous acceptance' to the Hall will hold up.\n\n\n--\ndchhabra@stpl.ists.ca\n\n###\n\n","output":" hockey"} -{"input":"From: tvartiai@vipunen.hut.fi (Tommi Vartiainen)\nSubject: Re: TPS will stay on the top...\nNntp-Posting-Host: vipunen.hut.fi\nOrganization: Helsinki University of Technology, Finland\nLines: 15\n\nIn <1993Apr6.171611.1@tnclus.tele.nokia.fi> hahietanen@tnclus.tele.nokia.fi writes:\n>BTW. Is Juha Yl|nen (centre, HPK) drafted by the Jets?? During last year\n>he has reached the top level among Finnish centres. He had very good\n>playoff games against TPS!\n\nI'm not sure about Juha, but another top center, Rauli Raitanen([ss{t)\nis drafted by Jets. Raitanen had very good year and he has played in the\nFinnish nationalteam. I believe that he'll be one of the best finns in\nthis year's WC, if Matikainen(Head coach) elects him to the team.\n\n> Hannu\n\n Tommi\n\n###\n\n","output":" hockey"} -{"input":"From: ferguson@cs.rochester.edu (George Ferguson)\nSubject: Re: ABC coverage\nReply-To: ferguson@cs.rochester.edu (George Ferguson)\nOrganization: University of Rochester Hockey Science Dept.\nDistribution: usa\n\n\nIn article Anna Matyas writes:\n>Thorne is good and I've always been a fan of Clement (but I miss\n>Mike Emrick!). My boyfriend, who is not a hockey fan, even looked up\n>at one point and said, \"These guys are pretty good announcers.\" (This\n>is the same guy who said that Rick Tocchet looks like Charles Bronson...:)\n\nDid your boyfriend comment on the fact that Clement looks like a\nwalking ad for Brillo pad hair replacement therapy? The guy's just a\nstuffed shirt who thinks he's the greatest hockey analyst since Howie\nMeeker (for gosh sakes). I'll take Schoenie any day.\n\nGeorge\n\n-- \nGeorge Ferguson ARPA: ferguson@cs.rochester.edu\nDept. of Computer Science UUCP: rutgers!rochester!ferguson\nUniversity of Rochester VOX: (716) 275-2527\nRochester NY 14627-0226 FAX: (716) 461-2018\n\n###\n\n","output":" hockey"} -{"input":"From: gld@cunixb.cc.columbia.edu (Gary L Dare)\nSubject: Re: The guy who bad-mouthed Ulf...\nNntp-Posting-Host: cunixb.cc.columbia.edu\nReply-To: gld@cunixb.cc.columbia.edu (Gary L Dare)\nOrganization: PhDs In The Hall\nLines: 14\n\nPatrick Walker writes:\n>\n>If he ever tried some like that on a Yzerman, he'd \n>would have to deal with Probert now wouldn't he?\n\nDo you realize how many smiles are crossing faces after you wrote that?\n(-;\n\ngld\n--\n~~~~~~~~~~~~~~~~~~~~~~~~ Je me souviens ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGary L. Dare\n> gld@columbia.EDU \t\t\tGO Winnipeg Jets GO!!!\n> gld@cunixc.BITNET\t\t\tSelanne + Domi ==> Stanley\n\n###\n\n","output":" hockey"} -{"input":"From: binkley@let.rug.nl (P.A. Binkley)\nSubject: Re: Jewish Baseball Players?\nLines: 7\nNntp-Posting-Host: pco204a.let.rug.nl\nOrganization: Faculteit der Letteren, Rijksuniversiteit Groningen, NL\n\nThere was an article on Jewish major leaguers in a recent issue of \"Elysian \nFields\", what used to be the \"Minnesota Review of Baseball\". As I recall, \nit had an amazing amount of research, with a long list of players and a \nlarge bibliography.\n\nPeter Binkley\nbinkley@let.rug.nl\n\n###\n\n","output":" baseball"} -{"input":"From: hamlet@stein.u.washington.edu (Mitch McGowan)\nSubject: Minnesota recalls McGowan (HELP!!!)\nOrganization: University of Washington\nLines: 24\nNNTP-Posting-Host: stein.u.washington.edu\n\n Derian Hatcher's game-misconduct penalty was rescinded by the NHL, \nallowing the Minnesota defenseman to play in the North Stars' last two \nregular-season games. Hatcher was given the penalty during a fight at \nthe end of a loss at St. Louis on Sunday, April 11. But the league \ndidn't rescind the game-misconduct penalty Shane Churla received. The \nStars recalled center Cal McGowan from their top minor league club in \nKalamazoo, Mich., to replace Churla.\n\nThe above is courtesy of The Washington Times on-line service.\n\nNow, here's where I need help. If anyone out there has a tape of Tuesday's\nChicago-Minnesota game, please contact me. Terms will be favorable.\n\nAlso, if anyone can tape tonight's Minnesota-Detroit game, please contact\nme. This could be quite important. Once again, I will make it worth\nyour trouble.\n\nThanks to all.\n\n--\nrec.sport.hockey contact for Minnesota North Stars\nand maintainer of the r.s.h FAQ file\nMitch McGowan a.k.a. | KALAMAZOO WINGS | MINNESOTA NORTH STARS |\nhamlet@u.washington.edu | ST. KILDA SAINTS | TORONTO BLUE JAYS |\n\n###\n\n","output":" hockey"} -{"input":"From: st902415@pip.cc.brandeis.edu (Adam Levin)\nSubject: Early BBDDD Returns?\nReply-To: st902415@pip.cc.brandeis.edu\nOrganization: Brandeis University\nLines: 13\n\nJust curious if anyone has started to standout early in the season in the\nBB DDD this year. I expect the Phillies staff, while getting the wins,\nwould have to rank up there. Luis Gonzalez and Derrick May are among\nthe early league leaders, and all 6 of their bombs have come at the\nPhils' expense. Neither of them have exactly been know for their tater\nprowess in the past. \n\nHow have the Rockies been early? I know Mile High has produced a ton of \nruns, but is it the launching pad everyone expected yet? \n\nA concerned fan of the BB DDD,\n\nAdam \"Witness to the Phillies lone loss of the season so far\" Levin\n\n###\n\n","output":" baseball"} -{"input":"From: andrew@idacom.hp.com (Andrew Scott)\nSubject: Re: This year's biggest and worst (opinion)...\nOrganization: IDACOM, A division of Hewlett-Packard\nKeywords: NHL, awards\nLines: 35\n\nIn article smale@healthy.uwaterloo.ca (Bryan Smale) writes:\n>\n>I was thinking about who on each of the teams were the MVPs, biggest\n>surprises, and biggest disappointments this year. Now, these are just\n>my observations and are admittedly lacking because I have not had an\n>opportunity to see all the teams the same amount. Anyway....\n> \n>Team: MVP: Surprise: Disappointment:\n>-----------------------------------------------------------------------\n>Edmonton Oilers Manson Buchberger Mellanby\n\nWell, since the Oilers didn't win a heck of a lot of games, I'm not sure\nthey deserve and MVP (\"can't win without him\"). However, I'd suggest Kelly\nBuchberger instead of Dave Manson, who has had a brutal year, his pick for\nthe All-Star game notwithstanding.\n\nAs for biggest surprise, I'd say that Buchberger had higher expectations\nthis year due to his \"breakthrough\" year (for him) last year, so he didn't\nreally raise his game. My suggestion would be Shjon Podein, one of the\ncallups from Cape Breton during the year. He was quite far down on the\ndepth chart in the Oilers stable of prospects, but made a big impact on\nthe team. He has 12 goals in his 33 games and is only -1. Those are decent\nnumbers for a third-line player who was seemingly doomed to minor-league\noblivion. The Oilers coaching staff likens his style to John Tonelli.\nI think he'll be on the full-time roster next year.\n\nAs for biggest disappointment, you could name any of the players the Oilers\ndumped for lousy production this year (Nicholls, Gilchrist, Tikkanen) or\neven Shayne Corson, but Mellanby isn't far off.\n\n-- \nAndrew Scott | andrew@idacom.hp.com\nHP IDACOM Telecom Division | (403) 462-0666 ext. 253\n\nDuring the Roman Era, 28 was considered old...\n\n###\n\n","output":" hockey"} -{"input":"From: snichols@adobe.com (Sherri Nichols)\nSubject: Re: Why Spanky?\nOrganization: Adobe Systems Incorporated\nLines: 18\n\nIn article <1ql93bINN1s5@postoffice1.psc.edu> boone@psc.edu (Jon Boone) writes:\n> Spanky is too slow! If he were quicker, he would still be here.\n>But with Slaught and Tom Prince, they didn't want to lose Prince in order\n>to bring up that 11th pitcher. Slaught is about as good as Spanky and\n>Prince is coming along nicely!\n\nTom Prince is a 28 year old no-hit catcher. Think of him as a young Dann\nBilardello. I can't begin to fathom why the Pirates have been so afraid of\nlosing this guy, who's been in AAA most of the last 5 seasons. The Pirates\nreleased Kirk Gibson last year because Prince was out of options, then\neventually sent Prince down anyway, and he cleared waivers without a peep.\nHe's another year older, and still can't hit; why do they think he wouldn't\nclear waivers now? Why would they care?\n\nSherri Nichols\nsnichols@adobe.com\n\n###\n\n","output":" baseball"} -{"input":"From: dswartz@osf.org (Dan Swartzendruber)\nSubject: Re: Best Homeruns\nOrganization: Open Software Foundation - Research Institute\nLines: 16\n\nIn article <4200419@hpcc01.corp.hp.com> boell@hpcc01.corp.hp.com (Donald P Boell) writes:\n>I'd have to say the most impressive HRs I've ever see came from Dave Kingman\n>and his infamous moon-raker drives...\n\nI remember one he hit circa 1976 at Wrigley Field that went across\nthe street (in dead center field) and hit a house on the roof. He\nwhiffed a lot, but when he *did* connect, watch out!\n\n\n\n\n-- \n\n#include \n\nDan S.\n\n###\n\n","output":" baseball"} -{"input":"From: u96_msopher@vaxc.stevens-tech.edu\nSubject: With a surge in the last two weeks...\nLines: 24\nOrganization: Stevens Institute Of Technology\n\n\n\n\nLadies and gentlemen, boys and girls, lend me your ears for but a moment,\n\n\n\n\tThe National Legue Eastern Division Champions will be the...\n\n\n\n \t\t\tPhiladelphia Phillies\n\n\n\t\tI one hundred and ten percent guarantee!!!\n\n\n\n\tChamberlain Hollins Dykstra Incaviglia Jackson Williams\n\tDaulton Greene Kruk Mulholland Rivera Thompson Duncan\n\n\n\t\t\tWatch us soar in 1993!\n\n###\n\n","output":" baseball"} -{"input":"From: jimg@cybernet.cse.fau.edu (Jim Gorycki)\nSubject: Panther's President\nOrganization: Cybernet BBS, Boca Raton, Florida\nLines: 46\n\nAs I promised, I would give you the name of the Panther's president.\nAfter Huizenga announced the team name, he announced that Bill\nTorrey is named the first president of the Panthers.\n\nA little Bio from _Sun-Sentinel_\nTorrey, the architect of four consecutive Stanley Cup champions as \npersident and general manager of the New York Islanders.\nThroughout his 27 years in the NHL, Bill Torrey's bow ties have become\nas much of a signature as Andre Agassi's hair.\n\nThe Panthers will introduce a uniform, insignia, and ticket-price \ninformation in early next month. In the meantime, Huizenga leaves the\nday-to-day operation in the hands of Torrey and Bob Clarke, the VP and\nGM.\n\nThe Florida Panthers was chosen as the name of South Florida's NHL team\nto focus attention on an endangered species. There are 30 to 50 Florida\nPanthers in the Everglades National Park, the Big Cypress National \nPreserve and other parts of southwestern Florida.\n\n\"The Panther is the quickest-striking of all cats,\" Torrey said. \n\"Hopefully that's the way we'll play on ice.\"\n\nMore BIO:\nIn Torrey, Huizenga has the first man hired by the expansion Islanders\nin 1972 and the one most responsible for guiding the Islanders to four\nconsecutive Stanley Cup championships (their first after only eight\nseasons) and 14 consecutive winning seasons. As executive vice president\nof the California Golden Seals, Torrey watched the Seals go to the play-\noffs in 1968, only their second NHL season.\n\n\"I guess this completes my own personal hat trick\", said Torrey, 58, a\nnative of Montreal but a resident of Bear Lakes Country Club in Palm\nBeach.\n\nJim G.\nother accounts:\ngorycki@sol.cse.fau.edu\njimg@cybernet.cse.fau.edu\n\n--------------------------------------------------------------------\n\"I repeat myself when under stress. I repeat myself when under stress.\nI repeat myself when under stress. I repeat myself when under stress.\nI repeat...\" Adrian Belew, \"Indicipline\"\n---------------------------------------------------------------------\n\n###\n\n","output":" hockey"} -{"input":"From: cubrj@uxa.ecn.bgu.edu (Brian Johnson)\nSubject: the hawks WILL return to the finals!!!!!\nOrganization: Educational Computing Network\nLines: 11\nDistribution: world\nNNTP-Posting-Host: uxa.ecn.bgu.edu\n\nWell now that the hawks have won the division the road is a little\neasier for the playoffs. Let toronto and detroit beat the hell out of\neach other while Chicago sweeps st.louis. That just makes it easier in\nthe second round with all the rest they will get and tor\/det getting\nnone. For the conf. champ they will have a hard time versus the division\nbut that div. will be pretty battered also so the advantage goes to the\nHawks again. Then bring pitt. and sure the Hawks will probably lose but\nits better to get that far and lose than to not go.\n\nbrian\n\n###\n\n","output":" hockey"} -{"input":"From: maynard@ramsey.cs.laurentian.ca (Roger Maynard)\nSubject: Re: hawks vs leafs lastnight\nOrganization: Dept. of Computer Science, Laurentian University, Sudbury, ON\nDistribution: na\nLines: 33\n\nIn <1993Apr18.153820.10118@alchemy.chem.utoronto.ca> golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy) writes:\n\n>In article <93106.082502ACPS6992@RyeVm.Ryerson.Ca> Raj Ramnarace writes:\n>>did anyone else see this game last night ? just like a playoff game!!\n>>lots of hitting...but I was disappointed by the video goal judge...\n>>on all replays, joe murphy's goal shouldn't have counted ! it didn't go in net\n>>!! and according to the tsn broadcasters, the video goal judge said that he\n>>saw the water bottle on top of the cage move so he assumed the puck went in!\n>>this is terrible...hope crap like this doesn't occur in the playoffs!\n>>the game would have ended in 2-2 tie !\n\n>I thought the red light went on...thus, in the review, the presumption\n>would be to find conclusive evidence that the puck did not go in the\n>net...from the replays I say, even from the rear, the evidence wasn't\n>conclusive that the puck was in or out...in my opinion...\n\nIt seemed pretty conclusive to me. The puck clearly hit the crossbar\nand then came down on the line. And the announcers, admittedly homers,\nkept harping about how they \"must have had a different view upstairs\"\nbecause it was obvious to them, and, I would have thought, to anyone who\nsaw the replay, that the puck didn't go in. The referee originally \nsignalled no goal but the video replay \"judges\" initiated contact with\nthe referee to claim that a goal was in fact scored. This, to me, is\nunheard of. Seeing stuff like this happen gives me a bad feeling about\nthe Leaf chances this year.\n\ncordially, as always,\n\nrm\n\n-- \nRoger Maynard \nmaynard@ramsey.cs.laurentian.ca\n\n###\n\n","output":" hockey"} -{"input":"Organization: University of Notre Dame - Office of Univ. Computing\nFrom: \nSubject: Re: Boog Powell (was re: CAMDEN YARDS)\n <1993Apr13.150904.25249@alchemy.chem.utoronto.ca>\nLines: 9\n\nIn article <1993Apr13.150904.25249@alchemy.chem.utoronto.ca>, Mark B. says:\n>\n> Was he better than Balboni?\n>\n\nthis borders on blasphemy.\n\nbob vesterman.\n\n###\n\n","output":" baseball"} -{"input":"From: v124p7kk@ubvmsc.cc.buffalo.edu (Darryl S Brooks)\nSubject: Re: Too Many Europeans in NHL (Euro-bashing?)\nOrganization: University at Buffalo\nLines: 60\nNews-Software: VAX\/VMS VNEWS 1.41\nNntp-Posting-Host: ubvmsc.cc.buffalo.edu\n\nIn article , rauser@fraser.sfu.ca (Richard John Rauser) writes...\n> \n> \n> Here's the point: there are far too many Europeans in the NHL. I am sick\n>of watching a game between an American and a Canadian team (let's say, the\n>Red Wings and the Canucks) and seeing names like \"Bure\" \"Konstantinov\" and\n>\"Borshevshky\". Is this North America or isn't it? Toronto, Detriot, Quebec,\n>and Edmonton are particularly annoying, but the numbers of Euros on other\n>teams is getting worse as well. \n> \n> I live in Vancouver and if I hear one more word about \"Pavel Bure, the\n>Russian Rocket\" I will completely throw up. As it is now, every time I see\n>the Canucks play I keep hoping someone will cross-check Bure into the plexiglassso hard they have to carry him out on a stretcher. (By the way, I'm not a\n>Canucks fan to begin with ;-). \n> \n> Okay, the stretcher remark was a little carried away. But the point is that\n>I resent NHL owners drafting all these Europeans INSTEAD of Canadians (and\n>some Americans). It denies young Canadians the opportunity to play in THEIR\n>NORTH AMERICAN LEAGUE and instead gives it to Europeans, who aren't even\n>better hockey players. It's all hype. This \"European mystique\" is sickening,\n>but until NHL owners get over it, Canadian and American players will continue\n>to have to fight harder to get drafted into their own league.\n> \n> With the numbers of Euros in the NHL escalating, the problem is clearly\n>only getting worse.\n> \n> I'm all for the creation of a European Hockey League, and let the Bures\n>and Selannes of the world play on their own continent.\n> \n> I just don't want them on mine.\n> \n> \n\tAh, so now we're into European player bashing? What next? \nNo more French Canadiens? Yeah, there's an idea! Let them French-\nspeaking Canadiens have their own hockey league! We don't want them!\n\tAre you _CRAZY_? The NHL is one of the true international\nleagues, and yes, there _ARE_ many Europeans who deserve to play in\nthe NHL and are better than some North Americans, look at Teemu!!!\nI, for one, am glad to see Europeans in the NHL and I hope the\nNHL soon expands to Europe. Its nice to see all these different\npeople come together to form the (soon to be) 26 hockey teams.\n\t\n> \n> \n>-- \n>Richard J. Rauser \"You have no idea what you're doing.\"\n>rauser@sfu.ca \"Oh, don't worry about that. We're professional\n>WNI outlaws - we do this for a living.\"\n>-----------------\n>\"Remember, no matter where you go, there you are.\" -Dr.Banzai\n\nDarryl Brooks University at Buffalo\n __ ______ \/\/\/\n | | \/ \\ \\ \\ \/ \/ \/ _____ \/ \/ \/\/\/\/\n | | \/ \/\\ \\ \\ \\___\/ \/ ( \\ ---\/-\/--- \/\/\/\n | | \/ \/__\\ \\ \\ \/ \\ \\ ---\/-\/--- \/\/\/\n| |____| | \/ ____ \\ | | ____\\ ) \/ \/ \/\/\/\n \\______\/ \/ \/ \\ \\ | | ______\/ \/\/\/\/\/\/\/\n\n Go Bills, Sabres, and Magic!!\n\n###\n\n","output":" hockey"} -{"input":"From: tedward@cs.cornell.edu (Edward [Ted] Fischer)\nSubject: Re: Defensive Averages 1988-1992 -- Shortstop\nOrganization: Cornell Univ. CS Dept, Ithaca NY 14853\nLines: 13\n\nIn article <1993Apr17.200602.8229@leland.Stanford.EDU> addison@leland.Stanford.EDU (Brett Rogers) writes:\n>In article steph@pegasus.cs.uiuc.edu (Dale Stephenson) writes:\n>>>Smith, Ozzie .742 .717 .697 .672 .664 0.701\n>> The Wizard's 1988 is the second highest year ever. Still very good,\n>>but I don't like the way his numbers have declined every year. In a few\n>>years may be a defensive liability.\n>\n>That's rich... Ozzie Smith a defensive liability...\n\nWhy not? Brooks Robinson is a defensive liability too, and Ted\nWilliams is a weak hitter. Even great players decline as they age.\n\n-Valentine\n\n###\n\n","output":" baseball"} -{"input":"From: luriem@alleg.edu The Liberalizer (Michael Lurie)\nSubject: Yankee Meditations.\nArticle-I.D.: alleg.1993Apr6.205911.2654\nOrganization: Allegheny College\nLines: 14\n\n\nDo you realize that the yankees are paying Matt Nokes 2,500,000 dollars \nthis year!!!! GEESH. And Maas only gets 125,000. \n\n\n\nBy the way, the yankees are going to WIN IT ALL\n\n\nYankees are the BEST.\n\n\n\nBy the way, JT Snow, an ex-yankee, will be rookie of the year.\n\n###\n\n","output":" baseball"} -{"input":"From: bbs-comarow@jwt.oau.org (Bob Comarow)\nSubject: Re: Jewish Baseball Players?\nReply-To: bbs-comarow@jwt.oau.org\nOrganization: The Matrix\nLines: 4\n\nDave Kingman is Jewish\n\nbob\ncomarow@eisner.decus.org\n\n###\n\n","output":" baseball"} -{"input":"Subject: Re: Players Rushed to Majors\nFrom: admiral@jhunix.hcf.jhu.edu (Steve C Liu)\nExpires: 5\/9\/93\nDistribution: usa\nOrganization: Homewood Academic Computing, Johns Hopkins University, Baltimore, Md, USA\nSummary: Big Ben\nNNTP-Posting-Host: jhunix.hcf.jhu.edu\nLines: 25\n\nI don't know if you could call him rushed, but \"Big\" Ben McDonald didn't\nmuch time at all in the minors. Of course that was because the balls used\nin AAA had seams too large and gave McDonald blisters forcing him to go\non the DL several times. He's done most of his learning here in the majors.\nOf course Gregg \"Wild Thing\" Olson and Mike \"Deserved a Cy Young\" Mussina\ndidn't spend much time in the minors either. I read somewhere that pitchers\nare less likely to need that much time in the minors anyway so maybe that\nhas something to do with it.\nLet's go O's! Why Not?\nAdmiral Steve \"Still reliving Sept. 30, 1989\" Liu\n____________________________________________________________________________\n|Admiral Steve C. Liu Internet Address: admiral@jhunix.hcf.jhu.edu|\n|Commander-In-Chief of the Security Division of the Pi Club - Earth Chapter|\n| President of the Earth Chapter of the Pi Club - Founded April 1990 |\n|1993 World Champions - Baltimore Orioles - Why Not? - Series in the Yards|\n| 1992-1993 Stanley Cup Champions - Washington Capitals |\n| \"Committee for the Liberation and Intergration of Terrifying Organisms |\n| and their Rehabilitation Into Society, the only problem is that the |\n| abbreviation is CLITORIS.\" from the \"Polymorph\" episode of Red Dwarf |\n|*****The Bangles are the greatest female rock band that ever existed!*****|\n| This sig has been brought to you by... Frungy! The Sport of Kings! |\n|\"My God man, drilling holes through his head is not the answer!\" Dr. McCoy|\n|\"You know, Susanna Hoffs has a really nice ass.\" - comment by M. Flanagan |\n| The Pi Club - Creating the largest .signatures for the past nine months | \n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n###\n\n","output":" baseball"} -{"input":"From: Eastgate@world.std.com (Mark Bernstein)\nSubject: Jewish Broadcasters (was Jewish Baseball Players?)\nOrganization: The World Public Access UNIX, Brookline, MA\nLines: 8\n\nFor that matter, how many Gentleman of The Press Box have been Jewish? The\nonly Jewish sportscaster that comes to mind is Steve Williams (?), who had\na Phillies show on KYW in Philadelphia in the 80s.\n-- \nMark Bernstein\nEastgate Systems, Inc. 134 Main Street Watertown MA 02172 USA\nvoice: (800) 562-1638 in USA +1(617) 924-9044\nEastgate@world.std.com Compuserve: 76146,262 AppleLink:Eastgate\n\n###\n\n","output":" baseball"} -{"input":"From: gballent@hudson.UVic.CA (Greg Ballentine)\nSubject: Re: Wings will win\nNntp-Posting-Host: hudson.uvic.ca\nReply-To: gballent@hudson.UVic.CA\nOrganization: University of Victoria, Victoria, BC, Canada\nLines: 25\n\n\nIn article 735249453@vela.acs.oakland.edu, ragraca@vela.acs.oakland.edu (Randy A. Graca) writes:\n\n>I also think that they will have a hard time with Pittsburgh if they\n>face them in the finals (which is what all the Detroit sportswriters \n>are predicting). Although I think Bryan Murray is probably the best GM\n>I have ever seen in hockey\n\nHow do you figure that?? When Bryan Murray took over the Wings they were\na pretty good team that was contending for the Stanley Cup but looked\nunlikely to win it. Now they are a pretty good team that is contending for\nthe Stanley Cup but looks unlikely to win it. A truly great GM would\nhave been able to make the moves to push the team to the upper echelon\nof the NHL and maybe win the Stanley Cup. A good GM (like Murray) can\nmaintain the team's success but can't push them to the next level.\n\nIn the history of hockey there have been several better GM's than Murray-\nway too many to name. Murray isn't even the best GM in the league today.\nHe fails in comparison to Sinden, Sather, Savard, Caron, Fletcher and\nQuinn in my estimation.\n\nI can't imagine how Bryan Murray can be the best GM anyone has ever seen\nin hockey- unless they have seen VERY few GM's.\n\nGregmeister\n\n###\n\n","output":" hockey"} -{"input":"From: schaefer@owlnet.rice.edu (Andrew James Schaefer)\nSubject: Re: Best Sportwriters...\nKeywords: Sportswriters\nOrganization: Rice University\nLines: 31\n\nIn article rkoffler@ux4.cso.uiuc.edu (Bighelmet) writes:\n>csc2imd@cabell.vcu.edu (Ian M. Derby) writes:\n>\n>\n>>Since someone brought up sports radio, howabout sportswriting???\n>\n>I happen to be a big fan of Jayson Stark. He is a baseball writer for the \n>Philadelphia Inquirer. Every tuesday he writes a \"Week in Review\" column. \n>He writes about unusual situations that occured during the week. Unusual\n>stats. He has a section called \"Kinerisms of the Week\" which are stupid\n>lines by Mets brodcaster Ralph Kiner. Every year he has the LGTGAH contest.\n>That stands for \"Last guy to get a hit.\" He also writes for Baseball \n>America. That column is sort of a highlights of \"Week in Review.\" If you \n>can, check his column out sometime. He might make you laugh.\n>\n>Rob Koffler\n\nIsn't Stark that idiot who writes in Baseball America? Twice a month he\nwrites a \"Who woulda thunk it\" article which is really the same piece\nevery time. \"Who would have thought that [Buddy Biancalana] would have\nmore home runs than [the Colorado Rockies, Babe Ruth, Omar Vizquel and\nNolan Ryan] COMBINED!\" He's an idiot, if it's the same guy.\n\n>\n>-- \n>******************************************************************\n>|You live day to day and rkoffler@ux4.cso.uiuc.edu|\n>|dream about tomorrow --Don Henley |\n>******************************************************************\n\nAndrew\n\n###\n\n","output":" baseball"} -{"input":"From: brucek@Ingres.COM (Bruce Kleinman)\nSubject: Re: Best record ever in baseball\nArticle-I.D.: pony.1993Apr6.195932.20451\nDistribution: usa\nOrganization: Ingres Corporation, A subsidiary of The ASK Group, Inc.\nLines: 5\n\nIn article <1psl0jINNam3@jhunix.hcf.jhu.edu> admiral@jhunix.hcf.jhu.edu (Steve C Liu) writes:\n>Of all teams, I believe the Cubs have the best record ever in baseball.\n>Sometime way far back. 110+ and something.\n\nI think it was the 1954 Cleveland Indians with 111.\n\n###\n\n","output":" baseball"} -{"input":"From: golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy)\nSubject: Re: Daigle\/Kariya\nOrganization: University of Toronto Chemistry Department\nLines: 15\n\nIn article <1qsmhtINNt5l@senator-bedfellow.MIT.EDU> ddlin@athena.mit.edu (David D Lin) writes:\n>I hear Daigle will eb the first pick next year. What is the word on Kariya???\n>Anybody ever seen him play on TV???? Is he also entering the draft???\n\nPeople are seeming to be less concerned about Kariya's size as he leads\nteams to championships (World Junior and US College) and collects\nawards...everyone is watching with interest as to how he will perform\non left wing with Eric Lindros and Mark Recchi at the world\nchampionships.\n\n4 months of go...chances were not very good that he would go in the\ntop five...now it has become probable...a great world championship\ncould put him in the top 3 with Daigle and Pronger.\n\nGerald\n\n###\n\n","output":" hockey"} -{"input":"From: pavalin@bnr.ca (Paul Valin)\nSubject: Re: Canadiens - another Stanley Cup???\nNntp-Posting-Host: bcarm4b8\nOrganization: Bell-Northern Research Ltd.\nLines: 31\n\nIn article <1993Apr6.044045.5215@ramsey.cs.laurentian.ca>,\nmaynard@ramsey.cs.laurentian.ca (Roger Maynard) wrote:\n> \n> In rauser@fraser.sfu.ca (Richard John Rauser) writes:\n> \n>>pereira@CAM.ORG (Dean Pereira) writes:\n> \n> \n>>>\t\tWith the kind of team Montreal has now, they can take the\n>>>cup easily. The only problem they have right now is that everyone is\n>>>trying to steal the show and play alone. They need some massive teamwork.\n> \n>This is known as the Savard syndrome - and we are talking Denis, not Serge.\n>No team will ever win squat with the likes of Denis Savard in their lineup.\n> \n> \n>They could tell Savard to stay home and watch the games on TV.\n\nIf life were so simple! Savard has not played in three of the last \nfour games and they are still playing like crap. Montreal's problems\nrun deeper than Savard (and Mouton) unfortunately; I hope they can\nget their act together before the playoffs.\n\nThe line-up in their game coming up against PittsburgH is said to be\nthe one they're likely to use for the playoffs. Let's hope they can\nforget about the nice weather we're having and play hockey.\n--------------------------------------------------------------------\nPaul Valin Tel: + 1 613 763 7394\nBell-Northern Research Ltd. Email: pavalin@bnr.ca\nP.O. Box 3511, Station C\nOttawa, Ontario, Canada K1Y 4H7 'only my opinions...'\n\n###\n\n","output":" hockey"} -{"input":"From: sepinwal@mail.sas.upenn.edu (Alan Sepinwall)\nSubject: Re: Jewish Baseball Players?\nArticle-I.D.: netnews.120665\nOrganization: University of Pennsylvania, School of Arts and Sciences\nLines: 18\nNntp-Posting-Host: mail.sas.upenn.edu\n\nIn article <15APR93.14691229.0062@lafibm.lafayette.edu> VB30@lafibm.lafayette.edu (VB30) writes:\n>Just wondering. A friend and I were talking the other day, and\n>we were (for some reason) trying to come up with names of Jewish\n>baseball players, past and present. We weren't able to come up\n>with much, except for Sandy Koufax, (somebody) Stankowitz, and\n\nIt's Stankiewicz, not Stankowitz, and he's not Jewish - he's Polish\n(by the way, the correct pronunciation - according to Stanky himself,\nis \"ston-KEV-itch\". all the sportscasters get it wrong)\n\n>maybe John Lowenstein. Can anyone come up with any more. I know\n>it sounds pretty lame to be racking our brains over this, but\n>humor us. Thanks for your help.\n\nThe only other Jewish ballplayer I can think of is Ron Blomberg, who is\nbest known as being the first DH to appear in a major league ballgame.\n\n-Alan\n\n###\n\n","output":" baseball"} -{"input":"From: gsu0033@uxa.ecn.bgu.edu (Eric Molas)\nSubject: Re: Playoff predictions\nOrganization: Educational Computing Network\nLines: 53\nNNTP-Posting-Host: uxa.ecn.bgu.edu\n\n\n>1st round: \n>----------\n\n>PITT vs NYI: PITT in 4. \n>WASH vs NJD: WASH in 6. \n\n>BOS vs BUF: BOS in 5. \n>QUE vs MON: MON in 7. \nI'd have to take Quebec in 6.\n\n>CHI vs STL: CHI in 4. \n\nHawks will win, but it will take 5.\n>DET vs TOR: DET in 6. \n\n>VAN vs WIN: WIN in 6. \n>CAL vs LA: CAL in 5. \nCal in 7.\n>2nd round: \n>----------\n\n>PITT vs WASH: PITT in 4. \n>BOS vs MON: BOS in 6. \nBoston will beat Quebec in 6.\n>CHI vs DET: CHI in 7. \n>WIN vs CAL: CAL in 5. \n\n>3rd round: \n>----------\n\n>PITT vs BOS: PITT in 5. \nPitt in 6. The Bruins arent a pushover.\n>CHI vs CAL: CHI in 5. \nThe hawks havent had problems with them all year. Yep, I agree.\n>Finals:\n>------\n\n>PITT vs CHI: PITT in 5. \nUnless the Hawks can somehow change fate, you're right. \n\nWho knows, though. Maybe some intensive forechecking aka normal Hawks\nstyle will nullify a seemingly unbeatable team. Maybe the Pens are due\nfor a let-down. Hell, how could they _possibly_ extend their record\nmaking play all the way through the playoffs.? \n\n>=============================================\n>Walter\n\n-- \n\/\/Damien Endemyr the Unpure Knight of Doom \/\/\n\/\/\"So I've acquired a taste for blood and have adopted a nocturnal \/\/\n\/\/lifestyle. That Doesnt mean I'm a vampire.....\" \/\/\n\n###\n\n","output":" hockey"} -{"input":"From: rickc@krill.corp.sgi.com (Richard Casares)\nSubject: Re: Jim Lefebvre is an idiot.\nNntp-Posting-Host: krill.corp.sgi.com\nOrganization: Silicon Graphics, Inc.\nLines: 32\n\nIn article , ada41546@uxa.cso.uiuc.edu\n(Driftwood) writes:\n|> \n|> \tI totally agree with each point you made. Jose Viscaino looked\n|> like a single A hitter up there. Who swings on 3-1 count with Maddux \n|> pitching and your teams down by a run, and you haven't touched the ball\n|> all \n|> day. I also think too much is made of that lefty-righty thing. \n|> Watching\n|> the Cubs games I get the feeling Steve Stone knows a lot more about\n|> what\n|> the Cubs should be doing than Lefebre does. Harry said it best when he\n|> stated after another terrible Vizcaino at bat-- we can't wait til\n|> Sandberg returns!\n\nI tell you, Steve Stone is like a prophet.\nHe must be making a ton in the boradcoast booth because\nI can't understand why he's not actually back in the game itself.\n\nThe other day he called Sosa's homerun against the Sox and\nclaimed the game would be going into extra innings when the\nscore was 8-3 in the 5th.\n\nSo yesterday he notices that Sosa's ahead in the count against\nMaddux and says, \"This is a fastball situation and Sosa will be\nlooking for it. But this is also the spot where Maddux throws\nthe straight change.\" Sure enough. Sosa gets ahead on it and pops\nit up to the infield.\n\nStoney for Cubs manager!\n\n-Rick\n\n###\n\n","output":" baseball"} -{"input":"From: mep@phoenix.oulu.fi (Marko Poutiainen)\nSubject: Re: Finland\/Sweden vs.NHL teams (WAS:Helsinki\/Stockholm & NHL expansion)\nOrganization: University of Oulu, Finland\nX-Newsreader: TIN [version 1.1 PL6]\nLines: 40\n\n: FINLAND: \n: \n: D-Jyrki Lumme.......20\n: D-Teppo Numminen....20\n: D-Peter Ahola.......13\n: \nWell well, they don't like our defenders (mainly Lumme and Numminen)...\n\n: C-Jari Kurri........25\n: C-Christian Ruuttu..16\n: \nNow, do YOU think that Ruuttu is only worth 16 ? I think it might be 20.\n\n: R-Teemu Selanne.....27\n: \nCompared to Kurri, Selanne's points are too high, lets make it 25 or 26.\n\n\n: well in the Canada Cup and World Championships largely due to the efforts of\n: Markus Ketterer (the goalie), 3-4 or the players listed above and luck. There's\n: presumably a lot of decent players in Finland that wouldn't be superstars at\n: the highest level but still valuable role players, however. My guess would be\n: that the Finnish Canada Cup team would be a .500 team in the NHL.\n\nWow, now, it looks like you don't like our players? What about guys like:\nNieminen, Jutila, Riihijarvi, Varvio, Laukkanen, Makela, Keskinen and (even\nif he is aging) Ruotsalainen? The main difference between finnish and North-\nAmerican players is, that our players tend to be better in the larger rink.\nThe Canadian defenders are usually slower that defenders in Europe. \nAnd I think that there was more in our success than Ketterer and luck (though\nthey helped). I think that the main reason was, that the team worked well\ntogether.\n--\n***********************************************************************\n* 'Howl howl gargle howl gargle howl howl howl gargle howl gargle howl* \n* howl gargle gargle howl gargle gargle gargle howl slurrp uuuurgh' *\n* -Prostetnic Vogon Jeltz *\n***********************************************************************\n\t-Marko Poutiainen\n\t mep@phoenix.oulu.fi\n\n###\n\n","output":" hockey"} -{"input":"From: paula@koufax.cv.hp.com (Paul Andresen)\nSubject: Re: A true story - Way to go Omar\nKeywords: Mariners, grand slam, Omar Vizquel\nNntp-Posting-Host: koufax.cv.hp.com\nOrganization: Hewlett-Packard Company, Corvallis, Oregon USA\nLines: 23\n\nIn article <1993Apr14.173236.14321@esca.com>, vigil@esca.com (Sandra Vigil) writes:\n|> Yesterday, April 14th, a friend and I were discussing the theory put\n|> forth by a local sports radio station personality that the\n|> Commissioner-less baseball owners had snuck a live ball into this years\n|> baseball games in an effort to increase home run numbers and attract\n|> fans. \n\nIt's always possible, but if this is the case, I think that there is some\nblatant discrimination going on here. Clearly Selig is allowing the opposition\nto use pre-1920 baseballs against the Dodgers.\n \n|> Well, guess who stepped up to the plate for his first career grand slam\n|> last night against the Jays? None other than my boy. It was truly a\n|> sight to behold.\n\nAnd almost more impressive was that he also got an intentional walk.\n--------------------------------------------------------------------------------\n We will stretch no farm animal beyond its natural length\n\n paula@koufax.cv.hp.com Paul Andresen Hewlett-Packard (503)-750-3511\n\n home: 3006 NW McKinley Corvallis, OR 97330 (503)-752-8424\n A SABR member since 1979\n\n###\n\n","output":" baseball"} -{"input":"From: gtd597a@prism.gatech.EDU (Hrivnak)\nSubject: Goalie mask poll\nArticle-I.D.: hydra.93158\nOrganization: Georgia Institute of Technology\nLines: 31\n\n\n\tHere is an update on the Goalie mask poll...\n\tFirst, since so many people gave me their 3 best, I decided to\ngive 3 pts for their favorite, 2 pts for 2nd, 1 for 3rd. If you e-mailed\na response with only one, I gave it 3 pts. Please feel free to send me\nyour 2 other favorites, if you only sent one before. \n\tAlso, votes are still welcome! Any mask you like will do, as I \nhave received votes for players not in the NHL. Please mention what team\nthey play for, though.\n\tSo here are the up-to-date results so far:\n\nPlayer Team Pts Votes\n-------------------------------------------------------\n1. Ed Belfour Chicago 8 4\n Andy Moog Boston 8 3\n3. Curtis Joseph St. Louis 5 2\n4. Brian Hayward San Jose 4 2\n5. Grant Fuhr Buffalo 3 1\n Ron Hextall Quebec 3 1\n7. Clint Malarchuk Buffalo 2 1\n Manon Rheaume Atlanta (IHL) 2 1\n9. John Casey Minnesota 1 1\n Rick Wamsley Toronto (retired) 1 1\n\n\tThanks to all that voted, and keep 'em coming!\n\n-- \nGO SKINS! ||\"Now for the next question... Does emotional music have quite\nGO BRAVES! || an effect on you?\" - Mike Patton, Faith No More \nGO HORNETS! ||\nGO CAPITALS! ||Mike Friedman (Hrivnak fan!) Internet: gtd597a@prism.gatech.edu\n\n###\n\n","output":" hockey"} -{"input":"From: jae2001@andy.bgsu.edu (Jason Ehas)\nSubject: Re: Giveaways\nOrganization: Home of 1984 NCAA hockey champs\nLines: 43\n\nIn article <1qi44l$kqr@access.digex.net>, steveg@cadkey.com (Steve\nGallichio) wrote:\n> \n> \n> John P. Curcio (jpc@philabs.philips.com) responded to my drivel:\n> \n> >steveg@cadkey.com (Steve Gallichio) writes:\n> > \n> >>I still am surprised that no one has tried giving away the goodies at the end\n> >>of the game. The two problems with that, of course, are that you would want\n> >>to make sure the first people in the building would be assured of getting\n> >>them (probably redeemable vouchers), and that the building managers want to\n> >>avoid at all costs delaying people as they leave the building, if, for\n> >>instance, the goodies are given to people as they exit.\n> >\n> >I went to the New Jersey Devils\/Carvel Ice Cream Puck Night (tm) last year to\n> >see the beloved Bruins play. The pucks were given out at the end of the game.\n> >I could just imagine what would have happened late in the third if the Bruins\n> >were winning....\n> \n> It figures, after I posted the first article, I found out that the Whalers are\n> going to be using coupons for the the giveaway on Friday Night. I believe that\n> is is the \"Some Big Corporation (Probably a Bank) Flying Disk Night.\" I think\n> that we could all see the potential for danger here...\n> \n> >|> All in all, I have seen a whole bunch of giveaways land on the ice, and it\n> >|> never ceases to amuse me. I'm just thankful for the players that no one has\n> >|> yet to sponsor 'Lead Pipe Night' at any arenas...\n> >\n> >That's probably because they couldn't find anyone to sponser it... Maybe USS\n> >could sponser the Pittsburgh Penguins\/US Steel Steel Rod Night-- close enough?\n> \n> Naah, it'd probably bounce off of Jay Caufield.\n> \n> -SG\n\nI was at a Cincinnati Cyclones game a year ago when the local country\nstation sponsored a kazoo giveaway. After a particularly bad call by the\nunderexperienced ECHL ref, it was Kazoostorm time down on the ice. I\nthought this was a pathetic display by the fans, but they were rightfully\nunhappy.\n\nJason\n\n###\n\n","output":" hockey"} -{"input":"From: jclouse@discover.wright.edu (Jim Clouse)\nSubject: World Series Stats\nNntp-Posting-Host: discgate\nOrganization: Wright State University\nX-Newsreader: TIN [version 1.1 PL8]\nLines: 3\n\nDoes anybody else think that WS stats should become part of\na player's career stats? Why not?\n\n###\n\n","output":" baseball"} -{"input":"From: snichols@adobe.com (Sherri Nichols)\nSubject: Re: Young Catchers\nOrganization: Adobe Systems Incorporated\nLines: 38\n\nIn article <7975@blue.cis.pitt.edu> genetic+@pitt.edu (David M. Tate) writes:\n>As for rushing... If there really is a qualitative difference between the\n>minors and the majors that requires a period of adjustment (and I don't\n>believe there is), then wouldn't you rather waste Lopez's 22-year old good\n>season than his 23-year old very good season or his 24-year-old excellent\n>season? The sooner you get him acclimated, the more of his prime you get to\n>use.\n\nCan anybody name a player who was 'rushed' to the majors (let's, for\nargument's sake, define \"rushed\" as brought up to the majors for more than\na cup of coffee prior at age 22 or younger, and performing below\nexpectations), whose career was damaged by this rushing? I'm serious; I\ntend to agree with David that bringing the player up sooner is better, but\nI'd like to look at players for whom this theory didn't work, if there are\nany. I'd prefer players within the last 10 years or so, because then I can\nlook up their minor league stats. (It's important to distinguish between\nplayers who legitimately had careers below what their minor league numbers\nwould have projected, as opposed to players who were hyped and failed, but\nactually had careers not out of line with their minor league numbers). \n\nLet's kick it off with an example of a player who was \"rushed\", although\nthere doesn't seem to have been any damage to his career. Jay Bell was\ngiven 135 PAs in the major leagues at age 21, and performed well below what\nyou would expect from his AAA numbers the same season. He got 236 PAs the\nnext year at age 22, and still underperformed. However, the next year, at\nage 24, his performance improved, and he won the everyday shortstop job,\nand has been there ever since. It's really hard for me to see where he\nwould have been better off staying in the minor league (where he was\nperformed quite well in AAA) during this time, rather than being \"rushed\";\nCleveland might have been better off, I suppose, because they might have\nbeen less likely to give up on him.\n\nYes, if you bring a player up early, he's likely going to struggle. But\ndoes that delay the time at which he stops struggling, and starts\nperforming up to expectations?\n\nSherri Nichols\nsnichols@adobe.com\n\n###\n\n","output":" baseball"} -{"input":"From: farenebt@logic.camp.clarkson.edu (Droopy)\nSubject: AHL final standings\nOrganization: Clarkson University\nLines: 35\nNntp-Posting-Host: logic.clarkson.edu\nX-Newsreader: TIN [version 1.1 PL8]\n\nFINAL 1992-93 AMERICAN HOCKEY LEAGUE STANDINGS\n\nNORTHERN DIVISION\tW\tL\tT\tPTS\tGF\tGA\tLYF*\nProvidence Bruins\t46\t32\t2\t94\t384\t348\t56\nAdirondack Red Wings\t36\t35\t9\t81\t331\t308\t84\nCapital District Isles\t34\t34\t12\t80\t280\t285\t75\nSpringfield Indians\t25\t41\t14\t64\t282\t336\t94\nNew Haven Senators\t22\t47\t11\t55\t262\t343\t--\n\nSOUTHERN DIVISION\tW\tL\tT\tPTS\tGF\tGA\tLYF\nBinghamton Rangers\t57\t13\t10\t124#\t392\t246\t91\nRochester Americans\t40\t33\t7\t87\t348\t332\t86\nUtica Devils\t\t33\t36\t11\t77\t325\t354\t74\nBaltimore Skipjacks\t28\t40\t12\t68\t318\t353\t66\nHershey Bears\t\t27\t41\t12\t66\t316\t339\t83\nHamilton Canucks\t29\t45\t6\t64\t284\t327\t--\n\nATLANTIC DIVISION\tW\tL\tT\tPTS\tGF\tGA\tLYF\nSt John's Maple Leafs\t41\t26\t13\t95\t351\t308\t90\nFredericton Canadiens\t38\t31\t11\t87\t314\t278\t96\nCape Breton Oilers\t36\t32\t12\t84\t356\t336\t82\nMoncton Hawks\t\t31\t33\t16\t78\t292\t306\t74\nHalifax Citadels\t33\t37\t10\t76\t312\t348\t67\n\n*- Last year's point total\n#- League record total\t\t\t\n\n ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n + Bri Farenell\t\t\tfarenebt@craft.camp.clarkson.edu +\n + AHL, ECAC and Boston Bruins contact for rec.sport.hockey\t\t +\n + Adirondack Red Wings, Calder Cup Champs: '81 '86 '89 '92\t +\n + Clarkson Hockey, ECAC Tournament Champs: '66 '91 '93\t\t +\n + Glens Falls High Hockey, NY Division II State Champs: '90 '91 +\n + AHL fans: join the AHL mailing list: ahl-news-request@andrew.cmu.edu +\n ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n###\n\n","output":" hockey"} -{"input":"From: fierkelab@bchm.biochem.duke.edu (Eric Roush)\nSubject: Re: quick way to tell if your local beat writer is dumb.\nArticle-I.D.: news.12787\nOrganization: Biochemistry\nLines: 28\nNntp-Posting-Host: bruchner.biochem.duke.edu\n\nIn article <1993Apr06.062907.108109@locus.com> aardvark@spica.la.locus.com\n(Warren Usui) writes:\n>In article gajarsky@pilot.njin.net\n(Bob Gajarsky - Hobokenite) writes:\n>>anyone who writes \"dean palmer has 2 homers - at this pace, he'll\n>> have 324 home runs!\" should be shot.\n\n\n\nNow, on the other hand, Juan Gonzales probably DOES have a shot at\n324 HR's. ;).\n\n>The Dodgers after one inning of play have committed one error. At this rate\n>they'll have 1,455 errors this season!\n\n>Well maybe I'm right this time...\n\n\n\nActually, you might be underpredicting? ;)\n\n-------------------------------------------------------\nEric Roush\t\tfierkelab@\tbchm.biochem.duke.edu\n\"I am a Marxist, of the Groucho sort\"\nGrafitti, Paris, 1968\n\nTANSTAAFL! (although the Internet comes close.)\n--------------------------------------------------------\n\n###\n\n","output":" baseball"} -{"input":"From: (jmhodapp@aplcomm.jhuapl.edu)\nSubject: Re: ALL-TIME BEST PLAYERS\nOrganization: master\/peon\nLines: 19\n\nIn article <1993Apr14.173428.12056@Princeton.EDU>, roger@crux.Princeton.EDU (Roger Lustig) writes:\n> \n\n> >In article <1993Apr13.115313.17986@bsu-ucs>, 00mbstultz@leo.bsuvc.bsu.edu \n> > writes...\n> \n> >>I've recently been working on project to determine the greatest\n> >>players at their respective postions. \n> \n> >>2B Career \n\nWhat about U. Johnny Hodapp, the greatest 2nd baseman in Cleveland Indians\nhistory? 225 hits in 1930, consistantly over .300. A great, great second baseman.\n\n\nJon \"Johnny\" Hodapp\njmhodapp@aplcomm.jhuapl.edu\n=-=-=--=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n\n###\n\n","output":" baseball"} -{"input":"From: vergolin@euler.lbs.msu.edu (David Vergolini)\nSubject: Detroit Tigers\nOrganization: Michigan State University\nLines: 7\nNNTP-Posting-Host: euler.lbs.msu.edu\nSummary: Who can stop the roar of the Tiger's bats.\nKeywords: Detroit is the top offensive team in the league\n\n The roar at Michigan and Trumbull should be loader than ever this year. With\nMike Illitch at the head and Ernie Harwell back at the booth, the tiger bats\nwill bang this summer. Already they have scored 20 runs in two games and with\nFielder, Tettleton, and Deer I think they can win the division. No pitching!\nBull! Gully, Moore, Wells, and Krueger make up a decent staff that will keep\nthe team into many games. Then there is Henneman to close it out. Watch out\nBoston, Toronto, and Baltimore - the Motor City Kittys are back.\n\n###\n\n","output":" baseball"} -{"input":"From: traven@pitt.edu (Neal Traven)\nSubject: Re: The 1964 Phillies: deja vu?\nLines: 25\nX-Newsreader: TIN [version 1.1 PL8]\n\nRobert C Hite (philly@bach.udel.edu) wrote:\n: I think most of the problems mainly arose from Manager Gene Mauch's\n: ineptitude in managing the pitching staff. Down the stretch, he\n: abused Jim Bunning, Chris Short, and Robin Roberts (I think those\n: are the three) pitching each on only 2 days rest for quite some\n: time. By the time they hit the last 2 weeks of the season,\n: obviously none of these guys had an ounce left in their arm. Oh\n: well.\n\nRoberts was long gone -- he was probably an Oriole in 1964. Or maybe a\nColt .45. The 3rd starter was Art Mahaffey, the previous year's ace.\nDennis Bennett was the 4th starter.\n\nThey were indeed 6.5 up with 12 to go, but they won their final two\ngames after the horrid 10-loss streak. The final game victory\n(Bunning's 19th win, if memory serves) kept the Reds from tying for the\ntitle; they and the Phils were both 1 game behind the Cards, with the\nGiants(?) another game back. The Mets couldn't hold an early lead\nagainst the Cards that final Sunday, or there would have been a 3-way\ntie. Too bad they couldn't have saved some of the 15 or so runs they\nscored on Saturday when they crushed St. Louis.\n--\n-----------------------------------------------------------------------------\nneal\ttraven+@pitt.edu\t You're only young once, but you can be\n\ttraven@vms.cis.pitt.edu\t immature forever. -- Larry Andersen\n\n###\n\n","output":" baseball"} -{"input":"From: thornley@micro.cs.umn.edu (David H. Thornley)\nSubject: Re: Erickson, Keith Miller?\nArticle-I.D.: news2.C5LHyD.GEx\nOrganization: University of Minnesota, Minneapolis, CSci dept.\nLines: 17\nNntp-Posting-Host: micro.cs.umn.edu\n\nIn article <1993Apr16.032554.12401@mintaka.lcs.mit.edu> frankkim@CATFISH.LCS.MIT.EDU (Frank Kim) writes:\n>\n>HI,\n>\n>I was just wondering if anyone knew when Erickson\n>and Keith Miller are expected to come back and what\n>exactly ails them.\n>\nDunno about Miller.\n\nIf you mean Scott Erickson, currently the reigning Twins Least Consistent\nGood Player, he pulled a muscle in the neighborhood of the rib cage that\nmade it essentially impossible for him to pitch temporarily, and is\nexpected back on the mound Sunday.\n\nDavid Thornley\n\"With tickets to see one of the Scott Ericksons pitch\"\n\n###\n\n","output":" baseball"} -{"input":"From: cr292@cleveland.Freenet.Edu (Jim Schenk)\nSubject: Re: the hawks WILL return to the finals!!!!!\nOrganization: Case Western Reserve University, Cleveland, Ohio (USA)\nLines: 9\nNNTP-Posting-Host: hela.ins.cwru.edu\n\n\nThe Hawks won the Norris div, and sealed their fate. It's bad luck\nto win the Norris. The Hawks will sweep the Blues in their dreams but will\nlose in 6 in reality. I predict that in the 6 game with the Blues Belfour\nwill go down on his knees 7000 time s and will spend the rest of the time \nlooking behind him self. Butcher will pound Roenick and The warthawks have\nno one tough enough to prevent it\n\nBye Bye Wart HAwks\n\n###\n\n","output":" hockey"} -{"input":"From: philly@ravel.udel.edu (Robert C Hite)\nSubject: Re: Old Predictions to laugh at...\nNntp-Posting-Host: ravel.udel.edu\nOrganization: University of Delaware\nLines: 24\n\n\nIn article <1993Apr15.160316.9170@cs.cornell.edu> tedward@cs.cornell.edu (Edward [Ted] Fischer) writes:\n>\n>Oops! I came across this file from last year. Thought you might\n>enjoy some of these thoughts. The predictions were made on the\n>date indicated. They are largely out of order.\n\nmuch crap deleted\n\n>>3. Managers to be fired this year (1992) in chronological order:\n>>Fregosi, Showalter, Valentine, Riddoch\n>\n>Three of them went, right? Showalter is still around (and likely to\n>stick, it seems).\n\nDEAD WRONG! Last time I checked, Jim Fregosi was still managing the\nPhillies, and doing quite a fine job thank you...best record in\nbaseball at 8-1\n\nMY PREDICTION FOR 1993:\nJim Fregosi will win manager of the year in the NL\n\n(don't flame me..flame the bum who thinks he got fired last year.\nPAY ATTENTION KIDDO!)\n\n###\n\n","output":" baseball"} -{"input":"From: steve@sep.Stanford.EDU (Steve Cole)\nSubject: Re: SHARKS: Kingston Fired!!!\nOrganization: Stanford Exploration Project\nLines: 38\nDistribution: world\nNNTP-Posting-Host: himalaya.stanford.edu\n\nIn article <1993Apr20.165132.9777@adobe.com>, snichols@adobe.com (Sherri Nichols) writes:\n|> In article <1993Apr20.085337.27224@leland.Stanford.EDU> terry@garfield.Stanford.EDU (Terry Wong) writes:\n|> >I think that Jack Ferreira's firing eventually led to Kingston's\n|> >firing. You mention consistency of vision. I think the\n|> >Sharks lost that with the loss of Ferreira. There has never\n|> >been a 3 headed G.M. that has ever worked. You need one\n|> >person making the personnel decisions at the top, not\n|> >management by committee. The conventional wisdom\n|> >from around the league is that Ferreira would have\n|> >made the moves that would have fielded a better product\n|> >on the ice.\n|> \n|> How exactly would Ferreira accomplished this? The three-headed GM-ship has\n|> taken a lot of heat, but nobody's explained how things would have been any\n|> different had Ferreira still been there. Would Ferreira have made more\n|> trades? Who would have he had traded? Would he have made fewer trades?\n|> Who should not have been traded?\n\nI think the three-headed GM's guiding principle was to keep veterans\nin favor of youngsters only if they offered a \"significant\" advantage.\nAt the end of last season, the contracts of several veterans with somewhat\nmaginal contributions (Fenton, Bozek, Anderson, and a couple others I\ncan't remember) were bought out. The idea was that youngsters could\nplay almost as well, and had the potential to improve where these\nolder guys did not. \nAnd they traded Mullen, because he wanted to go, not because he\nwasn't good enough, but I think they were a bit too optimistic\nin thinking they could make up for his contributions.\nAn example from this season, Skriko was brought in on a trial basis\nbut not kept, because of his age. I thought he was a decent\ncontributor worth keeping around.\n\nThe youth movement has its advantages; look at Gaudreau who\nmight still be in KC if more veterans had been kept around. But\nyou have to find the right balance.\n-----------------------------------------------------------------\nSteve Cole (steve@sep.stanford.edu, apple!sep!steve)\nDepartment of Geophysics, Stanford University, Stanford, CA 94305\n\n###\n\n","output":" hockey"} -{"input":"From: luriem@alleg.edu The Liberalizer (Michael Lurie)\nSubject: Re: Joe Robbie Stadium \"NOT FOR BASEBALL\"\nArticle-I.D.: alleg.1993Apr6.210510.2943\nOrganization: Allegheny College\nLines: 10\n\nIn article <1993Apr6.025027.4846@oswego.Oswego.EDU> iacs3650@Oswego.EDU \n(Kevin Mundstock) writes:\n> Did anyone notice the words \"NOT FOR BASEBALL\" printed on the picture\n> of Joe Robbie Stadium in the Opening Day season preview section in USA\n> Today? Any reason given for this?\n\n\n\nYes, and the answer is simple. To create a better feeling in the park, the \nseats will be folded back for baseball games where you saw those words.\n\n###\n\n","output":" baseball"} -{"input":"From: smale@healthy.uwaterloo.ca (Bryan Smale)\nSubject: This year's biggest and worst (opinion)...\nKeywords: NHL, awards\nOrganization: University of Waterloo\nLines: 55\n\n\nI was thinking about who on each of the teams were the MVPs, biggest\nsurprises, and biggest disappointments this year. Now, these are just\nmy observations and are admittedly lacking because I have not had an\nopportunity to see all the teams the same amount. Anyway....\n \nMVP = most valuable player to his team both in terms of points and\n in terms of leadership (\"can't win without him\")\n \nBiggest surprise = the player who rose above expectation -- the player\n that may have raised the level of his game to a new height, even\n if that new level doesn't necessarily warrant an allstar berth\n (includes those players who at the outset of the season, may not\n even have been in the team's plans).\n \nBiggest disappointment = the player from whom we expected more (e.g., I\n picked Denis Savard in Montreal because with the new emphasis on\n offence brought by Demers, shouldn't Savard have done better?)\n \n-----------------------------------------------------------------------\n \n Team Biggest Biggest\nTeam: MVP: Surprise: Disappointment:\n-----------------------------------------------------------------------\nBoston Bruins Oates D.Sweeney Wesley\nBuffalo Sabres Lafontaine Mogilny Audette (jinx?)\nCalgary Flames Roberts Reichel Petit\nChicago Blackhawks Roenick Ruuttu Goulet\nDetroit Red Wings Yzerman Chaisson Kozlov\nEdmonton Oilers Manson Buchberger Mellanby\nHartford Whalers Sanderson Cassells Corriveau\nLos Angeles Kings Robitaille Donnelly Hrudey\nMinnesota North Stars Modano Tinordi(not expected back) Broten\nMontreal Canadiens Muller Lebeau Savard\nNew Jersey Devils Stevens Semak MacLean\nNew York Islanders Turgeon King(finally) Marois\nNew York Rangers Messier Kovalev Bourque\nOttawa Senators MacIver Baker Jelinek\nPhiladelphia Flyers Lindros\/Recchi Fedyk\/Galley Eklund\nPittsburgh Penguins Lemieux Tocchet(even for him) Jagr\nQuebec Nordiques Sakic\/Ricci Kovalenko Pearson\nSan Jose Sharks Kisio Gaudreau Maley\nSt Louis Blues Shanahan C.Joseph Ron Sutter\nTampa Bay Lightening Bradley Bradley Creighton\/Kasper\nToronto Maple Leafs Gilmour Potvin Ellett\/Anderson\nVancouver Canucks Bure Nedved(finally) Momesso\nWashington Capitals Hatcher Bondra\/Cote Elynuik\nWinnipeg Jets Selanne Selanne Druce\n----------------------------------------------------------------------\n \nAs I mentioned up top, these are my *impressions* from where I sit. I\nwould welcome any opinions from those fans nearer their teams (in other\nwords, *anywhere* away from a Toronto newspaper!)\n \nBryan\n\n###\n\n","output":" hockey"} -{"input":"Subject: Travesty at the Joe Louis\nFrom: caldwell8102@mtroyal.ab.ca\nOrganization: Mount Royal College, Calgary, Alberta\nLines: 17\n\n(Detroit, April 19)\n\nIn a development that shocked most knowledgable observers, the Detroit Redwings\nscored no less than six goals against the best goaltender in the world en\nroute to a 6-3 win over the best team in the NHL, the Toronto Maple Leafs. \n\nThe Leafs could not be faulted, as they completely dominated the inferior\nDetroit squad and clearly deserved to win. Only the biased officiating of\nAndy Van Hellemond and the idiots that insisted upon throwing an octopus on\nthe ice at every stoppage in an obvious attempt to distract the superior \nvisiting side prevented an all-out massacre of the Wings by the league's best \nteam. \n\n \t\t\t\t\t\t\t Alan\n\nP.S. This is sweet, Roger. So sweet. I look forward to the next installment on\nWednesday night. I trust you do, too.\n\n###\n\n","output":" hockey"} -{"input":"From: rickert@NeXTwork.Rose-Hulman.Edu (John H. Rickert)\nSubject: Re: Players Rushed to Majors\nOrganization: Computer Science Department at Rose-Hulman\nLines: 13\nReply-To: rickert@NeXTwork.Rose-Hulman.Edu (John H. Rickert)\nNNTP-Posting-Host: g215a-1.nextwork.rose-hulman.edu\n\nIn article <93122@hydra.gatech.EDU> re4@prism.gatech.EDU (RUSSELL EARNEST) \nwrites:\n> This brings back the long suffering memories of pre-chop Braves fans who\n> kept being promised the Bob Horner - Dale Murphy back to back power slam. \n> Who could stop that? Guess we'll never know.\n\nWhy not? Horner played 130 games in 1985 and hit 27 HR.\nMurphy played 162 and hit 37.\nIn 1986 Horner hit 27 in 141 games and Murphy hit 29 in 160 games.\n(and the Braves lost 96 and 89 games).\n\njohn rickert\nrickert@nextwork.rose-hulman.edu\n\n###\n\n","output":" baseball"} -{"input":"From: ring@poseidon (Sue Rankin)\nSubject: Camden Yards\nOrganization: Athena Design, Inc.\nLines: 13\nNNTP-Posting-Host: poseidon.athena.com\n\nI am fortunate enough to have tickets for an Orioles-Red Sox game in \nBaltimore on Saturday, July 31st. I haven't been to the new park,\nand I was wondering if anyone out there can give me pointers or good tips \nor anything helpful about the place so that I can enjoy every moment spent\nthere.\nFor instance, what time do the gates open? Do we see the Orioles take BP?\nWhen will the Red Sox take BP? Anything you can tell me would be \nappreciated. Thank you in advance. \nPlease respond to my e-mail address.\nI know it's still three-and-a-half months away, but I'm psyched!\n\n\nSue\n\n###\n\n","output":" baseball"} -{"input":"From: lli+@cs.cmu.edu (Lori Iannamico)\nSubject: Pens box score 4\/14\nNntp-Posting-Host: lli.mach.cs.cmu.edu\nOrganization: School of Computer Science, Carnegie Mellon\nLines: 44\n\nPens-6 NJ Devils-6\n\nFIRST PERIOD: SCORING: 1, Pittsburgh, Daniels(Needham, Tippett)4:14.\n2, NJ Devils, C. Lemieux(Semak, Driver)10:19. 3, Pittsburgh, Stevens\n(Tocchet, Murphy)12:40ppg. 4, NJ Devils, Zelepukin(Driver, Niedermayer)\n17:26. PENALTIES: PGH, Stevens(roughing)1:30. NJD, Pellerin-double\nminor(cross-checking)1:30. NJD, Zelepukin(tripping)7:21. NJD,\nStasny(holding)11:15. PGH, Taglianetti(roughing)13:51. NJD, Lemieux\n(roughing)13:51. PGH, Jagr(tripping)15:23.\n\nSECOND PERIOD: SCORING: 5, Pittsburgh, Lemieux(Murphy, Tocchet)1:42.\n6, NJ Devils, Semak(Lemieux, Zelepukin)2:27. 7, Pittsburgh, McEachern\n(Jagr, Barrasso)4:24. 8, NJD, Stevens(Guerin, Pellerin)5:45. 9,\nPittsburgh, Lemieux(unassisted)12:40shg. 10, NJ Devils, Richer\n(Nicholls)15:53. 11, NJ Devils, Lemieux(Zelepukin)17:40. PENALTIES:\nPGH, Stevens(roughing)3:06. NJD, McKay(roughing)3:06. PGH, Mullen\n(hooking)10:42. PGH, Tocchet(roughing)12:06. NJD, Stevens(slashing)\n12:06. NJD, Lemieux(unsportsmanlike conduct)12:40. PGH, U.\nSamuelsson(cross checking)20:00. PGH, Barrasso-double minor(spearing)\nserved by McEachern, 20:00. NJD, Holik(cross checking)20:00. NJD,\nLemieux(roughing)20:00.\n\nTHIRD PERIOD: SCORING: 12, Pittsburgh, Mullen(Jagr, Lemieux)18:54.\nPENALTIES: NJD, Daneyko(interference)3:37. PGH, Stevens(roughing)\n9:18. NJD, Holik(roughing)9:18. PGH, match penalty-game misconduct,9:50.\nNJD, Zelepukin(tripping)12:01. PGH, Stevens(roughing)18:41. NJD,\nDaneyko(roughing)18:41.\n\nOVERTIME: SCORING: No scoring. PENALTIES: No penalties.\n\nSHOTS ON GOAL:\nPittsburgh: 9-11-8-2=30\nNJ Devils: 12-15-9-3=39\n\nGOALIES:\nBarrasso(39 shots, 33 saves. 43-14-5)\nBillington(30 shots, 24 saves)\n\nREF: Devorski Linesmen: Gauthier, Vines\n\nLori\nContact for the Penguins\nlli+@cs.cmu.edu\n\n###\n\n","output":" hockey"} -{"input":"From: maynard@ramsey.cs.laurentian.ca (Roger Maynard)\nSubject: Re: If You Were Pat Burns ...\nKeywords: Leaf Wings\nOrganization: Dept. of Computer Science, Laurentian University, Sudbury, ON\nLines: 24\n\nIn <1993Apr20.181549.11414@alchemy.chem.utoronto.ca> golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy) writes:\n\n>Pray for the Wings to become lazy and overconfident...the Wings\n>can only lose the series...Toronto cannot win it. Take away\n>Doug Gilmour and the Leafs are an old Tampa Bay.\n\nRight Gerald. And take away Bob Probert and the Wings are dead Octopuses.\n\n>The Leafs deserve a lot of credit for their diligent effort\n>during the regular season...but if Detroit puts in a reasonable\n>effort, this is not a contest.\n\nLet's wait for the body to get cold before we start in with the eulogies\nhm? They have only lost ONE game. The game was in Detroit after all and\nPotvin did not have his best evening. Nobody that I saw thought that the\nLeafs would sweep the Wings. It looks like it might go six. The Leafs\nwill take the Wings home advantage away in the next game.\n\n\n-- \n\ncordially, as always, maynard@ramsey.cs.laurentian.ca \n \"So many morons...\nrm ...and so little time.\"\n\n###\n\n","output":" hockey"} -{"input":"From: jfp001@acad.drake.edu\nSubject: Re: Goalie Mask Update\nLines: 41\nNntp-Posting-Host: acad.drake.edu\nOrganization: Drake University, Des Moines, Iowa, USA\n\nIn article <93289@hydra.gatech.EDU>, gtd597a@prism.gatech.EDU (Hrivnak) writes:\n> \n> \tHere are the results after three days of voting. Remember 3pts for \n> 1st, 2 for 2nd, and 1 for 3rd. Also, you can still turn in votes! And.. if\n> the guy isn't a regular goalie or he is retired, please include the team! \n> Thanks for your time, and keep on sending in those votes!\n> \n> Player Team Pts Votes\n> -----------------------------------------------------------\n> 1. Brian Hayward San Jose 15 6\n> Andy Moog Boston 15 6\n> 3. Curtis Joseph St. Louis 11 5\n> 4. Ed Belfour Chicago 10 5\n> 5. Gerry Cheevers Boston (retired) 5 3 \n> Manon Rheaume Atlanta (IHL) 5 2\n> Ron Hextall Quebec 5 2\n> 8. Don Beaupre Washington 4 2\n> -----------------------------------------------------------\n> Others receiving 1 vote: Artus Irbe (SJ), Tim Cheveldae (Det),\n> Clint Malarchuck (Buf\/SD,IHL), Grant Fuhr (Buf), Rick Wamsley \n> (Tor,ret), Jon Casey (Minn), John Vanbiesbrouck (NYR),\n> Ken Dryden (Mon,ret), Bob Essensa (Win), Mike Vernon (Cal),\n> Glenn Healy (NYI), Tommy Soderstron (???), Ray LeBlanc (USA).\n> \n\nC'mon, Tommy Soderstrom is having a fine rookie (I think he's a rookie)\nseason with the Flyers. I'm sure most of you knew that already, but just\nin case. \n\nJohn P.\njfp001@acad.drake.edu\nA longtime, but realistic Ranger fan who's willing to admit that the Rangers\nsucked big-time this year. They don't even deserve the luxury of a nice\ngolf course with a warm breeze. God, talk about underachievers!\nMike Keenan - we're waiting for you!\n> \n> -- \n> GO SKINS! ||\"Now for the next question... Does emotional music have quite\n> GO BRAVES! || an effect on you?\" - Mike Patton, Faith No More \n> GO HORNETS! ||\n> GO CAPITALS! ||Mike Friedman (Hrivnak fan!) Internet: gtd597a@prism.gatech.edu\n\n###\n\n","output":" hockey"} -{"input":"From: gld@cunixb.cc.columbia.edu (Gary L Dare)\nSubject: Stan Fischler, 4\/16 (Keenan stuff!)\nSummary: prior to Devils at Islanders Pregame\nNntp-Posting-Host: cunixb.cc.columbia.edu\nReply-To: gld@cunixb.cc.columbia.edu (Gary L Dare)\nOrganization: PhDs In The Hall\nLines: 30\n\n\n* The Keenan hiring is precipitated by the loss of an anticipated $5M\nin playoff revenue and fears of losing season ticket-holders (!), plus\nParamount chief Stan Jaffe's chip against the Flyers over l'Affaire\nLindros last autumn. Add to this that Neilsen might return as an\nassistant coach [Gerald, what'd I say earlier today??], and Roger\nconferred with Jaffe on the hiring. This hiring by Jaffe went over\nthe head of MSG, Inc. (Par. subsidiary) head Bob Gutkowski and over\nthe head and the protests of Pres.\/GM Neil Smith.\n\n* MSG is making the announcement on Saturday to get back at the\nIslanders for making the playoffs (i.e., steal the press).\n\n* Flyers owner Ed Snyder is livid and beside himself over this.\n\n* Keenan will make up to $900,000\/yr.\n\n* Gary Bettman has appointed an independent consul to look at\nGil Stein's admission into the Hall of Fame.\n\n* New crease colours, rather than blue?\n\n* The Oilers will charge to eat in the Press Room next year.\n\ngld\n--\n~~~~~~~~~~~~~~~~~~~~~~~~ Je me souviens ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGary L. Dare\n> gld@columbia.EDU \t\t\tGO Winnipeg Jets GO!!!\n> gld@cunixc.BITNET\t\t\tSelanne + Domi ==> Stanley\n\n###\n\n","output":" hockey"} -{"input":"From: damelio@progress.COM (Stephen D'Amelio)\nSubject: Re: What was Ray doing?\nNntp-Posting-Host: elba\nOrganization: Progress Software Corp.\nLines: 22\n\ndaveb@thewho.East.Sun.COM (Dave Brewer) writes:\n\n>In yesterday's fracus between Rob Ray and Brent Hughes, was it the camera angle or was\n>Ray actually punching Hughes where it appeared he was punching him? (For those that didn't\n>see the game - it was several inches below the belt and he punched him there quite a few\n>times.) Dreadful.\n\n>Also, why did Poulin get four minutes?\n\n\nI've been watching & playing hockey for a good long time now, and\nI've seen players with questionable tactics, but never have I seen\nwhat Ray did on Sunday. This guy gets my all time loser award. It's\none thing to repeatedly cross check someone to the back of the neck\nwhen they are down, it's another thing to have a fist fight with\nsomeones balls. Ray should be thrown out of the league, what an\na**hole.\n\n-Steve\n\n###\n\n","output":" hockey"} -{"input":"From: tjrad@iastate.edu (Thomas J Radosevich)\nSubject: Brewers injuries \nOrganization: Iowa State University, Ames IA\nLines: 21\n\n\n\nHi all,\n\nI've been locked in a small closet chained to a lab bench for the last week or\ntwo without access to really important information. I saw the 3.5 million\nshoulder back on the DL--How long is he out for (i.e. How many millions\/inning\nwill he get this year?) Nothing personal against Higuera mind you, just\nwondering how Bud can keep coffing up money for him when he lets current\nbig producers go over a relative pittance. (Please realize the term \n\"relative pittance\" can only be used with sarcasm when discussing baseball\nsalaries.)\n\nAdditional questions: I did'nt get to see Bones pitch this spring--how is\nhe looking and where is he going to fit in the rotation?\n\nHow is Surhoff shaping up defensively at third?\n\nAre they going to build a new stadium? When?\n\nTom\n\n###\n\n","output":" baseball"} diff --git a/internal/service/bedrock/test-fixtures/validation_data.jsonl b/internal/service/bedrock/test-fixtures/validation_data.jsonl deleted file mode 100644 index 6e346f5672d..00000000000 --- a/internal/service/bedrock/test-fixtures/validation_data.jsonl +++ /dev/null @@ -1,25 +0,0 @@ -{"input":"From: gld@cunixb.cc.columbia.edu (Gary L Dare)\nSubject: Re: Flames Truly Brutal in Loss\nNntp-Posting-Host: cunixb.cc.columbia.edu\nReply-To: gld@cunixb.cc.columbia.edu (Gary L Dare)\nOrganization: PhDs In The Hall\nDistribution: na\nLines: 13\n\n\nThis game would have been great as part of a double-header on ABC or\nESPN; the league would have been able to push back-to-back wins by\nLe Magnifique and The Great One. Unfortunately, the only network\nthat would have done that was SCA, seen in few areas and hard to\njustify as a pay channel. )-;\n\ngld\n--\n~~~~~~~~~~~~~~~~~~~~~~~~ Je me souviens ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nGary L. Dare\n> gld@columbia.EDU \t\t\tGO Winnipeg Jets GO!!!\n> gld@cunixc.BITNET\t\t\tSelanne + Domi ==> Stanley\n\n###\n\n","output":" hockey"} -{"input":"From: smorris@venus.lerc.nasa.gov (Ron Morris )\nSubject: Murray as GM (was: Wings will win\nOrganization: NASA Lewis Research Center\nLines: 37\nDistribution: world\nNNTP-Posting-Host: venus.lerc.nasa.gov\nNews-Software: VAX\/VMS VNEWS 1.41 \n\nIn article <1993Apr19.204348.8254@sol.UVic.CA>, gballent@hudson.UVic.CA writes...\n> \n>In article 735249453@vela.acs.oakland.edu, ragraca@vela.acs.oakland.edu (Randy A. Graca) writes:\n> \n>>are predicting). Although I think Bryan Murray is probably the best GM\n>>I have ever seen in hockey\n> \n>How do you figure that?? When Bryan Murray took over the Wings they were\n>a pretty good team that was contending for the Stanley Cup but looked\n>unlikely to win it. Now they are a pretty good team that is contending for\n>the Stanley Cup but looks unlikely to win it. A truly great GM would\n>have been able to make the moves to push the team to the upper echelon\n>of the NHL and maybe win the Stanley Cup. A good GM (like Murray) can\n\nI think Murray has done a great job. He's picked up Ciccarelli,\nSheppard, Ysebaert, Howe, Coffey, and Riendeau (plus some depth players) \nwithout giving up anything the Wings needed or any of his top prospects.\nAll of this in three years. Has anyone done better?\n\nThe year before he took over, the Wings didn't even make the playoffs.\nThere was about a year and a half during Demers' stint that the Wings\ndid OK, but that was due to Demers' motavational skills and clutch\nand grab style. They didn't have much talent.\n\nGerald, Murray wasn't responsible for Primeau (although I'm not\nready to admit that's a horrible pick). They hired him after the\ndraft (which has never made sense to me). His first pick was\nLapointe.\n\nRon \n\n**********\n\"And one of my major goals is to leave the next president a new set\nof things to worry about. I'm getting bored reading the same problems\nin the paper, decade after decade. I want people to have to deal\nwith new problems.\"\n ... President Bill Clinton 2-4-93\n\n###\n\n","output":" hockey"} -{"input":"From: golchowy@alchemy.chem.utoronto.ca (Gerald Olchowy)\nSubject: Re: Too Many Europeans in NHL\nArticle-I.D.: alchemy.1993Apr6.142037.9246\nOrganization: University of Toronto Chemistry Department\nLines: 14\n\nIn article <1993Apr6.044323.22829@pasteur.Berkeley.EDU> daniell@cory.Berkeley.EDU (Daniel Lyddy) writes:\n>\n>You know, you're absolutely right. I think we should round up all those\n>players of European descent and ship 'em back to where they came from. Let's\n>see, with whom should we start? I dunno, Lemieux? Hmmm...sounds like he\n>has *French* blood in him!!! Hey! France is part of Europe! Send that\n>Euro-blooded boy back!!!\n>\n\nDon't you Americans study history...the French settled in North America\nas early or before the British...Lemieux can probably trace back his\nNorth American heritage back a lot further than most of us.\n\nGerald\n\n###\n\n","output":" hockey"} -{"input":"From: krattige@hpcc01.corp.hp.com (Kim Krattiger)\nSubject: Re: Kevin Rogers\nOrganization: the HP Corporate notes server\nLines: 14\n\n>\/ hpcc01:rec.sport.baseball \/ pjtier01@ulkyvx.louisville.edu \/ 12:23 pm Apr 14, 1993 \/\n>\n>What's up with Kevin Rogers of San Francisco?? I thought he was slated to be\n>the fifth starter, but he's only gotten a few relief appearences. Are they\n>going with four starters for now, or is someone else the fifth?\n>\n> Thanks,\n> P. Tierney\n>----------\n>\nGiant's have a five man rotation of John Burkett, Trevor Wilson,\nBill Swift, Jeff Brantley, and Bud Black\/Dave Burba. Black has\nbeen put on the 15 day disables and Dave Burba will take his starts.\n\n###\n\n","output":" baseball"} -{"input":"From: warped@cs.montana.edu (Doug Dolven)\nSubject: Mel Hall\nOrganization: CS\nLines: 9\n\n\nHas anyone heard anything about Mel Hall this season? I'd heard he wasn't\nwith the Yankees any more. What happened to him?\n\n\t\t\t\tDoug Dolven\n-- \nDoug Dolven\nwarped@cs.montana.edu\ngdd7548@trex.oscs.montana.edu\n\n###\n\n","output":" baseball"} -{"input":"From: jerry@sheldev.shel.isc-br.com (Gerald Lanza)\nSubject: Re: '61 Orioles Trivia\nOrganization: Olivetti North America (Shelton, CT)\nLines: 20\n\nIn article <1993Apr14.190432.1706@hpcvaac.cv.hp.com> paula@koufax.cv.hp.com (Paul Andresen) writes:\n>In article <1993Apr13.151809.1286@galileo.cc.rochester.edu>, sparky@balsa.lle.rochester.edu (Michael Mueller) writes:\n>|> Hi All,\n>|> \n>|> Does anyone know who were the 4 pitchers for the 1961 Orioles \n>|> that were referred to as the \"Kiddy Corp\" because they were so young?\n>\n>Steve Barber 22 18-12\n>Chuck Estrada 23 15-9\n>Jack Fisher 22 10-13\n>Milt Pappas 22 13-9\n>\n\n\tThis list brings to mind possible the worst trade since Babe for\n\tNONO NANNETTE, i.e., Milt Pappas for Frank Robinson, I think in\n\t1965 ?. Robinson proceeded to win the triple crown in 1966 and\n\tmay have beaten out Yaz in '67 but was injured on a slide into \n\tsecond when he collided with the mighty Al Weis (Chisox). \n\n\t\t\t\t\tjerry\n\n###\n\n","output":" baseball"} -{"input":"From: kime@mongoose.torolab.ibm.com (Edward Kim)\nSubject: Re: Ind. Source Picks Baerga Over Alomar: Case Closed \nIn-Reply-To: tedward@cs.cornell.edu's message of Fri, 16 Apr 1993 19:07:35 GMT\nDistribution: na\nLines: 8\n\t<1993Apr16.190735.13322@cs.cornell.edu>\nOrganization: IBM Toronto Lab\n\n> That's a joke! (Alomar might not be a gold-glover, but he's certainly\n> no worse than Baerga defensively.)\nActually Alomar is a two-time gold-glover (91-92).\n\n> \n> -Valentine\n\nEdk\n\n###\n\n","output":" baseball"} -{"input":"From: cmk@athena.mit.edu (Charles M Kozierok)\nSubject: Re: Best Homeruns\nOrganization: Massachusetts Institute of Technology\nLines: 22\nNNTP-Posting-Host: electric-monk.mit.edu\n\nIn article <1993Apr16.172502.2301@osf.org> dswartz@osf.org (Dan Swartzendruber) writes:\n} In article <4200419@hpcc01.corp.hp.com> boell@hpcc01.corp.hp.com (Donald P Boell) writes:\n} >I'd have to say the most impressive HRs I've ever see came from Dave Kingman\n} >and his infamous moon-raker drives...\n} \n} I remember one he hit circa 1976 at Wrigley Field that went across\n} the street (in dead center field) and hit a house on the roof. He\n} whiffed a lot, but when he *did* connect, watch out!\n\nthe best home run i have *ever* seen came off, believe it or not,\nRoger Clemens (sorry, Val) a couple of years ago. he threw a ball to\nIncaviglia which was literally at Inky's neck, and he absolutely \nhammered the crap out of it. after the swing, Clemens nonchalantly\nmotioned for a new ball--he didn't even turn around to look, or\neven get upset. the ball hit the lights in the left-field standard,\nsome 70 or so feet about the Green Monster (over 100 feet above the\nground total!)\n\ntruly an amazing shot.\n\n-*-\ncharles\n\n###\n\n","output":" baseball"} -{"input":"From: pkortela@snakemail.hut.fi (Petteri Kortelainen)\nSubject: Re: Helsinki\/Stockholm & NHL expansion?\nOrganization: Helsinki University of Technology, Finland\nLines: 20\nDistribution: inet\n\t <1993Apr15.095653.17514@abo.fi>\nNNTP-Posting-Host: lk-hp-17.hut.fi\nIn-reply-to: MLINDROOS@FINABO.ABO.FI's message of Thu, 15 Apr 1993 09:56:53 GMT\n\nIn article <1993Apr15.095653.17514@abo.fi> MLINDROOS@FINABO.ABO.FI (Marcus Lindroos INF) writes:\n\n>In franti@polaris.utu.fi writes:\n\n\n>Not too low perhaps, but surely not as high as that of an European NHL\n>division. The Finnish team, for example, would contain all players currently \n on\n>the national team plus a top-class foreigner or two. They would be in an\n>entirely different league than TPS or Jokerit, both of whom have perhaps a\n>dozen players of international class - if even that. Why settle for a minor\n>league when you could have the best?\n\nHow many players of international class an average NHL team has. 6-10?\nTop players just play more in smaller rinks. Is the quality of European hockey\nreally poor, then recent years only few north-american (usually good farm \nplayers) players have got place in Finnish league or Elitserien, while most \nhave been shipped back. \n\nPetteri Kortelainen\n\n###\n\n","output":" hockey"} -{"input":"From: gak@wrs.com (Richard Stueven)\nSubject: Re: Octopus in Detroit?\nReply-To: gak@wrs.com\nOrganization: Wind River Systems, Inc.\nLines: 10\nNntp-Posting-Host: gakbox\n\nIt's in the FAQ.\n\nhave fun\ngak\n\n---\nRichard Stueven AHA# 22584 |----------| He has erected a multitude of new\nInternet: gak@wrs.com |----GO----| offices, and sent hither swarms\nATTMAIL: ...!attmail!gakhaus!gak |---SHARX--| of officers to harass our people,\nCow Palace: 107\/H\/3-4 |----------| and eat out their substance.\n\n###\n\n","output":" hockey"} -{"input":"From: fester@island.COM (Mike Fester)\nSubject: Re: Notes on Jays vs. Indians Series\nOrganization: \/usr\/local\/rn\/organization\nDistribution: na\nLines: 38\n\nIn article <1993Apr13.221704.4291@midway.uchicago.edu> thf2@midway.uchicago.edu writes:\n>In article rudy@netcom.com (Rudy Wade) writes:\n>>In article <1993Apr13.195301.22652@CSD-NewsHost.Stanford.EDU> nlu@Xenon.Stanford.EDU (Nelson Lu) writes:\n>>>Guess which line is which:\n>>>\tBA\tOBP\tSLG\tAB\tH\t2B\t3B\tHR\tBB\n>>>X\t.310\t.405\t.427\t571\t177\t27\t8\t8\t87\n>>>Y\t.312\t.354\t.455\t657\t205\t32\t1\t20\t35\n>>\n>>>The walks should give it away. OBP's, in general, somewhat more valuable than\n>>>slugging, and Alomar's edge in OBP was quite a bit larger than Baerga's edge\n>>>in slugging.\n>>\n>>I'm no SDCN, but what's more valuable:\n>>\n>>28 hits w\/5 more doubles, 12 more HRs OR\n>>7 more triples and 52 BBs? (Let's not forget the 39 extra SBs. How many CS?)\n>\n>Alomar had 9 CS. Baerga had 2.\n>\n>Don't forget the 59 more outs Baerga had (his GIDP balances out his CS, and\n>he had one more sacrifice than Alomar). A replacement level second baseman\n>could have had 17 hits, 5 walks, and a couple of XBH for the additional\n>outs Baerga had. A triple is little different than a home run. We're talking\n>exchanging almost 60 walks for six or seven home runs and four doubles. I \n>would say the almost-60 walks are more valuable.\n\nAlso, Alomar got a FAR greater boost from his home park than Baerga did from \nhis. And \"six or seven home runs\"? Hmm.\n\nSo, if you wanted to pick a second baseman to play in Toronto, you'd take \nAlomar. Anywhere else, and you'd probably take Baerga.\n\nMike\n-- \nDisclaimer - These opiini^H^H damn! ^H^H ^Q ^[ .... :w :q :wq :wq! ^d ^X ^?\nexit X Q ^C ^? :quitbye CtrlAltDel ~~q :~q logout save\/quit :!QUIT\n^[zz ^[ZZZZZZ ^vi man vi ^@ ^L ^[c ^# ^E ^X ^I ^T ? help helpquit ^D ^d !!\nman help ^C ^c :e! help exit ?Quit ?q CtrlShftDel \"Hey, what does Stop L1A d...\"\n\n###\n\n","output":" baseball"} -{"input":"From: brifre1@ac.dal.ca\nSubject: Yet more crazy predictions\nOrganization: Dalhousie University, Halifax, Nova Scotia, Canada\nLines: 36\n\n\nWell here it goes...my crazy predictions (which never come true, but hey..)\n\nAdams\n\tBos vs. Buf - Bos in 5 (cakewalk for the hot Bruins)\n\tQue vs. Mon - Que in 6 (best series of the first round)\n\nPatrick\n\tPit vs. NYI - Pit in 5 (NYI wins fourth game)\n\tWas vs. NJD - NJD in 7 (a grueling upset, possibly OT in game 7)\n\nNorris\n\tChi vs. StL - Chi in 5 (StL is no match for Keenan's Krew)\n\tDet vs. Tor - Tor in 6 (Clark steps it up in playoffs this year)\n\nSmythe (who cares?)\n\tVan vs. Win - Win in 7 (so I'm caught up in Teemu-mania, sue me!)\n\tCal vs. LAK - Cal in 5 (LA sucks!!!!!!!!! IMO)\n\nDivision finals\n\tBos vs. Que - Bos in 7 (killer games, watch for Cam to shine)\n\tPit vs. NJD - Pit in 6 (NJD go insane, kill all on ice, but Pit wins)\n\tChi vs. Tor - Tor in 7 (Tor defense finally get it together)\n\tCal vs. Win - Cal in 6 (Win too tired after 1st series)\n\nConference finals\n\tPit vs. Bos - Bos in 6 (Pit too beat up by NJD to play (I hope))\n\tCal vs. Tor - Tor in 6 (Vernon turns into a sieve)\n\nStanley Cup\n\tBos vs. Tor - Tor in 7 (Two totally different teams, who knows? Dreams\n\t\t\t\tcan come true, pig might one day evolve wings)\n\nFeel free to laugh at my predictions, I always do!\n\nBarfly\n\n###\n\n","output":" hockey"} -{"input":"From: drw3l@delmarva.evsc.Virginia.EDU (David Robert Walker)\nSubject: Re: Braves Pitching UpdateDIR\nOrganization: University of Virginia\nLines: 34\n\nIn article <8994@blue.cis.pitt.edu> traven@pitt.edu (Neal Traven) writes:\n>\n>One of the chapters in Palmer and Thorn's 'Hidden Game' is titled\n>'Pitching is 44% of Baseball,' implying that fielding is 6%. How do\n>they determine that? Beats me -- it's been a long, long time since I\n>read it.\n\nThis was (my opinion) the stupidest thing in the Hidden Game. The\nargument was\n\n1) Defense, or runs allowed, is 50% of the game.\n2) Unearned runs amount to 12% of the runs allowed; earned runs, 88%.\n\n3) Since unearned runs are the result of fielding, not pitching, and\nearned runs are the product of pitching, not fielding, fielding is 12%\nof defense and pitching is 88% of defense.\n4) Caombining with #1, pitching is 44% of the game, fielding 6%.\n\nPete is usually sharper than that. My own feel is that fielding is in\nthe 25-33% of defense range; call it 30-70 between fielding and\npitching.\n\n>One also has to separate offense into batting and baserunning, with the\n>split probably somewhere around 49.5% and 0.5%.\n\nI'd give baserunning a little more credit than that, maybe 45-5, or\neven 40-10. Give a team of Roberto Alomar and a team of John Oleruds\nidentical batting stats (which wouldn't be that unreasonable), and\neven if you don't let Roberto steal a single base, they'll score a lot\nmore than the Oleruds by going first-to-third more often. (No offense,\nGordon).\n\nClay D.\n\n###\n\n","output":" baseball"} -{"input":"From: stamber@rainbow.ecn.purdue.edu (Kevin L. Stamber)\nSubject: Re: How difficult is it to get Penguin tickets?\nOrganization: Purdue University Engineering Computer Network\nLines: 27\n\nIn article <1993Apr18.201811.28965@magnus.acs.ohio-state.edu>, dmoney@magnus.acs.ohio-state.edu (Dean R Money) writes:\n> The subject line says it all. Is it terribly difficult to get tickets\n> to Penguins games, especially now that they are in the playoffs? Would\n> it be easy to find scalpers outside of the Igloo selling tickets?\n> \n> Dean Money\n> dmoney@magnus.acs.ohio-state.edu\n\n Here is my traditional experience with tickets, playoffs and otherwise,\nat the Civic Arena.\n\n Scalping is illegal but nonetheless present outside the Arena. Best \nstrategy, given that you don't mind missing the Anthem (which is OK if B.E.\nTaylor decides to come back ever again :) ) is to wait until 7:40 or 7:45,\nwhen the game is rolling; the scalpers are at this point desperate to sell\nand will reduce to near or at face value to get rid of their tickets.\n\n Playoffs are a little different in that good seats will go early on; \nwhat's left at 7:45 may be nosebleed material (D, E sections).\n\nOthers can add on their opinions as well.\n\nKevin L. Stamber\nPurdue University\nPENGUINS 6 DEVILS 3 -- Pens lead series 1 game to none\n\n###\n\n","output":" hockey"} -{"input":"From: holger.ohlwein@ap.mchp.sni.de (Holger Ohlwein)\nSubject: Re: Canada 3 Sweden 1 at the World Champioships\nReply-To: holger.ohlwein@ap.mchp.sni.de (Holger Ohlwein)\nOrganization: Siemens Nixdorf Informationssysteme AG\nLines: 16\nNNTP-Posting-Host: 139.21.16.6\n\nIn article <20APR199319243244@venus.cc.hollandc.pe.ca>, white@venus.cc.hollandc.pe.ca (Take me Baby!) writes:\n> \n> \tToday at the World Championships in Munich, Canada scored an \n> impressive 3-1 victory over the defending World Champs, Sweden. \n \nIn the game *I* have seen yesterday in the Olympiahalle of Munich\nCanada won 4-1 against Sweden! The last goal for Canada was at 19:59 in\nthe 3rd period. Maybe you shouldn't go and get you another beer \nbefore the game is over and then post imaginary results...\n\nHolger\n\n-- \nS I E M E N S Holger Ohlwein AP153 Otto-Hahn-Ring 6 8000 Muenchen 83\n------------- Tel: + 49 (89) 636-3746 Email: holger.ohlwein@ap.mchp.sni.de\nN I X D O R F Never put off till tomorrow what you can avoid all together.\n\n###\n\n","output":" hockey"} -{"input":"From: steph@pegasus.cs.uiuc.edu (Dale Stephenson)\nSubject: Hits Stolen -- Second Base 1992\nSummary: Stolen Hits for all second basemen\nKeywords: second defense\nOrganization: University of Illinois, Dept. of Comp. Sci., Urbana, IL\nLines: 117\n\nDisclaimer -- This is for fun.\n\nIn my computerized baseball game, I keep track of a category called\n\"stolen hits\", defined as a play made that \"an average fielder would not\nmake with average effort.\" Using the 1992 Defensive Averages posted\nby Sherri Nichols (Thanks Sherri!), I've figured out some defensive stats\nfor the second basemen. Hits Stolen have been redefined as \"Plays Kurt\nStillwell would not have made.\"\n\nOK, I realize that's unfair. Kurt's probably the victim of pitching staff,\nfluke shots, and a monster park factor. But let's put it this way: If we\nreplaced every second baseman in the NL with someone with Kurt's 57.6% out\nmaking ability, how many extra hits would go by?\n\nTo try and correlate it to reality a little more, I've calculated Net\nHits Stolen, based on the number of outs made compared to what a league\naverage fielder would make. By the same method I've calculated Net Double\nPlays, and Net Extra Bases (doubles and triples let by).\n\nFinally, I throw all this into a a formula I call Defensive Contribution, or\nDCON :->. Basically, it represents the defensive contribution of a player.\nI add this number to OPS to get DOPS (Defense + Onbase Plus Slug), which\nshould represent the player's total contribution to the team. So don't\ntake it too seriously. The formula for DCON appears at the end of this\narticle.\n\nThe short version -- definition of terms\nHS -- Hits Stolen -- Extra outs compared to Kurt Stillwell\nNHS -- Net Hits Stolen -- Extra outs compared to average fielder\nNDP -- Net Double Plays -- Extra double plays turned compared to avg fielder\nNEB -- Net Extra Bases -- Extra bases prevented compared to avg. fielder\nDCON -- Defensive Contribution -- bases and hits prevented, as a rate.\nDOPS -- DCON + OPS -- quick & dirty measure of player's total contribution.\n\nNational League\n\nname HS NHS NDP NEB DCON DOPS\nAlicea, L. 50 21 2 -1 .160 .865\nSandberg, R. 108 42 1 1 .134 1.015\nThompson, R. 65 20 5 -1 .104 .852\nLind, J. 66 8 -2 1 .027 .571\nDoran, B. 31 -1 4 0 .014 .705\nDeShields, D. 51 1 -2 1 -.002 .755\nHarris, L. 25 -4 0 1 -.019 .602\nLemke, M. 43 -1 -5 -5 -.038 .573\nMorandini, M. 37 -9 -6 0 -.069 .580\nRandolph, W. 13 -16 3 -1 -.088 .582\nBiggio, C. 34 -26 -4 0 -.091 .656\nStillwell, K. 0 -43 -3 -1 -.236 .336\n\nOrdered by DOPS\n\n1.015 Sandberg\n .865 Alicea\n .852 Thompson\n .755 DeShields\n .705 Doran\n .678 *NL Average*\n .656 Biggio\n .602 Harris\n .582 Randolph\n .580 Morandini\n .573 Lemke\n .571 Lind\n .336 Stillwell\n\nAmerican League\n---------------\n\nname HS NHS NDP NEB DCON DOPS\nFletcher, S. 59 18 5 1 .116 .811\nReed, J. 83 17 3 1 .071 .708\nRipken, B. 56 9 -1 -1 .044 .631\nBaerga, C. 67 0 10 0 .029 .838\nBlankenship, L. 34 2 2 1 .023 .757\nMiller, K. 34 -4 1 -1 -.016 .725\nAlomar, R. 62 4 -9 -2 -.020 .812\nKnoblauch, C. 50 -13 7 -3 -.024 .718\nBordick, M. 37 -4 -2 -1 -.025 .704\nKelly, P. 42 -1 -5 -1 -.039 .636\nWhitaker, L. 40 -8 -1 -2 -.041 .806\nReynolds, H. 47 -6 -5 1 -.043 .603\nSax, S. 56 -6 -9 -1 -.052 .555\nSojo, L. 28 -11 -3 0 -.075 .602\n\nOrder by DOPS\n\n.838 Baerga\n.812 Alomar\n.811 Fletcher\n.806 Whitaker\n.757 Blankenship\n.725 Miller\n.718 Knoblauch\n.708 Reed\n.704 Bordick\n.691 *AL Average*\n.636 Kelly\n.631 Ripken\n.603 Reynolds\n.602 Sojo\n.555 Sax\n\nMore discussion --\n\nDCON formula: ((NHS + NDP)\/PA) + ((NHS + NDP + NEB)\/AB)\nWhy such a bizzare formula? Basically, it's designed to be added into the\nOPS, with the idea that \"a run prevented is as important as a run scored\".\nThe extra outs are factored into OBP, while the extra bases removed are \nfactored into SLG. That's why I used PA and AB as the divisors.\n\nFor more discussion see the post on Hits Stolen -- First Base 1992\n-- \nDale J. Stephenson |*| (steph@cs.uiuc.edu) |*| Baseball fanatic\n\n \"It is considered good to look wise, especially when not \n overburdened with information\" -- J. Golden Kimball\n\n###\n\n","output":" baseball"} -{"input":"From: genetic+@pitt.edu (David M. Tate)\nSubject: Re: Young Catchers\nArticle-I.D.: blue.7977\nOrganization: Department of Industrial Engineering\nLines: 65\n\nmss@netcom.com (Mark Singer) said:\n>In article <7862@blue.cis.pitt.edu> genetic+@pitt.edu (David M. Tate) writes:\n>\n>Well, perhaps if the Braves had no one else worth playing this year it\n>would be Lopez in there. But they do have others worth playing, at\n>least in *their* opinion. \n\nCatcher is their weakest position, with the possible exception of second base.\nThey have a chance to simultaneously replace their biggest offensive problem\nspot with a well-above-average offensive player *and* acclimate a highly\npromising potential star with no pressure on him to carry the team, and they\nwant to play *Olson* and *Berryhill* instead?!\n\n>>I disagree, in that I don't think it *is* a _tangible_ skill, any more than\n>>leadership is. I don't deny that it is a *real* skill, and that some catchers\n>>may be much better than others at it, but I really don't see any way that we\n>>could ever know who they are. Nichols's Law of Catcher Defense is eerily\n>>accurate far too often for me to take defensive assessments of catchers very\n>>seriously.\n>\n>Sorry. New. Don't know Nichols' Law. \n\n\"A catcher's defensive reputation will be inversely proportional to his\n recent offensive level of performance.\" Thus, Mickey Tettleton goes (in\n the media) from being a no-hit defensive whiz to a slugging thumb-finger\n in two short years. The rule doesn't apply to perceived \"superstars\", who\n get the Gold Glove Offensive Transfer effect instead. Greg Olson is probably\n considered to be a good defensive catcher precisely because he can't hit.\n\n\n>Don't believe in catchers'\n>era. But I am interested in pitchers' eras with different catchers.\n\nAren't they the same thing?\n\n>In other words, we know more than they do, so the only logic behind \n>a different decision than we would make must be financial. \n\nEither that or just stupidity.\n\n>I presume\n>we feel this way about other franchises than Atlanta, no?\n\nOf course.\n\n>>Is it fair to the young players? No. Does it make organizational sense? \n>>I think it does.\n>\n>Well if it does make organizational sense, one can hardly fault them\n>for their decisions. I mean, please don't tell me how to run my\n>business. Especially when I'm being successful.\n\nOne could make the same sort of argument in other cases. Pete Rose, in\npursuing Ty Cobb's record, was a huge gate attraction (and national media\nmagnet). The Reds made a lot of money off that; they also wasted the prime\nof Eric Davis. That may be \"good business\", but that doesn't mean I don't\nloathe them for it.\n\n\n\n-- \n David M. Tate | (i do not know what it is about you that closes\n posing as: | and opens; only something in me understands\n e e (can | the pocket of your glove is deeper than Pete Rose's)\n dy) cummings | nobody, not even Tim Raines, has such soft hands\n\n###\n\n","output":" baseball"} -{"input":"From: fmsalvat@eos.ncsu.edu (FRANK MICHAE SALVATORE)\nSubject: Re: Get Real. Caps have no chance\nOriginator: fmsalvat@c00532-106ps.eos.ncsu.edu\nReply-To: fmsalvat@eos.ncsu.edu (FRANK MICHAE SALVATORE)\nOrganization: North Carolina State University, Project Eos\nLines: 15\n\n\nIn article <1993Apr15.162719@staff.dccs.upenn.edu>, filinuk@staff.dccs.upenn.edu (Geoff Filinuk) writes:\n] \tAnyone who really believes that the Caps can beat\n> the Pens are kidding themselves. The Pens may not loose\n> one game in the playoffs.\n\n\nLet's be honest. The Pens may not 'loose' one game as you\nput it, but they will definitely lose one game. Remember,\nthe regular season doesn't mean much when it comes to \nplayoff time. The Caps have a shot at least - the Flyers\nsure don't\n\nFrank Salvatore\nfmsalvat@eos.ncsu.edu\n\n###\n\n","output":" hockey"} -{"input":"From: tedward@cs.cornell.edu (Edward [Ted] Fischer)\nSubject: Re: Rickey Henderson\nOrganization: Cornell Univ. CS Dept, Ithaca NY 14853\nDistribution: usa\nLines: 12\n\nIn article <1993Apr5.173500.26383@ra.msstate.edu> js1@Isis.MsState.Edu (Jiann-ming Su) writes:\n>I say buy out Henderson's contract and let him go bag groceries. Next \n>season, you'll be able to sign him for nothing. That goes for any bitching\n>ball player.\n\nI doubt Henderson would clear waivers. And if he did, he would\ninstantly be signed for the major league minimum, with Oakland picking\nup the remaining $3 million tab.\n\nSome GMs value on-field performance too...\n\n-Valentine\n\n###\n\n","output":" baseball"} -{"input":"From: dxf12@po.CWRU.Edu (Douglas Fowler)\nSubject: Re: Jack Morris\nOrganization: Case Western Reserve University, Cleveland, OH (USA)\nLines: 60\nReply-To: dxf12@po.CWRU.Edu (Douglas Fowler)\nNNTP-Posting-Host: slc12.ins.cwru.edu\n\n\nIn a previous article, tedward@cs.cornell.edu (Edward [Ted] Fischer) says:\n\n>In article <1qr05cINNpel@skeena.ucs.ubc.ca> stlouis@unixg.ubc.ca (Phill St. Louis) writes:\n>>Jack Morris' starts have been like his playoff starts. He has an ERA of\n>>17.18 in his 3 starts.\n>>\n>>What does luck have to do with a 17.18 ERA? He was lucky to get 21 wins\n>>last year, but he had an ERA of 4.04 with a team that scored a lot of\n>>runs. I would be happy if he could still pitch with an ERA of 4.04, but\n>>he seems to be suffering from a total callapse. \n>\n>Bad pitchers are more prone to this total collapse than good pitchers.\n>They are closer to the chasm of mediocrity. The smallest push and\n>they completely lose their grip.\n>\n But good ones can collapse somewhat, then come back the next year.\nBurleigh Grimes went from 20+ wins and an ERA of 3 or so in '24 to 13-19 and\nan ERA around 4 in '25. He pitched well for several more years. Carlton\nwon 13 and lost 20 the year after his 27-10 record. (Source: Bill James\nHistorical Baseball Abstract.)\n And let's not forget John Tudor, who started 1-5 and finished 21-6 in\n1985. He had a pretty bad ERA when you take Busch Stadium into account at\nthe start of the season.\n\n>>He gave up early runs\n>>in his '92 games and would get stronger as the game went on, thus giving\n>>up few runs in the last going. He stays in the game and gets the win.\n>>How else would he have pitched so many innings?\n>\n>Yup. He used to dig himself a hole, then get it together and stick in\n>until the run support eventually came through. This year he just\n>hasn't gotten it together.\n\n If I recall, he had a 4.50 ERA in the 1st half and a 3.50 ERA in the\n2nd half of last year. \n Hmmm, 21 runs in 11 innings. Suppose he starts 30 more games, and winds\nup w\/200 innings pitched. If he allows 4 runs a game in the next 189\ninnings, he'll have a 4.75 ERA or so at the end of the year. (I think I have\nhis totals right.) This is going to be hard to come back from.\n\n>>Jack may be finished. It is time to retire or be released, if he does\n>>not return to his form from last year.\n>\n>His $5 million contract is an awful lot to eat!\n\n My 1st hunch is that Morris is very gutsy, and that he may be pitching\nthrough an injury and not telling anyone. My 2nd guess is that he will be\nbanished to the bullpen the remainder of the season after a few more starts.\n(Perhaps when Stewart comes off the DL? Or will Danny Cox, who went 3 or 4\nscoreless innings against the Tribe today, start for Morris? He looks like\na really good one. Gaston is scrambling to find starters, I'd imagine.\nLuckily, the Jays have a very good offense.)\n I don't think they would dare release him before the end of the year.\nHe'll just be replaced by Stewart or Cox.\n-- \nDoug Fowler: dxf12@po.CWRU.edu : Me, age 4 & now: \"Mommys and Daddys & other\n Ever wonder if, after Casey : relatives have to give lots of hugs & love\nmissed the 3rd strike in the poem: & support, 'cause Heaven is just a great\nhe ran to first and made it? : big hug that lasts forever and ever!!!\"\n\n###\n\n","output":" baseball"} -{"input":"From: steph@cs.uiuc.edu (Dale Stephenson)\nSubject: Re: Notes on Jays vs. Indians Series\nOrganization: University of Illinois, Dept. of Comp. Sci., Urbana, IL\nDistribution: na\nLines: 38\n\nIn klopfens@andy.bgsu.edu (Bruce Klopfenstein) writes:\n\n>kime@mongoose.torolab.ibm.com (Edward Kim) writes:\n[...]\n>> \n>> I would tend to call the offensive contributions even, but Alomar wins hands\n>> down in defensive capabilities. I'm not just talking about the number of \n>> errors; nobody (including Lind!) has the range and athleticism at second base.\n>> I can't recall in the recent past anyone turning the double play better\n>> than Alomar. \n\n>Well, why don't you look up those stats? Baerga may not be the best defensive\n>second baseman in the league, but he's damn good. Check the stats for DPs\n>last year and see for yourself.\n\nAccording to the Defensive Average stats posted by Sherri, Baerga had the\nhighest percentage of DPs turned in the league, while Alomar had the worst.\nHowever, Alomar had a higher Defensive Average. So who would be better?\n\nUsing Alomar's opportunities (469 groundballs, 73 possible double plays)\nAlomar had 332 groundouts and turned 18 DPs.\nBaerga would have had (with same DA & DP%) 328 groundouts and 35 DPs.\n\nUsing Baerga's opportunites (545 groundballs, 99 possible double plays).\nAlomar would have had (with the same DA & DP%) 386 groundouts and 25 DPs.\nBaerga had 381 groundouts and 47 DPs.\n\nBaerga looks better, though it's possible his DP% would be lower with a \ndifferent SS.\n\nWill Baerga consistently turn twice as many double plays, however? Alomar\nhas established a high level of defense, Baerga has not. I would bet on\nAlomar to be better next year, but last year Baerga was just as good overall.\n-- \nDale J. Stephenson |*| (steph@cs.uiuc.edu) |*| Grad Student At Large\n\n \"It is considered good to look wise, especially when not \n overburdened with information\" -- J. Golden Kimball\n\n###\n\n","output":" baseball"} -{"input":"From: scott@asd.com (Scott Barman)\nSubject: Re: Jewish Baseball Players?\nOrganization: American Software Development Corp., West Babylon, NY\nLines: 18\n\nIn article <15APR93.14691229.0062@lafibm.lafayette.edu> VB30@lafibm.lafayette.edu (VB30) writes:\n>Just wondering. A friend and I were talking the other day, and\n>we were (for some reason) trying to come up with names of Jewish\n>baseball players, past and present. We weren't able to come up\n>with much, except for Sandy Koufax, (somebody) Stankowitz, and\n>maybe John Lowenstein. Can anyone come up with any more. I know\n>it sounds pretty lame to be racking our brains over this, but\n>humor us. Thanks for your help.\n>\n\nOh... I forgot... Art Shamsky, former Red and Mets player. Batted .301\nbetween injuries in 1969 (fell short of qualifying for Top 10 because of\ninjuries and platoon with Ron Swoboda; no Swobo wasn't Jewish).\n-- \nscott barman | Mets Mailing List (feed the following into your shell):\nscott@asd.com | mail mets-request@asd.com <\nSubject: Don Cherry - help me out, here\nOrganization: Administrative Computing & Info Services, Carnegie Mellon, Pittsburgh, PA\nLines: 12\nNNTP-Posting-Host: andrew.cmu.edu\n\n\n As a person who has rarely even SEEN Don Cherry and doesn't know\nanything about him, I don't know whether it is just this area\n(Pittsburgh) of the USA that is \"deprived\" of his broadcasts or whether\nhe's a Canadian thing altogether. Seriously, what is he all about? I\nknow he was a coach at one time, and from the volume of posts about him,\nSOMEONE surely is getting a steady diet of him somehow, but my question\nis, what is the deal with him? Secondly, are the comments of his that I\nread about on the net merely flame bait, or do people actually take him\nseriously? I gotta tell you, from what I see, he really sounds like an\nass. Let me know - maybe I'm missing something.\n\n###\n\n","output":" hockey"} -{"input":"From: Young-Soo Che \nSubject: Re: NHLPA poll (partial stats\/results)\nOrganization: Freshman, H&SS general, Carnegie Mellon, Pittsburgh, PA\nLines: 6\nNNTP-Posting-Host: andrew.cmu.edu\nIn-Reply-To: <1800@muller.loria.fr>\n\nAll these people who send in their polls should take a closer look at\nNJD, they are a very deep team, with two very capable goalies, and\nexcellent forwards and defensemen. Shooter in Richer, an all around do\nit all in Todd, chef Stasny-master of a thousand dishes, power play\ncaptain-Stevens. Take a look at the numbers, or play with them and see\nfor yourselves.\n\n###\n\n","output":" hockey"} -{"input":"From: mjones@fenway.aix.kingston.ibm.com (Mike Jones)\nSubject: Two stooges\nReply-To: mjones@donald.aix.kingston.ibm.com\nOrganization: IBM AIX\/ESA Development, Kingston NY\nLines: 9\n\nWell, the Red Sox have apparenly resigned Herm Winningham to a AAA contract.\nTed \"Larry\" Simmons signed him to a AAA contract then released him from\nBuffalo, allowing Lou \"Curly\" Gorman to circumvent the rule about not\nresigning free agents until May 1. Clearly, neither of these guys is bright\nenough to be Moe.\n\n Mike Jones | AIX High-End Development | mjones@donald.aix.kingston.ibm.com\n\nMake it right before you make it faster.\n\n###\n\n","output":" baseball"} diff --git a/website/docs/r/bedrock_custom_model.html.markdown b/website/docs/r/bedrock_custom_model.html.markdown index 091612e7691..473a4a30a68 100644 --- a/website/docs/r/bedrock_custom_model.html.markdown +++ b/website/docs/r/bedrock_custom_model.html.markdown @@ -24,7 +24,31 @@ This resource's [behaviors](https://developer.hashicorp.com/terraform/language/r ## Example Usage ```terraform -TODO +data "aws_bedrock_foundation_model" "example" { + model_id = "amazon.titan-text-express-v1" +} + +resource "aws_bedrock_custom_model" "example" { + custom_model_name = "example-model" + job_name = "example-job-1" + base_model_identifier = data.aws_bedrock_foundation_model.example.model_arn + role_arn = aws_iam_role.example.arn + + hyperparameters = { + "epochCount" = "1" + "batchSize" = "1" + "learningRate" = "0.005" + "learningRateWarmupSteps" = "0" + } + + output_data_config { + s3_uri = "s3://${aws_s3_bucket.output.id}/data/" + } + + training_data_config { + s3_uri = "s3://${aws_s3_bucket.training.id}/data/train.jsonl" + } +} ``` ## Argument Reference From ff0c84950b8bac31de6f32bf00b3e97d329431e0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 31 Jan 2024 16:25:19 -0500 Subject: [PATCH 41/62] Acceptance test output: % make testacc TESTARGS='-run=TestAccBedrockCustomModel_basic' PKG=bedrock ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/bedrock/... -v -count 1 -parallel 20 -run=TestAccBedrockCustomModel_basic -timeout 360m === RUN TestAccBedrockCustomModel_basic === PAUSE TestAccBedrockCustomModel_basic === CONT TestAccBedrockCustomModel_basic --- PASS: TestAccBedrockCustomModel_basic (69.19s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrock 79.063s From 3971cf9d6f39c6845774c218b4273567757f07c8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 31 Jan 2024 17:13:50 -0500 Subject: [PATCH 42/62] r/aws_bedrock_custom_model: Further acceptance tests. --- internal/service/bedrock/consts.go | 12 + internal/service/bedrock/custom_model.go | 6 +- internal/service/bedrock/custom_model_test.go | 234 ++++++++++++++++++ internal/service/bedrock/errors.go | 8 + internal/service/bedrock/exports_test.go | 2 +- 5 files changed, 259 insertions(+), 3 deletions(-) create mode 100644 internal/service/bedrock/consts.go create mode 100644 internal/service/bedrock/errors.go diff --git a/internal/service/bedrock/consts.go b/internal/service/bedrock/consts.go new file mode 100644 index 00000000000..e571fdc4591 --- /dev/null +++ b/internal/service/bedrock/consts.go @@ -0,0 +1,12 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package bedrock + +import ( + "time" +) + +const ( + propagationTimeout = 2 * time.Minute +) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index b454148e83f..10204dd2da1 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -299,7 +299,9 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat input.CustomModelTags = getTagsIn(ctx) input.JobTags = getTagsIn(ctx) - outputCJ, err := conn.CreateModelCustomizationJob(ctx, input) + outputRaw, err := tfresource.RetryWhenAWSErrMessageContains(ctx, propagationTimeout, func() (interface{}, error) { + return conn.CreateModelCustomizationJob(ctx, input) + }, errCodeValidationException, "Could not assume provided IAM role") if err != nil { response.Diagnostics.AddError("creating Bedrock Custom Model customization job", err.Error()) @@ -307,7 +309,7 @@ func (r *customModelResource) Create(ctx context.Context, request resource.Creat return } - jobARN := aws.ToString(outputCJ.JobArn) + jobARN := aws.ToString(outputRaw.(*bedrock.CreateModelCustomizationJobOutput).JobArn) job, err := findModelCustomizationJobByID(ctx, conn, jobARN) if err != nil { diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index e1689af2125..73c3c780538 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -70,6 +70,108 @@ func TestAccBedrockCustomModel_basic(t *testing.T) { }) } +func TestAccBedrockCustomModel_disappears(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrock_custom_model.test" + var v bedrock.GetModelCustomizationJobOutput + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckCustomModelDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccCustomModelConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCustomModelExists(ctx, resourceName, &v), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfbedrock.ResourceCustomModel, resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccBedrockCustomModel_tags(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrock_custom_model.test" + var v bedrock.GetModelCustomizationJobOutput + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckCustomModelDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccCustomModelConfig_tags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckCustomModelExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"base_model_identifier"}, + }, + { + Config: testAccCustomModelConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckCustomModelExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccCustomModelConfig_tags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckCustomModelExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func TestAccBedrockCustomModel_vpcConfig(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrock_custom_model.test" + var v bedrock.GetModelCustomizationJobOutput + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckCustomModelDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccCustomModelConfig_vpcConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCustomModelExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "vpc_config.0.security_group_ids.#", "1"), + resource.TestCheckResourceAttr(resourceName, "vpc_config.0.subnet_ids.#", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"base_model_identifier"}, + }, + }, + }) +} + func testAccCheckCustomModelDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).BedrockClient(ctx) @@ -265,3 +367,135 @@ resource "aws_bedrock_custom_model" "test" { } `, rName)) } + +func testAccCustomModelConfig_tags1(rName, tagKey1, tagValue1 string) string { + return acctest.ConfigCompose(testAccCustomModelConfig_base(rName), fmt.Sprintf(` +resource "aws_bedrock_custom_model" "test" { + custom_model_name = %[1]q + job_name = %[1]q + base_model_identifier = data.aws_bedrock_foundation_model.test.model_arn + role_arn = aws_iam_role.test.arn + + hyperparameters = { + "epochCount" = "1" + "batchSize" = "1" + "learningRate" = "0.005" + "learningRateWarmupSteps" = "0" + } + + output_data_config { + s3_uri = "s3://${aws_s3_bucket.output.id}/data/" + } + + training_data_config { + s3_uri = "s3://${aws_s3_bucket.training.id}/data/train.jsonl" + } + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1)) +} + +func testAccCustomModelConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return acctest.ConfigCompose(testAccCustomModelConfig_base(rName), fmt.Sprintf(` +resource "aws_bedrock_custom_model" "test" { + custom_model_name = %[1]q + job_name = %[1]q + base_model_identifier = data.aws_bedrock_foundation_model.test.model_arn + role_arn = aws_iam_role.test.arn + + hyperparameters = { + "epochCount" = "1" + "batchSize" = "1" + "learningRate" = "0.005" + "learningRateWarmupSteps" = "0" + } + + output_data_config { + s3_uri = "s3://${aws_s3_bucket.output.id}/data/" + } + + training_data_config { + s3_uri = "s3://${aws_s3_bucket.training.id}/data/train.jsonl" + } + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) +} + +func testAccCustomModelConfig_vpcConfig(rName string) string { + return acctest.ConfigCompose(testAccCustomModelConfig_base(rName), acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(` +resource "aws_security_group" "test" { + name = %[1]q + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} + +resource "aws_iam_policy" "vpc" { + name = "%[1]s-vpc" + + policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Effect" : "Allow", + "Action" : [ + "ec2:DescribeNetworkInterfaces", + "ec2:DescribeVpcs", + "ec2:DescribeDhcpOptions", + "ec2:DescribeSubnets", + "ec2:DescribeSecurityGroups", + "ec2:CreateNetworkInterface", + "ec2:CreateNetworkInterfacePermission", + "ec2:DeleteNetworkInterface", + "ec2:DeleteNetworkInterfacePermission", + "ec2:CreateTags" + ], + "Resource" : "*" + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "vpc" { + role = aws_iam_role.test.name + policy_arn = aws_iam_policy.vpc.arn +} + +resource "aws_bedrock_custom_model" "test" { + custom_model_name = %[1]q + job_name = %[1]q + base_model_identifier = data.aws_bedrock_foundation_model.test.model_arn + role_arn = aws_iam_role.test.arn + + hyperparameters = { + "epochCount" = "1" + "batchSize" = "1" + "learningRate" = "0.005" + "learningRateWarmupSteps" = "0" + } + + output_data_config { + s3_uri = "s3://${aws_s3_bucket.output.id}/data/" + } + + training_data_config { + s3_uri = "s3://${aws_s3_bucket.training.id}/data/train.jsonl" + } + + vpc_config { + security_group_ids = [aws_security_group.test.id] + subnet_ids = aws_subnet.test[*].id + } +} +`, rName)) +} diff --git a/internal/service/bedrock/errors.go b/internal/service/bedrock/errors.go new file mode 100644 index 00000000000..edf92a979c6 --- /dev/null +++ b/internal/service/bedrock/errors.go @@ -0,0 +1,8 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package bedrock + +const ( + errCodeValidationException = "ValidationException" +) diff --git a/internal/service/bedrock/exports_test.go b/internal/service/bedrock/exports_test.go index 2508f44cbf1..788d3926c16 100644 --- a/internal/service/bedrock/exports_test.go +++ b/internal/service/bedrock/exports_test.go @@ -5,7 +5,7 @@ package bedrock // Exports for use in tests only. var ( - ResourceCustomModelName = newCustomModelResource + ResourceCustomModel = newCustomModelResource ResourceModelInvocationLoggingConfiguration = newResourceModelInvocationLoggingConfiguration FindModelCustomizationJobByID = findModelCustomizationJobByID From fba2e9c6c59907cb85ce520f441e2b7f730a1d23 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 31 Jan 2024 17:14:12 -0500 Subject: [PATCH 43/62] Acceptance test output: % make testacc TESTARGS='-run=TestAccBedrockCustomModel_disappears\|TestAccBedrockCustomModel_tags\|TestAccBedrockCustomModel_vpcConfig' PKG=bedrock ACCTEST_PARALLELISM=2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/bedrock/... -v -count 1 -parallel 2 -run=TestAccBedrockCustomModel_disappears\|TestAccBedrockCustomModel_tags\|TestAccBedrockCustomModel_vpcConfig -timeout 360m === RUN TestAccBedrockCustomModel_disappears === PAUSE TestAccBedrockCustomModel_disappears === RUN TestAccBedrockCustomModel_tags === PAUSE TestAccBedrockCustomModel_tags === RUN TestAccBedrockCustomModel_vpcConfig === PAUSE TestAccBedrockCustomModel_vpcConfig === CONT TestAccBedrockCustomModel_disappears === CONT TestAccBedrockCustomModel_vpcConfig --- PASS: TestAccBedrockCustomModel_vpcConfig (60.12s) === CONT TestAccBedrockCustomModel_tags --- PASS: TestAccBedrockCustomModel_disappears (57.53s) --- PASS: TestAccBedrockCustomModel_tags (485.98s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrock 512.765s From 2ddfe549ea06081ff5c3b167874c76b18bff1faa Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 31 Jan 2024 17:18:09 -0500 Subject: [PATCH 44/62] Fix markdown-lint 'MD032/blanks-around-lists Lists should be surrounded by blank lines'. --- website/docs/r/bedrock_custom_model.html.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/r/bedrock_custom_model.html.markdown b/website/docs/r/bedrock_custom_model.html.markdown index 473a4a30a68..631e8cb21dc 100644 --- a/website/docs/r/bedrock_custom_model.html.markdown +++ b/website/docs/r/bedrock_custom_model.html.markdown @@ -12,10 +12,12 @@ Manages an Amazon Bedrock custom model. Model customization is the process of providing training data to a base model in order to improve its performance for specific use-cases. This Terraform resource interacts with two Amazon Bedrock entities: + 1. A Continued Pre-training or Fine-tuning job which is started when the Terraform resource is created. The customization job can take several hours to run to completion. The duration of the job depends on the size of the training data (number of records, input tokens, and output tokens), and [hyperparameters](https://docs.aws.amazon.com/bedrock/latest/userguide/custom-models-hp.html) (number of epochs, and batch size). 2. The custom model output on successful completion of the customization job. This resource's [behaviors](https://developer.hashicorp.com/terraform/language/resources/behavior) correspond to operations on these Amazon Bedrock entities: + * [_Create_](https://developer.hashicorp.com/terraform/plugin/framework/resources/create) starts the customization job and immediately returns. * [_Read_](https://developer.hashicorp.com/terraform/plugin/framework/resources/read) returns the status and results of the customization job. If the customization job has completed, the output model's properties are returned. * [_Update_](https://developer.hashicorp.com/terraform/plugin/framework/resources/update) updates the customization job's [tags](https://docs.aws.amazon.com/bedrock/latest/userguide/tagging.html). From 99cec8d789db7c4463979e56da6af7f27b6868d6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 07:30:51 -0500 Subject: [PATCH 45/62] Export 'waitModelCustomizationJobCompleted' for use in acceptance tests. --- internal/service/bedrock/exports_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/service/bedrock/exports_test.go b/internal/service/bedrock/exports_test.go index 788d3926c16..b86164beff4 100644 --- a/internal/service/bedrock/exports_test.go +++ b/internal/service/bedrock/exports_test.go @@ -8,5 +8,6 @@ var ( ResourceCustomModel = newCustomModelResource ResourceModelInvocationLoggingConfiguration = newResourceModelInvocationLoggingConfiguration - FindModelCustomizationJobByID = findModelCustomizationJobByID + FindModelCustomizationJobByID = findModelCustomizationJobByID + WaitModelCustomizationJobCompleted = waitModelCustomizationJobCompleted ) From 53d0a7441ae86fae5a0591027dc448258cedf235 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 07:32:39 -0500 Subject: [PATCH 46/62] 'flex.Float32FromFrameworkFloat64' not used. --- internal/framework/flex/float.go | 14 ---------- internal/framework/flex/float_test.go | 40 --------------------------- 2 files changed, 54 deletions(-) diff --git a/internal/framework/flex/float.go b/internal/framework/flex/float.go index 2760a18d399..d7f7250561b 100644 --- a/internal/framework/flex/float.go +++ b/internal/framework/flex/float.go @@ -10,20 +10,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -// Float32FromFrameworkFloat64 converts a Framework Float64 value to a float64 pointer. -func Float32FromFrameworkFloat64(ctx context.Context, v types.Float64) *float32 { - if v.IsNull() || v.IsUnknown() { - return nil - } - - f := v.ValueFloat64() - if f == 0 { - return nil - } - - return aws.Float32(float32(f)) -} - // Float64ToFramework converts a float64 pointer to a Framework Float64 value. // A nil float64 pointer is converted to a null Float64. func Float64ToFramework(ctx context.Context, v *float64) types.Float64 { diff --git a/internal/framework/flex/float_test.go b/internal/framework/flex/float_test.go index 176d751acda..167f33dd0e4 100644 --- a/internal/framework/flex/float_test.go +++ b/internal/framework/flex/float_test.go @@ -13,46 +13,6 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" ) -func TestFloat32FromFrameworkFloat64(t *testing.T) { - t.Parallel() - - type testCase struct { - input types.Float64 - expected *float32 - } - tests := map[string]testCase{ - "valid float64": { - input: types.Float64Value(42.1), - expected: aws.Float32(42.1), - }, - "valid float64Small": { - input: types.Float64Value(.3), - expected: aws.Float32(.3), - }, - "zero float64": { - input: types.Float64Value(0), - expected: nil, - }, - "nil float64": { - input: types.Float64Null(), - expected: nil, - }, - } - - for name, test := range tests { - name, test := name, test - t.Run(name, func(t *testing.T) { - t.Parallel() - - got := flex.Float32FromFrameworkFloat64(context.Background(), test.input) - - if diff := cmp.Diff(got, test.expected); diff != "" { - t.Errorf("unexpected diff (+wanted, -got): %s", diff) - } - }) - } -} - func TestFloat64ToFramework(t *testing.T) { t.Parallel() From c5ffce708b5167d16ae14d45135f4267a820cc12 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 07:59:13 -0500 Subject: [PATCH 47/62] Restore 'flex.StringEnum.StringEnumValue'. --- internal/framework/types/string_enum.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/internal/framework/types/string_enum.go b/internal/framework/types/string_enum.go index 41d52518eb6..650a8d0c3aa 100644 --- a/internal/framework/types/string_enum.go +++ b/internal/framework/types/string_enum.go @@ -174,3 +174,10 @@ func (v StringEnum[T]) Type(context.Context) attr.Type { func (v StringEnum[T]) ValueEnum() T { return T(v.ValueString()) } + +// StringEnumValue is useful if you have a zero value StringEnum but need a +// way to get a non-zero value such as when flattening. +// It's called via reflection inside AutoFlEx. +func (v StringEnum[T]) StringEnumValue(value string) StringEnum[T] { + return StringEnum[T]{StringValue: basetypes.NewStringValue(value)} +} From 1d468bbb103933ef106eef36ab9bd92ce2d65ba4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 08:01:14 -0500 Subject: [PATCH 48/62] bedrock: Move stuff around. --- internal/service/bedrock/custom_model.go | 29 +++++++++++++++++++ .../bedrock/custom_model_data_source.go | 29 ------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 10204dd2da1..a7f874b8a27 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -648,3 +648,32 @@ func (data *resourceCustomModelData) InitFromID() error { func (data *resourceCustomModelData) setID() { data.ID = data.JobARN } + +type customModelOutputDataConfigModel struct { + S3URI types.String `tfsdk:"s3_uri"` +} + +type customModelTrainingDataConfigModel struct { + S3URI types.String `tfsdk:"s3_uri"` +} + +type customModelTrainingMetricsModel struct { + TrainingLoss types.Float64 `tfsdk:"training_loss"` +} + +type customModelValidationDataConfigModel struct { + Validators fwtypes.ListNestedObjectValueOf[customModelValidatorConfigModel] `tfsdk:"validators"` +} + +type customModelValidationMetricsModel struct { + ValidationLoss types.Float64 `tfsdk:"validation_loss"` +} + +type customModelValidatorConfigModel struct { + S3URI types.String `tfsdk:"s3_uri"` +} + +type customModelVPCConfigModel struct { + SecurityGroupIDs fwtypes.SetValueOf[types.String] `tfsdk:"security_group_ids"` + SubnetIDs fwtypes.SetValueOf[types.String] `tfsdk:"subnet_ids"` +} diff --git a/internal/service/bedrock/custom_model_data_source.go b/internal/service/bedrock/custom_model_data_source.go index 4d9afd0eac7..35c65dd1bba 100644 --- a/internal/service/bedrock/custom_model_data_source.go +++ b/internal/service/bedrock/custom_model_data_source.go @@ -176,32 +176,3 @@ type customModelDataSourceModel struct { ValidationDataConfig fwtypes.ListNestedObjectValueOf[customModelValidationDataConfigModel] `tfsdk:"validation_data_config"` ValidationMetrics fwtypes.ListNestedObjectValueOf[customModelValidationMetricsModel] `tfsdk:"validation_metrics"` } - -type customModelOutputDataConfigModel struct { - S3URI types.String `tfsdk:"s3_uri"` -} - -type customModelTrainingDataConfigModel struct { - S3URI types.String `tfsdk:"s3_uri"` -} - -type customModelTrainingMetricsModel struct { - TrainingLoss types.Float64 `tfsdk:"training_loss"` -} - -type customModelValidationDataConfigModel struct { - Validators fwtypes.ListNestedObjectValueOf[customModelValidatorConfigModel] `tfsdk:"validators"` -} - -type customModelValidationMetricsModel struct { - ValidationLoss types.Float64 `tfsdk:"validation_loss"` -} - -type customModelValidatorConfigModel struct { - S3URI types.String `tfsdk:"s3_uri"` -} - -type customModelVPCConfigModel struct { - SecurityGroupIDs fwtypes.SetValueOf[types.String] `tfsdk:"security_group_ids"` - SubnetIDs fwtypes.SetValueOf[types.String] `tfsdk:"subnet_ids"` -} From 9906cb4c79056ee77d43be1f8386cf1bb8e55e66 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 08:29:53 -0500 Subject: [PATCH 49/62] Add 'TestAccBedrockCustomModel_validationDataConfig'. --- internal/service/bedrock/custom_model.go | 2 +- internal/service/bedrock/custom_model_test.go | 63 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index a7f874b8a27..2928594d2e2 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -662,7 +662,7 @@ type customModelTrainingMetricsModel struct { } type customModelValidationDataConfigModel struct { - Validators fwtypes.ListNestedObjectValueOf[customModelValidatorConfigModel] `tfsdk:"validators"` + Validators fwtypes.ListNestedObjectValueOf[customModelValidatorConfigModel] `tfsdk:"validator"` } type customModelValidationMetricsModel struct { diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index 73c3c780538..88bcb45eda5 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -141,6 +141,37 @@ func TestAccBedrockCustomModel_tags(t *testing.T) { }) } +func TestAccBedrockCustomModel_validationDataConfig(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrock_custom_model.test" + var v bedrock.GetModelCustomizationJobOutput + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckCustomModelDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccCustomModelConfig_validationDataConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCustomModelExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "validation_data_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "validation_data_config.0.validator.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "validation_data_config.0.validator.0.s3_uri"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"base_model_identifier"}, + }, + }, + }) +} + func TestAccBedrockCustomModel_vpcConfig(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -429,6 +460,38 @@ resource "aws_bedrock_custom_model" "test" { `, rName, tagKey1, tagValue1, tagKey2, tagValue2)) } +func testAccCustomModelConfig_validationDataConfig(rName string) string { + return acctest.ConfigCompose(testAccCustomModelConfig_base(rName), fmt.Sprintf(` +resource "aws_bedrock_custom_model" "test" { + custom_model_name = %[1]q + job_name = %[1]q + base_model_identifier = data.aws_bedrock_foundation_model.test.model_arn + role_arn = aws_iam_role.test.arn + + hyperparameters = { + "epochCount" = "1" + "batchSize" = "1" + "learningRate" = "0.005" + "learningRateWarmupSteps" = "0" + } + + output_data_config { + s3_uri = "s3://${aws_s3_bucket.output.id}/data/" + } + + training_data_config { + s3_uri = "s3://${aws_s3_bucket.training.id}/data/train.jsonl" + } + + validation_data_config { + validator { + s3_uri = "s3://${aws_s3_bucket.validation.id}/data/validate.jsonl" + } + } +} +`, rName)) +} + func testAccCustomModelConfig_vpcConfig(rName string) string { return acctest.ConfigCompose(testAccCustomModelConfig_base(rName), acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(` resource "aws_security_group" "test" { From ec95a52370ed7855a315eb0e43f9f73ace670ed3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 08:30:07 -0500 Subject: [PATCH 50/62] Acceptance test output: % make testacc TESTARGS='-run=TestAccBedrockCustomModel_validationDataConfig' PKG=bedrock ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/bedrock/... -v -count 1 -parallel 20 -run=TestAccBedrockCustomModel_validationDataConfig -timeout 360m === RUN TestAccBedrockCustomModel_validationDataConfig === PAUSE TestAccBedrockCustomModel_validationDataConfig === CONT TestAccBedrockCustomModel_validationDataConfig --- PASS: TestAccBedrockCustomModel_validationDataConfig (39.58s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrock 50.791s From 9e9023b2935fd58e79c93aa2a744f439073ea167 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 11:39:26 -0500 Subject: [PATCH 51/62] d/aws_bedrock_custom_models: Tidy up. --- internal/service/bedrock/custom_model_test.go | 39 +++++ .../bedrock/custom_models_data_source.go | 16 +- .../bedrock/custom_models_data_source_test.go | 149 +----------------- .../d/bedrock_custom_models.html.markdown | 28 +--- 4 files changed, 59 insertions(+), 173 deletions(-) diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index 88bcb45eda5..7aca6a47520 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -172,6 +172,45 @@ func TestAccBedrockCustomModel_validationDataConfig(t *testing.T) { }) } +func TestAccBedrockCustomModel_validationDataConfigWaitForCompletion(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrock_custom_model.test" + var v bedrock.GetModelCustomizationJobOutput + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckCustomModelDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccCustomModelConfig_validationDataConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCustomModelExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "validation_data_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "validation_data_config.0.validator.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "validation_data_config.0.validator.0.s3_uri"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"base_model_identifier"}, + }, + { + PreConfig: func() {}, + Config: testAccCustomModelConfig_validationDataConfig(rName), + RefreshState: true, + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "job_status", "Completed"), + ), + }, + }, + }) +} + func TestAccBedrockCustomModel_vpcConfig(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) diff --git a/internal/service/bedrock/custom_models_data_source.go b/internal/service/bedrock/custom_models_data_source.go index 6f8d4405581..c402f2896d0 100644 --- a/internal/service/bedrock/custom_models_data_source.go +++ b/internal/service/bedrock/custom_models_data_source.go @@ -39,11 +39,9 @@ func (d *customModelsDataSource) Schema(ctx context.Context, request datasource. Computed: true, ElementType: types.ObjectType{ AttrTypes: map[string]attr.Type{ - "base_model_arn": types.StringType, - "base_model_name": types.StringType, - "creation_time": fwtypes.TimestampType, - "model_arn": types.StringType, - "model_name": types.StringType, + "creation_time": fwtypes.TimestampType, + "model_arn": types.StringType, + "model_name": types.StringType, }, }, }, @@ -90,9 +88,7 @@ type customModelsDataSourceModel struct { } type customModelSummaryModel struct { - BaseModelARN types.String `tfsdk:"base_model_arn"` - BaseModelName types.String `tfsdk:"base_model_name"` - CreationTime fwtypes.Timestamp `tfsdk:"creation_time"` - ModelARN types.String `tfsdk:"model_arn"` - ModelName types.String `tfsdk:"model_name"` + CreationTime fwtypes.Timestamp `tfsdk:"creation_time"` + ModelARN types.String `tfsdk:"model_arn"` + ModelName types.String `tfsdk:"model_name"` } diff --git a/internal/service/bedrock/custom_models_data_source_test.go b/internal/service/bedrock/custom_models_data_source_test.go index f5c12bee1fc..9554b5c45d2 100644 --- a/internal/service/bedrock/custom_models_data_source_test.go +++ b/internal/service/bedrock/custom_models_data_source_test.go @@ -4,7 +4,6 @@ package bedrock_test import ( - "fmt" "testing" "github.com/aws/aws-sdk-go/service/bedrock" @@ -23,157 +22,23 @@ func TestAccBedrockCustomModelsDataSource_basic(t *testing.T) { ErrorCheck: acctest.ErrorCheck(t, bedrock.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, Steps: []resource.TestStep{ + // TODO: Create custom model and wait for it to be created. { Config: testAccCustomModelsDataSourceConfig_basic(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(datasourceName, "id"), acctest.CheckResourceAttrGreaterThanValue(datasourceName, "model_summaries.#", 0), + resource.TestCheckResourceAttrSet(datasourceName, "model_summaries.0.creation_time"), + resource.TestCheckResourceAttrSet(datasourceName, "model_summaries.0.model_arn"), + resource.TestCheckResourceAttrSet(datasourceName, "model_summaries.0.model_name"), ), }, }, }) } -// TODO Shared config with resource? func testAccCustomModelsDataSourceConfig_basic(rName string) string { - return fmt.Sprintf(` -data "aws_caller_identity" "current" {} -data "aws_region" "current" {} -data "aws_partition" "current" {} - -resource aws_s3_bucket training_data { - bucket = "bedrock-training-data-%[1]s" -} - -resource aws_s3_bucket validation_data { - bucket = "bedrock-validation-data-%[1]s" -} - -resource aws_s3_bucket output_data { - bucket = "bedrock-output-data-%[1]s" - force_destroy = true -} - -resource "aws_s3_bucket_object" "training_data" { - bucket = aws_s3_bucket.training_data.id - key = "myfolder/training_data.jsonl" - source = "./testdata/training_data.jsonl" - etag = filemd5("./testdata/training_data.jsonl") -} - -resource "aws_s3_bucket_object" "validation_data" { - bucket = aws_s3_bucket.validation_data.id - key = "myfolder/validation_data.jsonl" - source = "./testdata/validation_data.jsonl" - etag = filemd5("./testdata/validation_data.jsonl") -} - -resource "aws_iam_role" "bedrock_fine_tuning" { - name = "bedrock-fine-tuning-%[1]s" - - assume_role_policy = < Date: Thu, 1 Feb 2024 11:50:24 -0500 Subject: [PATCH 52/62] bedrock: Correct IAM permissions in acceptance tests. --- internal/service/bedrock/custom_model_test.go | 129 ++++++++---------- 1 file changed, 60 insertions(+), 69 deletions(-) diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index 7aca6a47520..8097cb7c441 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -200,6 +200,7 @@ func TestAccBedrockCustomModel_validationDataConfigWaitForCompletion(t *testing. ImportStateVerifyIgnore: []string{"base_model_identifier"}, }, { + // TODO Wait for completion. PreConfig: func() {}, Config: testAccCustomModelConfig_validationDataConfig(rName), RefreshState: true, @@ -323,53 +324,48 @@ resource "aws_s3_object" "validation" { resource "aws_iam_role" "test" { name = %[1]q + # See https://docs.aws.amazon.com/bedrock/latest/userguide/model-customization-iam-role.html#model-customization-iam-role-trust. assume_role_policy = < Date: Thu, 1 Feb 2024 12:14:32 -0500 Subject: [PATCH 53/62] d/aws_bedrock_custom_model: Tidy up. --- .../bedrock/custom_model_data_source.go | 31 ++-- .../bedrock/custom_model_data_source_test.go | 163 ++---------------- .../bedrock/custom_models_data_source_test.go | 6 +- .../foundation_model_data_source_test.go | 4 +- .../foundation_models_data_source_test.go | 13 +- .../service/bedrock/service_package_gen.go | 3 - .../docs/d/bedrock_custom_model.html.markdown | 27 +-- 7 files changed, 65 insertions(+), 182 deletions(-) diff --git a/internal/service/bedrock/custom_model_data_source.go b/internal/service/bedrock/custom_model_data_source.go index 35c65dd1bba..f335e8c30f8 100644 --- a/internal/service/bedrock/custom_model_data_source.go +++ b/internal/service/bedrock/custom_model_data_source.go @@ -20,7 +20,6 @@ import ( ) // @FrameworkDataSource(name="Custom Model") -// @Tags(identifierAttribute="model_arn") func newCustomModelDataSource(context.Context) (datasource.DataSourceWithConfigure, error) { return &customModelDataSource{}, nil } @@ -44,7 +43,7 @@ func (d *customModelDataSource) Schema(ctx context.Context, request datasource.S CustomType: fwtypes.TimestampType, Computed: true, }, - "hyper_parameters": schema.MapAttribute{ + "hyperparameters": schema.MapAttribute{ CustomType: fwtypes.MapOfStringType, Computed: true, ElementType: types.StringType, @@ -69,6 +68,7 @@ func (d *customModelDataSource) Schema(ctx context.Context, request datasource.S "model_name": schema.StringAttribute{ Computed: true, }, + "model_tags": tftags.TagsAttributeComputedOnly(), "output_data_config": schema.ListAttribute{ CustomType: fwtypes.NewListNestedObjectTypeOf[customModelOutputDataConfigModel](ctx), Computed: true, @@ -78,7 +78,6 @@ func (d *customModelDataSource) Schema(ctx context.Context, request datasource.S }, }, }, - names.AttrTags: tftags.TagsAttributeComputedOnly(), "training_data_config": schema.ListAttribute{ CustomType: fwtypes.NewListNestedObjectTypeOf[customModelTrainingDataConfigModel](ctx), Computed: true, @@ -102,7 +101,7 @@ func (d *customModelDataSource) Schema(ctx context.Context, request datasource.S Computed: true, ElementType: types.ObjectType{ AttrTypes: map[string]attr.Type{ - "validators": fwtypes.NewListNestedObjectTypeOf[customModelValidatorConfigModel](ctx), + "validator": fwtypes.NewListNestedObjectTypeOf[customModelValidatorConfigModel](ctx), }, }, }, @@ -128,10 +127,11 @@ func (d *customModelDataSource) Read(ctx context.Context, request datasource.Rea conn := d.Meta().BedrockClient(ctx) - output, err := findCustomModelByID(ctx, conn, data.ModelID.ValueString()) + modelID := data.ModelID.ValueString() + output, err := findCustomModelByID(ctx, conn, modelID) if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s)", data.ModelID.ValueString()), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s)", modelID), err.Error()) return } @@ -141,26 +141,37 @@ func (d *customModelDataSource) Read(ctx context.Context, request datasource.Rea return } - data.ID = data.ModelID + data.ID = types.StringValue(modelID) jobARN := aws.ToString(output.JobArn) jobTags, err := listTags(ctx, conn, jobARN) if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model Job (%s) tags", jobARN), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model customization job (%s) tags", jobARN), err.Error()) return } data.JobTags = fwflex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) + modelARN := aws.ToString(output.ModelArn) + modelTags, err := listTags(ctx, conn, modelARN) + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s) tags", modelARN), err.Error()) + + return + } + + data.ModelTags = fwflex.FlattenFrameworkStringValueMap(ctx, modelTags.IgnoreAWS().Map()) + response.Diagnostics.Append(response.State.Set(ctx, &data)...) } type customModelDataSourceModel struct { BaseModelARN types.String `tfsdk:"base_model_arn"` CreationTime fwtypes.Timestamp `tfsdk:"creation_time"` - HyperParameters fwtypes.MapValueOf[types.String] `tfsdk:"hyper_parameters"` + HyperParameters fwtypes.MapValueOf[types.String] `tfsdk:"hyperparameters"` ID types.String `tfsdk:"id"` JobARN types.String `tfsdk:"job_arn"` JobName types.String `tfsdk:"job_name"` @@ -169,8 +180,8 @@ type customModelDataSourceModel struct { ModelID types.String `tfsdk:"model_id"` ModelKMSKeyARN types.String `tfsdk:"model_kms_key_arn"` ModelName types.String `tfsdk:"model_name"` + ModelTags types.Map `tfsdk:"model_tags"` OutputDataConfig fwtypes.ListNestedObjectValueOf[customModelOutputDataConfigModel] `tfsdk:"output_data_config"` - Tags types.Map `tfsdk:"tags"` TrainingDataConfig fwtypes.ListNestedObjectValueOf[customModelTrainingDataConfigModel] `tfsdk:"training_data_config"` TrainingMetrics fwtypes.ListNestedObjectValueOf[customModelTrainingMetricsModel] `tfsdk:"training_metrics"` ValidationDataConfig fwtypes.ListNestedObjectValueOf[customModelValidationDataConfigModel] `tfsdk:"validation_data_config"` diff --git a/internal/service/bedrock/custom_model_data_source_test.go b/internal/service/bedrock/custom_model_data_source_test.go index bab02d015d4..6f0c28a480a 100644 --- a/internal/service/bedrock/custom_model_data_source_test.go +++ b/internal/service/bedrock/custom_model_data_source_test.go @@ -4,12 +4,12 @@ package bedrock_test import ( - "fmt" "testing" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" ) func TestAccBedrockCustomModelDataSource_basic(t *testing.T) { @@ -19,172 +19,33 @@ func TestAccBedrockCustomModelDataSource_basic(t *testing.T) { datasourceName := "data.aws_bedrock_custom_model.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, Steps: []resource.TestStep{ + // TODO: Create custom model and wait for it to be created. { Config: testAccCustomModelDataSourceConfig_basic(rName), - Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(datasourceName, "id"), - resource.TestCheckResourceAttrPair(resourceName, "base_model_arn", datasourceName, "base_model_arn"), - resource.TestCheckResourceAttrPair(resourceName, "creation_time", datasourceName, "creation_time"), - resource.TestCheckResourceAttrPair(resourceName, "hyper_parameters", datasourceName, "hyper_parameters"), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "hyperparameters", datasourceName, "hyperparameters"), resource.TestCheckResourceAttrPair(resourceName, "job_arn", datasourceName, "job_arn"), resource.TestCheckResourceAttrPair(resourceName, "job_name", datasourceName, "job_name"), - resource.TestCheckResourceAttrPair(resourceName, "job_tags", datasourceName, "job_tags"), resource.TestCheckResourceAttrPair(resourceName, "model_arn", datasourceName, "model_arn"), resource.TestCheckResourceAttrPair(resourceName, "model_kms_key_arn", datasourceName, "model_kms_key_arn"), resource.TestCheckResourceAttrPair(resourceName, "model_name", datasourceName, "model_name"), - resource.TestCheckResourceAttrPair(resourceName, "output_data_config", datasourceName, "output_data_config"), - resource.TestCheckResourceAttrPair(resourceName, "training_data_config", datasourceName, "training_data_config"), - resource.TestCheckResourceAttrPair(resourceName, "training_metrics", datasourceName, "training_metrics"), - resource.TestCheckResourceAttrPair(resourceName, "validation_data_config", datasourceName, "validation_data_config"), - resource.TestCheckResourceAttrPair(resourceName, "validation_metrics", datasourceName, "validation_metrics"), + resource.TestCheckResourceAttrPair(resourceName, "output_data_config.#", datasourceName, "output_data_config.#"), + resource.TestCheckResourceAttrPair(resourceName, "training_data_config.#", datasourceName, "training_data_config.#"), + resource.TestCheckResourceAttrPair(resourceName, "training_metrics.#", datasourceName, "training_metrics.#"), + resource.TestCheckResourceAttrPair(resourceName, "validation_data_config.#", datasourceName, "validation_data_config.#"), + resource.TestCheckResourceAttrPair(resourceName, "validation_metrics.#", datasourceName, "validation_metrics.#"), ), }, }, }) } -// TODO Shared config with resource? func testAccCustomModelDataSourceConfig_basic(rName string) string { - return fmt.Sprintf(` -data "aws_caller_identity" "current" {} -data "aws_region" "current" {} -data "aws_partition" "current" {} - -resource aws_s3_bucket training_data { - bucket = "bedrock-training-data-%[1]s" -} - -resource aws_s3_bucket validation_data { - bucket = "bedrock-validation-data-%[1]s" -} - -resource aws_s3_bucket output_data { - bucket = "bedrock-output-data-%[1]s" - force_destroy = true -} - -resource "aws_s3_bucket_object" "training_data" { - bucket = aws_s3_bucket.training_data.id - key = "myfolder/training_data.jsonl" - source = "./testdata/training_data.jsonl" - etag = filemd5("./testdata/training_data.jsonl") -} - -resource "aws_s3_bucket_object" "validation_data" { - bucket = aws_s3_bucket.validation_data.id - key = "myfolder/validation_data.jsonl" - source = "./testdata/validation_data.jsonl" - etag = filemd5("./testdata/validation_data.jsonl") -} - -resource "aws_iam_role" "bedrock_fine_tuning" { - name = "bedrock-fine-tuning-%[1]s" - - assume_role_policy = < Date: Thu, 1 Feb 2024 12:21:20 -0500 Subject: [PATCH 54/62] Add 'TestAccBedrockCustomModel_kmsKey'. --- internal/service/bedrock/custom_model_test.go | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index 8097cb7c441..2a13f7dff7d 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -141,6 +141,35 @@ func TestAccBedrockCustomModel_tags(t *testing.T) { }) } +func TestAccBedrockCustomModel_kmsKey(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrock_custom_model.test" + var v bedrock.GetModelCustomizationJobOutput + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckCustomModelDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccCustomModelConfig_kmsKey(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCustomModelExists(ctx, resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "custom_model_kms_key_id"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"base_model_identifier"}, + }, + }, + }) +} + func TestAccBedrockCustomModel_validationDataConfig(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -492,6 +521,40 @@ resource "aws_bedrock_custom_model" "test" { `, rName, tagKey1, tagValue1, tagKey2, tagValue2)) } +func testAccCustomModelConfig_kmsKey(rName string) string { + return acctest.ConfigCompose(testAccCustomModelConfig_base(rName), fmt.Sprintf(` +resource "aws_kms_key" "test" { + description = %[1]q + deletion_window_in_days = 7 +} + +resource "aws_bedrock_custom_model" "test" { + custom_model_name = %[1]q + job_name = %[1]q + base_model_identifier = data.aws_bedrock_foundation_model.test.model_arn + role_arn = aws_iam_role.test.arn + + custom_model_kms_key_id = aws_kms_key.test.arn + customization_type = "FINE_TUNING" + + hyperparameters = { + "epochCount" = "1" + "batchSize" = "1" + "learningRate" = "0.005" + "learningRateWarmupSteps" = "0" + } + + output_data_config { + s3_uri = "s3://${aws_s3_bucket.output.id}/data/" + } + + training_data_config { + s3_uri = "s3://${aws_s3_bucket.training.id}/data/train.jsonl" + } +} +`, rName)) +} + func testAccCustomModelConfig_validationDataConfig(rName string) string { return acctest.ConfigCompose(testAccCustomModelConfig_base(rName), fmt.Sprintf(` resource "aws_bedrock_custom_model" "test" { From 79553e1bd23f1e8b09eda0c8f88ad4e913e357cc Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 12:24:34 -0500 Subject: [PATCH 55/62] Acceptance test output: % make testacc TESTARGS='-run=TestAccBedrockCustomModel_kmsKey' PKG=bedrock ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/bedrock/... -v -count 1 -parallel 20 -run=TestAccBedrockCustomModel_kmsKey -timeout 360m === RUN TestAccBedrockCustomModel_kmsKey === PAUSE TestAccBedrockCustomModel_kmsKey === CONT TestAccBedrockCustomModel_kmsKey --- PASS: TestAccBedrockCustomModel_kmsKey (49.63s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrock 60.146s From b87c529405d69ba52158673468af00bd3b211876 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 13:11:46 -0500 Subject: [PATCH 56/62] d/aws_bedrock_custom_model: Read some attributes from the customization job. --- internal/service/bedrock/custom_model.go | 8 +++--- .../bedrock/custom_model_data_source.go | 25 ++++++++++++++++--- .../bedrock/custom_models_data_source_test.go | 4 ++- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/internal/service/bedrock/custom_model.go b/internal/service/bedrock/custom_model.go index 2928594d2e2..785ef799aa4 100644 --- a/internal/service/bedrock/custom_model.go +++ b/internal/service/bedrock/custom_model.go @@ -402,15 +402,15 @@ func (r *customModelResource) Read(ctx context.Context, request resource.ReadReq return } - var customModelData resourceCustomModelData - response.Diagnostics.Append(fwflex.Flatten(ctx, outputGM, &customModelData)...) + var dataFromGetCustomModel resourceCustomModelData + response.Diagnostics.Append(fwflex.Flatten(ctx, outputGM, &dataFromGetCustomModel)...) if response.Diagnostics.HasError() { return } data.CustomModelARN = fwflex.StringToFramework(ctx, outputGM.ModelArn) - data.TrainingMetrics = customModelData.TrainingMetrics - data.ValidationMetrics = customModelData.ValidationMetrics + data.TrainingMetrics = dataFromGetCustomModel.TrainingMetrics + data.ValidationMetrics = dataFromGetCustomModel.ValidationMetrics } response.Diagnostics.Append(response.State.Set(ctx, &data)...) diff --git a/internal/service/bedrock/custom_model_data_source.go b/internal/service/bedrock/custom_model_data_source.go index f335e8c30f8..f5e48f1df6f 100644 --- a/internal/service/bedrock/custom_model_data_source.go +++ b/internal/service/bedrock/custom_model_data_source.go @@ -128,7 +128,7 @@ func (d *customModelDataSource) Read(ctx context.Context, request datasource.Rea conn := d.Meta().BedrockClient(ctx) modelID := data.ModelID.ValueString() - output, err := findCustomModelByID(ctx, conn, modelID) + outputGM, err := findCustomModelByID(ctx, conn, modelID) if err != nil { response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model (%s)", modelID), err.Error()) @@ -136,14 +136,31 @@ func (d *customModelDataSource) Read(ctx context.Context, request datasource.Rea return } - response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + jobARN := aws.ToString(outputGM.JobArn) + outputGJ, err := findModelCustomizationJobByID(ctx, conn, jobARN) + + if err != nil { + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Custom Model customization job (%s)", jobARN), err.Error()) + + return + } + + response.Diagnostics.Append(fwflex.Flatten(ctx, outputGM, &data)...) + if response.Diagnostics.HasError() { + return + } + + // Some fields are only available in GetModelCustomizationJobOutput. + var dataFromGetModelCustomizationJob resourceCustomModelData + response.Diagnostics.Append(fwflex.Flatten(ctx, outputGJ, &dataFromGetModelCustomizationJob)...) if response.Diagnostics.HasError() { return } data.ID = types.StringValue(modelID) + data.JobName = dataFromGetModelCustomizationJob.JobName + data.ValidationDataConfig = dataFromGetModelCustomizationJob.ValidationDataConfig - jobARN := aws.ToString(output.JobArn) jobTags, err := listTags(ctx, conn, jobARN) if err != nil { @@ -154,7 +171,7 @@ func (d *customModelDataSource) Read(ctx context.Context, request datasource.Rea data.JobTags = fwflex.FlattenFrameworkStringValueMap(ctx, jobTags.IgnoreAWS().Map()) - modelARN := aws.ToString(output.ModelArn) + modelARN := aws.ToString(outputGM.ModelArn) modelTags, err := listTags(ctx, conn, modelARN) if err != nil { diff --git a/internal/service/bedrock/custom_models_data_source_test.go b/internal/service/bedrock/custom_models_data_source_test.go index aa62ced814a..b903d329ceb 100644 --- a/internal/service/bedrock/custom_models_data_source_test.go +++ b/internal/service/bedrock/custom_models_data_source_test.go @@ -39,6 +39,8 @@ func TestAccBedrockCustomModelsDataSource_basic(t *testing.T) { func testAccCustomModelsDataSourceConfig_basic(rName string) string { return acctest.ConfigCompose(testAccCustomModelConfig_basic(rName), ` -data "aws_bedrock_custom_models" "test" {} +data "aws_bedrock_custom_models" "test" { + depends_on = [aws_bedrock_custom_model.test] +} `) } From e8b5f392dd5f5ce817aff31714533440637ac2a4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 14:40:31 -0500 Subject: [PATCH 57/62] bedrock: Tweak custom model data source tests. --- .../bedrock/custom_model_data_source_test.go | 12 +++++++- internal/service/bedrock/custom_model_test.go | 28 ++++++++++++++++--- .../bedrock/custom_models_data_source_test.go | 13 ++++++++- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/internal/service/bedrock/custom_model_data_source_test.go b/internal/service/bedrock/custom_model_data_source_test.go index 6f0c28a480a..ed8a3e30622 100644 --- a/internal/service/bedrock/custom_model_data_source_test.go +++ b/internal/service/bedrock/custom_model_data_source_test.go @@ -6,6 +6,7 @@ package bedrock_test import ( "testing" + "github.com/aws/aws-sdk-go-v2/service/bedrock" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-provider-aws/internal/acctest" @@ -17,14 +18,23 @@ func TestAccBedrockCustomModelDataSource_basic(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrock_custom_model.test" datasourceName := "data.aws_bedrock_custom_model.test" + var v bedrock.GetModelCustomizationJobOutput resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, Steps: []resource.TestStep{ - // TODO: Create custom model and wait for it to be created. { + Config: testAccCustomModelConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCustomModelExists(ctx, resourceName, &v), + ), + }, + { + PreConfig: func() { + testAccWaitModelCustomizationJobCompleted(ctx, t, &v) + }, Config: testAccCustomModelDataSourceConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "hyperparameters", datasourceName, "hyperparameters"), diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index 2a13f7dff7d..34dabb00c82 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -7,7 +7,9 @@ import ( "context" "fmt" "testing" + "time" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/bedrock" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" @@ -229,12 +231,16 @@ func TestAccBedrockCustomModel_validationDataConfigWaitForCompletion(t *testing. ImportStateVerifyIgnore: []string{"base_model_identifier"}, }, { - // TODO Wait for completion. - PreConfig: func() {}, - Config: testAccCustomModelConfig_validationDataConfig(rName), - RefreshState: true, + PreConfig: func() { + testAccWaitModelCustomizationJobCompleted(ctx, t, &v) + }, + Config: testAccCustomModelConfig_validationDataConfig(rName), Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "job_status", "Completed"), + resource.TestCheckResourceAttr(resourceName, "training_metrics.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "training_metrics.0.training_loss"), + resource.TestCheckResourceAttr(resourceName, "validation_metrics.#", "1"), + resource.TestCheckResourceAttrSet(resourceName, "validation_metrics.0.validation_loss"), ), }, }, @@ -272,6 +278,20 @@ func TestAccBedrockCustomModel_vpcConfig(t *testing.T) { }) } +func testAccWaitModelCustomizationJobCompleted(ctx context.Context, t *testing.T, v *bedrock.GetModelCustomizationJobOutput) { + conn := acctest.Provider.Meta().(*conns.AWSClient).BedrockClient(ctx) + + jobARN := aws.ToString(v.JobArn) + const ( + timeout = 2 * time.Hour + ) + _, err := tfbedrock.WaitModelCustomizationJobCompleted(ctx, conn, jobARN, timeout) + + if err != nil { + t.Logf("waiting for Bedrock Custom Model customization job (%s) complete: %s", jobARN, err) + } +} + func testAccCheckCustomModelDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).BedrockClient(ctx) diff --git a/internal/service/bedrock/custom_models_data_source_test.go b/internal/service/bedrock/custom_models_data_source_test.go index b903d329ceb..9018089c3bb 100644 --- a/internal/service/bedrock/custom_models_data_source_test.go +++ b/internal/service/bedrock/custom_models_data_source_test.go @@ -6,6 +6,7 @@ package bedrock_test import ( "testing" + "github.com/aws/aws-sdk-go-v2/service/bedrock" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-provider-aws/internal/acctest" @@ -16,14 +17,24 @@ func TestAccBedrockCustomModelsDataSource_basic(t *testing.T) { ctx := acctest.Context(t) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) datasourceName := "data.aws_bedrock_custom_models.test" + resourceName := "aws_bedrock_custom_model.test" + var v bedrock.GetModelCustomizationJobOutput resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockEndpointID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, Steps: []resource.TestStep{ - // TODO: Create custom model and wait for it to be created. { + Config: testAccCustomModelConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckCustomModelExists(ctx, resourceName, &v), + ), + }, + { + PreConfig: func() { + testAccWaitModelCustomizationJobCompleted(ctx, t, &v) + }, Config: testAccCustomModelsDataSourceConfig_basic(rName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(datasourceName, "id"), From f5c11657a464a724fb91390fc408b918bd425450 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 14:48:25 -0500 Subject: [PATCH 58/62] testAccCheckCustomModelDestroy: Check for deleted custom model. --- internal/service/bedrock/custom_model_test.go | 15 ++++++++++++++- internal/service/bedrock/exports_test.go | 1 + 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index 34dabb00c82..d9388cdcaa4 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -301,7 +301,7 @@ func testAccCheckCustomModelDestroy(ctx context.Context) resource.TestCheckFunc continue } - _, err := tfbedrock.FindModelCustomizationJobByID(ctx, conn, rs.Primary.ID) + output, err := tfbedrock.FindModelCustomizationJobByID(ctx, conn, rs.Primary.ID) if tfresource.NotFound(err) { continue @@ -311,6 +311,19 @@ func testAccCheckCustomModelDestroy(ctx context.Context) resource.TestCheckFunc return err } + // Check the custom model. + if modelARN := aws.ToString(output.OutputModelArn); modelARN != "" { + _, err := tfbedrock.FindCustomModelByID(ctx, conn, modelARN) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + } + return fmt.Errorf("Bedrock Custom Model %s still exists", rs.Primary.ID) } diff --git a/internal/service/bedrock/exports_test.go b/internal/service/bedrock/exports_test.go index b86164beff4..03fe61d49ff 100644 --- a/internal/service/bedrock/exports_test.go +++ b/internal/service/bedrock/exports_test.go @@ -8,6 +8,7 @@ var ( ResourceCustomModel = newCustomModelResource ResourceModelInvocationLoggingConfiguration = newResourceModelInvocationLoggingConfiguration + FindCustomModelByID = findCustomModelByID FindModelCustomizationJobByID = findModelCustomizationJobByID WaitModelCustomizationJobCompleted = waitModelCustomizationJobCompleted ) From 81ddd4ac53b5e916293b4a741f8f38be9897aaa2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 17:21:29 -0500 Subject: [PATCH 59/62] bedrock: Use 'testing.Short()' guards. --- internal/service/bedrock/custom_model_data_source_test.go | 4 ++++ internal/service/bedrock/custom_model_test.go | 4 ++++ internal/service/bedrock/custom_models_data_source_test.go | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/internal/service/bedrock/custom_model_data_source_test.go b/internal/service/bedrock/custom_model_data_source_test.go index ed8a3e30622..351ad9bebec 100644 --- a/internal/service/bedrock/custom_model_data_source_test.go +++ b/internal/service/bedrock/custom_model_data_source_test.go @@ -15,6 +15,10 @@ import ( func TestAccBedrockCustomModelDataSource_basic(t *testing.T) { ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrock_custom_model.test" datasourceName := "data.aws_bedrock_custom_model.test" diff --git a/internal/service/bedrock/custom_model_test.go b/internal/service/bedrock/custom_model_test.go index d9388cdcaa4..7a04462d26c 100644 --- a/internal/service/bedrock/custom_model_test.go +++ b/internal/service/bedrock/custom_model_test.go @@ -205,6 +205,10 @@ func TestAccBedrockCustomModel_validationDataConfig(t *testing.T) { func TestAccBedrockCustomModel_validationDataConfigWaitForCompletion(t *testing.T) { ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrock_custom_model.test" var v bedrock.GetModelCustomizationJobOutput diff --git a/internal/service/bedrock/custom_models_data_source_test.go b/internal/service/bedrock/custom_models_data_source_test.go index 9018089c3bb..504f4e5b239 100644 --- a/internal/service/bedrock/custom_models_data_source_test.go +++ b/internal/service/bedrock/custom_models_data_source_test.go @@ -15,6 +15,10 @@ import ( func TestAccBedrockCustomModelsDataSource_basic(t *testing.T) { ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) datasourceName := "data.aws_bedrock_custom_models.test" resourceName := "aws_bedrock_custom_model.test" From 898f26e8f7afeafc904a39cd621afb01ff95f1a2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 17:30:33 -0500 Subject: [PATCH 60/62] d/aws_bedrock_foundation_models: Fix acceptance tests. --- .../service/bedrock/foundation_models_data_source_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/bedrock/foundation_models_data_source_test.go b/internal/service/bedrock/foundation_models_data_source_test.go index e7e723762c3..8fe5e3fce95 100644 --- a/internal/service/bedrock/foundation_models_data_source_test.go +++ b/internal/service/bedrock/foundation_models_data_source_test.go @@ -15,7 +15,7 @@ import ( func TestAccBedrockFoundationModelsDataSource_basic(t *testing.T) { ctx := acctest.Context(t) - datasourceName := "aws_bedrock_foundation_models.test" + datasourceName := "data.aws_bedrock_foundation_models.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, @@ -35,7 +35,7 @@ func TestAccBedrockFoundationModelsDataSource_basic(t *testing.T) { func TestAccBedrockFoundationModelsDataSource_byCustomizationType(t *testing.T) { ctx := acctest.Context(t) - datasourceName := "aws_bedrock_foundation_models.test" + datasourceName := "data.aws_bedrock_foundation_models.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, @@ -55,7 +55,7 @@ func TestAccBedrockFoundationModelsDataSource_byCustomizationType(t *testing.T) func TestAccBedrockFoundationModelsDataSource_byInferenceType(t *testing.T) { ctx := acctest.Context(t) - datasourceName := "aws_bedrock_foundation_models.test" + datasourceName := "data.aws_bedrock_foundation_models.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, @@ -75,7 +75,7 @@ func TestAccBedrockFoundationModelsDataSource_byInferenceType(t *testing.T) { func TestAccBedrockFoundationModelsDataSource_byOutputModality(t *testing.T) { ctx := acctest.Context(t) - datasourceName := "aws_bedrock_foundation_models.test" + datasourceName := "data.aws_bedrock_foundation_models.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID) }, From 4c781fbaa9ac8ed051475379c849c85a0a0e1209 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 17:48:37 -0500 Subject: [PATCH 61/62] Fix typo. --- internal/service/bedrock/custom_model_data_source_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/bedrock/custom_model_data_source_test.go b/internal/service/bedrock/custom_model_data_source_test.go index 351ad9bebec..1fb73d817d8 100644 --- a/internal/service/bedrock/custom_model_data_source_test.go +++ b/internal/service/bedrock/custom_model_data_source_test.go @@ -63,5 +63,5 @@ func testAccCustomModelDataSourceConfig_basic(rName string) string { data "aws_bedrock_custom_model" "test" { model_id = aws_bedrock_custom_model.test.model_arn } -`, rName) +`) } From 2222c5ca4abb01086e94db3936a34b13f00b6ed9 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 1 Feb 2024 19:24:40 -0500 Subject: [PATCH 62/62] d/aws_bedrock_custom_model: Fix acceptance tests. --- internal/service/bedrock/custom_model_data_source_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/bedrock/custom_model_data_source_test.go b/internal/service/bedrock/custom_model_data_source_test.go index 1fb73d817d8..ad4f04c142f 100644 --- a/internal/service/bedrock/custom_model_data_source_test.go +++ b/internal/service/bedrock/custom_model_data_source_test.go @@ -44,9 +44,9 @@ func TestAccBedrockCustomModelDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "hyperparameters", datasourceName, "hyperparameters"), resource.TestCheckResourceAttrPair(resourceName, "job_arn", datasourceName, "job_arn"), resource.TestCheckResourceAttrPair(resourceName, "job_name", datasourceName, "job_name"), - resource.TestCheckResourceAttrPair(resourceName, "model_arn", datasourceName, "model_arn"), - resource.TestCheckResourceAttrPair(resourceName, "model_kms_key_arn", datasourceName, "model_kms_key_arn"), - resource.TestCheckResourceAttrPair(resourceName, "model_name", datasourceName, "model_name"), + resource.TestCheckResourceAttrPair(resourceName, "custom_model_arn", datasourceName, "model_arn"), + resource.TestCheckResourceAttrPair(resourceName, "custom_model_kms_key_id", datasourceName, "model_kms_key_arn"), + resource.TestCheckResourceAttrPair(resourceName, "custom_model_name", datasourceName, "model_name"), resource.TestCheckResourceAttrPair(resourceName, "output_data_config.#", datasourceName, "output_data_config.#"), resource.TestCheckResourceAttrPair(resourceName, "training_data_config.#", datasourceName, "training_data_config.#"), resource.TestCheckResourceAttrPair(resourceName, "training_metrics.#", datasourceName, "training_metrics.#"), @@ -61,7 +61,7 @@ func TestAccBedrockCustomModelDataSource_basic(t *testing.T) { func testAccCustomModelDataSourceConfig_basic(rName string) string { return acctest.ConfigCompose(testAccCustomModelConfig_basic(rName), ` data "aws_bedrock_custom_model" "test" { - model_id = aws_bedrock_custom_model.test.model_arn + model_id = aws_bedrock_custom_model.test.custom_model_arn } `) }