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

"""
    create_assistant(name, type)
    create_assistant(name, type, params::Dict{String,<:Any})

Creates an Amazon Connect Wisdom assistant.

# Arguments
- `name`: The name of the assistant.
- `type`: The type of assistant.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"clientToken"`: A unique, case-sensitive identifier that you provide to ensure the
  idempotency of the request.
- `"description"`: The description of the assistant.
- `"serverSideEncryptionConfiguration"`: The KMS key used for encryption.
- `"tags"`: The tags used to organize, track, or control access for this resource.
"""
function create_assistant(name, type; aws_config::AbstractAWSConfig=global_aws_config())
    return wisdom(
        "POST",
        "/assistants",
        Dict{String,Any}("name" => name, "type" => type, "clientToken" => string(uuid4()));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_assistant(
    name,
    type,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/assistants",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "name" => name, "type" => type, "clientToken" => string(uuid4())
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_assistant_association(assistant_id, association, association_type)
    create_assistant_association(assistant_id, association, association_type, params::Dict{String,<:Any})

Creates an association between an Amazon Connect Wisdom assistant and another resource.
Currently, the only supported association is with a knowledge base. An assistant can have
only a single association.

# Arguments
- `assistant_id`: The identifier of the Wisdom assistant. Can be either the ID or the ARN.
  URLs cannot contain the ARN.
- `association`: The identifier of the associated resource.
- `association_type`: The type of association.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"clientToken"`: A unique, case-sensitive identifier that you provide to ensure the
  idempotency of the request.
- `"tags"`: The tags used to organize, track, or control access for this resource.
"""
function create_assistant_association(
    assistantId,
    association,
    associationType;
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/assistants/$(assistantId)/associations",
        Dict{String,Any}(
            "association" => association,
            "associationType" => associationType,
            "clientToken" => string(uuid4()),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_assistant_association(
    assistantId,
    association,
    associationType,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/assistants/$(assistantId)/associations",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "association" => association,
                    "associationType" => associationType,
                    "clientToken" => string(uuid4()),
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_content(knowledge_base_id, name, upload_id)
    create_content(knowledge_base_id, name, upload_id, params::Dict{String,<:Any})

Creates Wisdom content. Before to calling this API, use StartContentUpload to upload an
asset.

# Arguments
- `knowledge_base_id`: The the identifier of the knowledge base. Can be either the ID or
  the ARN. URLs cannot contain the ARN.
- `name`: The name of the content. Each piece of content in a knowledge base must have a
  unique name. You can retrieve a piece of content using only its knowledge base and its name
  with the SearchContent API.
- `upload_id`: A pointer to the uploaded asset. This value is returned by
  StartContentUpload.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"clientToken"`: A unique, case-sensitive identifier that you provide to ensure the
  idempotency of the request.
- `"metadata"`: A key/value map to store attributes without affecting tagging or
  recommendations. For example, when synchronizing data between an external system and
  Wisdom, you can store an external version identifier as metadata to utilize for determining
  drift.
- `"overrideLinkOutUri"`: The URI you want to use for the article. If the knowledge base
  has a templateUri, setting this argument overrides it for this piece of content.
- `"tags"`: The tags used to organize, track, or control access for this resource.
- `"title"`: The title of the content. If not set, the title is equal to the name.
"""
function create_content(
    knowledgeBaseId, name, uploadId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "POST",
        "/knowledgeBases/$(knowledgeBaseId)/contents",
        Dict{String,Any}(
            "name" => name, "uploadId" => uploadId, "clientToken" => string(uuid4())
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_content(
    knowledgeBaseId,
    name,
    uploadId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/knowledgeBases/$(knowledgeBaseId)/contents",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "name" => name, "uploadId" => uploadId, "clientToken" => string(uuid4())
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_knowledge_base(knowledge_base_type, name)
    create_knowledge_base(knowledge_base_type, name, params::Dict{String,<:Any})

Creates a knowledge base.  When using this API, you cannot reuse Amazon AppIntegrations
DataIntegrations with external knowledge bases such as Salesforce and ServiceNow. If you
do, you'll get an InvalidRequestException error.
For example, you're
programmatically managing your external knowledge base, and you want to add or remove one
of the fields that is being ingested from Salesforce. Do the following:

Call DeleteKnowledgeBase.

Call
DeleteDataIntegration.

Call CreateDataIntegration to recreate the DataIntegration or a
create different one.

Call
CreateKnowledgeBase.

 </note>

# Arguments
- `knowledge_base_type`: The type of knowledge base. Only CUSTOM knowledge bases allow you
  to upload your own content. EXTERNAL knowledge bases support integrations with third-party
  systems whose content is synchronized automatically.
- `name`: The name of the knowledge base.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"clientToken"`: A unique, case-sensitive identifier that you provide to ensure the
  idempotency of the request.
- `"description"`: The description.
- `"renderingConfiguration"`: Information about how to render the content.
- `"serverSideEncryptionConfiguration"`: The KMS key used for encryption.
- `"sourceConfiguration"`: The source of the knowledge base content. Only set this argument
  for EXTERNAL knowledge bases.
- `"tags"`: The tags used to organize, track, or control access for this resource.
"""
function create_knowledge_base(
    knowledgeBaseType, name; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "POST",
        "/knowledgeBases",
        Dict{String,Any}(
            "knowledgeBaseType" => knowledgeBaseType,
            "name" => name,
            "clientToken" => string(uuid4()),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_knowledge_base(
    knowledgeBaseType,
    name,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/knowledgeBases",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "knowledgeBaseType" => knowledgeBaseType,
                    "name" => name,
                    "clientToken" => string(uuid4()),
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_session(assistant_id, name)
    create_session(assistant_id, name, params::Dict{String,<:Any})

Creates a session. A session is a contextual container used for generating recommendations.
Amazon Connect creates a new Wisdom session for each contact on which Wisdom is enabled.

# Arguments
- `assistant_id`: The identifier of the Wisdom assistant. Can be either the ID or the ARN.
  URLs cannot contain the ARN.
- `name`: The name of the session.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"clientToken"`: A unique, case-sensitive identifier that you provide to ensure the
  idempotency of the request.
- `"description"`: The description.
- `"tags"`: The tags used to organize, track, or control access for this resource.
"""
function create_session(
    assistantId, name; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "POST",
        "/assistants/$(assistantId)/sessions",
        Dict{String,Any}("name" => name, "clientToken" => string(uuid4()));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_session(
    assistantId,
    name,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/assistants/$(assistantId)/sessions",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("name" => name, "clientToken" => string(uuid4())),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deletes an assistant.

# Arguments
- `assistant_id`: The identifier of the Wisdom assistant. Can be either the ID or the ARN.
  URLs cannot contain the ARN.

"""
function delete_assistant(assistantId; aws_config::AbstractAWSConfig=global_aws_config())
    return wisdom(
        "DELETE",
        "/assistants/$(assistantId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_assistant(
    assistantId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "DELETE",
        "/assistants/$(assistantId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_assistant_association(assistant_association_id, assistant_id)
    delete_assistant_association(assistant_association_id, assistant_id, params::Dict{String,<:Any})

Deletes an assistant association.

# Arguments
- `assistant_association_id`: The identifier of the assistant association. Can be either
  the ID or the ARN. URLs cannot contain the ARN.
- `assistant_id`: The identifier of the Wisdom assistant. Can be either the ID or the ARN.
  URLs cannot contain the ARN.

"""
function delete_assistant_association(
    assistantAssociationId, assistantId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "DELETE",
        "/assistants/$(assistantId)/associations/$(assistantAssociationId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_assistant_association(
    assistantAssociationId,
    assistantId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "DELETE",
        "/assistants/$(assistantId)/associations/$(assistantAssociationId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_content(content_id, knowledge_base_id)
    delete_content(content_id, knowledge_base_id, params::Dict{String,<:Any})

Deletes the content.

# Arguments
- `content_id`: The identifier of the content. Can be either the ID or the ARN. URLs cannot
  contain the ARN.
- `knowledge_base_id`: The the identifier of the knowledge base. Can be either the ID or
  the ARN. URLs cannot contain the ARN.

"""
function delete_content(
    contentId, knowledgeBaseId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "DELETE",
        "/knowledgeBases/$(knowledgeBaseId)/contents/$(contentId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_content(
    contentId,
    knowledgeBaseId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "DELETE",
        "/knowledgeBases/$(knowledgeBaseId)/contents/$(contentId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deletes the knowledge base.  When you use this API to delete an external knowledge base
such as Salesforce or ServiceNow, you must also delete the Amazon AppIntegrations
DataIntegration. This is because you can't reuse the DataIntegration after it's been
associated with an external knowledge base. However, you can delete and recreate it. See
DeleteDataIntegration and CreateDataIntegration in the Amazon AppIntegrations API
Reference.

# Arguments
- `knowledge_base_id`: The knowledge base to delete content from. Can be either the ID or
  the ARN. URLs cannot contain the ARN.

"""
function delete_knowledge_base(
    knowledgeBaseId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "DELETE",
        "/knowledgeBases/$(knowledgeBaseId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_knowledge_base(
    knowledgeBaseId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "DELETE",
        "/knowledgeBases/$(knowledgeBaseId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves information about an assistant.

# Arguments
- `assistant_id`: The identifier of the Wisdom assistant. Can be either the ID or the ARN.
  URLs cannot contain the ARN.

"""
function get_assistant(assistantId; aws_config::AbstractAWSConfig=global_aws_config())
    return wisdom(
        "GET",
        "/assistants/$(assistantId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_assistant(
    assistantId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "GET",
        "/assistants/$(assistantId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    get_assistant_association(assistant_association_id, assistant_id)
    get_assistant_association(assistant_association_id, assistant_id, params::Dict{String,<:Any})

Retrieves information about an assistant association.

# Arguments
- `assistant_association_id`: The identifier of the assistant association. Can be either
  the ID or the ARN. URLs cannot contain the ARN.
- `assistant_id`: The identifier of the Wisdom assistant. Can be either the ID or the ARN.
  URLs cannot contain the ARN.

"""
function get_assistant_association(
    assistantAssociationId, assistantId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "GET",
        "/assistants/$(assistantId)/associations/$(assistantAssociationId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_assistant_association(
    assistantAssociationId,
    assistantId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "GET",
        "/assistants/$(assistantId)/associations/$(assistantAssociationId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    get_content(content_id, knowledge_base_id)
    get_content(content_id, knowledge_base_id, params::Dict{String,<:Any})

Retrieves content, including a pre-signed URL to download the content.

# Arguments
- `content_id`: The identifier of the content. Can be either the ID or the ARN. URLs cannot
  contain the ARN.
- `knowledge_base_id`: The the identifier of the knowledge base. Can be either the ID or
  the ARN. URLs cannot contain the ARN.

"""
function get_content(
    contentId, knowledgeBaseId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "GET",
        "/knowledgeBases/$(knowledgeBaseId)/contents/$(contentId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_content(
    contentId,
    knowledgeBaseId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "GET",
        "/knowledgeBases/$(knowledgeBaseId)/contents/$(contentId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    get_content_summary(content_id, knowledge_base_id)
    get_content_summary(content_id, knowledge_base_id, params::Dict{String,<:Any})

Retrieves summary information about the content.

# Arguments
- `content_id`: The identifier of the content. Can be either the ID or the ARN. URLs cannot
  contain the ARN.
- `knowledge_base_id`: The the identifier of the knowledge base. Can be either the ID or
  the ARN. URLs cannot contain the ARN.

"""
function get_content_summary(
    contentId, knowledgeBaseId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "GET",
        "/knowledgeBases/$(knowledgeBaseId)/contents/$(contentId)/summary";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_content_summary(
    contentId,
    knowledgeBaseId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "GET",
        "/knowledgeBases/$(knowledgeBaseId)/contents/$(contentId)/summary",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves information about the knowledge base.

# Arguments
- `knowledge_base_id`: The the identifier of the knowledge base. Can be either the ID or
  the ARN. URLs cannot contain the ARN.

"""
function get_knowledge_base(
    knowledgeBaseId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "GET",
        "/knowledgeBases/$(knowledgeBaseId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_knowledge_base(
    knowledgeBaseId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "GET",
        "/knowledgeBases/$(knowledgeBaseId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    get_recommendations(assistant_id, session_id)
    get_recommendations(assistant_id, session_id, params::Dict{String,<:Any})

Retrieves recommendations for the specified session. To avoid retrieving the same
recommendations in subsequent calls, use NotifyRecommendationsReceived. This API supports
long-polling behavior with the waitTimeSeconds parameter. Short poll is the default
behavior and only returns recommendations already available. To perform a manual query
against an assistant, use QueryAssistant.

# Arguments
- `assistant_id`: The identifier of the Wisdom assistant. Can be either the ID or the ARN.
  URLs cannot contain the ARN.
- `session_id`: The identifier of the session. Can be either the ID or the ARN. URLs cannot
  contain the ARN.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results to return per page.
- `"waitTimeSeconds"`: The duration (in seconds) for which the call waits for a
  recommendation to be made available before returning. If a recommendation is available, the
  call returns sooner than WaitTimeSeconds. If no messages are available and the wait time
  expires, the call returns successfully with an empty list.
"""
function get_recommendations(
    assistantId, sessionId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "GET",
        "/assistants/$(assistantId)/sessions/$(sessionId)/recommendations";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_recommendations(
    assistantId,
    sessionId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "GET",
        "/assistants/$(assistantId)/sessions/$(sessionId)/recommendations",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    get_session(assistant_id, session_id)
    get_session(assistant_id, session_id, params::Dict{String,<:Any})

Retrieves information for a specified session.

# Arguments
- `assistant_id`: The identifier of the Wisdom assistant. Can be either the ID or the ARN.
  URLs cannot contain the ARN.
- `session_id`: The identifier of the session. Can be either the ID or the ARN. URLs cannot
  contain the ARN.

"""
function get_session(
    assistantId, sessionId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "GET",
        "/assistants/$(assistantId)/sessions/$(sessionId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_session(
    assistantId,
    sessionId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "GET",
        "/assistants/$(assistantId)/sessions/$(sessionId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Lists information about assistant associations.

# Arguments
- `assistant_id`: The identifier of the Wisdom assistant. Can be either the ID or the ARN.
  URLs cannot contain the ARN.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results to return per page.
- `"nextToken"`: The token for the next set of results. Use the value returned in the
  previous response in the next request to retrieve the next set of results.
"""
function list_assistant_associations(
    assistantId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "GET",
        "/assistants/$(assistantId)/associations";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_assistant_associations(
    assistantId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "GET",
        "/assistants/$(assistantId)/associations",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Lists information about assistants.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results to return per page.
- `"nextToken"`: The token for the next set of results. Use the value returned in the
  previous response in the next request to retrieve the next set of results.
"""
function list_assistants(; aws_config::AbstractAWSConfig=global_aws_config())
    return wisdom(
        "GET", "/assistants"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_assistants(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "GET", "/assistants", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

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

Lists the content.

# Arguments
- `knowledge_base_id`: The the identifier of the knowledge base. Can be either the ID or
  the ARN. URLs cannot contain the ARN.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results to return per page.
- `"nextToken"`: The token for the next set of results. Use the value returned in the
  previous response in the next request to retrieve the next set of results.
"""
function list_contents(knowledgeBaseId; aws_config::AbstractAWSConfig=global_aws_config())
    return wisdom(
        "GET",
        "/knowledgeBases/$(knowledgeBaseId)/contents";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_contents(
    knowledgeBaseId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "GET",
        "/knowledgeBases/$(knowledgeBaseId)/contents",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Lists the knowledge bases.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results to return per page.
- `"nextToken"`: The token for the next set of results. Use the value returned in the
  previous response in the next request to retrieve the next set of results.
"""
function list_knowledge_bases(; aws_config::AbstractAWSConfig=global_aws_config())
    return wisdom(
        "GET", "/knowledgeBases"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_knowledge_bases(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "GET",
        "/knowledgeBases",
        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})

Lists the tags for the specified resource.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the resource.

"""
function list_tags_for_resource(
    resourceArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "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 wisdom(
        "GET",
        "/tags/$(resourceArn)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    notify_recommendations_received(assistant_id, recommendation_ids, session_id)
    notify_recommendations_received(assistant_id, recommendation_ids, session_id, params::Dict{String,<:Any})

Removes the specified recommendations from the specified assistant's queue of newly
available recommendations. You can use this API in conjunction with GetRecommendations and
a waitTimeSeconds input for long-polling behavior and avoiding duplicate recommendations.

# Arguments
- `assistant_id`: The identifier of the Wisdom assistant. Can be either the ID or the ARN.
  URLs cannot contain the ARN.
- `recommendation_ids`: The identifiers of the recommendations.
- `session_id`: The identifier of the session. Can be either the ID or the ARN. URLs cannot
  contain the ARN.

"""
function notify_recommendations_received(
    assistantId,
    recommendationIds,
    sessionId;
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/assistants/$(assistantId)/sessions/$(sessionId)/recommendations/notify",
        Dict{String,Any}("recommendationIds" => recommendationIds);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function notify_recommendations_received(
    assistantId,
    recommendationIds,
    sessionId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/assistants/$(assistantId)/sessions/$(sessionId)/recommendations/notify",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("recommendationIds" => recommendationIds), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    query_assistant(assistant_id, query_text)
    query_assistant(assistant_id, query_text, params::Dict{String,<:Any})

Performs a manual search against the specified assistant. To retrieve recommendations for
an assistant, use GetRecommendations.

# Arguments
- `assistant_id`: The identifier of the Wisdom assistant. Can be either the ID or the ARN.
  URLs cannot contain the ARN.
- `query_text`: The text to search for.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results to return per page.
- `"nextToken"`: The token for the next set of results. Use the value returned in the
  previous response in the next request to retrieve the next set of results.
"""
function query_assistant(
    assistantId, queryText; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "POST",
        "/assistants/$(assistantId)/query",
        Dict{String,Any}("queryText" => queryText);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function query_assistant(
    assistantId,
    queryText,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/assistants/$(assistantId)/query",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("queryText" => queryText), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Removes a URI template from a knowledge base.

# Arguments
- `knowledge_base_id`: The the identifier of the knowledge base. Can be either the ID or
  the ARN. URLs cannot contain the ARN.

"""
function remove_knowledge_base_template_uri(
    knowledgeBaseId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "DELETE",
        "/knowledgeBases/$(knowledgeBaseId)/templateUri";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function remove_knowledge_base_template_uri(
    knowledgeBaseId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "DELETE",
        "/knowledgeBases/$(knowledgeBaseId)/templateUri",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    search_content(knowledge_base_id, search_expression)
    search_content(knowledge_base_id, search_expression, params::Dict{String,<:Any})

Searches for content in a specified knowledge base. Can be used to get a specific content
resource by its name.

# Arguments
- `knowledge_base_id`: The the identifier of the knowledge base. Can be either the ID or
  the ARN. URLs cannot contain the ARN.
- `search_expression`: The search expression to filter results.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results to return per page.
- `"nextToken"`: The token for the next set of results. Use the value returned in the
  previous response in the next request to retrieve the next set of results.
"""
function search_content(
    knowledgeBaseId, searchExpression; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "POST",
        "/knowledgeBases/$(knowledgeBaseId)/search",
        Dict{String,Any}("searchExpression" => searchExpression);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function search_content(
    knowledgeBaseId,
    searchExpression,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/knowledgeBases/$(knowledgeBaseId)/search",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("searchExpression" => searchExpression), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    search_sessions(assistant_id, search_expression)
    search_sessions(assistant_id, search_expression, params::Dict{String,<:Any})

Searches for sessions.

# Arguments
- `assistant_id`: The identifier of the Wisdom assistant. Can be either the ID or the ARN.
  URLs cannot contain the ARN.
- `search_expression`: The search expression to filter results.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results to return per page.
- `"nextToken"`: The token for the next set of results. Use the value returned in the
  previous response in the next request to retrieve the next set of results.
"""
function search_sessions(
    assistantId, searchExpression; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "POST",
        "/assistants/$(assistantId)/searchSessions",
        Dict{String,Any}("searchExpression" => searchExpression);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function search_sessions(
    assistantId,
    searchExpression,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/assistants/$(assistantId)/searchSessions",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("searchExpression" => searchExpression), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    start_content_upload(content_type, knowledge_base_id)
    start_content_upload(content_type, knowledge_base_id, params::Dict{String,<:Any})

Get a URL to upload content to a knowledge base. To upload content, first make a PUT
request to the returned URL with your file, making sure to include the required headers.
Then use CreateContent to finalize the content creation process or UpdateContent to modify
an existing resource. You can only upload content to a knowledge base of type CUSTOM.

# Arguments
- `content_type`: The type of content to upload.
- `knowledge_base_id`: The the identifier of the knowledge base. Can be either the ID or
  the ARN. URLs cannot contain the ARN.

"""
function start_content_upload(
    contentType, knowledgeBaseId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "POST",
        "/knowledgeBases/$(knowledgeBaseId)/upload",
        Dict{String,Any}("contentType" => contentType);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function start_content_upload(
    contentType,
    knowledgeBaseId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/knowledgeBases/$(knowledgeBaseId)/upload",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("contentType" => contentType), 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 the specified tags to the specified resource.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the resource.
- `tags`: The tags used to organize, track, or control access for this resource.

"""
function tag_resource(resourceArn, tags; aws_config::AbstractAWSConfig=global_aws_config())
    return wisdom(
        "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 wisdom(
        "POST",
        "/tags/$(resourceArn)",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("tags" => tags), 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 the specified tags from the specified resource.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the resource.
- `tag_keys`: The tag keys.

"""
function untag_resource(
    resourceArn, tagKeys; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "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 wisdom(
        "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_content(content_id, knowledge_base_id)
    update_content(content_id, knowledge_base_id, params::Dict{String,<:Any})

Updates information about the content.

# Arguments
- `content_id`: The identifier of the content. Can be either the ID or the ARN. URLs cannot
  contain the ARN.
- `knowledge_base_id`: The the identifier of the knowledge base. Can be either the ID or
  the ARN

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"metadata"`: A key/value map to store attributes without affecting tagging or
  recommendations. For example, when synchronizing data between an external system and
  Wisdom, you can store an external version identifier as metadata to utilize for determining
  drift.
- `"overrideLinkOutUri"`: The URI for the article. If the knowledge base has a templateUri,
  setting this argument overrides it for this piece of content. To remove an existing
  overrideLinkOurUri, exclude this argument and set removeOverrideLinkOutUri to true.
- `"removeOverrideLinkOutUri"`: Unset the existing overrideLinkOutUri if it exists.
- `"revisionId"`: The revisionId of the content resource to update, taken from an earlier
  call to GetContent, GetContentSummary, SearchContent, or ListContents. If included, this
  argument acts as an optimistic lock to ensure content was not modified since it was last
  read. If it has been modified, this API throws a PreconditionFailedException.
- `"title"`: The title of the content.
- `"uploadId"`: A pointer to the uploaded asset. This value is returned by
  StartContentUpload.
"""
function update_content(
    contentId, knowledgeBaseId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "POST",
        "/knowledgeBases/$(knowledgeBaseId)/contents/$(contentId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_content(
    contentId,
    knowledgeBaseId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/knowledgeBases/$(knowledgeBaseId)/contents/$(contentId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    update_knowledge_base_template_uri(knowledge_base_id, template_uri)
    update_knowledge_base_template_uri(knowledge_base_id, template_uri, params::Dict{String,<:Any})

Updates the template URI of a knowledge base. This is only supported for knowledge bases of
type EXTERNAL. Include a single variable in {variable} format; this interpolated by Wisdom
using ingested content. For example, if you ingest a Salesforce article, it has an Id
value, and you can set the template URI to
https://myInstanceName.lightning.force.com/lightning/r/Knowledge__kav/*{Id}*/view.

# Arguments
- `knowledge_base_id`: The the identifier of the knowledge base. Can be either the ID or
  the ARN. URLs cannot contain the ARN.
- `template_uri`: The template URI to update.

"""
function update_knowledge_base_template_uri(
    knowledgeBaseId, templateUri; aws_config::AbstractAWSConfig=global_aws_config()
)
    return wisdom(
        "POST",
        "/knowledgeBases/$(knowledgeBaseId)/templateUri",
        Dict{String,Any}("templateUri" => templateUri);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_knowledge_base_template_uri(
    knowledgeBaseId,
    templateUri,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return wisdom(
        "POST",
        "/knowledgeBases/$(knowledgeBaseId)/templateUri",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("templateUri" => templateUri), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end


text:
module TestConstructors

using Test, InMemoryDatasets, Random, CategoricalArrays, DataStructures, PooledArrays
using InMemoryDatasets: Index, _columns, index
const ≅ = isequal

#
# Dataset
#
@testset "constructors" begin
    ds = Dataset()
    @inferred Dataset()

    @test isempty(_columns(ds))
    @test _columns(ds) isa Vector{AbstractVector}
    @test index(ds) == Index()
    @test size(Dataset(copycols=false)) == (0, 0)

    vecvec = [CategoricalVector{Union{Float64, Missing}}(zeros(3)),
              CategoricalVector{Union{Float64, Missing}}(ones(3))]

    ds = Dataset(collect(Any, vecvec), Index([:x1, :x2]))
    @test size(ds, 1) == 3
    @test size(ds, 2) == 2

    ds2 = Dataset(collect(Any, vecvec), Index([:x1, :x2]), copycols=false)
    @test size(ds2, 1) == 3
    @test size(ds2, 2) == 2
    @test ds2.x1.val === vecvec[1]
    @test ds2.x2.val === vecvec[2]

    @test_throws ArgumentError Dataset([[1, 2]], :autos)
    @test_throws ArgumentError Dataset([1 2], :autos)

    for copycolsarg in (true, false)
        @test ds == Dataset(vecvec, :auto, copycols=copycolsarg)
        @test ds == Dataset(collect(Any, vecvec), :auto, copycols=copycolsarg)
        @test ds == Dataset(collect(AbstractVector, vecvec), :auto, copycols=copycolsarg)
        @test ds == Dataset(x1 = vecvec[1], x2 = vecvec[2], copycols=copycolsarg)

        for cols in ([:x1, :x2], ["x1", "x2"])
            @test ds == Dataset(vecvec, cols, copycols=copycolsarg)
            @test ds == Dataset(collect(Any, vecvec), cols, copycols=copycolsarg)
            @test ds == Dataset(collect(AbstractVector, vecvec), cols, copycols=copycolsarg)
            @test ds == Dataset([col=>vect for (col, vect) in zip(cols, vecvec)])
        end
    end

    @test Dataset([1:3, 1:3], :auto) == Dataset(Any[1:3, 1:3], :auto) ==
          Dataset(UnitRange[1:3, 1:3], :auto) == Dataset(AbstractVector[1:3, 1:3], :auto) ==
          Dataset([[1, 2, 3], [1, 2, 3]], :auto) == Dataset(Any[[1, 2, 3], [1, 2, 3]], :auto) ==
          Dataset([1:3, [1, 2, 3]], :auto)
          Dataset([:x1=>1:3, :x2=>[1, 2, 3]]) == Dataset(["x1"=>1:3, "x2"=>[1, 2, 3]])

    @inferred Dataset([1:3, 1:3], :auto)
    @inferred Dataset([1:3, 1:3], [:a, :b])
    @inferred Dataset([1:3, 1:3], ["a", "b"])

    @inferred Dataset([:x1=>1:3, :x2=>[1, 2, 3]])
    @inferred Dataset(["x1"=>1:3, "x2"=>[1, 2, 3]])

    @test ds !== Dataset(ds)
    @test ds == Dataset(ds)

    @test ds == Dataset(x1 = Union{Float64, Missing}[0.0, 0.0, 0.0],
                          x2 = Union{Float64, Missing}[1.0, 1.0, 1.0])
    @test ds == Dataset(x1 = Union{Float64, Missing}[0.0, 0.0, 0.0],
                          x2 = Union{Float64, Missing}[1.0, 1.0, 1.0],
                          x3 = Union{Float64, Missing}[2.0, 2.0, 2.0])[:, [:x1, :x2]]
    @test ds == Dataset(x1 = Union{Float64, Missing}[0.0, 0.0, 0.0],
                          x2 = Union{Float64, Missing}[1.0, 1.0, 1.0],
                          x3 = Union{Float64, Missing}[2.0, 2.0, 2.0])[:, ["x1", "x2"]]

    @test_throws BoundsError SubDataset(Dataset(A=1), 0:0, :)
    @test_throws ArgumentError SubDataset(Dataset(A=1), 0, :)
    @test_throws BoundsError Dataset(A=1)[0, :]
    @test_throws BoundsError Dataset(A=1)[0, 1:1]

    @test Dataset(a=1, b=1:2) == Dataset(a=[1, 1], b=[1, 2])

    @test_throws ArgumentError Dataset(makeunique=true)
    @test_throws ArgumentError Dataset(a=1, makeunique=true)
    @test_throws ArgumentError Dataset(a=1, makeunique=true, copycols=false)
end

@testset "Dataset keyword argument constructor" begin
    x = allowmissing([1, 2, 3])
    y = allowmissing([4, 5, 6])

    ds = Dataset(x=x, y=y)
    @test size(ds) == (3, 2)
    @test propertynames(ds) == [:x, :y]
    @test ds.x == x
    @test ds.y == y
    @test ds.x.val !== x
    @test ds.y.val !== y
    ds = Dataset(x=x, y=y, copycols=true)
    @test size(ds) == (3, 2)
    @test propertynames(ds) == [:x, :y]
    @test ds.x == x
    @test ds.y == y
    @test ds.x.val !== x
    @test ds.y.val !== y
    ds = Dataset(x=x, y=y, copycols=false)
    @test size(ds) == (3, 2)
    @test propertynames(ds) == [:x, :y]
    @test ds.x.val === x
    @test ds.y.val === y
    @test_throws ArgumentError Dataset(x=x, y=y, copycols=1)

    ds = Dataset(x=x, y=y, copycols=false)
    @test size(ds) == (3, 2)
    @test propertynames(ds) == [:x, :y]
    @test ds.x.val === x
    @test ds.y.val === y
end

@testset "Dataset constructor" begin
    ds1 = Dataset(x=1:3, y=1:3)

    ds2 = Dataset(ds1)
    ds3 = copy(ds1)
    @test ds1 == ds2 == ds3
    @test ds1.x.val !== ds2.x.val
    @test ds1.x.val !== ds3.x.val
    @test ds1.y.val !== ds2.y.val
    @test ds1.y.val !== ds3.y.val

    ds2 = Dataset(ds1)
    ds3 = copy(ds1)
    @test ds1 == ds2 == ds3
    @test ds1.x.val !== ds2.x.val
    @test ds1.x.val !== ds3.x.val
    @test ds1.y.val !== ds2.y.val
    @test ds1.y.val !== ds3.y.val

    ds1 = view(ds1, :, :)
    ds2 = Dataset(ds1)
    ds3 = copy(ds1)
    @test ds1 == ds2 == ds3
    @test ds1.x.val !== ds2.x.val
    @test ds1.x.val !== ds3.x.val
    @test ds1.y.val !== ds2.y.val
    @test ds1.y.val !== ds3.y.val

    # FIXME
    # ds2 = Dataset(ds1, copycols=false)
    # @test ds1 == ds2
    # @test ds1.x.val === ds2.x.val
    # @test ds1.y.val === ds2.y.val
end

@testset "pair constructor" begin
    @test Dataset(:x1 => zeros(3), :x2 => ones(3)) ==
          Dataset([:x1 => zeros(3), :x2 => ones(3)]) ==
          Dataset("x1" => zeros(3), "x2" => ones(3)) ==
          Dataset("x1" => zeros(3), "x2" => ones(3))

    @inferred Dataset(:x1 => zeros(3), :x2 => ones(3))
    ds = Dataset([:x1 => zeros(3), :x2 => ones(3)])
    @test size(ds, 1) == 3
    @test size(ds, 2) == 2
    @test isequal(ds, Dataset(x1 = [0.0, 0.0, 0.0], x2 = [1.0, 1.0, 1.0]))

    ds = Dataset(:type => [], :begin => [])
    @test propertynames(ds) == [:type, :begin]

    a=allowmissing([1, 2, 3])
    ds = Dataset(:a=>a, :b=>1, :c=>1:3)
    @test propertynames(ds) == [:a, :b, :c]
    @test ds.a.val == a
    @test ds.a.val !== a

    ds = Dataset(:a=>a, :b=>1, :c=>1:3)
    @test propertynames(ds) == [:a, :b, :c]
    @test ds.a.val == a

    ds = Dataset("x1" => zeros(3), "x2" => ones(3))
    @inferred Dataset("x1" => zeros(3), "x2" => ones(3))
    @test size(ds, 1) == 3
    @test size(ds, 2) == 2
    @test isequal(ds, Dataset(x1 = [0.0, 0.0, 0.0], x2 = [1.0, 1.0, 1.0]))

    ds = Dataset("type" => [], "begin" => [])
    @test propertynames(ds) == [:type, :begin]

    a=allowmissing([1, 2, 3])
    ds = Dataset("a"=>a, "b"=>1, "c"=>1:3)
    @test propertynames(ds) == [:a, :b, :c]
    @test ds."a" == a
    @test ds."a".val !== a

    ds = Dataset("a"=>a, "b"=>1, "c"=>1:3)
    @test propertynames(ds) == [:a, :b, :c]
    @test ds."a".val == a

    @test_throws ArgumentError Dataset(["type" => 1, :begin => 2])
end

@testset "associative" begin
    ds = Dataset(Dict(:A => 1:3, :B => 4:6))
    @inferred Dataset(Dict(:A => 1:3, :B => 4:6))
    @test ds == Dataset(A = 1:3, B = 4:6)
    @test eltype.(eachcol(ds)) == Union[Union{Missing, Int}, Union{Missing, Int}]

    a=allowmissing([1, 2, 3])
    ds = Dataset(Dict(:a=>a, :b=>1, :c=>1:3))
    @test propertynames(ds) == [:a, :b, :c]
    @test ds.a == a
    @test ds.a.val !== a

    ds = Dataset(Dict(:a=>a, :b=>1, :c=>1:3))
    @test propertynames(ds) == [:a, :b, :c]
    @test ds.a.val == a

    ds = Dataset(Dict("A" => 1:3, "B" => 4:6))
    @inferred Dataset(Dict("A" => 1:3, "B" => 4:6))
    @test ds == Dataset(A = 1:3, B = 4:6)
    @test eltype.(eachcol(ds)) == Union[Union{Missing, Int}, Union{Missing, Int}]

    a=allowmissing([1, 2, 3])
    ds = Dataset(Dict("a"=>a, "b"=>1, "c"=>1:3))
    @test propertynames(ds) == [:a, :b, :c]
    @test ds."a" == a
    @test ds."a".val !== a
    ds = Dataset(Dict("a"=>a, "b"=>1, "c"=>1:3))
    @test propertynames(ds) == [:a, :b, :c]
    @test ds."a".val == a
end

@testset "vector constructors" begin
    x = allowmissing([1, 2, 3])
    y = allowmissing([1, 2, 3])

    ds = Dataset([x, y], :auto)
    @test propertynames(ds) == [:x1, :x2]
    @test ds.x1 == x
    @test ds.x2 == y
    @test ds.x1.val !== x
    @test ds.x2.val !== y
    ds = Dataset([x, y], :auto, copycols=true)
    @test propertynames(ds) == [:x1, :x2]
    @test ds.x1 == x
    @test ds.x2 == y
    @test ds.x1.val !== x
    @test ds.x2.val !== y
    ds = Dataset([x, y], :auto, copycols=false)
    @test propertynames(ds) == [:x1, :x2]
    @test ds.x1.val === x
    @test ds.x2.val === y

    ds = Dataset([x, y], [:x1, :x2])
    @test propertynames(ds) == [:x1, :x2]
    @test ds.x1 == x
    @test ds.x2 == y
    @test ds.x1.val !== x
    @test ds.x2.val !== y
    ds = Dataset([x, y], [:x1, :x2], copycols=true)
    @test propertynames(ds) == [:x1, :x2]
    @test ds.x1 == x
    @test ds.x2 == y
    @test ds.x1.val !== x
    @test ds.x2.val !== y
    ds = Dataset([x, y], [:x1, :x2], copycols=false)
    @test propertynames(ds) == [:x1, :x2]
    @test ds.x1.val === x
    @test ds.x2.val === y

    ds = Dataset([x, y], ["x1", "x2"])
    @test names(ds) == ["x1", "x2"]
    @test ds."x1" == x
    @test ds."x2" == y
    @test ds."x1".val !== x
    @test ds."x2".val !== y
    ds = Dataset([x, y], ["x1", "x2"], copycols=true)
    @test names(ds) == ["x1", "x2"]
    @test ds."x1" == x
    @test ds."x2" == y
    @test ds."x1".val !== x
    @test ds."x2".val !== y
    ds = Dataset([x, y], ["x1", "x2"], copycols=false)
    @test names(ds) == ["x1", "x2"]
    @test ds."x1".val === x
    @test ds."x2".val === y

    n = [:x1, :x2]
    v = AbstractVector[1:3, [1, 2, 3]]
    @test Dataset(v, n).x1.val isa Vector{Union{Int, Missing}}
    @test v[1] isa AbstractRange

    n = ["x1", "x2"]
    v = AbstractVector[1:3, [1, 2, 3]]
    @test Dataset(v, n)."x1".val isa Vector{Union{Int, Missing}}
    @test v[1] isa AbstractRange
end

@testset "recyclers" begin
    @test Dataset(a = 1:5, b = 1) == Dataset(a = collect(1:5), b = fill(1, 5))
    @test Dataset(a = 1, b = 1:5) == Dataset(a = fill(1, 5), b = collect(1:5))
    @test size(Dataset(a=1, b=[])) == (0, 2)
    @test size(Dataset(a=1, b=[], copycols=false)) == (0, 2)
end

@testset "constructor thrown exceptions" begin
    for copycolsarg in (true, false)
        @test_throws DimensionMismatch Dataset(Any[collect(1:10)], InMemoryDatasets.Index([:A, :B]), copycols=copycolsarg)
        @test_throws ArgumentError Dataset(A = rand(2, 2), copycols=copycolsarg)
        @test_throws ArgumentError Dataset(A = rand(2, 1), copycols=copycolsarg)
        @test_throws ArgumentError Dataset([1, 2, 3], :auto, copycols=copycolsarg)
        @test_throws DimensionMismatch Dataset(AbstractVector[1:3, [1, 2]], :auto, copycols=copycolsarg)
        @test_throws ArgumentError Dataset([1:3, 1], [:x1, :x2], copycols=copycolsarg)
        @test_throws ArgumentError Dataset([1:3, 1], ["x1", "x2"], copycols=copycolsarg)
        @test_throws ErrorException Dataset([1:3, 1], copycols=copycolsarg)
    end

    @test_throws MethodError Dataset([1 2; 3 4], :auto, copycols=false)
end

@testset "column types" begin
    ds = Dataset(A = 1:3, B = 2:4, C = 3:5)
    answer = [Array{Union{Missing, Int}, 1}, Array{Union{Missing, Int}, 1}, Array{Union{Missing, Int}, 1}]
    @test typeof.(eachcol(ds)) == answer
    ds[!, :D] = [4, 5, missing]
    push!(answer, Vector{Union{Int, Missing}})
    @test typeof.(eachcol(ds)) == answer
    ds[!, :E] .= 'c'
    push!(answer, Vector{Union{Missing, Char}})
    @test typeof.(eachcol(ds)) == answer
end

@testset "expansion of Ref and 0-dimensional arrays" begin
    @test Dataset(a=Ref(1), b=fill(1)) == Dataset(a=[1], b=[1])
    @test Dataset(a=Ref(1), b=fill(1), c=1:3) ==
          Dataset(a=[1, 1, 1], b=[1, 1, 1], c=1:3)
end

@testset "broadcasting into 0 rows" begin
    for ds in [Dataset(x1=1:0, x2=1), Dataset(x1=1, x2=1:0)]
        @test size(ds) == (0, 2)
        @test ds.x1.val isa Vector{Union{Missing, Int}}
        @test ds.x2.val isa Vector{Union{Missing, Int}}
    end
end

@testset "Dict constructor corner case" begin
    @test_throws ArgumentError Dataset(Dict('a' => 1, true => 2))
    @test_throws ArgumentError Dataset(Dict(:z => 1, "true" => 2))
    @test Dataset(Dict("z" => 1, "true" => 2)) == Dataset("true" => 2, "z" => 1)
    @test Dataset(Dict([Symbol(c) => i for (i, c) in enumerate('a':'z')])) ==
          Dataset(Dict([string(c) => i for (i, c) in enumerate('a':'z')])) ==
          Dataset([Symbol(c) => i for (i, c) in enumerate('a':'z')])
    @test Dataset(OrderedDict(:z => 1, :a => 2)) == Dataset(z=1, a=2)

end

@testset "removed constructors" begin
    @test_throws ArgumentError Dataset([1 2; 3 4])
    @test_throws ArgumentError Dataset([[1, 2], [3, 4]])
    @test_throws ArgumentError Dataset([Int, Float64], [:a, :b])
    @test_throws ArgumentError Dataset([Int, Float64], [:a, :b], 2)
    @test_throws ArgumentError Dataset([Int, Float64], ["a", "b"])
    @test_throws ArgumentError Dataset([Int, Float64], ["a", "b"], 2)
end

@testset "threading correctness tests" begin
    for x in (10, 2*10^6), y in 1:4
        ds = Dataset(rand(x, y), :auto)
        InMemoryDatasets.insertcols!(ds, 1, :g => PooledArray(rand(1:10, nrow(ds))))
        InMemoryDatasets.insertcols!(ds, 1, :g2 => CategoricalArray(rand(1:10, nrow(ds))))
        @test ds == copy(ds)
        @test ds == ds[1:nrow(ds), :]
        p = shuffle(1:nrow(ds))
        @test ds[p, :] == ds[p, :]
    end
end

end # module

ext: jl


text:
using IntervalArithmetic
using Test

let x, b

setprecision(Interval, Float64)

@testset "setformat tests" begin

    @testset "Interval" begin

        a = 1..2
        b = -1.1..1.3
        c = Interval(pi)

        @testset "6 sig figs" begin
            setformat(:standard, sigfigs=6)

            @test string(a) == "[1, 2]"
            @test string(b) == "[-1.10001, 1.30001]"
            @test string(c) == "[3.14159, 3.1416]"
        end

        @testset "10 sig figs" begin
            setformat(sigfigs=10)

            @test string(a) == "[1, 2]"
            @test string(b) == "[-1.100000001, 1.300000001]"
            @test string(c) == "[3.141592653, 3.141592654]"
        end

        @testset "20 sig figs" begin
            setformat(sigfigs=20)

            @test string(a) == "[1, 2]"
            @test string(b) == "[-1.1000000000000000889, 1.3000000000000000445]"
            @test string(c) == "[3.1415926535897931159, 3.1415926535897935601]"
        end

        @testset "Full" begin
            setformat(:full)

            @test string(a) == "Interval(1.0, 2.0)"
            @test string(b) == "Interval(-1.1, 1.3)"
            @test string(c) == "Interval(3.141592653589793, 3.1415926535897936)"
        end

        @testset "Midpoint" begin
            setformat(:midpoint, sigfigs=6)

            @test string(a) == "1.5 ± 0.5"
            @test string(b) == "0.1 ± 1.20001"
            @test string(c) == "3.14159 ± 4.4409e-16"

            # issue 175:
            @test string(@biginterval(1, 2)) == "1.5 ± 0.5"
        end
    end

    @testset "Interval{Rational{T}}" begin
        a = Interval(1//3, 5//4)
        @test typeof(a)== Interval{Rational{Int}}
        setformat(:standard)
        @test string(a) == "[1//3, 5//4]"

        setformat(:full)
        @test string(a) == "Interval(1//3, 5//4)"

        setformat(:midpoint)
        @test string(a) == "19//24 ± 11//24"
    end

    @testset "Interval{Float32}" begin
        a = Interval{Float32}(1, 2)
        b = Interval{Float32}(-1, Inf)
        setformat(:standard)
        @test string(a) == "[1f0, 2f0]"
        @test string(b) == "[-1f0, ∞]"

        setformat(:full)
        @test string(a) == "Interval(1.0f0, 2.0f0)"
        @test string(b) == "Interval(-1.0f0, ∞)"

        setformat(:midpoint)
        @test string(a) == "1.5f0 ± 0.5f0"
    end

    @testset "Complex{Interval}" begin
        a = Complex(Interval(0, 2), 1)
        @test typeof(a) == Complex{Interval{Float64}}
        setformat(:standard)
        @test string(a) == "[0, 2] + [1, 1]im"
    end

    setprecision(Interval, 256)

    @testset "DecoratedInterval" begin
        a = @decorated(1, 2)
        @test typeof(a)== DecoratedInterval{Float64}

        setformat(:standard, decorations=false)
        @test string(a) == "[1, 2]"

        setformat(:standard, decorations=true)
        @test string(a) == "[1, 2]_com"

        # issue 131:
        a = DecoratedInterval(big(2), big(3), com)

        setformat(:standard, decorations=false)
        @test string(a) == "[2, 3]₂₅₆"

        setformat(decorations=true)
        @test string(a) == "[2, 3]₂₅₆_com"

        setformat(:full)
        @test string(a) == "DecoratedInterval(Interval(2.0, 3.0), com)"

        setformat(:midpoint)
        @test string(a) == "2.5 ± 0.5_com"

        setformat(decorations=false)
        @test string(a) == "2.5 ± 0.5"

    end

    setprecision(Interval, 128)

    @testset "BigFloat intervals" begin
        setformat(:standard, decorations=false)

        a = @interval big(1)
        @test typeof(a)== Interval{BigFloat}
        @test string(a) == "[1, 1]₁₂₈"

        setformat(:full)
        @test string(a) == "Interval(1.0, 1.0)"

        a = DecoratedInterval(big(2), big(3), com)
        @test typeof(a)== DecoratedInterval{BigFloat}

        setformat(:standard, decorations=false)
        @test string(a) == "[2, 3]₁₂₈"

        setformat(:standard, decorations=true)
        @test string(a) == "[2, 3]₁₂₈_com"

        setformat(:full)
        @test string(a) == "DecoratedInterval(Interval(2.0, 3.0), com)"
    end

    setprecision(Interval, Float64)

    @testset "IntervalBox" begin

        setformat(:standard, sigfigs=6)

        X = IntervalBox(1..2, 3..4)
        @test typeof(X) == IntervalBox{2,Float64}
        @test string(X) == "[1, 2] × [3, 4]"

        s = sprint(show, MIME("text/plain"), X)
        @test s == "[1, 2] × [3, 4]"

        X = IntervalBox(1.1..1.2, 2.1..2.2)
        @test string(X) == "[1.09999, 1.20001] × [2.09999, 2.20001]"

        X = IntervalBox(-Inf..Inf, -Inf..Inf)
        @test string(X) == "[-∞, ∞] × [-∞, ∞]"

        setformat(:full)
        @test string(X) == "IntervalBox(Interval(-Inf, Inf), Interval(-Inf, Inf))"

    end
end

@testset "showfull" begin
    setformat(:standard, decorations=false, sigfigs=6)
    setprecision(128)

    x = 0..1
    @test string(x) == "[0, 1]"
    @test sprint(showfull, x) == "Interval(0.0, 1.0)"

    x = @biginterval(0, 1)
    @test string(x) == "[0, 1]₁₂₈"
    @test sprint(showfull, x) == "Interval(0.0, 1.0)"

    x = DecoratedInterval(0, 1, dac)
    @test string(x) == "[0, 1]"
    @test sprint(showfull, x) == "DecoratedInterval(Interval(0.0, 1.0), dac)"

    x = DecoratedInterval(big(0), big(1), def)
    @test string(x) == "[0, 1]₁₂₈"
    @test sprint(showfull, x) == "DecoratedInterval(Interval(0.0, 1.0), def)"

    setformat(decorations=true)
    @test string(x) == "[0, 1]₁₂₈_def"

end

@testset "@format tests" begin
    x = 0.1..0.3

    @format full
    @test string(x) == "Interval(0.09999999999999999, 0.30000000000000004)"

    @format standard 3
    @test string(x) == "[0.0999, 0.301]"

    @format 10
    @test string(x) == "[0.09999999999, 0.3000000001]"
end

end


text:
export TicTacToeEnv

struct Nought end
const NOUGHT = Nought()
struct Cross end
const CROSS = Cross()

Base.:!(::Nought) = CROSS
Base.:!(::Cross) = NOUGHT

"""
This is a typical two player, zero sum game. Here we'll also demonstrate how to
implement an environment with multiple state representations.

You might be interested in this [blog](http://www.occasionalenthusiast.com/tag/tic-tac-toe/)
"""
mutable struct TicTacToeEnv <: AbstractEnv
    board::BitArray{3}
    player::Union{Nought,Cross}
end

function TicTacToeEnv()
    board = BitArray{3}(undef, 3, 3, 3)
    fill!(board, false)
    board[:, :, 1] .= true
    TicTacToeEnv(board, CROSS)
end

function RLBase.reset!(env::TicTacToeEnv)
    fill!(env.board, false)
    env.board[:, :, 1] .= true
    env.player = CROSS
end

struct TicTacToeInfo
    is_terminated::Bool
    winner::Union{Nothing,Nought,Cross}
end

const TIC_TAC_TOE_STATE_INFO = Dict{
    TicTacToeEnv,
    NamedTuple{
        (:index, :is_terminated, :winner),
        Tuple{Int,Bool,Union{Nothing,Nought,Cross}},
    },
}()

Base.hash(env::TicTacToeEnv, h::UInt) = hash(env.board, h)
Base.isequal(a::TicTacToeEnv, b::TicTacToeEnv) = isequal(a.board, b.board)

Base.to_index(::TicTacToeEnv, ::Cross) = 2
Base.to_index(::TicTacToeEnv, ::Nought) = 3

RLBase.action_space(::TicTacToeEnv, player) = Space(OneTo(9))

RLBase.legal_action_space(env::TicTacToeEnv, p) =
    Space(findall(legal_action_space_mask(env)))

function RLBase.legal_action_space_mask(env::TicTacToeEnv, p)
    if is_win(env, CROSS) || is_win(env, NOUGHT)
        falses(9)
    else
        vec(env.board[:, :, 1])
    end
end

(env::TicTacToeEnv)(action::Int) = env(CartesianIndices((3, 3))[action])

function (env::TicTacToeEnv)(action::CartesianIndex{2})
    env.board[action, 1] = false
    env.board[action, Base.to_index(env, env.player)] = true
    env.player = !env.player
end

RLBase.current_player(env::TicTacToeEnv) = env.player
RLBase.players(env::TicTacToeEnv) = (CROSS, NOUGHT)

RLBase.state(env::TicTacToeEnv, ::Observation{BitArray{3}}, p) = env.board
RLBase.state_space(env::TicTacToeEnv, ::Observation{BitArray{3}}, p) = Space(Bool, 3, 3, 3)
RLBase.state(env::TicTacToeEnv, ::Observation{Int}, p) =
    get_tic_tac_toe_state_info()[env].index
RLBase.state_space(env::TicTacToeEnv, ::Observation{Int}, p) =
    Space(OneTo(length(get_tic_tac_toe_state_info())))
RLBase.state_space(env::TicTacToeEnv, ::Observation{String}, p) = Space(String)

function RLBase.state(env::TicTacToeEnv, ::Observation{String}, p)
    buff = IOBuffer()
    for i in 1:3
        for j in 1:3
            if env.board[i, j, 1]
                x = '.'
            elseif env.board[i, j, 2]
                x = 'x'
            else
                x = 'o'
            end
            print(buff, x)
        end
        print(buff, '\n')
    end
    String(take!(buff))
end

RLBase.is_terminated(env::TicTacToeEnv) = get_tic_tac_toe_state_info()[env].is_terminated

function RLBase.reward(env::TicTacToeEnv, player)
    if is_terminated(env)
        winner = get_tic_tac_toe_state_info()[env].winner
        if isnothing(winner)
            0
        elseif winner === player
            1
        else
            -1
        end
    else
        0
    end
end

function is_win(env::TicTacToeEnv, player)
    b = env.board
    p = Base.to_index(env, player)
    @inbounds begin
        b[1, 1, p] & b[1, 2, p] & b[1, 3, p] ||
            b[2, 1, p] & b[2, 2, p] & b[2, 3, p] ||
            b[3, 1, p] & b[3, 2, p] & b[3, 3, p] ||
            b[1, 1, p] & b[2, 1, p] & b[3, 1, p] ||
            b[1, 2, p] & b[2, 2, p] & b[3, 2, p] ||
            b[1, 3, p] & b[2, 3, p] & b[3, 3, p] ||
            b[1, 1, p] & b[2, 2, p] & b[3, 3, p] ||
            b[1, 3, p] & b[2, 2, p] & b[3, 1, p]
    end
end

function get_tic_tac_toe_state_info()
    if isempty(TIC_TAC_TOE_STATE_INFO)
        @info "initializing tictactoe state info cache..."
        t = @elapsed begin
            n = 1
            root = TicTacToeEnv()
            TIC_TAC_TOE_STATE_INFO[root] =
                (index = n, is_terminated = false, winner = nothing)
            walk(root) do env
                if !haskey(TIC_TAC_TOE_STATE_INFO, env)
                    n += 1
                    has_empty_pos = any(view(env.board, :, :, 1))
                    w = if is_win(env, CROSS)
                        CROSS
                    elseif is_win(env, NOUGHT)
                        NOUGHT
                    else
                        nothing
                    end
                    TIC_TAC_TOE_STATE_INFO[env] = (
                        index = n,
                        is_terminated = !(has_empty_pos && isnothing(w)),
                        winner = w,
                    )
                end
            end
        end
        @info "finished initializing tictactoe state info cache in $t seconds"
    end
    TIC_TAC_TOE_STATE_INFO
end

RLBase.NumAgentStyle(::TicTacToeEnv) = MultiAgent(2)
RLBase.DynamicStyle(::TicTacToeEnv) = SEQUENTIAL
RLBase.ActionStyle(::TicTacToeEnv) = FULL_ACTION_SET
RLBase.InformationStyle(::TicTacToeEnv) = PERFECT_INFORMATION
RLBase.StateStyle(::TicTacToeEnv) =
    (Observation{String}(), Observation{Int}(), Observation{BitArray{3}}())
RLBase.RewardStyle(::TicTacToeEnv) = TERMINAL_REWARD
RLBase.UtilityStyle(::TicTacToeEnv) = ZERO_SUM
RLBase.ChanceStyle(::TicTacToeEnv) = DETERMINISTIC


text:
export Fun, evaluate, values, points, extrapolate, setdomain
export coefficients, ncoefficients, coefficient
export integrate, differentiate, domain, space, linesum, linenorm

include("Domain.jl")
include("Space.jl")

##  Constructors

mutable struct Fun{S,T,VT} <: Function
    space::S
    coefficients::VT
    function Fun{S,T,VT}(sp::S,coeff::VT) where {S,T,VT}
        @assert length(coeff) ≤ dimension(sp)
        new{S,T,VT}(sp,coeff)
    end
end

const VFun{S,T} = Fun{S,T,Vector{T}}

Fun(sp::Space,coeff::AbstractVector) = Fun{typeof(sp),eltype(coeff),typeof(coeff)}(sp,coeff)
Fun() = Fun(identity)
Fun(d::Domain) = Fun(identity,d)
Fun(d::Space) = Fun(identity,d)

function Fun(sp::Space,v::AbstractVector{Any})
    if isempty(v)
        Fun(sp,Float64[])
    elseif all(x->isa(x,Number),v)
        Fun(sp,Vector{mapreduce(typeof,promote_type,v)}(v))
    else
        error("Cannot construct Fun with coefficients $v and space $sp")
    end
end

hasnumargs(f::Fun,k) = k == 1 || domaindimension(f) == k  # all funs take a single argument as a Vec

##Coefficient routines
#TODO: domainscompatible?

function coefficients(f::Fun,msp::Space)
    #zero can always be converted
    if ncoefficients(f)==1 && f.coefficients[1]==0
        f.coefficients
    else
        coefficients(f.coefficients,space(f),msp)
    end
end
coefficients(f::Fun,::Type{T}) where {T<:Space} = coefficients(f,T(domain(f)))
coefficients(f::Fun) = f.coefficients
coefficients(c::Number,sp::Space) = Fun(c,sp).coefficients

function coefficient(f::Fun,k::Integer)
    if k > dimension(space(f)) || k < 1
        throw(BoundsError())
    elseif k > ncoefficients(f)
        zero(cfstype(f))
    else
        f.coefficients[k]
    end
end

function coefficient(f::Fun,kr::AbstractRange)
    b = maximum(kr)

    if b ≤ ncoefficients(f)
        f.coefficients[kr]
    else
        [coefficient(f,k) for k in kr]
    end
end

coefficient(f::Fun,K::Block) = coefficient(f,blockrange(space(f),K.n[1]))
coefficient(f::Fun,::Colon) = coefficient(f,1:dimension(space(f)))

##Convert routines

convert(::Type{Fun{S,T,VT}},f::Fun{S}) where {T,S,VT} =
    Fun(f.space,convert(VT,f.coefficients))
convert(::Type{Fun{S,T,VT}},f::Fun) where {T,S,VT} =
    Fun(Fun(f.space,convert(VT,f.coefficients)),convert(S,space(f)))

convert(::Type{Fun{S,T}},f::Fun{S}) where {T,S} =
    Fun(f.space,convert(AbstractVector{T},f.coefficients))

convert(::Type{VFun{S,T}},x::Number) where {T,S} =
    x==0 ? zeros(T,S(AnyDomain())) : x*ones(T,S(AnyDomain()))
convert(::Type{Fun{S}},x::Number) where {S} =
    x==0 ? zeros(S(AnyDomain())) : x*ones(S(AnyDomain()))
convert(::Type{IF},x::Number) where {IF<:Fun} = convert(IF,Fun(x))

Fun{S,T,VT}(f::Fun) where {S,T,VT} = convert(Fun{S,T,VT}, f)
Fun{S,T}(f::Fun) where {S,T} = convert(Fun{S,T}, f)
Fun{S}(f::Fun) where {S} = convert(Fun{S}, f)

# if we are promoting, we need to change to a VFun
Base.promote_rule(::Type{Fun{S,T,VT1}},::Type{Fun{S,V,VT2}}) where {T,V,S,VT1,VT2} =
    VFun{S,promote_type(T,V)}

# TODO: Never assume!
Base.promote_op(::typeof(*),::Type{F1},::Type{F2}) where {F1<:Fun,F2<:Fun} =
    promote_type(F1,F2) # assume multiplication is defined between same types

# we know multiplication by numbers preserves types
Base.promote_op(::typeof(*),::Type{N},::Type{Fun{S,T,VT}}) where {N<:Number,S,T,VT} =
    VFun{S,promote_type(T,N)}
Base.promote_op(::typeof(*),::Type{Fun{S,T,VT}},::Type{N}) where {N<:Number,S,T,VT} =
    VFun{S,promote_type(T,N)}

Base.promote_op(::typeof(LinearAlgebra.matprod),::Type{Fun{S1,T1,VT1}},::Type{Fun{S2,T2,VT2}}) where {S1,T1,VT1,S2,T2,VT2} =
            VFun{promote_type(S1,S2),promote_type(T1,T2)}
# Fun's are always vector spaces, so we know matprod will preserve the space
Base.promote_op(::typeof(LinearAlgebra.matprod),::Type{Fun{S,T,VT}},::Type{NN}) where {S,T,VT,NN<:Number} =
            VFun{S,promote_type(T,NN)}
Base.promote_op(::typeof(LinearAlgebra.matprod),::Type{NN},::Type{Fun{S,T,VT}}) where {S,T,VT,NN<:Number} =
            VFun{S,promote_type(T,NN)}

zero(::Type{Fun}) = Fun(0.)
zero(::Type{Fun{S,T,VT}}) where {T,S<:Space,VT} = zeros(T,S(AnyDomain()))
one(::Type{Fun{S,T,VT}}) where {T,S<:Space,VT} = ones(T,S(AnyDomain()))
zero(f::Fun{S,T}) where {S,T} = zeros(T,f.space)
one(f::Fun{S,T}) where {S,T} = ones(T,f.space)

cfstype(::Fun{S,T}) where {S,T} = T
cfstype(::Type{Fun{S,T,VT}}) where {S,T,VT} = T

# Number and Array conform to the Fun interface
cfstype(::Type{T}) where T<: Number = T
cfstype(::T) where T<: Number = T
cfstype(::Type{<:AbstractArray{T}}) where T = T
cfstype(::AbstractArray{T}) where T = T

coefficients(f::Number) = [f]
coefficients(f::AbstractArray) = f

#supports broadcasting and scalar iterator
const ScalarFun = Fun{S} where S<:Space{D,R} where {D,R<:Number}
const ArrayFun = Fun{S} where {S<:Space{D,R}} where {D,R<:AbstractArray}
const MatrixFun = Fun{S} where {S<:Space{D,R}} where {D,R<:AbstractMatrix}
const VectorFun = Fun{S} where {S<:Space{D,R}} where {D,R<:AbstractVector}

size(f::Fun,k...) = size(space(f),k...)
length(f::Fun) = length(space(f))

getindex(f::ScalarFun, ::CartesianIndex{0}) = f
getindex(f::ScalarFun, k::Integer) = k == 1 ? f : throw(BoundsError())

iterate(x::ScalarFun) = (x, nothing)
iterate(x::ScalarFun, ::Any) = nothing
isempty(x::ScalarFun) = false

iterate(A::ArrayFun, i=1) = (@_inline_meta; (i % UInt) - 1 < length(A) ? (@inbounds A[i], i + 1) : nothing)

in(x::ScalarFun, y::ScalarFun) = x == y

setspace(v::AbstractVector,s::Space) = Fun(s,v)
setspace(f::Fun,s::Space) = Fun(s,f.coefficients)

## domain

## General routines

domain(f::Fun) = domain(f.space)
domain(v::AbstractMatrix{T}) where {T<:Fun} = map(domain,v)
domaindimension(f::Fun) = domaindimension(f.space)

setdomain(f::Fun,d::Domain) = Fun(setdomain(space(f),d),f.coefficients)

for op in (:tocanonical,:tocanonicalD,:fromcanonical,:fromcanonicalD,:invfromcanonicalD)
    @eval $op(f::Fun,x...) = $op(space(f),x...)
end

for op in (:tocanonical,:tocanonicalD)
    @eval $op(d::Domain) = $op(d,Fun(identity,d))
end
for op in (:fromcanonical,:fromcanonicalD,:invfromcanonicalD)
    @eval $op(d::Domain) = $op(d,Fun(identity,canonicaldomain(d)))
end

space(f::Fun) = f.space
spacescompatible(f::Fun,g::Fun) = spacescompatible(space(f),space(g))
pointscompatible(f::Fun,g::Fun) = pointscompatible(space(f),space(g))
canonicalspace(f::Fun) = canonicalspace(space(f))
canonicaldomain(f::Fun) = canonicaldomain(space(f))

##Evaluation

function evaluate(f::AbstractVector,S::Space,x...)
    csp=canonicalspace(S)
    if spacescompatible(csp,S)
        error("Override evaluate for " * string(typeof(csp)))
    else
        evaluate(coefficients(f,S,csp),csp,x...)
    end
end

evaluate(f::Fun,x) = evaluate(f.coefficients,f.space,x)
evaluate(f::Fun,x,y,z...) = evaluate(f.coefficients,f.space,Vec(x,y,z...))

(f::Fun)(x...) = evaluate(f,x...)

dynamic(f::Fun) = f # Fun's are already dynamic in that they compile by type

for (op,dop) in ((:first,:leftendpoint),(:last,:rightendpoint))
    @eval $op(f::Fun{S,T}) where {S,T} = f($dop(domain(f)))
end

## Extrapolation

# Default extrapolation is evaluation. Override this function for extrapolation enabled spaces.
extrapolate(f::AbstractVector,S::Space,x...) = evaluate(f,S,x...)

# Do not override these
extrapolate(f::Fun,x) = extrapolate(f.coefficients,f.space,x)
extrapolate(f::Fun,x,y,z...) = extrapolate(f.coefficients,f.space,Vec(x,y,z...))

##Data routines

values(f::Fun,dat...) = itransform(f.space,f.coefficients,dat...)
points(f::Fun) = points(f.space,ncoefficients(f))
ncoefficients(f::Fun) = length(f.coefficients)
blocksize(f::Fun) = (block(space(f),ncoefficients(f)).n[1],)

function stride(f::Fun)
    # Check only for stride 2 at the moment
    # as higher stride is very rare anyways
    M=maximum(abs,f.coefficients)
    for k=2:2:ncoefficients(f)
        if abs(f.coefficients[k])>40*M*eps()
            return 1
        end
    end

    2
end

## Manipulate length

pad!(f::Fun,n::Integer) = (pad!(f.coefficients,n);f)
pad(f::Fun,n::Integer) = Fun(f.space,pad(f.coefficients,n))

function chop!(sp::UnivariateSpace,cfs,tol::Real)
    n=standardchoplength(cfs,tol)
    resize!(cfs,n)
    cfs
end

chop!(sp::Space,cfs,tol::Real) = chop!(cfs,maximum(abs,cfs)*tol)
chop!(sp::Space,cfs) = chop!(sp,cfs,10eps())

function chop!(f::Fun,tol...)
    chop!(space(f),f.coefficients,tol...)
    f
end

chop(f::Fun,tol) = chop!(Fun(f.space,copy(f.coefficients)),tol)
chop(f::Fun) = chop!(Fun(f.space,copy(f.coefficients)))

copy(f::Fun) = Fun(space(f),copy(f.coefficients))

## Addition and multiplication

for op in (:+,:-)
    @eval begin
        function $op(f::Fun,g::Fun)
            if spacescompatible(f,g)
                n = max(ncoefficients(f),ncoefficients(g))
                f2 = pad(f,n); g2 = pad(g,n)

                Fun(isambiguous(domain(f)) ? g.space : f.space,($op)(f2.coefficients,g2.coefficients))
            else
                m=union(f.space,g.space)
                if isa(m,NoSpace)
                    error("Cannot "*string($op)*" because no space is the union of "*string(typeof(f.space))*" and "*string(typeof(g.space)))
                end
                $op(Fun(f,m),Fun(g,m)) # convert to same space
            end
        end
        $op(f::Fun{S,T},c::T) where {S,T<:Number} = c==0 ? f : $op(f,Fun(c))
        $op(f::Fun,c::Number) = $op(f,Fun(c))
        $op(f::Fun,c::UniformScaling) = $op(f,c.λ)
        $op(c::UniformScaling,f::Fun) = $op(c.λ,f)
    end
end

# equivalent to Y+=a*X
axpy!(a,X::Fun,Y::Fun)=axpy!(a,coefficients(X,space(Y)),Y)
function axpy!(a,xcfs::AbstractVector,Y::Fun)
    if a!=0
        n=ncoefficients(Y); m=length(xcfs)

        if n≤m
            resize!(Y.coefficients,m)
            for k=1:n
                @inbounds Y.coefficients[k]+=a*xcfs[k]
            end
            for k=n+1:m
                @inbounds Y.coefficients[k]=a*xcfs[k]
            end
        else #X is smaller
            for k=1:m
                @inbounds Y.coefficients[k]+=a*xcfs[k]
            end
        end
    end

    Y
end

-(f::Fun) = Fun(f.space,-f.coefficients)
-(c::Number,f::Fun) = -(f-c)

for op = (:*,:/)
    @eval $op(f::Fun, c::Number) = Fun(f.space,$op(f.coefficients,c))
end

for op = (:*,:+)
    @eval $op(c::Number, f::Fun) = $op(f,c)
end

\(c::Number, f::Fun) = Fun(f.space, c \ f.coefficients)

function intpow(f::Fun,k::Integer)
    if k == 0
        ones(space(f))
    elseif k==1
        f
    elseif k > 1
        f*f^(k-1)
    else
        1/f^(-k)
    end
end

^(f::Fun, k::Integer) = intpow(f,k)

inv(f::Fun) = 1/f

# Integrals over two Funs, which are fast with the orthogonal weight.

export bilinearform, linebilinearform, innerproduct, lineinnerproduct

# Having fallbacks allow for the fast implementations.

defaultbilinearform(f::Fun,g::Fun)=sum(f*g)
defaultlinebilinearform(f::Fun,g::Fun)=linesum(f*g)

bilinearform(f::Fun,g::Fun)=defaultbilinearform(f,g)
bilinearform(c::Number,g::Fun)=sum(c*g)
bilinearform(g::Fun,c::Number)=sum(g*c)

linebilinearform(f::Fun,g::Fun)=defaultbilinearform(f,g)
linebilinearform(c::Number,g::Fun)=linesum(c*g)
linebilinearform(g::Fun,c::Number)=linesum(g*c)

# Conjugations

innerproduct(f::Fun,g::Fun)=bilinearform(conj(f),g)
innerproduct(c::Number,g::Fun)=bilinearform(conj(c),g)
innerproduct(g::Fun,c::Number)=bilinearform(conj(g),c)

lineinnerproduct(f::Fun,g::Fun)=linebilinearform(conj(f),g)
lineinnerproduct(c::Number,g::Fun)=linebilinearform(conj(c),g)
lineinnerproduct(g::Fun,c::Number)=linebilinearform(conj(g),c)

## Norm

for (OP,SUM) in ((:(norm),:(sum)),(:linenorm,:linesum))
    @eval begin
        $OP(f::Fun) = $OP(f,2)

        function $OP(f::Fun{S},p::Real) where S<:Space{D,R} where {D,R<:Number}
            if p < 1
                return error("p should be 1 ≤ p ≤ ∞")
            elseif 1 ≤ p < Inf
                return abs($SUM(abs2(f)^(p/2)))^(1/p)
            else
                return maximum(abs,f)
            end
        end

        function $OP(f::Fun{S},p::Int) where S<:Space{D,R} where {D,R<:Number}
            if 1 ≤ p < Inf
                return iseven(p) ? abs($SUM(abs2(f)^(p÷2)))^(1/p) : abs($SUM(abs2(f)^(p/2)))^(1/p)
            else
                return error("p should be 1 ≤ p ≤ ∞")
            end
        end
    end
end

## Mapped functions

transpose(f::Fun) = f  # default no-op

for op = (:(real),:(imag),:(conj))
    @eval ($op)(f::Fun{S}) where {S<:RealSpace} = Fun(f.space,($op)(f.coefficients))
end

conj(f::Fun) = error("Override conj for $(typeof(f))")

abs2(f::Fun{S,T}) where {S<:RealSpace,T<:Real} = f^2
abs2(f::Fun{S,T}) where {S<:RealSpace,T<:Complex} = real(f)^2+imag(f)^2
abs2(f::Fun)=f*conj(f)

##  integration

function cumsum(f::Fun)
    cf = integrate(f)
    cf - first(cf)
end

cumsum(f::Fun,d::Domain)=cumsum(Fun(f,d))
cumsum(f::Fun,d)=cumsum(f,Domain(d))

function differentiate(f::Fun,k::Integer)
    @assert k >= 0
    (k==0) ? f : differentiate(differentiate(f),k-1)
end

# use conj(transpose(f)) for ArraySpace
adjoint(f::Fun) = differentiate(f)

==(f::Fun,g::Fun) =  (f.coefficients == g.coefficients && f.space == g.space)

coefficientnorm(f::Fun,p::Real=2) = norm(f.coefficients,p)

Base.rtoldefault(::Type{F}) where {F<:Fun} = Base.rtoldefault(cfstype(F))
Base.rtoldefault(x::Union{T,Type{T}}, y::Union{S,Type{S}}, atol) where {T<:Fun,S<:Fun} =
    Base.rtoldefault(cfstype(x),cfstype(y), atol)

Base.rtoldefault(x::Union{T,Type{T}}, y::Union{S,Type{S}}, atol) where {T<:Number,S<:Fun} =
    Base.rtoldefault(cfstype(x),cfstype(y), atol)
Base.rtoldefault(x::Union{T,Type{T}}, y::Union{S,Type{S}}, atol) where {T<:Fun,S<:Number} =
    Base.rtoldefault(cfstype(x),cfstype(y), atol)

function isapprox(f::Fun{S1,T},g::Fun{S2,S};rtol::Real=Base.rtoldefault(T,S,0), atol::Real=0, norm::Function=coefficientnorm) where {S1,S2,T,S}
    if spacescompatible(f,g)
        d = norm(f - g)
        if isfinite(d)
            return d <= atol + rtol*max(norm(f), norm(g))
        else
            # Fall back to a component-wise approximate comparison
            return false
        end
    else
        sp=union(f.space,g.space)
        if isa(sp,NoSpace)
            false
        else
            isapprox(Fun(f,sp),Fun(g,sp);rtol=rtol,atol=atol,norm=norm)
        end
    end
end

isapprox(f::Fun, g::Number) = f ≈ g*ones(space(f))
isapprox(g::Number, f::Fun) = g*ones(space(f)) ≈ f

isreal(f::Fun{<:RealSpace,<:Real}) = true
isreal(f::Fun) = false

iszero(x::Number) = x == 0
iszero(f::Fun)    = all(iszero,f.coefficients)

# sum, integrate, and idfferentiate are in CalculusOperator

function reverseorientation(f::Fun)
    csp=canonicalspace(f)
    if spacescompatible(csp,space(f))
        error("Implement reverseorientation for $(typeof(f))")
    else
        reverseorientation(Fun(f,csp))
    end
end

## non-vector notation

for op in (:+,:-,:*,:/,:^)
    @eval begin
        broadcast(::typeof($op), a::Fun, b::Fun) = $op(a,b)
        broadcast(::typeof($op), a::Fun, b::Number) = $op(a,b)
        broadcast(::typeof($op), a::Number, b::Fun) = $op(a,b)
    end
end

## broadcasting
# for broadcasting, we support broadcasting over `Fun`s, e.g.
#
#       exp.(f) is equivalent to Fun(x->exp(f(x)),domain(f)),
#       exp.(f .+ g) is equivalent to Fun(x->exp(f(x)+g(x)),domain(f) ∪ domain(g)),
#       exp.(f .+ 2) is equivalent to Fun(x->exp(f(x)+2),domain(f)),
#
# When we are broadcasting over arrays and scalar Fun's together,
# it broadcasts over the Array and treats the scalar Fun's as constants, so will not
# necessarily call the constructor:
#
#       exp.( x .+ [1,2,3]) is equivalent to [exp(x + 1),exp(x+2),exp(x+3)]
#
# When broadcasting over Fun's with array values, it treats them like Fun's:
#
#   exp.( [x;x]) throws an error as it is equivalent to Fun(x->exp([x;x](x)),domain(f))
#
# This is consistent with the deprecation thrown by exp.([[1,2],[3,4]). Note that
#
#   exp.( [x,x]) is equivalent to [exp(x),exp(x)]
#
# does not throw the same error. When array values are mixed with arrays, the Array
# takes presidence:
#
#   exp.([x;x] .+ [x,x]) is equivalent to exp.(Array([x;x]) .+ [x,x])
#
# This presidence is picked by the `promote_containertype` overrides.

struct FunStyle <: BroadcastStyle end

BroadcastStyle(::Type{<:Fun}) = FunStyle()

BroadcastStyle(::FunStyle, ::FunStyle) = FunStyle()
BroadcastStyle(::AbstractArrayStyle{0}, ::FunStyle) = FunStyle()
BroadcastStyle(::FunStyle, ::AbstractArrayStyle{0}) = FunStyle()
BroadcastStyle(A::AbstractArrayStyle, ::FunStyle) = A
BroadcastStyle(::FunStyle, A::AbstractArrayStyle) = A

# Treat Array Fun's like Arrays when broadcasting with an Array
# note this only gets called when containertype returns Array,
# so will not be used when no argument is an Array
Base.broadcast_axes(::Type{Fun}, A) = axes(A)
Base.broadcastable(x::Fun) = x

broadcastdomain(b) = AnyDomain()
broadcastdomain(b::Fun) = domain(b)
broadcastdomain(b::Broadcasted) = mapreduce(broadcastdomain, ∪, b.args)

broadcasteval(f::Function, x) = f(x)
broadcasteval(c, x) = c
broadcasteval(c::Ref, x) = c.x
broadcasteval(b::Broadcasted, x) = b.f(broadcasteval.(b.args, x)...)

# TODO: use generated function to improve the following
function copy(bc::Broadcasted{FunStyle})
    d = broadcastdomain(bc)
    Fun(x -> broadcasteval(bc, x), d)
end

function copyto!(dest::Fun, bc::Broadcasted{FunStyle})
    if broadcastdomain(bc) ≠ domain(dest)
        throw(ArgumentError("Domain of right-hand side incompatible with destination"))
    end
    ret = copy(bc)
    cfs = coefficients(ret,space(dest))
    resize!(dest.coefficients, length(cfs))
    dest.coefficients[:] = cfs
    dest
end

include("constructors.jl")


text:
struct NestedParticleFilter
    jittering_width::Int
end

struct NestedParticleState{T1, T2}
    state::T1
    model::T2
end

function NestedParticleState(
    m_out::Int, m_in::Int,
    my_Nrng, my_prng, my_qrng, my_σrng, my_τrng
)
    model = BinomialGridModel(m_out, my_Nrng, my_prng, my_qrng, my_σrng, my_τrng)
    n     = repeat(model.N, 1, m_in)
    k     = CUDA.zeros(Int, m_out, m_in)
    state = BinomialState(n, k)
    propagate!(state, model, 0f0)
    return NestedParticleState(state, model)
end

function update!(
    filterstate::NestedParticleState,
    observation::BinomialObservation,
    filter::NestedParticleFilter
)
    state = filterstate.state
    model = filterstate.model

    jitter!(model, filter.jittering_width)
    propagate!(state, model, observation.dt)
    u = likelihood_resample!(state, model, observation)
    outer_resample!(state, model, u)
    return filterstate
end


text:
module TestDoctest

using Documenter
using Reagents

test() = doctest(Reagents; manual = false)

end  # module


text:
_split_line(line) = filter(x->x!="", split(line, [' ', '-']))
_parse_int(i) =  try parse(Int, i) catch ArgumentError
    parse(Int, replace(i, ".00"=>"")) end
_parse_line(line) = map(n->_parse_int(n), _split_line(line))
_find_end(lines) = try first(findall(l->strip(l)=="END OF BENCHMARK", lines)) - 1
        catch BoundsError length(lines) end

function extract_block(data; header=true)::Group
    if header
        useless_number = popat!(data, 1)
        @assert length(useless_number) == 1
    end
    extracted = Group()
    while length(data) > 0 && length(first(data)) > 1
        push!(extracted, Item(popat!(data, 1)))
    end
    extracted
end

function extract_fl_block(data, n_items::Int)::Group
    extracted = Group()
    for _ in 1:n_items
        push!(extracted, Item(popat!(data, 1)))
    end
    extracted
end

function load_catA(path)
    lines = readlines(open(path))
    end_index = _find_end(lines)
    file = map(_parse_line, lines[2:end_index]) #skip first empty line
    file = filter(l->!isempty(l), file) #remove any empty lines
    header_row = popat!(file, 1)
    resource_limits = popat!(file, 1)

    blocks = []
    while length(file) > 0
        push!(blocks, extract_block(file))
    end

    MMKP_Data(resource_limits, blocks)
end

const load_catB = load_catA

function load_catC(path)
    lines = readlines(open(path))
    file = map(_parse_line, lines)
    file = filter(l->!isempty(l), file)
    amount_of_groups = popat!(file, 1)
    amount_of_resources = popat!(file, 1)
    resource_limits = popat!(file, 1)
    max_items_per_group = popat!(file, 1)

    blocks = []
    push!(blocks, extract_block(file, header=false))
    while length(file) > 0
        push!(blocks, extract_block(file))
    end

    MMKP_Data(resource_limits, blocks)
end

function load_catD(path)
    lines = readlines(open(path))
    file = map(_parse_line, lines)
    file = filter(l->!isempty(l), file)
    file
    number_of_blocks, number_of_rows_per_block, number_of_items = popat!(file, 1)
    resource_limits = popat!(file, 1)
    file

    blocks = Vector{Group}()
    for _ in 1:number_of_blocks
        push!(blocks, extract_fl_block(file, number_of_rows_per_block))
    end

    typeof(resource_limits)
    typeof(blocks)
    MMKP_Data(resource_limits, blocks)
end

folder_keys = [
	"Class A"=>load_catA,
	"Class B"=>load_catB,
	"Class C"=>load_catC,
	"Class D"=>load_catD
]

max_stars_repo_name: Dibillilia/JuliaOptHeuristics

max_issues_repo_name: Dibillilia/JuliaOptHeuristics

max_forks_repo_name: Dibillilia/JuliaOptHeuristics


text:
gauss_lowpass(x, λc)  = exp(-π*((√(log(2)/π)*λc)/x)^2)
gauss_highpass(x, λc) = 1-gauss_lowpass(x, λc)

"""
    separatefeatures(frequencies, rate; filterwavelengths=[2.5, 250, 2500])

Filter frequencies for roughness-, waviness- and form-components. `rate`(points/mm) is needed to convert `filterwavelengths`(μm) to corresponding filter bins.
"""
function separatefeatures(profile::SurfaceProfile; filterwavelengths=[profile.λs, profile.λc, profile.λf])
    frequencies = dct(profile.data)
    bins = length(frequencies)
    N = 1 / profile.resolution / 2 # maximal spatial frequency (points/mm)
    filterbins = 1 ./ (filterwavelengths*1e-3) / (N/bins)

    weights(b1, b2) = gauss_highpass.(1:bins, b1) .* gauss_lowpass.(1:bins, b2)

    res = Array{Array{Float64, 1}, 1}(length(filterwavelengths))
    for i in 1:length(filterwavelengths)
        b1 = filterbins[i]
        b2 = i == length(filterwavelengths) ? 0 : filterbins[i+1]
        res[i] = frequencies .* weights(b1, b2)
    end
    return res
end


text:
function _fundamental(func::String, symbol::String; client = GLOBAL[], outputsize::String="compact", datatype::Union{String, Nothing}=nothing, parser = "default")
    @argcheck in(datatype, ["json", "csv", nothing])
    params = Dict(
        "function"=>func,
        "symbol"=>symbol,
        "outputsize"=>outputsize,
        "datatype"=>datatype,
        "apikey"=>key(client)
    )
    uri = _build_uri(client.scheme, client.host, "query", params)
    data = retry(_get_request, delays=Base.ExponentialBackOff(n=3, first_delay=5, max_delay=1000))(uri)
    p = _parser(parser, datatype)
    return p(data)
end

company_overview(symbol::String; kwargs...) = _fundamental("OVERVIEW", symbol::String; kwargs...)
income_statement(symbol::String; kwargs...) = _fundamental("INCOME_STATEMENT", symbol::String; kwargs...)
balance_sheet(symbol::String; kwargs...) = _fundamental("BALANCE_SHEET", symbol::String; kwargs...)
cash_flow(symbol::String; kwargs...) = _fundamental("CASH_FLOW", symbol::String; kwargs...)
earnings(symbol::String; kwargs...) = _fundamental("EARNINGS", symbol::String; kwargs...)

# Listing Status (https://www.alphavantage.co/documentation/#listing-status)
# ex: https://www.alphavantage.co/query?function=LISTING_STATUS&apikey=demo
function listing_status(; client = GLOBAL[], date = nothing, state = nothing, parser = "default")
    query = ""
    if !isnothing(state)
        @argcheck in(state, ["active", "delisted"])
        query *= "&state=$state"
    end
    !isnothing(date) && (query *= "&date=$date")

    params = Dict(
        "function"=>"LISTING_STATUS",
        "date"=>date,
        "state"=>state,
        "apikey"=>key(client)
    )
    uri = _build_uri(client.scheme, client.host, "query", params)
    data = retry(_get_request, delays=Base.ExponentialBackOff(n=3, first_delay=5, max_delay=1000))(uri)
    p = _parser(parser, "csv")
    return p(data)
end

for (timeframe, f, value, dateKey) in FUNDAMENTAL_VALUES

    timeframeF = replace(timeframe, "Report"=>"")
    timeframeF = replace(timeframeF, "Earnings"=>"")
    fname = Symbol(value * "_" * timeframeF)
    fS = Symbol(f)
    @eval begin
        function $fname(symbol::String; kwargs...)
            data = $fS(symbol; kwargs...)
            dts = get.(data[$timeframe], $dateKey, "")
            vals = get.(data[$timeframe], $value, "")
            Dict(:Date => dts, Symbol($value)=>vals)
        end
        export $fname
    end
 end

function earnings_calendar(horizon::Int64; client=GLOBAL[], parser = "default")
    params = Dict(
         "function"=>"EARNINGS_CALENDAR",
         "horizon"=>"$(horizon)month",
         "apikey"=>key(client)
    )
    uri = _build_uri(client.scheme, client.host, "query", params)
    data = retry(_get_request, delays=Base.ExponentialBackOff(n=3, first_delay=4, max_delay=1000))(uri)
    p = _parser(parser, "csv")
    return p(data)
end

function ipo_calendar(; client = GLOBAL[], parser = "default")
    params = Dict(
        "function"=>"IPO_CALENDAR",
        "apikey"=>key(client)
    )
    uri = _build_uri(client.scheme, client.host, "query", params)
    data = retry(_get_request, delays=Base.ExponentialBackOff(n=3, first_delay=4, max_delay=1000))(uri)
    p = _parser(parser, "csv")
    return p(data)
end


text:
@testset "weak scatterers" begin

    # angular frequencies
    ωs = [0.001,20.]
    # ωs = [20.] # use only one frequency to speed up test

    # tolerance
    tol = 1e-5;
    basis_order = 2;

    # background medium
    medium = Acoustic(2; ρ=1.0, c=1.0)
    ms = MultipleScattering

    p1 = Particle(Acoustic(2; ρ=10.0, c=12.),ms.Circle(0.01))
    p2 = Particle(Acoustic(2; ρ=3.0, c=2.0),ms.Circle(0.2))

    species = [
        Specie(p1; volume_fraction=0.03),
        Specie(p2; volume_fraction=0.04)
    ]

    # wavenumbers
    eff_medium = effective_medium(medium, species)

    k_eff_lows = ωs./eff_medium.c
    k_eff_φs = wavenumber_low_volumefraction(ωs, medium, species; basis_order = basis_order)

    k_effs_arr = [
        wavenumbers(ω, medium, species;
            num_wavenumbers=1, tol = tol, basis_order = basis_order)
    for ω in ωs]

    inds = [argmin(abs.(k_effs_arr[i] .- k_eff_φs[i])) for i in eachindex(ωs)]
    k_effs = [k_effs_arr[i][inds[i]] for i in eachindex(inds)]

    # k_effs =
    # 0.0010101407549128578 + 7.824113157942236e-13im
    # 20.207827596241156 + 0.11344062283733775im

    @test norm( (k_effs - k_eff_φs) ./ norm.(k_eff_φs) ) < 0.001
    @test norm( (k_effs - k_eff_lows) ./ norm.(k_eff_lows) ) < 0.01
    @test norm(k_effs[1] - k_eff_lows[1])/norm(k_effs[1]) < 1e-7

    normal = [-1.0,0.0] # an outward normal to the surface
    material = Material(Halfspace(normal),species)

    # define a plane wave source travelling at a 45 degree angle in relation to the material
    source = PlaneSource(medium, -normal)

    wave_effs_φs = [WaveMode(ωs[i], k_eff_φs[i], source, material; tol = tol) for i in eachindex(ωs)]

    # reflection coefficient
    Rs2 = reflection_coefficients(ωs, source, material; tol = tol, num_wavenumbers = 1, basis_order = basis_order)

    # if the wavenumber k_effs are already calculated, the below is faster
    # pairs each ω in ωs with each wave in wave_effs2 to calculate the refleciton coefficients
    Rs = map(eachindex(ωs)) do i
        w_effs = [
            WaveMode(ωs[i], k_eff, source, material; tol = tol, basis_order=basis_order)
        for k_eff in k_effs_arr[i]]
        reflection_coefficient(ωs[i], w_effs, source, material; tol = tol)
    end

    @test Rs ≈ Rs2 # same keywords should lead to the same reflection coefficient, except for numerically rounding

    Rs1 = map(eachindex(ωs)) do i
        w_eff = WaveMode(ωs[i], k_effs[i][1], source, material; tol = 1e-9)
        reflection_coefficient(ωs[i], w_eff, source, material)
    end

    # Direct incidence
    R_low = reflection_transmission_coefficients(ωs[1], source, eff_medium, material.shape)[1]
    Rs_φs = reflection_coefficients(ωs, wave_effs_φs, source, material; tol=1e-9)
    # the below takes a low-volfrac expansion for both the wavenumber and reflection coefficient
    Rs_φs2 = reflection_coefficient_low_volumefraction(ωs, source, material; basis_order = basis_order)

    @test maximum(abs.(Rs_φs - Rs1)) < 1e-4 # already relative to incident wave amplitude = 1
    @test maximum(abs.(Rs_φs2 - Rs1)) < 1e-3
    @test abs(R_low - Rs1[1]) < 1e-7

    # Vary angle of incidence θin. Beware of extreme angles θ ~= -pi/2 or pi/2.
    θs = (-π/2.1):0.3:(π/2.1)
    sources = [PlaneSource(medium, [cos(θ),sin(θ)]) for θ in θs]

    R_low = map(sources) do s
        reflection_transmission_coefficients(ωs[1], s, eff_medium, material.shape)[1]
    end

    Rs = map(sources) do s
        wave_effs_2 = [
            WaveMode(ωs[i], k_effs[i], s, material; tol = tol, basis_order = basis_order)
        for i in eachindex(ωs)]
        reflection_coefficients(ωs, wave_effs_2, s, material)
    end
    Rs_φs = [
        reflection_coefficient_low_volumefraction(ωs, s, material; basis_order = basis_order)
    for s in sources]

    len = length(ωs)

    @test maximum(abs(R_low[i] - Rs[i][1]) for i in eachindex(R_low)) < 1e-7
    @test maximum(norm(R)/len for R in (Rs_φs - Rs)[2:end-2]) < 5e-3
end

max_stars_repo_name: arturgower/EffectiveWaves


text:
using DexApiClients
using Test

include("testdex.jl")
@testset "Dex" begin
    test_all()
end


text:
"""
$(SIGNATURES)

Checks if upcoming integration is a new bit for GalileoE1B.
"""
function is_upcoming_integration_new_bit(galileo_e1b::GalileoE1B, prns, num_prns)
    num_prns < 8 && return false
    masked_bit_synchronizer = prns & 0xff # First 8 bits
    # Upcoming integration will be a new bit if masked_bit_synchronizer contains
    # 20 zeros and 20 ones or 20 ones and 20 zeros
    masked_bit_synchronizer == 0xf || masked_bit_synchronizer == 0xf0
end

# TODO: Very early very late correlator?
function get_default_correlator(galileo_e1b::GalileoE1B, num_ants::NumAnts{N}) where N
    EarlyPromptLateCorrelator(num_ants)
end


text:
module EndowmentScripts

const Nothing = Void #NOTE: 0.7 compatabiltiy hack, delete on ugrade

if  pwd() ∉ LOAD_PATH
  push!(LOAD_PATH,pwd())
end

using Endowment, CSV, DataFrames

const WORKERS=0

const CLEAN_WORKERS=false

#set up for parallel operations
initializePar(WORKERS, reset=CLEAN_WORKERS)

#a list of high-level functions to run at the script level
function endowmentTasks()::Nothing
  preProcessData(refreshData=false, validateDownloads=false,
    refreshMetadata = true, reserializeData = true)

  return nothing
end

@time endowmentTasks()

#cleanup the extra processes if desired
if CLEAN_WORKERS
  cleanup()
end
end

max_stars_repo_path: Test Case/Test Case/EndowmentScripts.jl

max_stars_repo_name: clintonTE/CCA

max_issues_repo_path: Test Case/Test Case/EndowmentScripts.jl

max_issues_repo_name: clintonTE/CCA

max_forks_repo_path: Test Case/Test Case/EndowmentScripts.jl

max_forks_repo_name: clintonTE/CCA


text:
using CmdStan, Turing, ContinuousBenchmarks

include(joinpath(ContinuousBenchmarks.STAN_DATA_DIR, "normal-mixture-stan.data.jl"))
include(joinpath(ContinuousBenchmarks.STAN_MODELS_DIR, "normal-mixture-stan.model.jl"))

stan_model_name = "normalmixture"
simplenormalmixturestan = Stanmodel(name=stan_model_name, model=simplenormalmixturemodel, nchains=1);

rc, nm_stan_sim = stan(simplenormalmixturestan, [Dict("N"=>100, "y"=>simplenormalmixturestandata[1]["y"][1:100])], CmdStanDir=ContinuousBenchmarks.CMDSTAN_HOME, summary=false)
# describe(nm_stan_sim)

nm_theta = nm_stan_sim[1:1000, ["theta"], :].value[:]
nm_mu_1 = nm_stan_sim[1:1000, ["mu.1"], :].value[:]
nm_mu_2 = nm_stan_sim[1:1000, ["mu.2"], :].value[:]
nm_time = get_stan_time(stan_model_name)