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

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

Accepts an Amazon Macie membership invitation that was received from a specific account.

# Arguments
- `invitation_id`: The unique identifier for the invitation to accept.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"administratorAccountId"`: The Amazon Web Services account ID for the account that sent
  the invitation.
- `"masterAccount"`: (Deprecated) The Amazon Web Services account ID for the account that
  sent the invitation. This property has been replaced by the administratorAccountId property
  and is retained only for backward compatibility.
"""
function accept_invitation(invitationId; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/invitations/accept",
        Dict{String,Any}("invitationId" => invitationId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function accept_invitation(
    invitationId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "POST",
        "/invitations/accept",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("invitationId" => invitationId), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves information about one or more custom data identifiers.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ids"`: An array of custom data identifier IDs, one for each custom data identifier to
  retrieve information about.
"""
function batch_get_custom_data_identifiers(;
    aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/custom-data-identifiers/get";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function batch_get_custom_data_identifiers(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/custom-data-identifiers/get",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_classification_job(client_token, job_type, name, s3_job_definition)
    create_classification_job(client_token, job_type, name, s3_job_definition, params::Dict{String,<:Any})

Creates and defines the settings for a classification job.

# Arguments
- `client_token`: A unique, case-sensitive token that you provide to ensure the idempotency
  of the request.
- `job_type`: The schedule for running the job. Valid values are: ONE_TIME - Run the job
  only once. If you specify this value, don't specify a value for the scheduleFrequency
  property. SCHEDULED - Run the job on a daily, weekly, or monthly basis. If you specify this
  value, use the scheduleFrequency property to define the recurrence pattern for the job.
- `name`: A custom name for the job. The name can contain as many as 500 characters.
- `s3_job_definition`: The S3 buckets that contain the objects to analyze, and the scope of
  that analysis.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"customDataIdentifierIds"`: An array of unique identifiers, one for each custom data
  identifier for the job to use when it analyzes data. To use only managed data identifiers,
  don't specify a value for this property and specify a value other than NONE for the
  managedDataIdentifierSelector property.
- `"description"`: A custom description of the job. The description can contain as many as
  200 characters.
- `"initialRun"`: For a recurring job, specifies whether to analyze all existing, eligible
  objects immediately after the job is created (true). To analyze only those objects that are
  created or changed after you create the job and before the job's first scheduled run, set
  this value to false.If you configure the job to run only once, don't specify a value for
  this property.
- `"managedDataIdentifierIds"`: An array of unique identifiers, one for each managed data
  identifier for the job to include (use) or exclude (not use) when it analyzes data.
  Inclusion or exclusion depends on the managed data identifier selection type that you
  specify for the job (managedDataIdentifierSelector).To retrieve a list of valid values for
  this property, use the ListManagedDataIdentifiers operation.
- `"managedDataIdentifierSelector"`: The selection type to apply when determining which
  managed data identifiers the job uses to analyze data. Valid values are: ALL - Use all the
  managed data identifiers that Amazon Macie provides. If you specify this value, don't
  specify any values for the managedDataIdentifierIds property. EXCLUDE - Use all the managed
  data identifiers that Macie provides except the managed data identifiers specified by the
  managedDataIdentifierIds property. INCLUDE - Use only the managed data identifiers
  specified by the managedDataIdentifierIds property. NONE - Don't use any managed data
  identifiers. If you specify this value, specify at least one custom data identifier for the
  job (customDataIdentifierIds) and don't specify any values for the managedDataIdentifierIds
  property. If you don't specify a value for this property, the job uses all managed data
  identifiers. If you don't specify a value for this property or you specify ALL or EXCLUDE
  for a recurring job, the job also uses new managed data identifiers as they are released.
- `"samplingPercentage"`: The sampling depth, as a percentage, for the job to apply when
  processing objects. This value determines the percentage of eligible objects that the job
  analyzes. If this value is less than 100, Amazon Macie selects the objects to analyze at
  random, up to the specified percentage, and analyzes all the data in those objects.
- `"scheduleFrequency"`: The recurrence pattern for running the job. To run the job only
  once, don't specify a value for this property and set the value for the jobType property to
  ONE_TIME.
- `"tags"`: A map of key-value pairs that specifies the tags to associate with the job. A
  job can have a maximum of 50 tags. Each tag consists of a tag key and an associated tag
  value. The maximum length of a tag key is 128 characters. The maximum length of a tag value
  is 256 characters.
"""
function create_classification_job(
    clientToken,
    jobType,
    name,
    s3JobDefinition;
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "POST",
        "/jobs",
        Dict{String,Any}(
            "clientToken" => clientToken,
            "jobType" => jobType,
            "name" => name,
            "s3JobDefinition" => s3JobDefinition,
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_classification_job(
    clientToken,
    jobType,
    name,
    s3JobDefinition,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "POST",
        "/jobs",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "clientToken" => clientToken,
                    "jobType" => jobType,
                    "name" => name,
                    "s3JobDefinition" => s3JobDefinition,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Creates and defines the criteria and other settings for a custom data identifier.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"clientToken"`: A unique, case-sensitive token that you provide to ensure the
  idempotency of the request.
- `"description"`: A custom description of the custom data identifier. The description can
  contain as many as 512 characters. We strongly recommend that you avoid including any
  sensitive data in the description of a custom data identifier. Other users of your account
  might be able to see this description, depending on the actions that they're allowed to
  perform in Amazon Macie.
- `"ignoreWords"`: An array that lists specific character sequences (ignore words) to
  exclude from the results. If the text matched by the regular expression contains any string
  in this array, Amazon Macie ignores it. The array can contain as many as 10 ignore words.
  Each ignore word can contain 4-90 UTF-8 characters. Ignore words are case sensitive.
- `"keywords"`: An array that lists specific character sequences (keywords), one of which
  must be within proximity (maximumMatchDistance) of the regular expression to match. The
  array can contain as many as 50 keywords. Each keyword can contain 3-90 UTF-8 characters.
  Keywords aren't case sensitive.
- `"maximumMatchDistance"`: The maximum number of characters that can exist between text
  that matches the regular expression and the character sequences specified by the keywords
  array. Amazon Macie includes or excludes a result based on the proximity of a keyword to
  text that matches the regular expression. The distance can be 1-300 characters. The default
  value is 50.
- `"name"`: A custom name for the custom data identifier. The name can contain as many as
  128 characters. We strongly recommend that you avoid including any sensitive data in the
  name of a custom data identifier. Other users of your account might be able to see this
  name, depending on the actions that they're allowed to perform in Amazon Macie.
- `"regex"`: The regular expression (regex) that defines the pattern to match. The
  expression can contain as many as 512 characters.
- `"severityLevels"`: The severity to assign to findings that the custom data identifier
  produces, based on the number of occurrences of text that matches the custom data
  identifier's detection criteria. You can specify as many as three SeverityLevel objects in
  this array, one for each severity: LOW, MEDIUM, or HIGH. If you specify more than one, the
  occurrences thresholds must be in ascending order by severity, moving from LOW to HIGH. For
  example, 1 for LOW, 50 for MEDIUM, and 100 for HIGH. If an S3 object contains fewer
  occurrences than the lowest specified threshold, Amazon Macie doesn't create a finding. If
  you don't specify any values for this array, Macie creates findings for S3 objects that
  contain at least one occurrence of text that matches the detection criteria, and Macie
  assigns the MEDIUM severity to those findings.
- `"tags"`: A map of key-value pairs that specifies the tags to associate with the custom
  data identifier. A custom data identifier can have a maximum of 50 tags. Each tag consists
  of a tag key and an associated tag value. The maximum length of a tag key is 128
  characters. The maximum length of a tag value is 256 characters.
"""
function create_custom_data_identifier(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/custom-data-identifiers",
        Dict{String,Any}("clientToken" => string(uuid4()));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_custom_data_identifier(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/custom-data-identifiers",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("clientToken" => string(uuid4())), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_findings_filter(action, finding_criteria, name)
    create_findings_filter(action, finding_criteria, name, params::Dict{String,<:Any})

Creates and defines the criteria and other settings for a findings filter.

# Arguments
- `action`: The action to perform on findings that meet the filter criteria
  (findingCriteria). Valid values are: ARCHIVE, suppress (automatically archive) the
  findings; and, NOOP, don't perform any action on the findings.
- `finding_criteria`: The criteria to use to filter findings.
- `name`: A custom name for the filter. The name must contain at least 3 characters and can
  contain as many as 64 characters. We strongly recommend that you avoid including any
  sensitive data in the name of a filter. Other users of your account might be able to see
  this name, depending on the actions that they're allowed to perform in Amazon Macie.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"clientToken"`: A unique, case-sensitive token that you provide to ensure the
  idempotency of the request.
- `"description"`: A custom description of the filter. The description can contain as many
  as 512 characters. We strongly recommend that you avoid including any sensitive data in the
  description of a filter. Other users of your account might be able to see this description,
  depending on the actions that they're allowed to perform in Amazon Macie.
- `"position"`: The position of the filter in the list of saved filters on the Amazon Macie
  console. This value also determines the order in which the filter is applied to findings,
  relative to other filters that are also applied to the findings.
- `"tags"`: A map of key-value pairs that specifies the tags to associate with the filter.
  A findings filter can have a maximum of 50 tags. Each tag consists of a tag key and an
  associated tag value. The maximum length of a tag key is 128 characters. The maximum length
  of a tag value is 256 characters.
"""
function create_findings_filter(
    action, findingCriteria, name; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/findingsfilters",
        Dict{String,Any}(
            "action" => action,
            "findingCriteria" => findingCriteria,
            "name" => name,
            "clientToken" => string(uuid4()),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_findings_filter(
    action,
    findingCriteria,
    name,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "POST",
        "/findingsfilters",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "action" => action,
                    "findingCriteria" => findingCriteria,
                    "name" => name,
                    "clientToken" => string(uuid4()),
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Sends an Amazon Macie membership invitation to one or more accounts.

# Arguments
- `account_ids`: An array that lists Amazon Web Services account IDs, one for each account
  to send the invitation to.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"disableEmailNotification"`: Specifies whether to send the invitation as an email
  message. If this value is false, Amazon Macie sends the invitation (as an email message) to
  the email address that you specified for the recipient's account when you associated the
  account with your account. The default value is false.
- `"message"`: Custom text to include in the email message that contains the invitation.
  The text can contain as many as 80 alphanumeric characters.
"""
function create_invitations(accountIds; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/invitations",
        Dict{String,Any}("accountIds" => accountIds);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_invitations(
    accountIds,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "POST",
        "/invitations",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("accountIds" => accountIds), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Associates an account with an Amazon Macie administrator account.

# Arguments
- `account`: The details of the account to associate with the administrator account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"tags"`: A map of key-value pairs that specifies the tags to associate with the account
  in Amazon Macie. An account can have a maximum of 50 tags. Each tag consists of a tag key
  and an associated tag value. The maximum length of a tag key is 128 characters. The maximum
  length of a tag value is 256 characters.
"""
function create_member(account; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/members",
        Dict{String,Any}("account" => account);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_member(
    account, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/members",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("account" => account), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Creates sample findings.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"findingTypes"`: An array of finding types, one for each type of sample finding to
  create. To create a sample of every type of finding that Amazon Macie supports, don't
  include this array in your request.
"""
function create_sample_findings(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST", "/findings/sample"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function create_sample_findings(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/findings/sample",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Declines Amazon Macie membership invitations that were received from specific accounts.

# Arguments
- `account_ids`: An array that lists Amazon Web Services account IDs, one for each account
  that sent an invitation to decline.

"""
function decline_invitations(accountIds; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/invitations/decline",
        Dict{String,Any}("accountIds" => accountIds);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function decline_invitations(
    accountIds,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "POST",
        "/invitations/decline",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("accountIds" => accountIds), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Soft deletes a custom data identifier.

# Arguments
- `id`: The unique identifier for the Amazon Macie resource or account that the request
  applies to.

"""
function delete_custom_data_identifier(
    id; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "DELETE",
        "/custom-data-identifiers/$(id)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_custom_data_identifier(
    id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "DELETE",
        "/custom-data-identifiers/$(id)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deletes a findings filter.

# Arguments
- `id`: The unique identifier for the Amazon Macie resource or account that the request
  applies to.

"""
function delete_findings_filter(id; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "DELETE",
        "/findingsfilters/$(id)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_findings_filter(
    id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "DELETE",
        "/findingsfilters/$(id)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deletes Amazon Macie membership invitations that were received from specific accounts.

# Arguments
- `account_ids`: An array that lists Amazon Web Services account IDs, one for each account
  that sent an invitation to delete.

"""
function delete_invitations(accountIds; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/invitations/delete",
        Dict{String,Any}("accountIds" => accountIds);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_invitations(
    accountIds,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "POST",
        "/invitations/delete",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("accountIds" => accountIds), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deletes the association between an Amazon Macie administrator account and an account.

# Arguments
- `id`: The unique identifier for the Amazon Macie resource or account that the request
  applies to.

"""
function delete_member(id; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "DELETE", "/members/$(id)"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function delete_member(
    id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "DELETE",
        "/members/$(id)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves (queries) statistical data and other information about one or more S3 buckets
that Amazon Macie monitors and analyzes.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"criteria"`: The criteria to use to filter the query results.
- `"maxResults"`: The maximum number of items to include in each page of the response. The
  default value is 50.
- `"nextToken"`: The nextToken string that specifies which page of results to return in a
  paginated response.
- `"sortCriteria"`: The criteria to use to sort the query results.
"""
function describe_buckets(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST", "/datasources/s3"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_buckets(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/datasources/s3",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves the status and settings for a classification job.

# Arguments
- `job_id`: The unique identifier for the classification job.

"""
function describe_classification_job(
    jobId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET", "/jobs/$(jobId)"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_classification_job(
    jobId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/jobs/$(jobId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves the Amazon Macie configuration settings for an organization in Organizations.

"""
function describe_organization_configuration(;
    aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/admin/configuration";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function describe_organization_configuration(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/admin/configuration",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Disables Amazon Macie and deletes all settings and resources for a Macie account.

"""
function disable_macie(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "DELETE", "/macie"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function disable_macie(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "DELETE", "/macie", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

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

Disables an account as the delegated Amazon Macie administrator account for an organization
in Organizations.

# Arguments
- `admin_account_id`: The Amazon Web Services account ID of the delegated Amazon Macie
  administrator account.

"""
function disable_organization_admin_account(
    adminAccountId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "DELETE",
        "/admin",
        Dict{String,Any}("adminAccountId" => adminAccountId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function disable_organization_admin_account(
    adminAccountId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "DELETE",
        "/admin",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("adminAccountId" => adminAccountId), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Disassociates a member account from its Amazon Macie administrator account.

"""
function disassociate_from_administrator_account(;
    aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/administrator/disassociate";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function disassociate_from_administrator_account(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/administrator/disassociate",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

(Deprecated) Disassociates a member account from its Amazon Macie administrator account.
This operation has been replaced by the DisassociateFromAdministratorAccount operation.

"""
function disassociate_from_master_account(;
    aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/master/disassociate";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function disassociate_from_master_account(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/master/disassociate",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Disassociates an Amazon Macie administrator account from a member account.

# Arguments
- `id`: The unique identifier for the Amazon Macie resource or account that the request
  applies to.

"""
function disassociate_member(id; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/members/disassociate/$(id)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function disassociate_member(
    id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/members/disassociate/$(id)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Enables Amazon Macie and specifies the configuration settings for a Macie account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"clientToken"`: A unique, case-sensitive token that you provide to ensure the
  idempotency of the request.
- `"findingPublishingFrequency"`: Specifies how often to publish updates to policy findings
  for the account. This includes publishing updates to Security Hub and Amazon EventBridge
  (formerly called Amazon CloudWatch Events).
- `"status"`: Specifies the new status for the account. To enable Amazon Macie and start
  all Macie activities for the account, set this value to ENABLED.
"""
function enable_macie(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/macie",
        Dict{String,Any}("clientToken" => string(uuid4()));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function enable_macie(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/macie",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("clientToken" => string(uuid4())), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Designates an account as the delegated Amazon Macie administrator account for an
organization in Organizations.

# Arguments
- `admin_account_id`: The Amazon Web Services account ID for the account to designate as
  the delegated Amazon Macie administrator account for the organization.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"clientToken"`: A unique, case-sensitive token that you provide to ensure the
  idempotency of the request.
"""
function enable_organization_admin_account(
    adminAccountId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/admin",
        Dict{String,Any}(
            "adminAccountId" => adminAccountId, "clientToken" => string(uuid4())
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function enable_organization_admin_account(
    adminAccountId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "POST",
        "/admin",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "adminAccountId" => adminAccountId, "clientToken" => string(uuid4())
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves information about the Amazon Macie administrator account for an account.

"""
function get_administrator_account(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "GET", "/administrator"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function get_administrator_account(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/administrator",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves (queries) aggregated statistical data about S3 buckets that Amazon Macie monitors
and analyzes.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"accountId"`: The unique identifier for the Amazon Web Services account.
"""
function get_bucket_statistics(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/datasources/s3/statistics";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_bucket_statistics(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/datasources/s3/statistics",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves the configuration settings for storing data classification results.

"""
function get_classification_export_configuration(;
    aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/classification-export-configuration";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_classification_export_configuration(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/classification-export-configuration",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves the criteria and other settings for a custom data identifier.

# Arguments
- `id`: The unique identifier for the Amazon Macie resource or account that the request
  applies to.

"""
function get_custom_data_identifier(id; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "GET",
        "/custom-data-identifiers/$(id)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_custom_data_identifier(
    id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/custom-data-identifiers/$(id)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Retrieves (queries) aggregated statistical data about findings.

# Arguments
- `group_by`: The finding property to use to group the query results. Valid values are:
  classificationDetails.jobId - The unique identifier for the classification job that
  produced the finding. resourcesAffected.s3Bucket.name - The name of the S3 bucket that the
  finding applies to. severity.description - The severity level of the finding, such as High
  or Medium. type - The type of finding, such as Policy:IAMUser/S3BucketPublic and
  SensitiveData:S3Object/Personal.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"findingCriteria"`: The criteria to use to filter the query results.
- `"size"`: The maximum number of items to include in each page of the response.
- `"sortCriteria"`: The criteria to use to sort the query results.
"""
function get_finding_statistics(groupBy; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/findings/statistics",
        Dict{String,Any}("groupBy" => groupBy);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_finding_statistics(
    groupBy, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/findings/statistics",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("groupBy" => groupBy), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves the details of one or more findings.

# Arguments
- `finding_ids`: An array of strings that lists the unique identifiers for the findings to
  retrieve.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"sortCriteria"`: The criteria for sorting the results of the request.
"""
function get_findings(findingIds; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/findings/describe",
        Dict{String,Any}("findingIds" => findingIds);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_findings(
    findingIds,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "POST",
        "/findings/describe",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("findingIds" => findingIds), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves the criteria and other settings for a findings filter.

# Arguments
- `id`: The unique identifier for the Amazon Macie resource or account that the request
  applies to.

"""
function get_findings_filter(id; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "GET",
        "/findingsfilters/$(id)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_findings_filter(
    id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/findingsfilters/$(id)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves the configuration settings for publishing findings to Security Hub.

"""
function get_findings_publication_configuration(;
    aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/findings-publication-configuration";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_findings_publication_configuration(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/findings-publication-configuration",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves the count of Amazon Macie membership invitations that were received by an account.

"""
function get_invitations_count(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "GET", "/invitations/count"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function get_invitations_count(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/invitations/count",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves the current status and configuration settings for an Amazon Macie account.

"""
function get_macie_session(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2("GET", "/macie"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET)
end
function get_macie_session(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET", "/macie", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

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

(Deprecated) Retrieves information about the Amazon Macie administrator account for an
account. This operation has been replaced by the GetAdministratorAccount operation.

"""
function get_master_account(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2("GET", "/master"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET)
end
function get_master_account(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET", "/master", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

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

Retrieves information about an account that's associated with an Amazon Macie administrator
account.

# Arguments
- `id`: The unique identifier for the Amazon Macie resource or account that the request
  applies to.

"""
function get_member(id; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "GET", "/members/$(id)"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function get_member(
    id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/members/$(id)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves (queries) quotas and aggregated usage data for one or more accounts.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filterBy"`: An array of objects, one for each condition to use to filter the query
  results. If you specify more than one condition, Amazon Macie uses an AND operator to join
  the conditions.
- `"maxResults"`: The maximum number of items to include in each page of the response.
- `"nextToken"`: The nextToken string that specifies which page of results to return in a
  paginated response.
- `"sortBy"`: The criteria to use to sort the query results.
- `"timeRange"`: The inclusive time period to query usage data for. Valid values are:
  MONTH_TO_DATE, for the current calendar month to date; and, PAST_30_DAYS, for the preceding
  30 days. If you don't specify a value, Amazon Macie provides usage data for the preceding
  30 days.
"""
function get_usage_statistics(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST", "/usage/statistics"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function get_usage_statistics(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/usage/statistics",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves (queries) aggregated usage data for an account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"timeRange"`: The inclusive time period to retrieve the data for. Valid values are:
  MONTH_TO_DATE, for the current calendar month to date; and, PAST_30_DAYS, for the preceding
  30 days. If you don't specify a value for this parameter, Amazon Macie provides aggregated
  usage data for the preceding 30 days.
"""
function get_usage_totals(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2("GET", "/usage"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET)
end
function get_usage_totals(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET", "/usage", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

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

Retrieves a subset of information about one or more classification jobs.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filterCriteria"`: The criteria to use to filter the results.
- `"maxResults"`: The maximum number of items to include in each page of the response.
- `"nextToken"`: The nextToken string that specifies which page of results to return in a
  paginated response.
- `"sortCriteria"`: The criteria to use to sort the results.
"""
function list_classification_jobs(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST", "/jobs/list"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_classification_jobs(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST", "/jobs/list", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

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

Retrieves a subset of information about all the custom data identifiers for an account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of items to include in each page of the response.
- `"nextToken"`: The nextToken string that specifies which page of results to return in a
  paginated response.
"""
function list_custom_data_identifiers(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/custom-data-identifiers/list";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_custom_data_identifiers(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/custom-data-identifiers/list",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves a subset of information about one or more findings.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"findingCriteria"`: The criteria to use to filter the results.
- `"maxResults"`: The maximum number of items to include in each page of the response.
- `"nextToken"`: The nextToken string that specifies which page of results to return in a
  paginated response.
- `"sortCriteria"`: The criteria to use to sort the results.
"""
function list_findings(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST", "/findings"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_findings(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST", "/findings", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

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

Retrieves a subset of information about all the findings filters for an account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of items to include in each page of a paginated
  response.
- `"nextToken"`: The nextToken string that specifies which page of results to return in a
  paginated response.
"""
function list_findings_filters(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "GET", "/findingsfilters"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_findings_filters(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/findingsfilters",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves information about the Amazon Macie membership invitations that were received by
an account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of items to include in each page of a paginated
  response.
- `"nextToken"`: The nextToken string that specifies which page of results to return in a
  paginated response.
"""
function list_invitations(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "GET", "/invitations"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_invitations(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/invitations",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves information about all the managed data identifiers that Amazon Macie currently
provides.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"nextToken"`: The nextToken string that specifies which page of results to return in a
  paginated response.
"""
function list_managed_data_identifiers(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/managed-data-identifiers/list";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_managed_data_identifiers(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/managed-data-identifiers/list",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves information about the accounts that are associated with an Amazon Macie
administrator account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of items to include in each page of a paginated
  response.
- `"nextToken"`: The nextToken string that specifies which page of results to return in a
  paginated response.
- `"onlyAssociated"`: Specifies which accounts to include in the response, based on the
  status of an account's relationship with the administrator account. By default, the
  response includes only current member accounts. To include all accounts, set this value to
  false.
"""
function list_members(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2("GET", "/members"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET)
end
function list_members(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET", "/members", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

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

Retrieves information about the delegated Amazon Macie administrator account for an
organization in Organizations.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of items to include in each page of a paginated
  response.
- `"nextToken"`: The nextToken string that specifies which page of results to return in a
  paginated response.
"""
function list_organization_admin_accounts(;
    aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2("GET", "/admin"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET)
end
function list_organization_admin_accounts(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET", "/admin", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

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

Retrieves the tags (keys and values) that are associated with a classification job, custom
data identifier, findings filter, or member account.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the classification job, custom data
  identifier, findings filter, or member account.

"""
function list_tags_for_resource(
    resourceArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "GET",
        "/tags/$(resourceArn)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_tags_for_resource(
    resourceArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "GET",
        "/tags/$(resourceArn)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Creates or updates the configuration settings for storing data classification results.

# Arguments
- `configuration`: The location to store data classification results in, and the encryption
  settings to use when storing results in that location.

"""
function put_classification_export_configuration(
    configuration; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "PUT",
        "/classification-export-configuration",
        Dict{String,Any}("configuration" => configuration);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function put_classification_export_configuration(
    configuration,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "PUT",
        "/classification-export-configuration",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("configuration" => configuration), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Updates the configuration settings for publishing findings to Security Hub.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"clientToken"`: A unique, case-sensitive token that you provide to ensure the
  idempotency of the request.
- `"securityHubConfiguration"`: The configuration settings that determine which findings to
  publish to Security Hub.
"""
function put_findings_publication_configuration(;
    aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "PUT",
        "/findings-publication-configuration",
        Dict{String,Any}("clientToken" => string(uuid4()));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function put_findings_publication_configuration(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "PUT",
        "/findings-publication-configuration",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("clientToken" => string(uuid4())), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves (queries) statistical data and other information about Amazon Web Services
resources that Amazon Macie monitors and analyzes.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"bucketCriteria"`: The filter conditions that determine which S3 buckets to include or
  exclude from the query results.
- `"maxResults"`: The maximum number of items to include in each page of the response. The
  default value is 50.
- `"nextToken"`: The nextToken string that specifies which page of results to return in a
  paginated response.
- `"sortCriteria"`: The criteria to use to sort the results.
"""
function search_resources(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/datasources/search-resources";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function search_resources(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/datasources/search-resources",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    tag_resource(resource_arn, tags)
    tag_resource(resource_arn, tags, params::Dict{String,<:Any})

Adds or updates one or more tags (keys and values) that are associated with a
classification job, custom data identifier, findings filter, or member account.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the classification job, custom data
  identifier, findings filter, or member account.
- `tags`: A map of key-value pairs that specifies the tags to associate with the resource.
  A resource can have a maximum of 50 tags. Each tag consists of a tag key and an associated
  tag value. The maximum length of a tag key is 128 characters. The maximum length of a tag
  value is 256 characters.

"""
function tag_resource(resourceArn, tags; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "POST",
        "/tags/$(resourceArn)",
        Dict{String,Any}("tags" => tags);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function tag_resource(
    resourceArn,
    tags,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "POST",
        "/tags/$(resourceArn)",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("tags" => tags), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    test_custom_data_identifier(regex, sample_text)
    test_custom_data_identifier(regex, sample_text, params::Dict{String,<:Any})

Tests a custom data identifier.

# Arguments
- `regex`: The regular expression (regex) that defines the pattern to match. The expression
  can contain as many as 512 characters.
- `sample_text`: The sample text to inspect by using the custom data identifier. The text
  can contain as many as 1,000 characters.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ignoreWords"`: An array that lists specific character sequences (ignore words) to
  exclude from the results. If the text matched by the regular expression contains any string
  in this array, Amazon Macie ignores it. The array can contain as many as 10 ignore words.
  Each ignore word can contain 4-90 UTF-8 characters. Ignore words are case sensitive.
- `"keywords"`: An array that lists specific character sequences (keywords), one of which
  must be within proximity (maximumMatchDistance) of the regular expression to match. The
  array can contain as many as 50 keywords. Each keyword can contain 3-90 UTF-8 characters.
  Keywords aren't case sensitive.
- `"maximumMatchDistance"`: The maximum number of characters that can exist between text
  that matches the regular expression and the character sequences specified by the keywords
  array. Amazon Macie includes or excludes a result based on the proximity of a keyword to
  text that matches the regular expression. The distance can be 1-300 characters. The default
  value is 50.
"""
function test_custom_data_identifier(
    regex, sampleText; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "POST",
        "/custom-data-identifiers/test",
        Dict{String,Any}("regex" => regex, "sampleText" => sampleText);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function test_custom_data_identifier(
    regex,
    sampleText,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "POST",
        "/custom-data-identifiers/test",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("regex" => regex, "sampleText" => sampleText),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    untag_resource(resource_arn, tag_keys)
    untag_resource(resource_arn, tag_keys, params::Dict{String,<:Any})

Removes one or more tags (keys and values) from a classification job, custom data
identifier, findings filter, or member account.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the classification job, custom data
  identifier, findings filter, or member account.
- `tag_keys`: The key of the tag to remove from the resource. To remove multiple tags,
  append the tagKeys parameter and argument for each additional tag to remove, separated by
  an ampersand (&).

"""
function untag_resource(
    resourceArn, tagKeys; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "DELETE",
        "/tags/$(resourceArn)",
        Dict{String,Any}("tagKeys" => tagKeys);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function untag_resource(
    resourceArn,
    tagKeys,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "DELETE",
        "/tags/$(resourceArn)",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("tagKeys" => tagKeys), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    update_classification_job(job_id, job_status)
    update_classification_job(job_id, job_status, params::Dict{String,<:Any})

Changes the status of a classification job.

# Arguments
- `job_id`: The unique identifier for the classification job.
- `job_status`: The new status for the job. Valid values are: CANCELLED - Stops the job
  permanently and cancels it. This value is valid only if the job's current status is IDLE,
  PAUSED, RUNNING, or USER_PAUSED. If you specify this value and the job's current status is
  RUNNING, Amazon Macie immediately begins to stop all processing tasks for the job. You
  can't resume or restart a job after you cancel it. RUNNING - Resumes the job. This value is
  valid only if the job's current status is USER_PAUSED. If you paused the job while it was
  actively running and you specify this value less than 30 days after you paused the job,
  Macie immediately resumes processing from the point where you paused the job. Otherwise,
  Macie resumes the job according to the schedule and other settings for the job. USER_PAUSED
  - Pauses the job temporarily. This value is valid only if the job's current status is IDLE,
  PAUSED, or RUNNING. If you specify this value and the job's current status is RUNNING,
  Macie immediately begins to pause all processing tasks for the job. If you pause a one-time
  job and you don't resume it within 30 days, the job expires and Macie cancels the job. If
  you pause a recurring job when its status is RUNNING and you don't resume it within 30
  days, the job run expires and Macie cancels the run. To check the expiration date, refer to
  the UserPausedDetails.jobExpiresAt property.

"""
function update_classification_job(
    jobId, jobStatus; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "PATCH",
        "/jobs/$(jobId)",
        Dict{String,Any}("jobStatus" => jobStatus);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_classification_job(
    jobId,
    jobStatus,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "PATCH",
        "/jobs/$(jobId)",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("jobStatus" => jobStatus), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Updates the criteria and other settings for a findings filter.

# Arguments
- `id`: The unique identifier for the Amazon Macie resource or account that the request
  applies to.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"action"`: The action to perform on findings that meet the filter criteria
  (findingCriteria). Valid values are: ARCHIVE, suppress (automatically archive) the
  findings; and, NOOP, don't perform any action on the findings.
- `"clientToken"`: A unique, case-sensitive token that you provide to ensure the
  idempotency of the request.
- `"description"`: A custom description of the filter. The description can contain as many
  as 512 characters. We strongly recommend that you avoid including any sensitive data in the
  description of a filter. Other users might be able to see this description, depending on
  the actions that they're allowed to perform in Amazon Macie.
- `"findingCriteria"`: The criteria to use to filter findings.
- `"name"`: A custom name for the filter. The name must contain at least 3 characters and
  can contain as many as 64 characters. We strongly recommend that you avoid including any
  sensitive data in the name of a filter. Other users might be able to see this name,
  depending on the actions that they're allowed to perform in Amazon Macie.
- `"position"`: The position of the filter in the list of saved filters on the Amazon Macie
  console. This value also determines the order in which the filter is applied to findings,
  relative to other filters that are also applied to the findings.
"""
function update_findings_filter(id; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2(
        "PATCH",
        "/findingsfilters/$(id)",
        Dict{String,Any}("clientToken" => string(uuid4()));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_findings_filter(
    id, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "PATCH",
        "/findingsfilters/$(id)",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("clientToken" => string(uuid4())), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Suspends or re-enables Amazon Macie, or updates the configuration settings for a Macie
account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"findingPublishingFrequency"`: Specifies how often to publish updates to policy findings
  for the account. This includes publishing updates to Security Hub and Amazon EventBridge
  (formerly called Amazon CloudWatch Events).
- `"status"`: Specifies a new status for the account. Valid values are: ENABLED, resume all
  Amazon Macie activities for the account; and, PAUSED, suspend all Macie activities for the
  account.
"""
function update_macie_session(; aws_config::AbstractAWSConfig=global_aws_config())
    return macie2("PATCH", "/macie"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET)
end
function update_macie_session(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "PATCH", "/macie", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

"""
    update_member_session(id, status)
    update_member_session(id, status, params::Dict{String,<:Any})

Enables an Amazon Macie administrator to suspend or re-enable Macie for a member account.

# Arguments
- `id`: The unique identifier for the Amazon Macie resource or account that the request
  applies to.
- `status`: Specifies the new status for the account. Valid values are: ENABLED, resume all
  Amazon Macie activities for the account; and, PAUSED, suspend all Macie activities for the
  account.

"""
function update_member_session(
    id, status; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "PATCH",
        "/macie/members/$(id)",
        Dict{String,Any}("status" => status);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_member_session(
    id,
    status,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "PATCH",
        "/macie/members/$(id)",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("status" => status), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Updates the Amazon Macie configuration settings for an organization in Organizations.

# Arguments
- `auto_enable`: Specifies whether to enable Amazon Macie automatically for an account when
  the account is added to the organization in Organizations.

"""
function update_organization_configuration(
    autoEnable; aws_config::AbstractAWSConfig=global_aws_config()
)
    return macie2(
        "PATCH",
        "/admin/configuration",
        Dict{String,Any}("autoEnable" => autoEnable);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_organization_configuration(
    autoEnable,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return macie2(
        "PATCH",
        "/admin/configuration",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("autoEnable" => autoEnable), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end


text:
# dummy types for testing
struct MyStronglyConvexType <: LearnBase.SupervisedLoss end
LearnBase.isstronglyconvex(::MyStronglyConvexType) = true
LearnBase.islipschitzcont(::MyStronglyConvexType) = true

@testset "Costs" begin
    @test LearnBase.Cost <: Any
    @test LearnBase.Penalty <: LearnBase.Cost
    @test LearnBase.Loss <: LearnBase.Cost
    @test LearnBase.UnsupervisedLoss <: LearnBase.Loss
    @test LearnBase.SupervisedLoss <: LearnBase.Loss
    @test LearnBase.MarginLoss <: LearnBase.SupervisedLoss
    @test LearnBase.DistanceLoss <: LearnBase.SupervisedLoss

    @test typeof(LearnBase.value) <: Function
    @test typeof(LearnBase.deriv) <: Function
    @test typeof(LearnBase.deriv2) <: Function

    @test typeof(LearnBase.isminimizable) <: Function
    @test typeof(LearnBase.isdifferentiable) <: Function
    @test typeof(LearnBase.istwicedifferentiable) <: Function
    @test typeof(LearnBase.isconvex) <: Function
    @test typeof(LearnBase.isstrictlyconvex) <: Function
    @test typeof(LearnBase.isstronglyconvex) <: Function
    @test typeof(LearnBase.isnemitski) <: Function
    @test typeof(LearnBase.islipschitzcont) <: Function
    @test typeof(LearnBase.islocallylipschitzcont) <: Function
    @test typeof(LearnBase.isfishercons) <: Function
    @test typeof(LearnBase.isunivfishercons) <: Function
    @test typeof(LearnBase.isclipable) <: Function
    @test typeof(LearnBase.ismarginbased) <: Function
    @test typeof(LearnBase.isdistancebased) <: Function
    @test typeof(LearnBase.isclasscalibrated) <: Function
    @test typeof(LearnBase.issymmetric) <: Function

    # test fallback methods
    @test LearnBase.isstronglyconvex(MyStronglyConvexType())
    @test LearnBase.isstrictlyconvex(MyStronglyConvexType())
    @test LearnBase.isconvex(MyStronglyConvexType())
    @test LearnBase.islipschitzcont(MyStronglyConvexType())
    @test LearnBase.islocallylipschitzcont(MyStronglyConvexType())
end

ext: jl


text:
@testset "Balanced" begin

    # Call function and determine threshold on some synthetic data.
    samples = map(x->gaussian_mixture(x, P₁ = 0.5, μ₁ = 64, σ₁ = 15, P₂ = 0.5, μ₂ = 192, σ₂ = 15), 0:255)
    edges = 0:255
    t = find_threshold(Balanced(), samples, edges)
    @test t == 128

    # Call function and determine threshold on moonsurface image
    img = testimage("moonsurface")
    edges, counts = build_histogram(img,  256)
    t = find_threshold(Balanced(), counts[1:end], edges)
    @test t == 0.5530790786724538

    # Call function and determine threshold on cameraman image
    img = testimage("cameraman")
    edges, counts = build_histogram(img,  256)
    t = find_threshold(Balanced(), counts[1:end], edges)
    @test t == 0.16796875

end


text:
import Statistics: mean, cov
import Random.rand
struct WGaussian{P,T} <: AbstractMeasure
    par::NamedTuple{P,T}
end
WGaussian{P}(nt::NamedTuple{P,T}) where {P,T} = WGaussian{P,T}(nt)
WGaussian{P}(args...) where {P} = WGaussian(NamedTuple{P}(args))
WGaussian(;args...) = WGaussian(args.data)
WGaussian{P}(;args...) where {P} = WGaussian{P}(args.data)

# the following propagates uncertainty if `μ` is `Gaussian`
WGaussian(par::NamedTuple{(:μ,:Σ,:c),Tuple{T,S,U}}) where {T<:WGaussian,S,U} = WGaussian((;μ=mean(par.μ), Σ=par.Σ +cov(par.μ), c=par.c + par.μ.c))
WGaussian{P}(par::NamedTuple{(:μ,:Σ,:c),Tuple{T,S,U}}) where {P,T<:WGaussian,S,U} = WGaussian{P}(mean(par.μ), par.Σ + cov(par.μ), par.c + par.μ.c)

Base.getproperty(p::WGaussian, s::Symbol) = getproperty(getfield(p, :par), s)

const WGaussianOrNdTuple{P} = Union{WGaussian{P},NamedTuple{P}}

Base.keys(p::WGaussian{P}) where {P} = P
params(p::WGaussian) = getfield(p, :par)

dim(p::WGaussian{(:F, :Γ, :c)}) = length(p.F)

mean(p::WGaussian{(:μ, :Σ, :c)}) = p.μ
cov(p::WGaussian{(:μ, :Σ, :c)}) = p.Σ

mean(p::WGaussian{(:F, :Γ, :c)}) = p.Γ\p.F
cov(p::WGaussian{(:F, :Γ, :c)}) = inv(p.Γ)
moment1(p::WGaussian{(:F, :Γ, :c)}) = p.c*p.Γ\p.F

Base.isapprox(p1::WGaussian, p2::WGaussian; kwargs...) =
    all(isapprox.(Tuple(params(p1)), Tuple(params(p2)); kwargs...))

function MeasureTheory.logdensity(p::WGaussian{(:F,:Γ,:c)}, x)
    C = cholesky_(sym(p.Γ))
    p.c - x'*p.Γ*x/2 + x'*p.F - p.F'*(C\p.F)/2  + logdet(C)/2 - dim(p)*log(2pi)/2
end
density(p::WGaussian, x) = exp(logdensity(p, x))

StatsBase.rand(p::WGaussian) = rand(Random.GLOBAL_RNG, p)
StatsBase.rand(RNG::AbstractRNG, p::WGaussian{(:μ,:Σ,:c)}) = weighted(unwhiten(Gaussian{(:μ,:Σ)}(p.μ, p.Σ), randn!(RNG, zero(mean(p)))), p.c)
weighted(p::WGaussian{(:μ, :Σ, :c)}, ll) = WGaussian{(:μ, :Σ, :c)}(p.μ, p.Σ, p.c + ll)

function Base.convert(::Type{WGaussian{(:F,:Γ,:c)}}, p::WGaussian{(:μ,:Σ,:c)})
    Γ = inv(p.Σ)
    return WGaussian{(:F,:Γ,:c)}(Γ*p.μ, Γ, p.c)
end
function Base.convert(::Type{WGaussian{(:μ,:Σ,:c)}}, p::WGaussian{(:F,:Γ,:c)})
    Σ = inv(p.Γ)
    return WGaussian{(:μ,:Σ,:c)}(Σ*p.F, Σ, p.c)
end
#=
Base.:(==)(p1::WGaussian, p2::WGaussian) = mean(p1) == mean(p2) && cov(p1) == cov(p2)
Base.isapprox(p1::WGaussian, p2::WGaussian; kwargs...) =
    isapprox(mean(p1), mean(p2); kwargs...) && isapprox(cov(p1), cov(p2); kwargs...)

mean(p::WGaussian{(:μ, :Σ)}) = p.μ
cov(p::WGaussian{(:μ, :Σ)})  = p.Σ
meancov(p) = mean(p), cov(p)

precision(p::WGaussian{(:μ, :Σ)}) = inv(p.Σ)

mean(p::WGaussian{(:F, :Γ)}) = Γ\p.F
cov(p::WGaussian{(:F, :Γ)}) = inv(p.Γ)
precision(p::WGaussian{(:F, :Γ)}) = p.Γ

dim(p::WGaussian) = length(mean(p))
whiten(p::WGaussian{(:μ, :Σ)}, x) = cholesky(p.Σ).U'\(x - p.μ)
unwhiten(p::WGaussian{(:μ, :Σ)}, z) = cholesky(p.Σ).U'*z + p.μ
sqmahal(p::WGaussian, x) = norm_sqr(whiten(p, x))

rand(p::WGaussian) = rand(Random.GLOBAL_RNG, p)
rand(RNG::AbstractRNG, p::WGaussian) = unwhiten(p, randn!(RNG, zero(mean(p))))

MeasureTheory.logdensity(p::WGaussian, x) = -(sqmahal(p,x) + _logdet(p, dim(p)) + dim(p)*log(2pi))/2
MeasureTheory.density(p::WGaussian, x) = exp(logpdf(p, x))

=#


text:
using CatmullRom
using Test

@testset "closed curve interpositions" begin
  xs = [sinpi(t) for t=range(0.0, length=5, stop=2.0)];
  ys = [cospi(t) for t=range(0.0, length=5, stop=2.0)];
  points = collect(zip(xs,ys));
  cr_xys = catmullrom(points, 2)
  @test length(cr_xys[1]) == length(xs) + 2*(length(xs)-1)
  @test length(points) == length(xs)
  points = close_seq!(points)
  @test points[1] == points[end]
end

#=
    example from
    Block-based Thiele-like blending rational interpolation
    Qian-Jin Zhao, Jieqing Tan
    Journal of Computational and Applied Mathematics
    https://doi.org/10.1016/j.cam.2005.03.089
=#
@testset "interpolation" begin
  xs=[0.0, 1.0, 2.0,  3.0,  4.0, 5.0]
  ys=[0.0, 1.0, 4.0, -1.0, -2.0, 2.0]
  points = collect(zip(xs,ys))
  p1,p2,p3,p4,p5,p6 = points
  @test CatmullRom.thiele4(p1,p2,p3,p4, 6.0)[1] == 2.6666666666666665 # v1.1+
  @test CatmullRom.thiele4(p2,p3,p4,p5, 1.0)[1] == 1.0                # v1.1+
  @test iszero((CatmullRom.quadratic(p3,p4,p5, 1.5) .- (8.0,))[1])
end

@testset "approximate arclengths" begin
  xs=[0.0, 1.0, 2.0,  3.0,  4.0, 5.0]
  ys=[0.0, 1.0, 4.0, -1.0, -2.0, 2.0]
  points = collect(zip(xs,ys))
  @test length(points) - 2*2 + 1 == length(CatmullRom.approx_catmullrom_arclengths(points))
end


text:
using KernelAbstractions
using CUDA

has_cuda_gpu() || exit()

@kernel function transpose_kernel_naive!(b, a)
    i, j = @index(Global, NTuple)
    @inbounds b[i, j] = a[j, i]
end

const block_dim = 32
const grid_dim = 256

const T = Float32
const N = grid_dim * block_dim
const shape = N, N
const nreps = 1

NVTX.@range "Naive transpose ($block_dim, $block_dim)" let
    a = CuArray(rand(T, shape))
    b = similar(a, shape[2], shape[1])
    kernel! = transpose_kernel_naive!(CUDADevice(), (block_dim, block_dim), size(b))

    event = kernel!(b, a)
    wait(event)
    @assert Array(b) == Array(a)'
    CUDA.@profile begin
        for rep in 1:nreps
          event = kernel!(b, a, dependencies=(event,))
        end
        wait(event)
    end
end

NVTX.@range "Naive transpose ($(block_dim^2), 1)" let
    a = CuArray(rand(T, shape))
    b = similar(a, shape[2], shape[1])
    kernel! = transpose_kernel_naive!(CUDADevice(), (block_dim*block_dim, 1), size(b))

    event = kernel!(b, a)
    wait(event)
    @assert Array(b) == Array(a)'
    CUDA.@profile begin
        for rep in 1:nreps
          event = kernel!(b, a, dependencies=(event,))
        end
        wait(event)
    end
end

NVTX.@range "Naive transpose (1, $(block_dim^2))" let
    a = CuArray(rand(T, shape))
    b = similar(a, shape[2], shape[1])
    kernel! = transpose_kernel_naive!(CUDADevice(), (1, block_dim*block_dim), size(b))

    event = kernel!(b, a)
    wait(event)
    @assert Array(b) == Array(a)'
    CUDA.@profile begin
        for rep in 1:nreps
          event = kernel!(b, a, dependencies=(event,))
        end
        wait(event)
    end
end


text:
# Code for dealing with Core level counters.
include("lowlevel.jl")
include("utils.jl")

# This is the high level API for core monitoring
mutable struct CoreMonitor{T,N,U} <: AbstractMonitor
    # Collection of CPUs for which to collect data.
    cpus::T

    # The events that we are collecting
    events::NTuple{N, CoreSelectRegister}
    fixed_events::U

    # For cleaning up after ourselves
    initial_state::CounterState
    initial_affinity::PtrWrap
    isrunning::Bool
end

"""
    CoreMonitor(events, cpus; program = true)

Construct a `CoreMonitor` monitoring `events` on `cpus`.
Arguments `events` should be a `Tuple` of [`CounterTools.CoreSelectRegister`](@ref) and
`cpus` is any iterable collection of CPU indices.

If `program == true`, then also program the performance counters to on each CPU.
"""
function CoreMonitor(
        events::NTuple{N, CoreSelectRegister},
        cpus::T;
        fixed_events = nothing,
        program = true
    ) where {T, N}

    # Make sure nothing crazy's going down!!
    if length(events) > numcounters()
        errmsg = """
        Number of Hardware Events must be less than or equal the number of programmable
        performance counters.

        On your CPU, this number is $ncounters.
        """
        throw(ArgumentError(errmsg))
    end

    # Validate the fixed events
    if fixed_events !== nothing
        if !isa(fixed_events, NTuple{U, FixedCounter} where {U})
            errmsg = """
                Keyword argument `fixed_events` must either be `nothing` or a tuple of
                `FixedCounter` enums.
            """
            throw(ArgumentError(errmsg))
        end
    else
        fixed_events = ()
    end

    # Build up the initial values list to save this for later.
    initial_state = CounterState(;cpus = cpus)
    initial_affinity = getaffinity()

    # Get the original state of the hardware performance counters.
    monitor = CoreMonitor{T,N,typeof(fixed_events)}(
        cpus,
        events,
        fixed_events,
        initial_state,
        initial_affinity,
        false
    )

    finalizer(reset!, monitor)
    program && program!(monitor)
    return monitor
end

function program(cpu, counter, reg::CoreSelectRegister)
    writemsr(cpu, EVENT_SELECT_MSRS[counter], reg)
    return nothing
end

# When programming fixed counters, we need to set the enable bits in IA32_FIXED_CTR_CTRL_MSR
program(cpu, ::Tuple{}) = nothing
function program(cpu, events::NTuple{<:Any, FixedCounter})
    v = zero(UInt)
    for event in events
        v |= UInt(0x3) << (4 * Int(event))
    end
    writemsr(cpu, IA32_FIXED_CTR_CTRL_MSR, v)
    return nothing
end

function program!(M::CoreMonitor)
    for cpu in M.cpus
        # Enable counters on this cpu
        enablecounters(cpu)

        # Program each of the events to the CPU
        for (i, event) in enumerate(M.events)
            program(cpu, i, event)
        end

        # Enable fixed counters
        program(cpu, M.fixed_events)
    end
    M.isrunning = true
    return nothing
end

function Base.read(M::CoreMonitor{T, N}) where {T, N}
    pid = getpid()
    results = map(M.cpus) do cpu
        # Set the affinity to this CPU
        setaffinity(pid, cpu)

        # Read fixed and programmable events.
        fixed = map(unsafe_rdpmc, M.fixed_events)
        programmable = ntuple(i -> unsafe_rdpmc(i), Val{N}())

        # Return all counter values.
        return Record{:cpu}((fixed..., programmable...))
    end |> Record{:cpu_set}

    # Reset the affinity.
    setaffinity(M.initial_affinity)
    return results
end

function reset!(M::CoreMonitor)
    # Set all the counters back to their original state.
    restore!(M.initial_state)
    M.isrunning = false
    return nothing
end


text:
## higher-order functions ##

Base.map(f, d::DArray) = DArray(I->map(f, localpart(d)), d)

Base.map!{F}(f::F, d::DArray) = begin
    @sync for p in procs(d)
        @async remotecall_fetch((f,d)->(map!(f, localpart(d)); nothing), p, f, d)
    end
    return d
end

# FixMe! We'll have to handle the general n args case but it seems tricky
Base.broadcast(f, d::DArray) = DArray(I -> broadcast(f, localpart(d)), d)

function Base.reduce(f, d::DArray)
    results=[]
    @sync begin
        for p in procs(d)
            @async push!(results, remotecall_fetch((f,d)->reduce(f, localpart(d)), p, f, d))
        end
    end
    reduce(f, results)
end

function _mapreduce(f, opt, d::DArray)
# TODO Change to an @async remotecall_fetch - will reduce one extra network hop -
# once bug in master is fixed.
    results=[]
    @sync begin
        for p in procs(d)
            @async push!(results, remotecall_fetch((f,opt,d)->mapreduce(f, opt, localpart(d)), p, f, opt, d))
        end
    end
    reduce(opt, results)
end
Base.mapreduce(f, opt::Union{typeof(|), typeof(&)}, d::DArray) = _mapreduce(f, opt, d)
Base.mapreduce(f, opt::Function, d::DArray) = _mapreduce(f, opt, d)
Base.mapreduce(f, opt, d::DArray) = _mapreduce(f, opt, d)

# mapreducedim
Base.reducedim_initarray{R}(A::DArray, region, v0, ::Type{R}) = begin
    # Store reduction on lowest pids
    pids = A.pids[ntuple(i -> i in region ? (1:1) : (:), ndims(A))...]
    chunks = similar(pids, Future)
    @sync for i in eachindex(pids)
        @async chunks[i...] = remotecall_wait(() -> Base.reducedim_initarray(localpart(A), region, v0, R), pids[i...])
    end
    return DArray(chunks)
end
Base.reducedim_initarray{T}(A::DArray, region, v0::T) = Base.reducedim_initarray(A, region, v0, T)

Base.reducedim_initarray0{R}(A::DArray, region, v0, ::Type{R}) = begin
    # Store reduction on lowest pids
    pids = A.pids[ntuple(i -> i in region ? (1:1) : (:), ndims(A))...]
    chunks = similar(pids, Future)
    @sync for i in eachindex(pids)
        @async chunks[i...] = remotecall_wait(() -> Base.reducedim_initarray0(localpart(A), region, v0, R), pids[i...])
    end
    return DArray(chunks)
end
Base.reducedim_initarray0{T}(A::DArray, region, v0::T) = Base.reducedim_initarray0(A, region, v0, T)

# Compute mapreducedim of each localpart and store the result in a new DArray
mapreducedim_within(f, op, A::DArray, region) = begin
    arraysize = [size(A)...]
    gridsize = [size(A.indexes)...]
    arraysize[[region...]] = gridsize[[region...]]
    indx = similar(A.indexes)
    for i in CartesianRange(size(indx))
        indx[i] = ntuple(j -> j in region ? (i.I[j]:i.I[j]) : A.indexes[i][j], ndims(A))
    end
    cuts = [i in region ? collect(1:arraysize[i] + 1) : A.cuts[i] for i in 1:ndims(A)]
    return DArray(next_did(), I -> mapreducedim(f, op, localpart(A), region),
        tuple(arraysize...), procs(A), indx, cuts)
end

# Compute mapreducedim accros the processes. This should be done after mapreducedim
# has been run on each localpart with mapreducedim_within. Eventually, we might
# want to write mapreducedim_between! as a binary reduction.
function mapreducedim_between!(f, op, R::DArray, A::DArray, region)
    @sync for p in procs(R)
        @async remotecall_fetch(p, f, op, R, A, region) do f, op, R, A, region
            localind = [r for r = localindexes(A)]
            localind[[region...]] = [1:n for n = size(A)[[region...]]]
            B = convert(Array, A[localind...])
            Base.mapreducedim!(f, op, localpart(R), B)
            nothing
        end
    end
    return R
end

Base.mapreducedim!(f, op, R::DArray, A::DArray) = begin
    lsize = Base.check_reducedims(R,A)
    if isempty(A)
        return copy(R)
    end
    region = tuple(collect(1:ndims(A))[[size(R)...] .!= [size(A)...]]...)
    if isempty(region)
        return copy!(R, A)
    end
    B = mapreducedim_within(f, op, A, region)
    return mapreducedim_between!(identity, op, R, B, region)
end

Base.mapreducedim(f, op, R::DArray, A::DArray) = begin
    Base.mapreducedim!(f, op, Base.reducedim_initarray(A, region, v0), A)
end

function nnz(A::DArray)
    B = Array(Any, size(A.pids))
    @sync begin
        for i in eachindex(A.pids)
            @async B[i...] = remotecall_fetch(x -> nnz(localpart(x)), A.pids[i...], A)
        end
    end
    return reduce(+, B)
end

# reduce like
for (fn, fr) in ((:sum, :+),
                 (:prod, :*),
                 (:maximum, :max),
                 (:minimum, :min),
                 (:any, :|),
                 (:all, :&))
    @eval (Base.$fn)(d::DArray) = reduce($fr, d)
end

# mapreduce like
for (fn, fr1, fr2) in ((:maxabs, :abs, :max),
                       (:minabs, :abs, :min),
                       (:sumabs, :abs, :+),
                       (:sumabs2, :abs2, :+))
    @eval (Base.$fn)(d::DArray) = mapreduce($fr1, $fr2, d)
end

# semi mapreduce
for (fn, fr) in ((:any, :|),
                 (:all, :&),
                 (:count, :+))
    @eval begin
        (Base.$fn)(f::typeof(identity), d::DArray) = mapreduce(f, $fr, d)
        (Base.$fn)(f::Base.Predicate{1}, d::DArray) = mapreduce(f, $fr, d)
        (Base.$fn)(f::Callable, d::DArray) = mapreduce(f, $fr, d)
    end
end

# Unary vector functions
(-)(D::DArray) = map(-, D)

# scalar ops
(+)(A::DArray{Bool}, x::Bool) = A .+ x
(+)(x::Bool, A::DArray{Bool}) = x .+ A
(-)(A::DArray{Bool}, x::Bool) = A .- x
(-)(x::Bool, A::DArray{Bool}) = x .- A
(+)(A::DArray, x::Number) = A .+ x
(+)(x::Number, A::DArray) = x .+ A
(-)(A::DArray, x::Number) = A .- x
(-)(x::Number, A::DArray) = x .- A

map_localparts(f::Callable, d::DArray) = DArray(i->f(localpart(d)), d)
map_localparts(f::Callable, d1::DArray, d2::DArray) = DArray(d1) do I
    f(localpart(d1), localpart(d2))
end

function map_localparts(f::Callable, DA::DArray, A::Array)
    s = verified_destination_serializer(procs(DA), size(DA.indexes)) do pididx
        A[DA.indexes[pididx]...]
    end
    DArray(DA) do I
        f(localpart(DA), localpart(s))
    end
end

function map_localparts(f::Callable, A::Array, DA::DArray)
    s = verified_destination_serializer(procs(DA), size(DA.indexes)) do pididx
        A[DA.indexes[pididx]...]
    end
    DArray(DA) do I
        f(localpart(s), localpart(DA))
    end
end

function map_localparts!(f::Callable, d::DArray)
    @sync for p in procs(d)
        @async remotecall_fetch((f,d)->(f(localpart(d)); nothing), p, f, d)
    end
    return d
end

# Here we assume all the DArrays have
# the same size and distribution
map_localparts(f::Callable, As::DArray...) = DArray(I->f(map(localpart, As)...), As[1])

for f in (:.+, :.-, :.*, :./, :.%, :.<<, :.>>, :div, :mod, :rem, :&, :|, :$)
    @eval begin
        ($f){T}(A::DArray{T}, B::Number) = map_localparts(r->($f)(r, B), A)
        ($f){T}(A::Number, B::DArray{T}) = map_localparts(r->($f)(A, r), B)
    end
end

function samedist(A::DArray, B::DArray)
    (size(A) == size(B)) || throw(DimensionMismatch())
    if (procs(A) != procs(B)) || (A.cuts != B.cuts)
        B = DArray(x->B[x...], A)
    end
    B
end

for f in (:+, :-, :div, :mod, :rem, :&, :|, :$)
    @eval begin
        function ($f){T}(A::DArray{T}, B::DArray{T})
            B = samedist(A, B)
            map_localparts($f, A, B)
        end
        ($f){T}(A::DArray{T}, B::Array{T}) = map_localparts($f, A, B)
        ($f){T}(A::Array{T}, B::DArray{T}) = map_localparts($f, A, B)
    end
end
for f in (:.+, :.-, :.*, :./, :.%, :.<<, :.>>)
    @eval begin
        function ($f){T}(A::DArray{T}, B::DArray{T})
            map_localparts($f, A, B)
        end
        ($f){T}(A::DArray{T}, B::Array{T}) = map_localparts($f, A, B)
        ($f){T}(A::Array{T}, B::DArray{T}) = map_localparts($f, A, B)
    end
end

function mapslices{T,N,A}(f::Function, D::DArray{T,N,A}, dims::AbstractVector)
    if !all(t -> t == 1, size(D.indexes)[dims])
        p = ones(Int, ndims(D))
        nondims = filter(t -> !(t in dims), 1:ndims(D))
        p[nondims] = defaultdist([size(D)...][[nondims...]], procs(D))
        DD = DArray(size(D), procs(D), p) do I
            return convert(A, D[I...])
        end
        return mapslices(f, DD, dims)
    end

    refs = Future[remotecall((x,y,z)->mapslices(x,localpart(y),z), p, f, D, dims) for p in procs(D)]

    DArray(reshape(refs, size(procs(D))))
end

function _ppeval(f, A...; dim = map(ndims, A))
    if length(dim) != length(A)
        throw(ArgumentError("dim argument has wrong length. length(dim) = $(length(dim)) but should be $(length(A))"))
    end
    narg = length(A)
    dimlength = size(A[1], dim[1])
    for i = 2:narg
        if dim[i] > 0 && dimlength != size(A[i], dim[i])
            throw(ArgumentError("lengths of broadcast dimensions must be the same. size(A[1], $(dim[1])) = $dimlength but size(A[$i], $(dim[i])) = $(size(A[i], dim[i]))"))
        end
    end
    dims = []
    idx  = []
    args = []
    for i = 1:narg
        push!(dims, ndims(A[i]))
        push!(idx, Any[1:size(A[i], d) for d in 1:dims[i]])
        if dim[i] > 0
            idx[i][dim[i]] = 1
            push!(args, view(A[i], idx[i]...))
        else
            push!(args, A[i])
        end
    end
    R1 = f(args...)
    ridx = Any[1:size(R1, d) for d in 1:ndims(R1)]
    push!(ridx, 1)
    Rsize = map(last, ridx)
    Rsize[end] = dimlength
    R = Array(eltype(R1), Rsize...)

    for i = 1:dimlength
        for j = 1:narg
            if dim[j] > 0
                idx[j][dim[j]] = i
                args[j] = view(A[j], idx[j]...)
            else
                args[j] = A[j]
            end
        end
        ridx[end] = i
        R[ridx...] = f(args...)
    end

    return R
end

"""
     ppeval(f, D...; dim::NTuple)

Evaluates the callable argument `f` on slices of the elements of the `D` tuple.

#### Arguments
`f` can be any callable object that accepts sliced or broadcasted elements of `D`.
The result returned from `f` must be either an array or a scalar.

`D` has any number of elements and the alements can have any type. If an element
of `D` is a distributed array along the dimension specified by `dim`. If an
element of `D` is not distributed, the element is by default broadcasted and
applied on all evaluations of `f`.

`dim` is a tuple of integers specifying the dimension over which the elements
of `D` is slices. The length of the tuple must therefore be the same as the
number of arguments `D`. By default distributed arrays are slides along the
last dimension. If the value is less than or equal to zero the element are
broadcasted to all evaluations of `f`.

#### Result
`ppeval` returns a distributed array of dimension `p+1` where the first `p`
sizes correspond to the sizes of return values of `f`. The last dimention of
the return array from `ppeval` has the same length as the dimension over which
the input arrays are sliced.

#### Examples
```jl
addprocs(JULIA_CPU_CORES)

using DistributedArrays

A = drandn((10, 10, JULIA_CPU_CORES), workers(), [1, 1, JULIA_CPU_CORES])

ppeval(eigvals, A)

ppeval(eigvals, A, randn(10,10)) # broadcasting second argument

B = drandn((10, JULIA_CPU_CORES), workers(), [1, JULIA_CPU_CORES])

ppeval(*, A, B)
```
"""
function ppeval(f, D...; dim::NTuple = map(t -> isa(t, DArray) ? ndims(t) : 0, D))
    #Ensure that the complete DArray is available on the specified dims on all processors
    for i = 1:length(D)
        if isa(D[i], DArray)
            for idxs in D[i].indexes
                for d in setdiff(1:ndims(D[i]), dim[i])
                    if length(idxs[d]) != size(D[i], d)
                        throw(DimensionMismatch(string("dimension $d is distributed. ",
                            "ppeval requires dimension $d to be completely available on all processors.")))
                    end
                end
            end
        end
    end

    refs = Future[remotecall((x, y, z) -> _ppeval(x, map(localpart, y)...; dim = z), p, f, D, dim) for p in procs(D[1])]

    # The array of Futures has to be reshaped for the DArray constructor to work correctly.
    # This requires a fetch and the DArray is also fetching so it might be better to modify
    # the DArray constructor.
    sd = [size(D[1].pids)...]
    nd = remotecall_fetch((r)->ndims(fetch(r)), refs[1].where, refs[1])
    DArray(reshape(refs, tuple([sd[1:nd - 1], sd[end];]...)))
end


text:
function causality(source::Vector{<:UVT1}, target::Vector{<:UVT2}, test::CT) where {
        UVT1<:AbstractUncertainValue,
        UVT2<:AbstractUncertainValue,
        CT<:CausalityTest}
    causality(resample.(source), resample.(target), test)
end

function causality(source, target::Vector{<:UVT}, test::CT) where {
        UVT<:AbstractUncertainValue,
        CT<:CausalityTest}
    causality(source, resample.(target), test)
end

function causality(source::Vector{<:UVT}, target, test::CT) where {
        UVT<:AbstractUncertainValue,
        CT<:CausalityTest}
    causality(resample.(source), target, test)
end

function causality(source::UVT1, target::UVT2, test::CT) where {
        UVT1<:AbstractUncertainValueDataset,
        UVT2<:AbstractUncertainValueDataset,
        CT<:CausalityTest}
    causality(resample.(source), resample.(target), test)
end

function causality(source, target::UVT, test::CT) where {
        UVT<:AbstractUncertainValueDataset,
        CT<:CausalityTest}
    causality(source, resample.(target), test)
end

function causality(source::UVT, target, test::CT) where {
        UVT<:AbstractUncertainValueDataset,
        CT<:CausalityTest}
    causality(resample.(source), target, test)
end


text:
using Images
using ImageView
using FileIO
using Interpolations
using Caesar
using RoME
using RoME: MeanMaxPPE
using ProgressMeter
using ImageView
using Statistics

using TensorCast
using UnicodePlots
# using Gadfly
# Gadfly.set_default_plot_size(35cm, 25cm)

using TensorCast

##

prjPath = dirname(dirname(pathof(Caesar)))
include( joinpath(prjPath, "examples","dev","scalar","CommonUtils.jl") )
using .CommonUtils

##

x, y, dem = buildDEMSimulated(1, 100, x_is_north=true)

imshow(dem)

##

# z_elevation = 0.5,      # actual measurement
# sigma_elevation = 0.001 # measurement uncertainty
hmd = LevelSetGridNormal(dem, (x,y), 0.5, 0.001)

# pr = Mixture(PriorPoint2, [hmd; MvNormal([0;0], [....])], [0.5;0.5])
# addFactor!(fg, [:x17;], pr)

##

M = TranslationGroup(2)
pts_ = [sampleTangent(M, hmd) for _ in 1:10000]

# pseudo code
# getSample(hmd, 100, hint_belief)

##

@cast pts[i,j] := pts_[j][i]

imscatter(img) = scatterplot(img[2,:], -img[1,:])
imdensity(img) = densityplot(img[2,:], -img[1,:])
imscatter(pts)
imdensity(pts)