text:
# This file is auto-generated by AWSMetadata.jl
using AWS
using AWS.AWSServices: cloudwatch_logs
using AWS.Compat
using AWS.UUIDs

"""
    associate_kms_key(kms_key_id, log_group_name)
    associate_kms_key(kms_key_id, log_group_name, params::Dict{String,<:Any})

Associates the specified Key Management Service customer master key (CMK) with the
specified log group. Associating an KMS CMK with a log group overrides any existing
associations between the log group and a CMK. After a CMK is associated with a log group,
all newly ingested data for the log group is encrypted using the CMK. This association is
stored as long as the data encrypted with the CMK is still within CloudWatch Logs. This
enables CloudWatch Logs to decrypt this data whenever it is requested.  CloudWatch Logs
supports only symmetric CMKs. Do not use an associate an asymmetric CMK with your log
group. For more information, see Using Symmetric and Asymmetric Keys.  It can take up to 5
minutes for this operation to take effect. If you attempt to associate a CMK with a log
group but the CMK does not exist or the CMK is disabled, you receive an
InvalidParameterException error.

# Arguments
- `kms_key_id`: The Amazon Resource Name (ARN) of the CMK to use when encrypting log data.
  This must be a symmetric CMK. For more information, see Amazon Resource Names - Key
  Management Service and Using Symmetric and Asymmetric Keys.
- `log_group_name`: The name of the log group.

"""
function associate_kms_key(
    kmsKeyId, logGroupName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "AssociateKmsKey",
        Dict{String,Any}("kmsKeyId" => kmsKeyId, "logGroupName" => logGroupName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function associate_kms_key(
    kmsKeyId,
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "AssociateKmsKey",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("kmsKeyId" => kmsKeyId, "logGroupName" => logGroupName),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    cancel_export_task(task_id)
    cancel_export_task(task_id, params::Dict{String,<:Any})

Cancels the specified export task. The task must be in the PENDING or RUNNING state.

# Arguments
- `task_id`: The ID of the export task.

"""
function cancel_export_task(taskId; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "CancelExportTask",
        Dict{String,Any}("taskId" => taskId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function cancel_export_task(
    taskId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "CancelExportTask",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("taskId" => taskId), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_export_task(destination, from, log_group_name, to)
    create_export_task(destination, from, log_group_name, to, params::Dict{String,<:Any})

Creates an export task, which allows you to efficiently export data from a log group to an
Amazon S3 bucket. When you perform a CreateExportTask operation, you must use credentials
that have permission to write to the S3 bucket that you specify as the destination. This is
an asynchronous call. If all the required information is provided, this operation initiates
an export task and responds with the ID of the task. After the task has started, you can
use DescribeExportTasks to get the status of the export task. Each account can only have
one active (RUNNING or PENDING) export task at a time. To cancel an export task, use
CancelExportTask. You can export logs from multiple log groups or multiple time ranges to
the same S3 bucket. To separate out log data for each export task, you can specify a prefix
to be used as the Amazon S3 key prefix for all exported objects. Exporting to S3 buckets
that are encrypted with AES-256 is supported. Exporting to S3 buckets encrypted with
SSE-KMS is not supported.

# Arguments
- `destination`: The name of S3 bucket for the exported log data. The bucket must be in the
  same Amazon Web Services region.
- `from`: The start time of the range for the request, expressed as the number of
  milliseconds after Jan 1, 1970 00:00:00 UTC. Events with a timestamp earlier than this time
  are not exported.
- `log_group_name`: The name of the log group.
- `to`: The end time of the range for the request, expreswatchlogsdocused as the number of
  milliseconds after Jan 1, 1970 00:00:00 UTC. Events with a timestamp later than this time
  are not exported.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"destinationPrefix"`: The prefix used as the start of the key for every object exported.
  If you don't specify a value, the default is exportedlogs.
- `"logStreamNamePrefix"`: Export only log streams that match the provided prefix. If you
  don't specify a value, no prefix filter is applied.
- `"taskName"`: The name of the export task.
"""
function create_export_task(
    destination, from, logGroupName, to; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "CreateExportTask",
        Dict{String,Any}(
            "destination" => destination,
            "from" => from,
            "logGroupName" => logGroupName,
            "to" => to,
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_export_task(
    destination,
    from,
    logGroupName,
    to,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "CreateExportTask",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "destination" => destination,
                    "from" => from,
                    "logGroupName" => logGroupName,
                    "to" => to,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_log_group(log_group_name)
    create_log_group(log_group_name, params::Dict{String,<:Any})

Creates a log group with the specified name. You can create up to 20,000 log groups per
account. You must use the following guidelines when naming a log group:   Log group names
must be unique within a region for an Amazon Web Services account.   Log group names can be
between 1 and 512 characters long.   Log group names consist of the following characters:
a-z, A-Z, 0-9, '_' (underscore), '-' (hyphen), '/' (forward slash), '.' (period), and '#'
(number sign)   When you create a log group, by default the log events in the log group
never expire. To set a retention policy so that events expire and are deleted after a
specified time, use PutRetentionPolicy. If you associate a Key Management Service customer
master key (CMK) with the log group, ingested data is encrypted using the CMK. This
association is stored as long as the data encrypted with the CMK is still within CloudWatch
Logs. This enables CloudWatch Logs to decrypt this data whenever it is requested. If you
attempt to associate a CMK with the log group but the CMK does not exist or the CMK is
disabled, you receive an InvalidParameterException error.   CloudWatch Logs supports only
symmetric CMKs. Do not associate an asymmetric CMK with your log group. For more
information, see Using Symmetric and Asymmetric Keys.

# Arguments
- `log_group_name`: The name of the log group.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"kmsKeyId"`: The Amazon Resource Name (ARN) of the CMK to use when encrypting log data.
  For more information, see Amazon Resource Names - Key Management Service.
- `"tags"`: The key-value pairs to use for the tags. CloudWatch Logs doesn’t support IAM
  policies that prevent users from assigning specified tags to log groups using the
  aws:Resource/key-name  or aws:TagKeys condition keys. For more information about using tags
  to control access, see Controlling access to Amazon Web Services resources using tags.
"""
function create_log_group(logGroupName; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "CreateLogGroup",
        Dict{String,Any}("logGroupName" => logGroupName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_log_group(
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "CreateLogGroup",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("logGroupName" => logGroupName), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_log_stream(log_group_name, log_stream_name)
    create_log_stream(log_group_name, log_stream_name, params::Dict{String,<:Any})

Creates a log stream for the specified log group. A log stream is a sequence of log events
that originate from a single source, such as an application instance or a resource that is
being monitored. There is no limit on the number of log streams that you can create for a
log group. There is a limit of 50 TPS on CreateLogStream operations, after which
transactions are throttled. You must use the following guidelines when naming a log stream:
  Log stream names must be unique within the log group.   Log stream names can be between 1
and 512 characters long.   The ':' (colon) and '*' (asterisk) characters are not allowed.

# Arguments
- `log_group_name`: The name of the log group.
- `log_stream_name`: The name of the log stream.

"""
function create_log_stream(
    logGroupName, logStreamName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "CreateLogStream",
        Dict{String,Any}("logGroupName" => logGroupName, "logStreamName" => logStreamName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_log_stream(
    logGroupName,
    logStreamName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "CreateLogStream",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "logGroupName" => logGroupName, "logStreamName" => logStreamName
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_destination(destination_name)
    delete_destination(destination_name, params::Dict{String,<:Any})

Deletes the specified destination, and eventually disables all the subscription filters
that publish to it. This operation does not delete the physical resource encapsulated by
the destination.

# Arguments
- `destination_name`: The name of the destination.

"""
function delete_destination(
    destinationName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DeleteDestination",
        Dict{String,Any}("destinationName" => destinationName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_destination(
    destinationName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "DeleteDestination",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("destinationName" => destinationName), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_log_group(log_group_name)
    delete_log_group(log_group_name, params::Dict{String,<:Any})

Deletes the specified log group and permanently deletes all the archived log events
associated with the log group.

# Arguments
- `log_group_name`: The name of the log group.

"""
function delete_log_group(logGroupName; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "DeleteLogGroup",
        Dict{String,Any}("logGroupName" => logGroupName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_log_group(
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "DeleteLogGroup",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("logGroupName" => logGroupName), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_log_stream(log_group_name, log_stream_name)
    delete_log_stream(log_group_name, log_stream_name, params::Dict{String,<:Any})

Deletes the specified log stream and permanently deletes all the archived log events
associated with the log stream.

# Arguments
- `log_group_name`: The name of the log group.
- `log_stream_name`: The name of the log stream.

"""
function delete_log_stream(
    logGroupName, logStreamName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DeleteLogStream",
        Dict{String,Any}("logGroupName" => logGroupName, "logStreamName" => logStreamName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_log_stream(
    logGroupName,
    logStreamName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "DeleteLogStream",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "logGroupName" => logGroupName, "logStreamName" => logStreamName
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_metric_filter(filter_name, log_group_name)
    delete_metric_filter(filter_name, log_group_name, params::Dict{String,<:Any})

Deletes the specified metric filter.

# Arguments
- `filter_name`: The name of the metric filter.
- `log_group_name`: The name of the log group.

"""
function delete_metric_filter(
    filterName, logGroupName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DeleteMetricFilter",
        Dict{String,Any}("filterName" => filterName, "logGroupName" => logGroupName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_metric_filter(
    filterName,
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "DeleteMetricFilter",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "filterName" => filterName, "logGroupName" => logGroupName
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_query_definition(query_definition_id)
    delete_query_definition(query_definition_id, params::Dict{String,<:Any})

Deletes a saved CloudWatch Logs Insights query definition. A query definition contains
details about a saved CloudWatch Logs Insights query. Each DeleteQueryDefinition operation
can delete one query definition. You must have the logs:DeleteQueryDefinition permission to
be able to perform this operation.

# Arguments
- `query_definition_id`: The ID of the query definition that you want to delete. You can
  use DescribeQueryDefinitions to retrieve the IDs of your saved query definitions.

"""
function delete_query_definition(
    queryDefinitionId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DeleteQueryDefinition",
        Dict{String,Any}("queryDefinitionId" => queryDefinitionId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_query_definition(
    queryDefinitionId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "DeleteQueryDefinition",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("queryDefinitionId" => queryDefinitionId), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_resource_policy()
    delete_resource_policy(params::Dict{String,<:Any})

Deletes a resource policy from this account. This revokes the access of the identities in
that policy to put log events to this account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"policyName"`: The name of the policy to be revoked. This parameter is required.
"""
function delete_resource_policy(; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "DeleteResourcePolicy"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function delete_resource_policy(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DeleteResourcePolicy",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_retention_policy(log_group_name)
    delete_retention_policy(log_group_name, params::Dict{String,<:Any})

Deletes the specified retention policy. Log events do not expire if they belong to log
groups without a retention policy.

# Arguments
- `log_group_name`: The name of the log group.

"""
function delete_retention_policy(
    logGroupName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DeleteRetentionPolicy",
        Dict{String,Any}("logGroupName" => logGroupName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_retention_policy(
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "DeleteRetentionPolicy",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("logGroupName" => logGroupName), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_subscription_filter(filter_name, log_group_name)
    delete_subscription_filter(filter_name, log_group_name, params::Dict{String,<:Any})

Deletes the specified subscription filter.

# Arguments
- `filter_name`: The name of the subscription filter.
- `log_group_name`: The name of the log group.

"""
function delete_subscription_filter(
    filterName, logGroupName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DeleteSubscriptionFilter",
        Dict{String,Any}("filterName" => filterName, "logGroupName" => logGroupName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_subscription_filter(
    filterName,
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "DeleteSubscriptionFilter",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "filterName" => filterName, "logGroupName" => logGroupName
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    describe_destinations()
    describe_destinations(params::Dict{String,<:Any})

Lists all your destinations. The results are ASCII-sorted by destination name.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DestinationNamePrefix"`: The prefix to match. If you don't specify a value, no prefix
  filter is applied.
- `"limit"`: The maximum number of items returned. If you don't specify a value, the
  default is up to 50 items.
- `"nextToken"`: The token for the next set of items to return. (You received this token
  from a previous call.)
"""
function describe_destinations(; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "DescribeDestinations"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_destinations(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DescribeDestinations",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    describe_export_tasks()
    describe_export_tasks(params::Dict{String,<:Any})

Lists the specified export tasks. You can list all your export tasks or filter the results
based on task ID or task status.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"limit"`: The maximum number of items returned. If you don't specify a value, the
  default is up to 50 items.
- `"nextToken"`: The token for the next set of items to return. (You received this token
  from a previous call.)
- `"statusCode"`: The status code of the export task. Specifying a status code filters the
  results to zero or more export tasks.
- `"taskId"`: The ID of the export task. Specifying a task ID filters the results to zero
  or one export tasks.
"""
function describe_export_tasks(; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "DescribeExportTasks"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_export_tasks(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DescribeExportTasks",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    describe_log_groups()
    describe_log_groups(params::Dict{String,<:Any})

Lists the specified log groups. You can list all your log groups or filter the results by
prefix. The results are ASCII-sorted by log group name. CloudWatch Logs doesn’t support
IAM policies that control access to the DescribeLogGroups action by using the
aws:ResourceTag/key-name  condition key. Other CloudWatch Logs actions do support the use
of the aws:ResourceTag/key-name  condition key to control access. For more information
about using tags to control access, see Controlling access to Amazon Web Services resources
using tags.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"limit"`: The maximum number of items returned. If you don't specify a value, the
  default is up to 50 items.
- `"logGroupNamePrefix"`: The prefix to match.
- `"nextToken"`: The token for the next set of items to return. (You received this token
  from a previous call.)
"""
function describe_log_groups(; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "DescribeLogGroups"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_log_groups(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DescribeLogGroups", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

"""
    describe_log_streams(log_group_name)
    describe_log_streams(log_group_name, params::Dict{String,<:Any})

Lists the log streams for the specified log group. You can list all the log streams or
filter the results by prefix. You can also control how the results are ordered. This
operation has a limit of five transactions per second, after which transactions are
throttled.

# Arguments
- `log_group_name`: The name of the log group.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"descending"`: If the value is true, results are returned in descending order. If the
  value is to false, results are returned in ascending order. The default value is false.
- `"limit"`: The maximum number of items returned. If you don't specify a value, the
  default is up to 50 items.
- `"logStreamNamePrefix"`: The prefix to match. If orderBy is LastEventTime, you cannot
  specify this parameter.
- `"nextToken"`: The token for the next set of items to return. (You received this token
  from a previous call.)
- `"orderBy"`: If the value is LogStreamName, the results are ordered by log stream name.
  If the value is LastEventTime, the results are ordered by the event time. The default value
  is LogStreamName. If you order the results by event time, you cannot specify the
  logStreamNamePrefix parameter.  lastEventTimestamp represents the time of the most recent
  log event in the log stream in CloudWatch Logs. This number is expressed as the number of
  milliseconds after Jan 1, 1970 00:00:00 UTC. lastEventTimestamp updates on an eventual
  consistency basis. It typically updates in less than an hour from ingestion, but in rare
  situations might take longer.
"""
function describe_log_streams(
    logGroupName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DescribeLogStreams",
        Dict{String,Any}("logGroupName" => logGroupName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function describe_log_streams(
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "DescribeLogStreams",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("logGroupName" => logGroupName), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    describe_metric_filters()
    describe_metric_filters(params::Dict{String,<:Any})

Lists the specified metric filters. You can list all of the metric filters or filter the
results by log name, prefix, metric name, or metric namespace. The results are ASCII-sorted
by filter name.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filterNamePrefix"`: The prefix to match. CloudWatch Logs uses the value you set here
  only if you also include the logGroupName parameter in your request.
- `"limit"`: The maximum number of items returned. If you don't specify a value, the
  default is up to 50 items.
- `"logGroupName"`: The name of the log group.
- `"metricName"`: Filters results to include only those with the specified metric name. If
  you include this parameter in your request, you must also include the metricNamespace
  parameter.
- `"metricNamespace"`: Filters results to include only those in the specified namespace. If
  you include this parameter in your request, you must also include the metricName parameter.
- `"nextToken"`: The token for the next set of items to return. (You received this token
  from a previous call.)
"""
function describe_metric_filters(; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "DescribeMetricFilters"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_metric_filters(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DescribeMetricFilters",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    describe_queries()
    describe_queries(params::Dict{String,<:Any})

Returns a list of CloudWatch Logs Insights queries that are scheduled, executing, or have
been executed recently in this account. You can request all queries or limit it to queries
of a specific log group or queries with a certain status.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"logGroupName"`: Limits the returned queries to only those for the specified log group.
- `"maxResults"`: Limits the number of returned queries to the specified number.
- `"nextToken"`:
- `"status"`: Limits the returned queries to only those that have the specified status.
  Valid values are Cancelled, Complete, Failed, Running, and Scheduled.
"""
function describe_queries(; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "DescribeQueries"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_queries(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DescribeQueries", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

"""
    describe_query_definitions()
    describe_query_definitions(params::Dict{String,<:Any})

This operation returns a paginated list of your saved CloudWatch Logs Insights query
definitions. You can use the queryDefinitionNamePrefix parameter to limit the results to
only the query definitions that have names that start with a certain string.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: Limits the number of returned query definitions to the specified number.
- `"nextToken"`:
- `"queryDefinitionNamePrefix"`: Use this parameter to filter your results to only the
  query definitions that have names that start with the prefix you specify.
"""
function describe_query_definitions(; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "DescribeQueryDefinitions"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_query_definitions(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DescribeQueryDefinitions",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    describe_resource_policies()
    describe_resource_policies(params::Dict{String,<:Any})

Lists the resource policies in this account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"limit"`: The maximum number of resource policies to be displayed with one call of this
  API.
- `"nextToken"`:
"""
function describe_resource_policies(; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "DescribeResourcePolicies"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_resource_policies(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DescribeResourcePolicies",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    describe_subscription_filters(log_group_name)
    describe_subscription_filters(log_group_name, params::Dict{String,<:Any})

Lists the subscription filters for the specified log group. You can list all the
subscription filters or filter the results by prefix. The results are ASCII-sorted by
filter name.

# Arguments
- `log_group_name`: The name of the log group.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filterNamePrefix"`: The prefix to match. If you don't specify a value, no prefix filter
  is applied.
- `"limit"`: The maximum number of items returned. If you don't specify a value, the
  default is up to 50 items.
- `"nextToken"`: The token for the next set of items to return. (You received this token
  from a previous call.)
"""
function describe_subscription_filters(
    logGroupName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DescribeSubscriptionFilters",
        Dict{String,Any}("logGroupName" => logGroupName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function describe_subscription_filters(
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "DescribeSubscriptionFilters",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("logGroupName" => logGroupName), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    disassociate_kms_key(log_group_name)
    disassociate_kms_key(log_group_name, params::Dict{String,<:Any})

Disassociates the associated Key Management Service customer master key (CMK) from the
specified log group. After the KMS CMK is disassociated from the log group, CloudWatch Logs
stops encrypting newly ingested data for the log group. All previously ingested data
remains encrypted, and CloudWatch Logs requires permissions for the CMK whenever the
encrypted data is requested. Note that it can take up to 5 minutes for this operation to
take effect.

# Arguments
- `log_group_name`: The name of the log group.

"""
function disassociate_kms_key(
    logGroupName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "DisassociateKmsKey",
        Dict{String,Any}("logGroupName" => logGroupName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function disassociate_kms_key(
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "DisassociateKmsKey",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("logGroupName" => logGroupName), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    filter_log_events(log_group_name)
    filter_log_events(log_group_name, params::Dict{String,<:Any})

Lists log events from the specified log group. You can list all the log events or filter
the results using a filter pattern, a time range, and the name of the log stream. By
default, this operation returns as many log events as can fit in 1 MB (up to 10,000 log
events) or all the events found within the time range that you specify. If the results
include a token, then there are more log events available, and you can get additional
results by specifying the token in a subsequent call. This operation can return empty
results while there are more log events available through the token. The returned log
events are sorted by event timestamp, the timestamp when the event was ingested by
CloudWatch Logs, and the ID of the PutLogEvents request.

# Arguments
- `log_group_name`: The name of the log group to search.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"endTime"`: The end of the time range, expressed as the number of milliseconds after Jan
  1, 1970 00:00:00 UTC. Events with a timestamp later than this time are not returned.
- `"filterPattern"`: The filter pattern to use. For more information, see Filter and
  Pattern Syntax. If not provided, all the events are matched.
- `"interleaved"`: If the value is true, the operation makes a best effort to provide
  responses that contain events from multiple log streams within the log group, interleaved
  in a single response. If the value is false, all the matched log events in the first log
  stream are searched first, then those in the next log stream, and so on. The default is
  false.  Important: Starting on June 17, 2019, this parameter is ignored and the value is
  assumed to be true. The response from this operation always interleaves events from
  multiple log streams within a log group.
- `"limit"`: The maximum number of events to return. The default is 10,000 events.
- `"logStreamNamePrefix"`: Filters the results to include only events from log streams that
  have names starting with this prefix. If you specify a value for both logStreamNamePrefix
  and logStreamNames, but the value for logStreamNamePrefix does not match any log stream
  names specified in logStreamNames, the action returns an InvalidParameterException error.
- `"logStreamNames"`: Filters the results to only logs from the log streams in this list.
  If you specify a value for both logStreamNamePrefix and logStreamNames, the action returns
  an InvalidParameterException error.
- `"nextToken"`: The token for the next set of events to return. (You received this token
  from a previous call.)
- `"startTime"`: The start of the time range, expressed as the number of milliseconds after
  Jan 1, 1970 00:00:00 UTC. Events with a timestamp before this time are not returned.
"""
function filter_log_events(logGroupName; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "FilterLogEvents",
        Dict{String,Any}("logGroupName" => logGroupName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function filter_log_events(
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "FilterLogEvents",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("logGroupName" => logGroupName), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    get_log_events(log_group_name, log_stream_name)
    get_log_events(log_group_name, log_stream_name, params::Dict{String,<:Any})

Lists log events from the specified log stream. You can list all of the log events or
filter using a time range. By default, this operation returns as many log events as can fit
in a response size of 1MB (up to 10,000 log events). You can get additional log events by
specifying one of the tokens in a subsequent call. This operation can return empty results
while there are more log events available through the token.

# Arguments
- `log_group_name`: The name of the log group.
- `log_stream_name`: The name of the log stream.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"endTime"`: The end of the time range, expressed as the number of milliseconds after Jan
  1, 1970 00:00:00 UTC. Events with a timestamp equal to or later than this time are not
  included.
- `"limit"`: The maximum number of log events returned. If you don't specify a value, the
  maximum is as many log events as can fit in a response size of 1 MB, up to 10,000 log
  events.
- `"nextToken"`: The token for the next set of items to return. (You received this token
  from a previous call.)
- `"startFromHead"`: If the value is true, the earliest log events are returned first. If
  the value is false, the latest log events are returned first. The default value is false.
  If you are using a previous nextForwardToken value as the nextToken in this operation, you
  must specify true for startFromHead.
- `"startTime"`: The start of the time range, expressed as the number of milliseconds after
  Jan 1, 1970 00:00:00 UTC. Events with a timestamp equal to this time or later than this
  time are included. Events with a timestamp earlier than this time are not included.
"""
function get_log_events(
    logGroupName, logStreamName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "GetLogEvents",
        Dict{String,Any}("logGroupName" => logGroupName, "logStreamName" => logStreamName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_log_events(
    logGroupName,
    logStreamName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "GetLogEvents",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "logGroupName" => logGroupName, "logStreamName" => logStreamName
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    get_log_group_fields(log_group_name)
    get_log_group_fields(log_group_name, params::Dict{String,<:Any})

Returns a list of the fields that are included in log events in the specified log group,
along with the percentage of log events that contain each field. The search is limited to a
time period that you specify. In the results, fields that start with @ are fields generated
by CloudWatch Logs. For example, @timestamp is the timestamp of each log event. For more
information about the fields that are generated by CloudWatch logs, see Supported Logs and
Discovered Fields. The response results are sorted by the frequency percentage, starting
with the highest percentage.

# Arguments
- `log_group_name`: The name of the log group to search.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"time"`: The time to set as the center of the query. If you specify time, the 15 minutes
  before this time are queries. If you omit time the 8 minutes before and 8 minutes after
  this time are searched. The time value is specified as epoch time, the number of seconds
  since January 1, 1970, 00:00:00 UTC.
"""
function get_log_group_fields(
    logGroupName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "GetLogGroupFields",
        Dict{String,Any}("logGroupName" => logGroupName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_log_group_fields(
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "GetLogGroupFields",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("logGroupName" => logGroupName), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    get_log_record(log_record_pointer)
    get_log_record(log_record_pointer, params::Dict{String,<:Any})

Retrieves all of the fields and values of a single log event. All fields are retrieved,
even if the original query that produced the logRecordPointer retrieved only a subset of
fields. Fields are returned as field name/field value pairs. The full unparsed log event is
returned within @message.

# Arguments
- `log_record_pointer`: The pointer corresponding to the log event record you want to
  retrieve. You get this from the response of a GetQueryResults operation. In that response,
  the value of the @ptr field for a log event is the value to use as logRecordPointer to
  retrieve that complete log event record.

"""
function get_log_record(logRecordPointer; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "GetLogRecord",
        Dict{String,Any}("logRecordPointer" => logRecordPointer);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_log_record(
    logRecordPointer,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "GetLogRecord",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("logRecordPointer" => logRecordPointer), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    get_query_results(query_id)
    get_query_results(query_id, params::Dict{String,<:Any})

Returns the results from the specified query. Only the fields requested in the query are
returned, along with a @ptr field, which is the identifier for the log record. You can use
the value of @ptr in a GetLogRecord operation to get the full log record.  GetQueryResults
does not start a query execution. To run a query, use StartQuery. If the value of the
Status field in the output is Running, this operation returns only partial results. If you
see a value of Scheduled or Running for the status, you can retry the operation later to
see the final results.

# Arguments
- `query_id`: The ID number of the query.

"""
function get_query_results(queryId; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "GetQueryResults",
        Dict{String,Any}("queryId" => queryId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_query_results(
    queryId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "GetQueryResults",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("queryId" => queryId), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_tags_log_group(log_group_name)
    list_tags_log_group(log_group_name, params::Dict{String,<:Any})

Lists the tags for the specified log group.

# Arguments
- `log_group_name`: The name of the log group.

"""
function list_tags_log_group(
    logGroupName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "ListTagsLogGroup",
        Dict{String,Any}("logGroupName" => logGroupName);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_tags_log_group(
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "ListTagsLogGroup",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("logGroupName" => logGroupName), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    put_destination(destination_name, role_arn, target_arn)
    put_destination(destination_name, role_arn, target_arn, params::Dict{String,<:Any})

Creates or updates a destination. This operation is used only to create destinations for
cross-account subscriptions. A destination encapsulates a physical resource (such as an
Amazon Kinesis stream) and enables you to subscribe to a real-time stream of log events for
a different account, ingested using PutLogEvents. Through an access policy, a destination
controls what is written to it. By default, PutDestination does not set any access policy
with the destination, which means a cross-account user cannot call PutSubscriptionFilter
against this destination. To enable this, the destination owner must call
PutDestinationPolicy after PutDestination. To perform a PutDestination operation, you must
also have the iam:PassRole permission.

# Arguments
- `destination_name`: A name for the destination.
- `role_arn`: The ARN of an IAM role that grants CloudWatch Logs permissions to call the
  Amazon Kinesis PutRecord operation on the destination stream.
- `target_arn`: The ARN of an Amazon Kinesis stream to which to deliver matching log events.

"""
function put_destination(
    destinationName, roleArn, targetArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "PutDestination",
        Dict{String,Any}(
            "destinationName" => destinationName,
            "roleArn" => roleArn,
            "targetArn" => targetArn,
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function put_destination(
    destinationName,
    roleArn,
    targetArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "PutDestination",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "destinationName" => destinationName,
                    "roleArn" => roleArn,
                    "targetArn" => targetArn,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    put_destination_policy(access_policy, destination_name)
    put_destination_policy(access_policy, destination_name, params::Dict{String,<:Any})

Creates or updates an access policy associated with an existing destination. An access
policy is an IAM policy document that is used to authorize claims to register a
subscription filter against a given destination. If multiple Amazon Web Services accounts
are sending logs to this destination, each sender account must be listed separately in the
policy. The policy does not support specifying * as the Principal or the use of the
aws:PrincipalOrgId global key.

# Arguments
- `access_policy`: An IAM policy document that authorizes cross-account users to deliver
  their log events to the associated destination. This can be up to 5120 bytes.
- `destination_name`: A name for an existing destination.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"forceUpdate"`: Specify true if you are updating an existing destination policy to grant
  permission to an organization ID instead of granting permission to individual AWS accounts.
  Before you update a destination policy this way, you must first update the subscription
  filters in the accounts that send logs to this destination. If you do not, the subscription
  filters might stop working. By specifying true for forceUpdate, you are affirming that you
  have already updated the subscription filters. For more information, see  Updating an
  existing cross-account subscription  If you omit this parameter, the default of false is
  used.
"""
function put_destination_policy(
    accessPolicy, destinationName; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "PutDestinationPolicy",
        Dict{String,Any}(
            "accessPolicy" => accessPolicy, "destinationName" => destinationName
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function put_destination_policy(
    accessPolicy,
    destinationName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "PutDestinationPolicy",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "accessPolicy" => accessPolicy, "destinationName" => destinationName
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    put_log_events(log_events, log_group_name, log_stream_name)
    put_log_events(log_events, log_group_name, log_stream_name, params::Dict{String,<:Any})

Uploads a batch of log events to the specified log stream. You must include the sequence
token obtained from the response of the previous call. An upload in a newly created log
stream does not require a sequence token. You can also get the sequence token in the
expectedSequenceToken field from InvalidSequenceTokenException. If you call PutLogEvents
twice within a narrow time period using the same value for sequenceToken, both calls might
be successful or one might be rejected. The batch of events must satisfy the following
constraints:   The maximum batch size is 1,048,576 bytes. This size is calculated as the
sum of all event messages in UTF-8, plus 26 bytes for each log event.   None of the log
events in the batch can be more than 2 hours in the future.   None of the log events in the
batch can be older than 14 days or older than the retention period of the log group.   The
log events in the batch must be in chronological order by their timestamp. The timestamp is
the time the event occurred, expressed as the number of milliseconds after Jan 1, 1970
00:00:00 UTC. (In Amazon Web Services Tools for PowerShell and the Amazon Web Services SDK
for .NET, the timestamp is specified in .NET format: yyyy-mm-ddThh:mm:ss. For example,
2017-09-15T13:45:30.)    A batch of log events in a single request cannot span more than 24
hours. Otherwise, the operation fails.   The maximum number of log events in a batch is
10,000.   There is a quota of 5 requests per second per log stream. Additional requests are
throttled. This quota can't be changed.   If a call to PutLogEvents returns
\"UnrecognizedClientException\" the most likely cause is an invalid Amazon Web Services
access key ID or secret key.

# Arguments
- `log_events`: The log events.
- `log_group_name`: The name of the log group.
- `log_stream_name`: The name of the log stream.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"sequenceToken"`: The sequence token obtained from the response of the previous
  PutLogEvents call. An upload in a newly created log stream does not require a sequence
  token. You can also get the sequence token using DescribeLogStreams. If you call
  PutLogEvents twice within a narrow time period using the same value for sequenceToken, both
  calls might be successful or one might be rejected.
"""
function put_log_events(
    logEvents,
    logGroupName,
    logStreamName;
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "PutLogEvents",
        Dict{String,Any}(
            "logEvents" => logEvents,
            "logGroupName" => logGroupName,
            "logStreamName" => logStreamName,
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function put_log_events(
    logEvents,
    logGroupName,
    logStreamName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "PutLogEvents",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "logEvents" => logEvents,
                    "logGroupName" => logGroupName,
                    "logStreamName" => logStreamName,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    put_metric_filter(filter_name, filter_pattern, log_group_name, metric_transformations)
    put_metric_filter(filter_name, filter_pattern, log_group_name, metric_transformations, params::Dict{String,<:Any})

Creates or updates a metric filter and associates it with the specified log group. Metric
filters allow you to configure rules to extract metric data from log events ingested
through PutLogEvents. The maximum number of metric filters that can be associated with a
log group is 100. When you create a metric filter, you can also optionally assign a unit
and dimensions to the metric that is created.  Metrics extracted from log events are
charged as custom metrics. To prevent unexpected high charges, do not specify
high-cardinality fields such as IPAddress or requestID as dimensions. Each different value
found for a dimension is treated as a separate metric and accrues charges as a separate
custom metric.  To help prevent accidental high charges, Amazon disables a metric filter if
it generates 1000 different name/value pairs for the dimensions that you have specified
within a certain amount of time. You can also set up a billing alarm to alert you if your
charges are higher than expected. For more information, see  Creating a Billing Alarm to
Monitor Your Estimated Amazon Web Services Charges.

# Arguments
- `filter_name`: A name for the metric filter.
- `filter_pattern`: A filter pattern for extracting metric data out of ingested log events.
- `log_group_name`: The name of the log group.
- `metric_transformations`: A collection of information that defines how metric data gets
  emitted.

"""
function put_metric_filter(
    filterName,
    filterPattern,
    logGroupName,
    metricTransformations;
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "PutMetricFilter",
        Dict{String,Any}(
            "filterName" => filterName,
            "filterPattern" => filterPattern,
            "logGroupName" => logGroupName,
            "metricTransformations" => metricTransformations,
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function put_metric_filter(
    filterName,
    filterPattern,
    logGroupName,
    metricTransformations,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "PutMetricFilter",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "filterName" => filterName,
                    "filterPattern" => filterPattern,
                    "logGroupName" => logGroupName,
                    "metricTransformations" => metricTransformations,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    put_query_definition(name, query_string)
    put_query_definition(name, query_string, params::Dict{String,<:Any})

Creates or updates a query definition for CloudWatch Logs Insights. For more information,
see Analyzing Log Data with CloudWatch Logs Insights. To update a query definition, specify
its queryDefinitionId in your request. The values of name, queryString, and logGroupNames
are changed to the values that you specify in your update operation. No current values are
retained from the current query definition. For example, if you update a current query
definition that includes log groups, and you don't specify the logGroupNames parameter in
your update operation, the query definition changes to contain no log groups. You must have
the logs:PutQueryDefinition permission to be able to perform this operation.

# Arguments
- `name`: A name for the query definition. If you are saving a lot of query definitions, we
  recommend that you name them so that you can easily find the ones you want by using the
  first part of the name as a filter in the queryDefinitionNamePrefix parameter of
  DescribeQueryDefinitions.
- `query_string`: The query string to use for this definition. For more information, see
  CloudWatch Logs Insights Query Syntax.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"logGroupNames"`: Use this parameter to include specific log groups as part of your
  query definition. If you are updating a query definition and you omit this parameter, then
  the updated definition will contain no log groups.
- `"queryDefinitionId"`: If you are updating a query definition, use this parameter to
  specify the ID of the query definition that you want to update. You can use
  DescribeQueryDefinitions to retrieve the IDs of your saved query definitions. If you are
  creating a query definition, do not specify this parameter. CloudWatch generates a unique
  ID for the new query definition and include it in the response to this operation.
"""
function put_query_definition(
    name, queryString; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "PutQueryDefinition",
        Dict{String,Any}("name" => name, "queryString" => queryString);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function put_query_definition(
    name,
    queryString,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "PutQueryDefinition",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("name" => name, "queryString" => queryString),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    put_resource_policy()
    put_resource_policy(params::Dict{String,<:Any})

Creates or updates a resource policy allowing other Amazon Web Services services to put log
events to this account, such as Amazon Route 53. An account can have up to 10 resource
policies per Amazon Web Services Region.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"policyDocument"`: Details of the new policy, including the identity of the principal
  that is enabled to put logs to this account. This is formatted as a JSON string. This
  parameter is required. The following example creates a resource policy enabling the Route
  53 service to put DNS query logs in to the specified log group. Replace \"logArn\" with the
  ARN of your CloudWatch Logs resource, such as a log group or log stream. CloudWatch Logs
  also supports aws:SourceArn and aws:SourceAccount condition context keys. In the example
  resource policy, you would replace the value of SourceArn with the resource making the call
  from Route 53 to CloudWatch Logs and replace the value of SourceAccount with the Amazon
  Web Services account ID making that call.   { \"Version\": \"2012-10-17\", \"Statement\": [
  { \"Sid\": \"Route53LogsToCloudWatchLogs\", \"Effect\": \"Allow\", \"Principal\": {
  \"Service\": [ \"route53.amazonaws.com\" ] }, \"Action\": \"logs:PutLogEvents\",
  \"Resource\": \"logArn\", \"Condition\": { \"ArnLike\": { \"aws:SourceArn\":
  \"myRoute53ResourceArn\" }, \"StringEquals\": { \"aws:SourceAccount\": \"myAwsAccountId\" }
  } } ] }
- `"policyName"`: Name of the new policy. This parameter is required.
"""
function put_resource_policy(; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "PutResourcePolicy"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function put_resource_policy(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "PutResourcePolicy", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

"""
    put_retention_policy(log_group_name, retention_in_days)
    put_retention_policy(log_group_name, retention_in_days, params::Dict{String,<:Any})

Sets the retention of the specified log group. A retention policy allows you to configure
the number of days for which to retain log events in the specified log group.

# Arguments
- `log_group_name`: The name of the log group.
- `retention_in_days`:

"""
function put_retention_policy(
    logGroupName, retentionInDays; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "PutRetentionPolicy",
        Dict{String,Any}(
            "logGroupName" => logGroupName, "retentionInDays" => retentionInDays
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function put_retention_policy(
    logGroupName,
    retentionInDays,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "PutRetentionPolicy",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "logGroupName" => logGroupName, "retentionInDays" => retentionInDays
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    put_subscription_filter(destination_arn, filter_name, filter_pattern, log_group_name)
    put_subscription_filter(destination_arn, filter_name, filter_pattern, log_group_name, params::Dict{String,<:Any})

Creates or updates a subscription filter and associates it with the specified log group.
Subscription filters allow you to subscribe to a real-time stream of log events ingested
through PutLogEvents and have them delivered to a specific destination. When log events are
sent to the receiving service, they are Base64 encoded and compressed with the gzip format.
The following destinations are supported for subscription filters:   An Amazon Kinesis
stream belonging to the same account as the subscription filter, for same-account delivery.
  A logical destination that belongs to a different account, for cross-account delivery.
An Amazon Kinesis Firehose delivery stream that belongs to the same account as the
subscription filter, for same-account delivery.   An Lambda function that belongs to the
same account as the subscription filter, for same-account delivery.   Each log group can
have up to two subscription filters associated with it. If you are updating an existing
filter, you must specify the correct name in filterName.  To perform a
PutSubscriptionFilter operation, you must also have the iam:PassRole permission.

# Arguments
- `destination_arn`: The ARN of the destination to deliver matching log events to.
  Currently, the supported destinations are:   An Amazon Kinesis stream belonging to the same
  account as the subscription filter, for same-account delivery.   A logical destination
  (specified using an ARN) belonging to a different account, for cross-account delivery. If
  you are setting up a cross-account subscription, the destination must have an IAM policy
  associated with it that allows the sender to send logs to the destination. For more
  information, see PutDestinationPolicy.   An Amazon Kinesis Firehose delivery stream
  belonging to the same account as the subscription filter, for same-account delivery.   A
  Lambda function belonging to the same account as the subscription filter, for same-account
  delivery.
- `filter_name`: A name for the subscription filter. If you are updating an existing
  filter, you must specify the correct name in filterName. To find the name of the filter
  currently associated with a log group, use DescribeSubscriptionFilters.
- `filter_pattern`: A filter pattern for subscribing to a filtered stream of log events.
- `log_group_name`: The name of the log group.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"distribution"`: The method used to distribute log data to the destination. By default,
  log data is grouped by log stream, but the grouping can be set to random for a more even
  distribution. This property is only applicable when the destination is an Amazon Kinesis
  stream.
- `"roleArn"`: The ARN of an IAM role that grants CloudWatch Logs permissions to deliver
  ingested log events to the destination stream. You don't need to provide the ARN when you
  are working with a logical destination for cross-account delivery.
"""
function put_subscription_filter(
    destinationArn,
    filterName,
    filterPattern,
    logGroupName;
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "PutSubscriptionFilter",
        Dict{String,Any}(
            "destinationArn" => destinationArn,
            "filterName" => filterName,
            "filterPattern" => filterPattern,
            "logGroupName" => logGroupName,
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function put_subscription_filter(
    destinationArn,
    filterName,
    filterPattern,
    logGroupName,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "PutSubscriptionFilter",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "destinationArn" => destinationArn,
                    "filterName" => filterName,
                    "filterPattern" => filterPattern,
                    "logGroupName" => logGroupName,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    start_query(end_time, query_string, start_time)
    start_query(end_time, query_string, start_time, params::Dict{String,<:Any})

Schedules a query of a log group using CloudWatch Logs Insights. You specify the log group
and time range to query and the query string to use. For more information, see CloudWatch
Logs Insights Query Syntax. Queries time out after 15 minutes of execution. If your queries
are timing out, reduce the time range being searched or partition your query into a number
of queries.

# Arguments
- `end_time`: The end of the time range to query. The range is inclusive, so the specified
  end time is included in the query. Specified as epoch time, the number of seconds since
  January 1, 1970, 00:00:00 UTC.
- `query_string`: The query string to use. For more information, see CloudWatch Logs
  Insights Query Syntax.
- `start_time`: The beginning of the time range to query. The range is inclusive, so the
  specified start time is included in the query. Specified as epoch time, the number of
  seconds since January 1, 1970, 00:00:00 UTC.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"limit"`: The maximum number of log events to return in the query. If the query string
  uses the fields command, only the specified fields and their values are returned. The
  default is 1000.
- `"logGroupName"`: The log group on which to perform the query. A StartQuery operation
  must include a logGroupNames or a logGroupName parameter, but not both.
- `"logGroupNames"`: The list of log groups to be queried. You can include up to 20 log
  groups. A StartQuery operation must include a logGroupNames or a logGroupName parameter,
  but not both.
"""
function start_query(
    endTime, queryString, startTime; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "StartQuery",
        Dict{String,Any}(
            "endTime" => endTime, "queryString" => queryString, "startTime" => startTime
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function start_query(
    endTime,
    queryString,
    startTime,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "StartQuery",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "endTime" => endTime,
                    "queryString" => queryString,
                    "startTime" => startTime,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    stop_query(query_id)
    stop_query(query_id, params::Dict{String,<:Any})

Stops a CloudWatch Logs Insights query that is in progress. If the query has already ended,
the operation returns an error indicating that the specified query is not running.

# Arguments
- `query_id`: The ID number of the query to stop. To find this ID number, use
  DescribeQueries.

"""
function stop_query(queryId; aws_config::AbstractAWSConfig=global_aws_config())
    return cloudwatch_logs(
        "StopQuery",
        Dict{String,Any}("queryId" => queryId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function stop_query(
    queryId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "StopQuery",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("queryId" => queryId), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    tag_log_group(log_group_name, tags)
    tag_log_group(log_group_name, tags, params::Dict{String,<:Any})

Adds or updates the specified tags for the specified log group. To list the tags for a log
group, use ListTagsLogGroup. To remove tags, use UntagLogGroup. For more information about
tags, see Tag Log Groups in Amazon CloudWatch Logs in the Amazon CloudWatch Logs User
Guide. CloudWatch Logs doesn’t support IAM policies that prevent users from assigning
specified tags to log groups using the aws:Resource/key-name  or aws:TagKeys condition
keys. For more information about using tags to control access, see Controlling access to
Amazon Web Services resources using tags.

# Arguments
- `log_group_name`: The name of the log group.
- `tags`: The key-value pairs to use for the tags.

"""
function tag_log_group(
    logGroupName, tags; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "TagLogGroup",
        Dict{String,Any}("logGroupName" => logGroupName, "tags" => tags);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function tag_log_group(
    logGroupName,
    tags,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "TagLogGroup",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("logGroupName" => logGroupName, "tags" => tags),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    test_metric_filter(filter_pattern, log_event_messages)
    test_metric_filter(filter_pattern, log_event_messages, params::Dict{String,<:Any})

Tests the filter pattern of a metric filter against a sample of log event messages. You can
use this operation to validate the correctness of a metric filter pattern.

# Arguments
- `filter_pattern`:
- `log_event_messages`: The log event messages to test.

"""
function test_metric_filter(
    filterPattern, logEventMessages; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "TestMetricFilter",
        Dict{String,Any}(
            "filterPattern" => filterPattern, "logEventMessages" => logEventMessages
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function test_metric_filter(
    filterPattern,
    logEventMessages,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "TestMetricFilter",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "filterPattern" => filterPattern, "logEventMessages" => logEventMessages
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    untag_log_group(log_group_name, tags)
    untag_log_group(log_group_name, tags, params::Dict{String,<:Any})

Removes the specified tags from the specified log group. To list the tags for a log group,
use ListTagsLogGroup. To add tags, use TagLogGroup. CloudWatch Logs doesn’t support IAM
policies that prevent users from assigning specified tags to log groups using the
aws:Resource/key-name  or aws:TagKeys condition keys.

# Arguments
- `log_group_name`: The name of the log group.
- `tags`: The tag keys. The corresponding tags are removed from the log group.

"""
function untag_log_group(
    logGroupName, tags; aws_config::AbstractAWSConfig=global_aws_config()
)
    return cloudwatch_logs(
        "UntagLogGroup",
        Dict{String,Any}("logGroupName" => logGroupName, "tags" => tags);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function untag_log_group(
    logGroupName,
    tags,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return cloudwatch_logs(
        "UntagLogGroup",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("logGroupName" => logGroupName, "tags" => tags),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end


text:
using Base: @kwdef, ident_cmp
using Flux: Chain, Dense, Conv, BatchNorm, SkipConnection, flatten, relu, elu, softmax, unstack
import Zygote
using CUDA

to_singletons(x) = reshape(x, size(x)..., 1)
from_singletons(x) = reshape(x, size(x)[1:end-1])

abstract type AbstractPrediction end  # gspec, hyper, common, policyhead, valuehead
abstract type AbstractDynamics end    # gspec, hyper, common, statehead, rewardhead
abstract type AbstractRepresentation end # gspec, hyper, common

function forward(nn::AbstractRepresentation, observation)
  hiddenstate = nn.common(observation)
  return hiddenstate
end

function evaluate(nn::AbstractRepresentation, observation)
  x = GI.vectorize_state(nn.gspec, observation)
  # TODO: convert_input for GPU usage
  xnet = to_singletons(x)
  net_output = forward(nn, xnet)
  hiddenstate = from_singletons(net_output)
  #hiddenstate = net_output
  return hiddenstate
end

(nn::AbstractRepresentation)(observation) = evaluate(nn, observation)

function evaluate_batch(nn::AbstractRepresentation, batch)
  X = Flux.batch(GI.vectorize_state(nn.gspec, b) for b in batch)
  Xnet = to_nndevice(nn,X)
  net_outputs = forward(nn, Xnet)
  Hiddenstates = from_nndevice(nn, net_outputs)
  batchdim = ndims(Hiddenstates)
  return unstack(Hiddenstates, batchdim)
end

### Dynamics ###

function forward(nn::AbstractDynamics, hiddenstate_action)
  c = nn.common(hiddenstate_action)
  r = nn.rewardhead(c)
  s⁺¹ = nn.statehead(c)
  return (r, s⁺¹)
end

#TODO add GPU support
function evaluate(nn::AbstractDynamics, hiddenstate, action)
  snet = to_singletons(hiddenstate)
  batchdim = ndims(snet)
  if batchdim == 2
    avalactions = Base.OneTo(length(GI.actions(nn.gspec)))
    encoded_action = onehot(action, avalactions)
  else
    encoded_action = GI.encode_action(nn.gspec, action)
  end
  # gspec = nn.gspec
  # action_one_hot = onehot(action, GI.actions(gspec))
  anet = to_singletons(encoded_action)
  dim = ndims(snet)
  dim == 2 && (anet = Flux.flatten(anet))
  xnet = cat(snet, anet, dims=dim-1) # make dims=3 universal
  net_output = forward(nn, xnet)
  r, s = from_singletons.(net_output)
  return (r[1], s)
end

(nn::AbstractDynamics)((hiddenstate, action)) = evaluate(nn, hiddenstate, action)

function onehot(x::Integer, labels::Base.OneTo; type=Float32)
  result = zeros(type, length(labels))
  result[x] = one(type)
  return result
end

function encode_a(gspec, a; batchdim=4)
  if batchdim==2
    avalactions = Base.OneTo(length(GI.actions(gspec)))
    ret_a = onehot(a, avalactions)
  else
    ret_a = GI.encode_action(gspec, a)
  end
  return ret_a
end

function evaluate_batch(nn::AbstractDynamics, batch)
  S = Flux.batch(b[1] for b in batch)
  batchdim = ndims(S)
  A = Flux.batch(encode_a(nn.gspec, b[2]; batchdim) for b in batch)
  batchdim == 2 && (A = Flux.flatten(A))
  X = cat(S, A, dims=batchdim-1)
  Xnet = to_nndevice(nn,X)
  net_outputs = forward(nn, Xnet)
  (R, S⁺¹) = from_nndevice(nn,net_outputs)
  # #
  # R_itr = unstack_itr(R, 2)
  # S⁺¹_itr = unstack_itr(S⁺¹, batchdim)
  # return collect(zip(R_itr, S⁺¹_itr))
  # return [(R[1,i], S⁺¹[:,i]) for i in eachindex(batch)]
  # return [(R[1,i], S⁺¹[:,:,:,i]) for i in eachindex(batch)]
  # return [(R[1,i], collect(selectdim(S⁺¹,batchdim,i))) for i in eachindex(batch)]
  return collect(zip(unstack(R,2), unstack(S⁺¹,batchdim)))
end

### Prediction ###

function forward(nn::AbstractPrediction, hiddenstate)
  c = nn.common(hiddenstate)
  v = nn.valuehead(c)
  p = nn.policyhead(c)
  return (p, v)
end

function evaluate(nn::AbstractPrediction, hiddenstate)
  x = hiddenstate
  xnet = to_singletons(x)
  net_output = forward(nn, xnet)
  p, v = from_singletons.(net_output)
  return (p, v[1])
end

(nn::AbstractPrediction)(hiddenstate) = evaluate(nn, hiddenstate)

function evaluate_batch(nn::AbstractPrediction, batch)
  X = Flux.batch(batch)
  Xnet = to_nndevice(nn, X)
  net_output = forward(nn, Xnet)
  P, V = from_nndevice(nn, net_output)
  return collect(zip(unstack(P,2), unstack(V,2)))
end

# TODO create constructor from gspec, hidden_state_shape... and get rid of gspecs
struct MuNetworkHP{GameSpec, Fhp, Ghp, Hhp}
  # hidden_state_shape
  gspec :: GameSpec
  predictionHP :: Fhp
  dynamicsHP :: Ghp
  representationHP :: Hhp
end

struct MuNetwork{F<:AbstractPrediction,G<:AbstractDynamics,H<:AbstractRepresentation}
  params :: MuNetworkHP
  f :: F
  g :: G
  h :: H
end

function MuNetwork(params::MuNetworkHP)
  fHP = params.predictionHP
  gHP = params.dynamicsHP
  hHP = params.representationHP
  # @assert fHP.hiddenstate_shape == gHP.hiddenstate_shape == hHP.hiddenstate_shape
  f = PredictionNetwork(params.gspec, fHP)
  g = DynamicsNetwork(params.gspec, gHP)
  h = RepresentationNetwork(params.gspec, hHP)
  return MuNetwork(params, f, g, h)
end

# takes output form neural netrork back to CPU, and unstack it along last dimmension
function convert_output(X)
  X = from_nndevice(nothing, X)
  return Flux.unstack(X, ndims(X))
end

struct InitialOracle{H<:AbstractRepresentation, F<:AbstractPrediction}
  h :: H
  f :: F
end

InitialOracle(nns::MuNetwork) = InitialOracle(nns.h, nns.f)

(init::InitialOracle)(observation) = evaluate(init, observation)

# function evaluate_batch(init::InitialOracle, batch)
#   X = Flux.batch(GI.vectorize_state(init.f.gspec, b) for b in batch) #obsrvation
#   Xnet = to_nndevice(init.f, X)
#   S⁰ = forward(init.h, Xnet) # hiddenstate
#   P⁰, V⁰ = forward(init.f, S⁰) # policy, value

#   P⁰, V⁰, S⁰ = map(convert_output, (P⁰, V⁰, S⁰))
#   V⁰ = [v[1] for v in V⁰]
#   return collect(zip(P⁰, V⁰, S⁰, zero(V⁰)))
# end
function evaluate_batch(init::InitialOracle, batch)
  X = Flux.batch(GI.vectorize_state(init.f.gspec, b) for b in batch) #obsrvation
  Xnet = to_nndevice(init.f, X)
  S⁰ = forward(init.h, Xnet) # hiddenstate
  P⁰, V⁰ = forward(init.f, S⁰) # policy, value
  P⁰, V⁰, S⁰ = map(convert_output, (P⁰, V⁰, S⁰))
  V⁰ = [v[1] for v in V⁰]
  return collect(zip(P⁰, V⁰, S⁰, zero(V⁰)))
end

#TODO test nonmutable struct
struct RecurrentOracle{G<:AbstractDynamics, F<:AbstractPrediction}
  g :: G
  f :: F
end

RecurrentOracle(nns::MuNetwork) = RecurrentOracle(nns.g, nns.f)

(recur::RecurrentOracle)((state,action)) = evaluate(recur, (state,action))

function evaluate_batch(recur::RecurrentOracle, batch)
  S = Flux.batch(b[1] for b in batch)
  batchdim = ndims(S)
  A = Flux.batch(encode_a(recur.f.gspec, b[2]; batchdim) for b in batch)
  S_A = cat(S,A,dims=batchdim-1)
  S_A_net = to_nndevice(recur.f, S_A) # assuming all networks are on the same device
  R, S⁺¹ = forward(recur.g, S_A_net)
  P⁺¹, V⁺¹ = forward(recur.f, S⁺¹)
  P⁺¹, V⁺¹, R, S⁺¹ = map(convert_output, (P⁺¹, V⁺¹, R, S⁺¹))
  V⁺¹ = (v[1] for v in V⁺¹)
  R = (r[1] for r in R)
  return collect(zip(P⁺¹, V⁺¹, S⁺¹, R)) #TODO check for memory consumption;s implement this everywhere,
end
 # TODO cleanup the rest
evaluate(nn, x) = evaluate_batch(nn, [x])[1]

# TODO regularized params
regularized_params_(l) = []
regularized_params_(l::Flux.Dense) = [l.weight]
regularized_params_(l::Flux.Conv) = [l.weight]

function regularized_params(net::MuNetwork)
  return (w for l in Flux.modules(net) for w in regularized_params_(l))
end

#adhoc
function regularized_params(net)
  return (w for l in Flux.modules(net.f.net) for w in regularized_params_(l))
end

array_on_gpu(::Array) = false
array_on_gpu(::CuArray) = true
array_on_gpu(arr) = error("Usupported array type: ", typeof(arr))

include("./architectures/simplemlp.jl")
include("./architectures/resnet.jl")

#TODO this it kinda ugly, maybe create macro that create proper on_gpu based on networks
on_gpu(nn::Union{PredictionSimpleNetwork,PredictionResnetNetwork}) = array_on_gpu(nn.valuehead[end].bias)
on_gpu(nn::Union{DynamicsSimpleNetwork,DynamicsResnetNetwork}) = array_on_gpu(nn.rewardhead[end].bias)
on_gpu(nn::RepresentationSimpleNetwork) = array_on_gpu(nn.common[end].bias)
on_gpu(nn::RepresentationResnetNetwork) = array_on_gpu(nn.common[end][1].layers[1].weight)

to_nndevice(nn, x) = on_gpu(nn) ? Flux.gpu(x) : x
from_nndevice(nn, x) = Flux.cpu(x)

# remembert to put fields in correct order, otherwise they are swapped when |>gpu
Flux.@functor RepresentationSimpleNetwork (common,)
Flux.@functor RepresentationResnetNetwork (common,)
Flux.@functor DynamicsSimpleNetwork       (common, statehead, rewardhead)
Flux.@functor DynamicsResnetNetwork       (common, statehead, rewardhead)
Flux.@functor PredictionSimpleNetwork     (common, policyhead, valuehead)
Flux.@functor PredictionResnetNetwork     (common, policyhead, valuehead)
Flux.@functor MuNetwork                   (f, g, h)

ext: jl


text:
function _make_initial_condition_outage_status(
    container,
    device::T,
    value,
    cache = nothing,
) where {T <: PSY.Component}
    return PSI.InitialCondition(device, _get_ref_outage_status(T, container), value, cache)
end

function _get_ref_outage_status(
    ::Type{T},
    container::PSI.InitialConditions,
) where {T <: PSY.Component}
    return PSI.UpdateRef{T}(OUTAGE, "outage")
end

function _get_outage_initial_value(
    d::PSY.Component,
    key::PSI.ICKey,
    ::PSI.AbstractDeviceFormulation,
    ::Nothing,
)
    return 0.0
end


text:
# Autogenerated wrapper script for hsa_rocr_jll for x86_64-linux-musl-cxx03
export libhsa_runtime64

using hsakmt_roct_jll
using NUMA_jll
using Zlib_jll
using Elfutils_jll
JLLWrappers.@generate_wrapper_header("hsa_rocr")
JLLWrappers.@declare_library_product(libhsa_runtime64, "libhsa-runtime64.so.1")
function __init__()
    JLLWrappers.@generate_init_header(hsakmt_roct_jll, NUMA_jll, Zlib_jll, Elfutils_jll)
    JLLWrappers.@init_library_product(
        libhsa_runtime64,
        "lib/libhsa-runtime64.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@generate_init_footer()
end  # __init__()


text:
function hfun_bar(vname)
  val = Meta.parse(vname[1])
  return round(sqrt(val), digits=2)
end

function hfun_m1fill(vname)
  var = vname[1]
  return pagevar("index", var)
end

function lx_baz(com, _)
  # keep this first line
  brace_content = Franklin.content(com.braces[1]) # input string
  # do whatever you want here
  return uppercase(brace_content)
end

max_stars_repo_name: KnutAM/LinearContinuumMechanics

max_issues_repo_name: KnutAM/LinearContinuumMechanics

max_forks_repo_name: KnutAM/LinearContinuumMechanics


text:
#=
This file defines additional functions to return objects of type Distribution. This is
necessary because we specify prior distributions wrt mean and SD
(for beta and gamma-distributed parameters) and ν and σ (for inverse gamma-distributed
parameters). Note these functions are NOT new methods for the Distributions.Beta, etc.
functions, but rather new functions with the same names.
=#

import Distributions: params, mean, std, pdf, logpdf, rand, Distribution, Matrixvariate
import Base: length, rank

"""
```
BetaAlt(μ::AbstractFloat, σ::AbstractFloat)
```

Given μ and σ, calculate α and β and return a Distributions.Beta Distribution object.

### Arguments
`μ`: The mean of the desired distribution
`σ`: The standard deviation of the desired distribution
"""
function BetaAlt(μ::AbstractFloat, σ::AbstractFloat)
    α = (1-μ) * μ^2 / σ^2 - μ
    β = α * (1/μ - 1)
    return Distributions.Beta(α, β)
end

"""
```
GammaAlt(μ::AbstractFloat, σ::AbstractFloat)
```

Given μ and σ, calculate α and β and return a Distributions.Gamma object.

### Arguments
`μ`: The mean of the desired distribution
`σ`: The standard deviation of the desired distribution
"""
function GammaAlt(μ::AbstractFloat, σ::AbstractFloat)
    β = σ^2 / μ
    α = μ / β
    return Distributions.Gamma(α, β)
end

"""
```
type RootInverseGamma <: Distribution{Univariate, Continuous}
```

If x ~ RootInverseGamma(ν, τ²), then
  x² ~ ScaledInverseChiSquared(ν, τ²)
  x² ~ InverseGamma(ν/2, ντ²/2)

ν represents the degrees of freedom.
"""
type RootInverseGamma <: Distribution{Univariate, Continuous}
    ν::Float64
    τ::Float64
end

Distributions.params(d::RootInverseGamma) = (d.ν, d.τ)

"""
```
Distributions.pdf(d::RootInverseGamma, x::AbstractFloat)
```

Compute the pdf of a RootInverseGamma distribution at x.
"""
function Distributions.pdf(d::RootInverseGamma, x::AbstractFloat)
    (ν, τ) = params(d)
    return 2 * (ν*τ^2/2)^(ν/2) * exp((-ν*τ^2)/(2x^2)) / gamma(ν/2) / x^(ν+1)
end

"""
```
Distributions.logpdf(d::RootInverseGamma, x::AbstractFloat)
```

Compute the log pdf of a RootInverseGamma distribution at x.
"""
function Distributions.logpdf(d::RootInverseGamma, x::AbstractFloat)
    (ν, τ) = params(d)
    return log(2) - log(gamma(ν/2)) + (ν/2)*log(ν*τ^2/2) - ((ν+1)/2)*log(x^2) - ν*τ^2/(2x^2)
end

"""
```
Distributions.rand{T<:AbstractFloat}(d::RootInverseGamma; cc::T = 1.0)
```

Generate a draw from d with variance optionally scaled by cc^2 (for a RootInverseGamma)
"""
function Distributions.rand{T<:AbstractFloat}(d::RootInverseGamma; cc::T = 1.0)
    return sqrt(d.ν * d.τ^2 / sum(randn(round(Int,d.ν)).^2))
end

"""
```
DegenerateMvNormal <: Distribution{Multivariate, Continuous}
```

The `DegenerateMvNormal` type implements a degenerate multivariate normal
distribution. The covariance matrix may not be full rank (hence degenerate).

See [Multivariate normal distribution - Degenerate case](en.wikipedia.org/wiki/Multivariate_normal_distribution#Degenerate_case).
"""
type DegenerateMvNormal <: Distribution{Multivariate, Continuous}
    μ::Vector          # mean
    σ::Matrix          # standard deviation
end

"""
```
rank(d::DegenerateMvNormal)
```

Returns the rank of `d.σ`.
"""
function rank(d::DegenerateMvNormal)
    return rank(d.σ)
end

"""
```
length(d::DegenerateMvNormal)
```

Returns the dimension of `d`.
"""
Base.length(d::DegenerateMvNormal) = length(d.μ)

"""
```
Distributions.rand{T<:AbstractFloat}(d::DegenerateMvNormal; cc::T = 1.0)
```

Generate a draw from `d` with variance optionally scaled by `cc^2`.
"""
function Distributions.rand{T<:AbstractFloat}(d::DegenerateMvNormal; cc::T = 1.0)
    return d.μ + cc*d.σ*randn(length(d))
end

"""
```
Distributions.rand(d::DegenerateMvNormal, n::Int)
```

Generate `n` draws from `d`. This returns a matrix of size `(length(d), n)`,
where each column is a sample.
"""
function Distributions.rand(d::DegenerateMvNormal, n::Int)
    return d.μ .+ d.σ*randn(length(d), n)
end

"""
```
DegenerateDiagMvTDist <: Distribution{Multivariate, Continuous}
```

The `DegenerateDiagMvTDist` type implements a degenerate multivariate Student's t
distribution, where the covariance matrix is diagonal. The covariance matrix may
not be full rank (hence degenerate).
"""
type DegenerateDiagMvTDist <: Distribution{Multivariate, Continuous}
    μ::Vector          # mean
    σ::Matrix          # standard deviation
    ν::Int             # degrees of freedom

    function DegenerateDiagMvTDist(μ::Vector, σ::Matrix, ν::Int)
        ν > 0       ? nothing : error("Degrees of freedom (ν) must be positive")
        isdiag(σ^2) ? nothing : error("Covariance matrix (σ^2) must be diagonal")
        return new(μ, σ, ν)
    end
end

"""
```
rank(d::DegenerateDiagMvTDist)
```

Returns the rank of `d.σ`.
"""
function rank(d::DegenerateDiagMvTDist)
    return rank(d.σ)
end

"""
```
length(d::DegenerateDiagMvTDist)
```

Returns the dimension of `d`.
"""
Base.length(d::DegenerateDiagMvTDist) = length(d.μ)

"""
```
Distributions.rand(d::DegenerateDiagMvTDist)
```

Generate a draw from `d`.
"""
function Distributions.rand(d::DegenerateDiagMvTDist)
    return d.μ + d.σ*rand(TDist(d.ν), length(d))
end

"""
```
Distributions.rand(d::DegenerateDiagMvTDist, n::Int)
```

Generate `n` draws from `d`. This returns a matrix of size `(length(d), n)`,
where each column is a sample.
"""
function Distributions.rand(d::DegenerateDiagMvTDist, n::Int)
    return d.μ .+ d.σ*rand(TDist(d.ν), length(d), n)
end

# Compute the mean μ and standard deviation σ of a DSGE.RootInverseGamma object.

# A Root Inverse Gamma / Nagasaki Scaled Chi2 Distribution's mean and standard deviation
# can be computed as follows:

#     μ = √(β) * Γ(α - 0.5) / Γ(α)
#     σ = √(β / (α - 1) - μ²)

# where α = ν/2 and β = τ²*ν/2.
function mean(dist::RootInverseGamma)
    α = dist.ν/2
    β = dist.τ^2 * dist.ν/2

    μ = β^(.5) * gamma(α - 0.5) / gamma(α)
    return μ
end

function std(dist::RootInverseGamma)
    α = dist.ν/2
    β = dist.τ^2 * dist.ν/2

    σ = (β / (α - 1) - μ^2)^(0.5)
    return σ
end

"""
```
MatrixNormal <: Distribution{Matrixvariate, Continuous}
```

The `MatrixNormal` type implements a matrixvariate normal
distribution. Note that the matrix must be square.

See [Matrix normal distribution - Degenerate case](en.wikipedia.org/wiki/Matrix_normal_distribution).
"""
type MatrixNormal <: Distribution{Matrixvariate, Continuous}
    μ::Matrix # mean
    U::Matrix # row variance
    V::Matrix # col variance
    U_sqrt::Matrix # cholesky of U
    V_sqrt::Matrix # choleksy of V
    U_inv::Matrix # inverse of U
    V_inv::Matrix # inverse of V

    function MatrixNormal(μ::Matrix, U::Matrix, V::Matrix)
        size(μ,1) == size(U,1) || error("μ and U must have the same number of rows")
        size(μ,2) == size(V,1) || error("μ and V must have the same number of columns")
        isposdef(U) || error("U is not a positive definite matrix")
        isposdef(V) || error("V is not a positive definite matrix")

        U_sqrt = Matrix(chol(U))
        V_sqrt = Matrix(chol(V))
        U_inv = inv(U)
        V_inv = inv(V)

        return new(μ, U, V, U_sqrt, V_sqrt, U_inv, V_inv)
    end

    function MatrixNormal(μ::Matrix, Σ::Matrix)
        size(μ) == size(Σ) || error("μ and Σ must be the same size")
        isposdef(Σ) || error("Σ is not a positive definite matrix")
        Σ_sqrt = Matrix(chol(U))
        Σ_inv = inv(U)

        return new(μ, Σ, Σ, Σ_sqrt, Σ_sqrt, Σ_inv, Σ_inv)
    end

end

"""
```
size(d::MatrixNormal)
```

Returns the dimension of `d`.
"""
Base.size(d::MatrixNormal) = size(d.μ)

"""
```
Distributions.rand{T<:AbstractFloat}(d::MatrixNormal)
```

Generate a draw from `d`.
"""
function Distributions.rand(d::MatrixNormal)
    return d.μ + d.U_sqrt*randn(size(d.μ))*d.V_sqrt'
end

function mean(d::MatrixNormal)
    return d.μ
end

Distributions.params(d::MatrixNormal) = d.μ, d.U, d.V

"""
```
Distributions.pdf(d::MatrixNormal, x::Matrix)
```

Compute the pdf of a MatrixNormal distribution at x.
"""
function Distributions.pdf(d::MatrixNormal, x::Matrix)
    μ, U, V = params(d)
    n, p = size(μ)
    U_inv = d.U_inv
    V_inv = d.V_inv
    return exp(-.5*trace(V_inv * (x-μ)' * U_inv * (x-μ))) / ((2π)^(n*p/2) * det(U)^(p/2) * det(V)^(n/2))
end

"""
```
Distributions.logpdf(d::MatrixNormal, x::Matrix)
```

Compute the logpdf of a MatrixNormal distribution at x.
"""
function Distributions.logpdf(d::MatrixNormal, x::Matrix)
    μ, U, V = params(d)
    n, p = size(μ)
    U_inv = d.U_inv
    V_inv = d.V_inv
    return -.5*trace(V_inv * (x-μ)' * U_inv * (x-μ)) - log((2π)^(n*p/2) * det(U)^(p/2) * det(V)^(n/2))
end