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

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

Indexes the search suggestions. For more information, see Configuring Suggesters in the
Amazon CloudSearch Developer Guide.

# Arguments
- `domain_name`:

"""
build_suggesters(DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("BuildSuggesters", Dict{String, Any}("DomainName"=>DomainName); aws_config=aws_config)
build_suggesters(DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("BuildSuggesters", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName), params)); aws_config=aws_config)

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

Creates a new search domain. For more information, see Creating a Search Domain in the
Amazon CloudSearch Developer Guide.

# Arguments
- `domain_name`: A name for the domain you are creating. Allowed characters are a-z
  (lower-case letters), 0-9, and hyphen (-). Domain names must start with a letter or number
  and be at least 3 and no more than 28 characters long.

"""
create_domain(DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("CreateDomain", Dict{String, Any}("DomainName"=>DomainName); aws_config=aws_config)
create_domain(DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("CreateDomain", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName), params)); aws_config=aws_config)

"""
    define_analysis_scheme(analysis_scheme, domain_name)
    define_analysis_scheme(analysis_scheme, domain_name, params::Dict{String,<:Any})

Configures an analysis scheme that can be applied to a text or text-array field to define
language-specific text processing options. For more information, see Configuring Analysis
Schemes in the Amazon CloudSearch Developer Guide.

# Arguments
- `analysis_scheme`:
- `domain_name`:

"""
define_analysis_scheme(AnalysisScheme, DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DefineAnalysisScheme", Dict{String, Any}("AnalysisScheme"=>AnalysisScheme, "DomainName"=>DomainName); aws_config=aws_config)
define_analysis_scheme(AnalysisScheme, DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DefineAnalysisScheme", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("AnalysisScheme"=>AnalysisScheme, "DomainName"=>DomainName), params)); aws_config=aws_config)

"""
    define_expression(domain_name, expression)
    define_expression(domain_name, expression, params::Dict{String,<:Any})

Configures an Expression for the search domain. Used to create new expressions and modify
existing ones. If the expression exists, the new configuration replaces the old one. For
more information, see Configuring Expressions in the Amazon CloudSearch Developer Guide.

# Arguments
- `domain_name`:
- `expression`:

"""
define_expression(DomainName, Expression; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DefineExpression", Dict{String, Any}("DomainName"=>DomainName, "Expression"=>Expression); aws_config=aws_config)
define_expression(DomainName, Expression, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DefineExpression", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "Expression"=>Expression), params)); aws_config=aws_config)

"""
    define_index_field(domain_name, index_field)
    define_index_field(domain_name, index_field, params::Dict{String,<:Any})

Configures an IndexField for the search domain. Used to create new fields and modify
existing ones. You must specify the name of the domain you are configuring and an index
field configuration. The index field configuration specifies a unique name, the index field
type, and the options you want to configure for the field. The options you can specify
depend on the IndexFieldType. If the field exists, the new configuration replaces the old
one. For more information, see Configuring Index Fields in the Amazon CloudSearch Developer
Guide.

# Arguments
- `domain_name`:
- `index_field`: The index field and field options you want to configure.

"""
define_index_field(DomainName, IndexField; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DefineIndexField", Dict{String, Any}("DomainName"=>DomainName, "IndexField"=>IndexField); aws_config=aws_config)
define_index_field(DomainName, IndexField, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DefineIndexField", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "IndexField"=>IndexField), params)); aws_config=aws_config)

"""
    define_suggester(domain_name, suggester)
    define_suggester(domain_name, suggester, params::Dict{String,<:Any})

Configures a suggester for a domain. A suggester enables you to display possible matches
before users finish typing their queries. When you configure a suggester, you must specify
the name of the text field you want to search for possible matches and a unique name for
the suggester. For more information, see Getting Search Suggestions in the Amazon
CloudSearch Developer Guide.

# Arguments
- `domain_name`:
- `suggester`:

"""
define_suggester(DomainName, Suggester; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DefineSuggester", Dict{String, Any}("DomainName"=>DomainName, "Suggester"=>Suggester); aws_config=aws_config)
define_suggester(DomainName, Suggester, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DefineSuggester", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "Suggester"=>Suggester), params)); aws_config=aws_config)

"""
    delete_analysis_scheme(analysis_scheme_name, domain_name)
    delete_analysis_scheme(analysis_scheme_name, domain_name, params::Dict{String,<:Any})

Deletes an analysis scheme. For more information, see Configuring Analysis Schemes in the
Amazon CloudSearch Developer Guide.

# Arguments
- `analysis_scheme_name`: The name of the analysis scheme you want to delete.
- `domain_name`:

"""
delete_analysis_scheme(AnalysisSchemeName, DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DeleteAnalysisScheme", Dict{String, Any}("AnalysisSchemeName"=>AnalysisSchemeName, "DomainName"=>DomainName); aws_config=aws_config)
delete_analysis_scheme(AnalysisSchemeName, DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DeleteAnalysisScheme", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("AnalysisSchemeName"=>AnalysisSchemeName, "DomainName"=>DomainName), params)); aws_config=aws_config)

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

Permanently deletes a search domain and all of its data. Once a domain has been deleted, it
cannot be recovered. For more information, see Deleting a Search Domain in the Amazon
CloudSearch Developer Guide.

# Arguments
- `domain_name`: The name of the domain you want to permanently delete.

"""
delete_domain(DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DeleteDomain", Dict{String, Any}("DomainName"=>DomainName); aws_config=aws_config)
delete_domain(DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DeleteDomain", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName), params)); aws_config=aws_config)

"""
    delete_expression(domain_name, expression_name)
    delete_expression(domain_name, expression_name, params::Dict{String,<:Any})

Removes an Expression from the search domain. For more information, see Configuring
Expressions in the Amazon CloudSearch Developer Guide.

# Arguments
- `domain_name`:
- `expression_name`: The name of the Expression to delete.

"""
delete_expression(DomainName, ExpressionName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DeleteExpression", Dict{String, Any}("DomainName"=>DomainName, "ExpressionName"=>ExpressionName); aws_config=aws_config)
delete_expression(DomainName, ExpressionName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DeleteExpression", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "ExpressionName"=>ExpressionName), params)); aws_config=aws_config)

"""
    delete_index_field(domain_name, index_field_name)
    delete_index_field(domain_name, index_field_name, params::Dict{String,<:Any})

Removes an IndexField from the search domain. For more information, see Configuring Index
Fields in the Amazon CloudSearch Developer Guide.

# Arguments
- `domain_name`:
- `index_field_name`: The name of the index field your want to remove from the domain's
  indexing options.

"""
delete_index_field(DomainName, IndexFieldName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DeleteIndexField", Dict{String, Any}("DomainName"=>DomainName, "IndexFieldName"=>IndexFieldName); aws_config=aws_config)
delete_index_field(DomainName, IndexFieldName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DeleteIndexField", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "IndexFieldName"=>IndexFieldName), params)); aws_config=aws_config)

"""
    delete_suggester(domain_name, suggester_name)
    delete_suggester(domain_name, suggester_name, params::Dict{String,<:Any})

Deletes a suggester. For more information, see Getting Search Suggestions in the Amazon
CloudSearch Developer Guide.

# Arguments
- `domain_name`:
- `suggester_name`: Specifies the name of the suggester you want to delete.

"""
delete_suggester(DomainName, SuggesterName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DeleteSuggester", Dict{String, Any}("DomainName"=>DomainName, "SuggesterName"=>SuggesterName); aws_config=aws_config)
delete_suggester(DomainName, SuggesterName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DeleteSuggester", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "SuggesterName"=>SuggesterName), params)); aws_config=aws_config)

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

Gets the analysis schemes configured for a domain. An analysis scheme defines
language-specific text processing options for a text field. Can be limited to specific
analysis schemes by name. By default, shows all analysis schemes and includes any pending
changes to the configuration. Set the Deployed option to true to show the active
configuration and exclude pending changes. For more information, see Configuring Analysis
Schemes in the Amazon CloudSearch Developer Guide.

# Arguments
- `domain_name`: The name of the domain you want to describe.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"AnalysisSchemeNames"`: The analysis schemes you want to describe.
- `"Deployed"`: Whether to display the deployed configuration (true) or include any pending
  changes (false). Defaults to false.
"""
describe_analysis_schemes(DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeAnalysisSchemes", Dict{String, Any}("DomainName"=>DomainName); aws_config=aws_config)
describe_analysis_schemes(DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeAnalysisSchemes", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName), params)); aws_config=aws_config)

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

Gets the availability options configured for a domain. By default, shows the configuration
with any pending changes. Set the Deployed option to true to show the active configuration
and exclude pending changes. For more information, see Configuring Availability Options in
the Amazon CloudSearch Developer Guide.

# Arguments
- `domain_name`: The name of the domain you want to describe.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Deployed"`: Whether to display the deployed configuration (true) or include any pending
  changes (false). Defaults to false.
"""
describe_availability_options(DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeAvailabilityOptions", Dict{String, Any}("DomainName"=>DomainName); aws_config=aws_config)
describe_availability_options(DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeAvailabilityOptions", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName), params)); aws_config=aws_config)

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

Returns the domain's endpoint options, specifically whether all requests to the domain must
arrive over HTTPS. For more information, see Configuring Domain Endpoint Options in the
Amazon CloudSearch Developer Guide.

# Arguments
- `domain_name`: A string that represents the name of a domain.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Deployed"`: Whether to retrieve the latest configuration (which might be in a
  Processing state) or the current, active configuration. Defaults to false.
"""
describe_domain_endpoint_options(DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeDomainEndpointOptions", Dict{String, Any}("DomainName"=>DomainName); aws_config=aws_config)
describe_domain_endpoint_options(DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeDomainEndpointOptions", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName), params)); aws_config=aws_config)

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

Gets information about the search domains owned by this account. Can be limited to specific
domains. Shows all domains by default. To get the number of searchable documents in a
domain, use the console or submit a matchall request to your domain's search endpoint:
q=matchall&amp;q.parser=structured&amp;size=0. For more information, see Getting
Information about a Search Domain in the Amazon CloudSearch Developer Guide.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DomainNames"`: The names of the domains you want to include in the response.
"""
describe_domains(; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeDomains"; aws_config=aws_config)
describe_domains(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeDomains", params; aws_config=aws_config)

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

Gets the expressions configured for the search domain. Can be limited to specific
expressions by name. By default, shows all expressions and includes any pending changes to
the configuration. Set the Deployed option to true to show the active configuration and
exclude pending changes. For more information, see Configuring Expressions in the Amazon
CloudSearch Developer Guide.

# Arguments
- `domain_name`: The name of the domain you want to describe.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Deployed"`: Whether to display the deployed configuration (true) or include any pending
  changes (false). Defaults to false.
- `"ExpressionNames"`: Limits the DescribeExpressions response to the specified
  expressions. If not specified, all expressions are shown.
"""
describe_expressions(DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeExpressions", Dict{String, Any}("DomainName"=>DomainName); aws_config=aws_config)
describe_expressions(DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeExpressions", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName), params)); aws_config=aws_config)

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

Gets information about the index fields configured for the search domain. Can be limited to
specific fields by name. By default, shows all fields and includes any pending changes to
the configuration. Set the Deployed option to true to show the active configuration and
exclude pending changes. For more information, see Getting Domain Information in the Amazon
CloudSearch Developer Guide.

# Arguments
- `domain_name`: The name of the domain you want to describe.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Deployed"`: Whether to display the deployed configuration (true) or include any pending
  changes (false). Defaults to false.
- `"FieldNames"`: A list of the index fields you want to describe. If not specified,
  information is returned for all configured index fields.
"""
describe_index_fields(DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeIndexFields", Dict{String, Any}("DomainName"=>DomainName); aws_config=aws_config)
describe_index_fields(DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeIndexFields", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName), params)); aws_config=aws_config)

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

Gets the scaling parameters configured for a domain. A domain's scaling parameters specify
the desired search instance type and replication count. For more information, see
Configuring Scaling Options in the Amazon CloudSearch Developer Guide.

# Arguments
- `domain_name`:

"""
describe_scaling_parameters(DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeScalingParameters", Dict{String, Any}("DomainName"=>DomainName); aws_config=aws_config)
describe_scaling_parameters(DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeScalingParameters", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName), params)); aws_config=aws_config)

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

Gets information about the access policies that control access to the domain's document and
search endpoints. By default, shows the configuration with any pending changes. Set the
Deployed option to true to show the active configuration and exclude pending changes. For
more information, see Configuring Access for a Search Domain in the Amazon CloudSearch
Developer Guide.

# Arguments
- `domain_name`: The name of the domain you want to describe.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Deployed"`: Whether to display the deployed configuration (true) or include any pending
  changes (false). Defaults to false.
"""
describe_service_access_policies(DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeServiceAccessPolicies", Dict{String, Any}("DomainName"=>DomainName); aws_config=aws_config)
describe_service_access_policies(DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeServiceAccessPolicies", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName), params)); aws_config=aws_config)

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

Gets the suggesters configured for a domain. A suggester enables you to display possible
matches before users finish typing their queries. Can be limited to specific suggesters by
name. By default, shows all suggesters and includes any pending changes to the
configuration. Set the Deployed option to true to show the active configuration and exclude
pending changes. For more information, see Getting Search Suggestions in the Amazon
CloudSearch Developer Guide.

# Arguments
- `domain_name`: The name of the domain you want to describe.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Deployed"`: Whether to display the deployed configuration (true) or include any pending
  changes (false). Defaults to false.
- `"SuggesterNames"`: The suggesters you want to describe.
"""
describe_suggesters(DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeSuggesters", Dict{String, Any}("DomainName"=>DomainName); aws_config=aws_config)
describe_suggesters(DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("DescribeSuggesters", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName), params)); aws_config=aws_config)

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

Tells the search domain to start indexing its documents using the latest indexing options.
This operation must be invoked to activate options whose OptionStatus is
RequiresIndexDocuments.

# Arguments
- `domain_name`:

"""
index_documents(DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("IndexDocuments", Dict{String, Any}("DomainName"=>DomainName); aws_config=aws_config)
index_documents(DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("IndexDocuments", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName), params)); aws_config=aws_config)

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

Lists all search domains owned by an account.

"""
list_domain_names(; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("ListDomainNames"; aws_config=aws_config)
list_domain_names(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("ListDomainNames", params; aws_config=aws_config)

"""
    update_availability_options(domain_name, multi_az)
    update_availability_options(domain_name, multi_az, params::Dict{String,<:Any})

Configures the availability options for a domain. Enabling the Multi-AZ option expands an
Amazon CloudSearch domain to an additional Availability Zone in the same Region to increase
fault tolerance in the event of a service disruption. Changes to the Multi-AZ option can
take about half an hour to become active. For more information, see Configuring
Availability Options in the Amazon CloudSearch Developer Guide.

# Arguments
- `domain_name`:
- `multi_az`: You expand an existing search domain to a second Availability Zone by setting
  the Multi-AZ option to true. Similarly, you can turn off the Multi-AZ option to downgrade
  the domain to a single Availability Zone by setting the Multi-AZ option to false.

"""
update_availability_options(DomainName, MultiAZ; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("UpdateAvailabilityOptions", Dict{String, Any}("DomainName"=>DomainName, "MultiAZ"=>MultiAZ); aws_config=aws_config)
update_availability_options(DomainName, MultiAZ, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("UpdateAvailabilityOptions", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "MultiAZ"=>MultiAZ), params)); aws_config=aws_config)

"""
    update_domain_endpoint_options(domain_endpoint_options, domain_name)
    update_domain_endpoint_options(domain_endpoint_options, domain_name, params::Dict{String,<:Any})

Updates the domain's endpoint options, specifically whether all requests to the domain must
arrive over HTTPS. For more information, see Configuring Domain Endpoint Options in the
Amazon CloudSearch Developer Guide.

# Arguments
- `domain_endpoint_options`: Whether to require that all requests to the domain arrive over
  HTTPS. We recommend Policy-Min-TLS-1-2-2019-07 for TLSSecurityPolicy. For compatibility
  with older clients, the default is Policy-Min-TLS-1-0-2019-07.
- `domain_name`: A string that represents the name of a domain.

"""
update_domain_endpoint_options(DomainEndpointOptions, DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("UpdateDomainEndpointOptions", Dict{String, Any}("DomainEndpointOptions"=>DomainEndpointOptions, "DomainName"=>DomainName); aws_config=aws_config)
update_domain_endpoint_options(DomainEndpointOptions, DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("UpdateDomainEndpointOptions", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainEndpointOptions"=>DomainEndpointOptions, "DomainName"=>DomainName), params)); aws_config=aws_config)

"""
    update_scaling_parameters(domain_name, scaling_parameters)
    update_scaling_parameters(domain_name, scaling_parameters, params::Dict{String,<:Any})

Configures scaling parameters for a domain. A domain's scaling parameters specify the
desired search instance type and replication count. Amazon CloudSearch will still
automatically scale your domain based on the volume of data and traffic, but not below the
desired instance type and replication count. If the Multi-AZ option is enabled, these
values control the resources used per Availability Zone. For more information, see
Configuring Scaling Options in the Amazon CloudSearch Developer Guide.

# Arguments
- `domain_name`:
- `scaling_parameters`:

"""
update_scaling_parameters(DomainName, ScalingParameters; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("UpdateScalingParameters", Dict{String, Any}("DomainName"=>DomainName, "ScalingParameters"=>ScalingParameters); aws_config=aws_config)
update_scaling_parameters(DomainName, ScalingParameters, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("UpdateScalingParameters", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "ScalingParameters"=>ScalingParameters), params)); aws_config=aws_config)

"""
    update_service_access_policies(access_policies, domain_name)
    update_service_access_policies(access_policies, domain_name, params::Dict{String,<:Any})

Configures the access rules that control access to the domain's document and search
endpoints. For more information, see  Configuring Access for an Amazon CloudSearch Domain.

# Arguments
- `access_policies`: The access rules you want to configure. These rules replace any
  existing rules.
- `domain_name`:

"""
update_service_access_policies(AccessPolicies, DomainName; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("UpdateServiceAccessPolicies", Dict{String, Any}("AccessPolicies"=>AccessPolicies, "DomainName"=>DomainName); aws_config=aws_config)
update_service_access_policies(AccessPolicies, DomainName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = cloudsearch("UpdateServiceAccessPolicies", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("AccessPolicies"=>AccessPolicies, "DomainName"=>DomainName), params)); aws_config=aws_config)


text:
"""
    discard(to_delete, centers, [...]) -> centers::AbstractMatrix{<:AbstractFloat}

    Discard all cluster centers in `centers` based on indices in `to_delete`.

    # Arguments
    - `to_delete`: vector of indices to delete
    -   `centers`: array of cluster centers
"""
function discard(to_delete::Vector{Int}, centers::AbstractMatrix{<:AbstractFloat})
    unique!(to_delete)
    sort!(to_delete)
    l = size(to_delete, 1)
    k = size(centers, 2)

    if l > 0 && k > l
        temp = centers[:, setdiff(1:end, to_delete)]
        return temp
    end

    return centers
end

"""
    discard_clusters!(X, centers, counts, θn) -> None

    Discard all cluster centers that meet the criteria and update `centers`
    in-place.

    The criteria for deleting clusters are as follows:
        1. If the number of member patterns in a cluster is less than (θn*n)
    Discard `if(1)`

    # Arguments
    -          `X`: input data matrix
    -    `centers`: array of cluster centers
    -     `counts`: array of the number of patterns assigned to each cluster
    -         `θn`: minimum number of cluster members (as percentage)
"""
function discard_clusters!(
    X::AbstractMatrix{<:Real},
    centers::AbstractMatrix{<:AbstractFloat},
    counts::Vector{Int},
    θn::Float64,
)
    d, n = size(X)
    k = size(centers, 2)

    to_delete = Vector{Int}()
    for j = 1:k
        if (counts[j] < (θn * n))
            push!(to_delete, j)
        end
    end

    # if clusters are to be deleted, set flag
    flag = !isempty(to_delete)

    if flag
        centers = discard(to_delete, centers)
        return centers, flag
    else
        return centers, flag
    end
end

"""
    split!(to_split, centers, sd) -> None

    Split all cluster centers in `centers` based on indices in `to_split`
    and update `centers` in-place.

    To split a cluster, find the dimension which contributes the most to its
        variance (highest standard deviation) and create two copies of the
        cluster. In one of the copies, add 1 to that dimension, and in the
        other, subtract 1 from that dimension.

    # Arguments
    - `to_split`: vector of indices to split
    -  `centers`: array of cluster centers
    -       `sd`: array of the standard deviation of each cluster
                    in each dimension
"""
function split!(
    to_split::Vector{Int},
    centers::AbstractMatrix{<:AbstractFloat},
    sd::AbstractMatrix{<:AbstractFloat},
)
    unique!(to_split)
    l = size(to_split, 1)
    to_delete = Vector{Int}()

    if l > 0
        for j = 1:l
            k = to_split[j]

            # create a copy
            c = view(centers, :, k)

            # find the dimension which contributes most to the variance
            p, i = findmax(view(sd, :, k))

            # create a plus copy, which has plus 1 in the p dimension
            c_plus = copy(c)
            c_plus[i] += 1

            # create a minus copy, which has minus 1 in the p dimension
            c_minus = copy(c)
            c_minus[i] -= 1

            push!(to_delete, k)
            centers = cat(centers, c_plus, dims = 2)
            centers = cat(centers, c_minus, dims = 2)
        end
    end

    centers = discard(to_delete, centers)
    return centers
end

"""
    split_clusters!(
        X, centers, counts, sd, maxclusters, AVEDIST, AD, θn, θe) -> None

    Split all cluster centers that meet the criteria and update `centers`
        in-place.

    The criteria for splitting clusters are as follows:
        1. If the standard deviation of a cluster in any of its dimensions
            exceeds θe.
        2. If the average distance of a cluster's center to its members
            exceeds the overall average.
        3. If the number of member patterns in a cluster exceeds 2*(θn*n)+2),
            where n is the total number of patterns in the dataset.
        4. If the number of clusters is less than half of the clusters expected
            (based on maxclusters)
    Split `if(1 AND ((2 AND 3) OR 4)`

    # Arguments
    -           `X`: input data matrix
    -     `centers`: array of cluster centers
    -      `counts`: array of the number of patterns assigned to each cluster
    -          `sd`: vector of the standard deviation of each cluster
                        in each dimension
    - `maxclusters`: user defined parameter for the maximum number of clusters to create
    -     `AVEDIST`: vector with the average distance of a cluster center to each of its members
    -          `AD`: the overall average distance of cluster centers to their members
    -          `θn`: minimum number of cluster members (as percentage)
    -          `θe`: maximum standard deviation allowed for a cluster
"""
function split_clusters!(
    X::AbstractMatrix{<:Real},
    centers::AbstractMatrix{<:AbstractFloat},
    counts::Vector{Int},
    sd::AbstractMatrix{<:AbstractFloat},
    maxclusters::Integer,
    AVEDIST::Vector{Float64},
    AD::Float64,
    θn::Float64,
    θe::Float64,
)
    d, n = size(X)
    k = size(centers, 2)

    to_split = Vector{Int}()
    for j = 1:k
        for i = 1:d
            if sd[i, j] > θe
                if (
                    (AVEDIST[j] > AD && counts[j] > 2 * (θn * n) + 2) ||
                    k <= 0.5 * maxclusters
                )
                    push!(to_split, j)
                end
            end
        end
    end

    centers = split!(to_split, centers, sd)
    return centers
end

"""
    lump!(to_lump, centers, counts) -> None

    Lump all pairs of cluster centers in `centers` based on indices in
    `to_lump` and update `centers` in-place.

    To lump two clusters, create a new cluster based off the weighted centers
    of the clusters to merge. The weights are equal to the number of member
    patterns for each cluster.

    -  `to_lump`: vector of indices to split
    -  `centers`: array of cluster centers
    -   `counts`: array of the number of patterns assigned to each cluster
"""
function lump!(
    to_lump::Vector{Int},
    centers::AbstractMatrix{<:AbstractFloat},
    counts::Vector{Int},
)
    l = size(to_lump, 1)
    to_delete = Vector{Int}()

    if l > 0
        for j in range(1, l, step = 2)
            # create a copy of each cluster to merge
            i1 = to_lump[j]
            i2 = to_lump[j+1]
            c1 = view(centers, :, i1)
            c2 = view(centers, :, i2)

            # empty cluster based on c1
            p = copy(c1)
            fill!(p, 0)

            d = size(centers, 1)
            for i = 1:d
                p[d] = (
                    1 / (counts[i1] + counts[i2]) * (counts[i1] * c1[i]) +
                    counts[i2] * c2[d]
                )
            end

            push!(to_delete, i1)
            push!(to_delete, i2)
            centers = cat(centers, p, dims = 2)
        end
    end

    centers = discard(to_delete, centers)
    return centers
end

"""
    lump_clusters!(centers, counts, L, θc) -> None

    Lump all cluster centers that meet the criteria and update `centers`
        in-place.

    The criteria for lumping two clusters are as follows:
        1. If the distance between two clusters is less than θc
        2. If the clusters have not already been assigned to lump
        3. If the number of clusters to lump does not exceed L
    Lump `if(1 AND 2 AND 3)`

    # Arguments
    -     `centers`: array of cluster centers
    -      `counts`: array of the number of patterns assigned to each cluster
    -           `L`: maximum number of clusters to lump
    -          `θc`: maximum standard deviation allowed for a cluster
"""
function lump_clusters!(
    centers::AbstractMatrix{<:AbstractFloat},
    counts::Vector{Int},
    L::Integer,
    θc::Float64,
)
    k = size(centers, 2)
    dist = pairwise(Euclidean(), centers, centers)

    to_lump = Vector{Int}()
    while k > L
        for j = 1:k
            for i = 1:k
                if (i != j && dist[i, j] < θc)
                    if (i ∉ to_lump && j ∉ to_lump)
                        push!(to_lump, i)
                        push!(to_lump, j)
                        k -= 2 # two fewer clusters available to lump
                    end
                end
            end
        end
        break
    end

    centers = lump!(to_lump, centers, counts)
    return centers
end

ext: jl


text:
using EDA
launch()


text:
using Test, Sandbox, SHA

all_executors = Sandbox.all_executors

# Can we run `sudo` without a password?  If not, don't attempt to test the privileged runner
if !success(`sudo -k -n true`)
    all_executors = filter(exe -> exe != PrivilegedUserNamespacesExecutor, all_executors)
end

function print_if_nonempty(stderr::Vector{UInt8})
    if !isempty(stderr)
        stderr = String(stderr)
        @error("not empty")
        println(stderr)
        return false
    end
    return true
end

rootfs_dir = Sandbox.alpine_rootfs()
for executor in all_executors
    if !executor_available(executor)
        @error("Skipping $(executor) tests, as it does not seem to be available")
        continue
    end

    @testset "$(executor) Sandboxing" begin
        @testset "capturing stdout/stderr" begin
            stdout = IOBuffer()
            stderr = IOBuffer()
            config = SandboxConfig(
                Dict("/" => rootfs_dir);
                stdout,
                stderr,
            )
            with_executor(executor) do exe
                @test success(exe, config, `/bin/sh -c "echo stdout; echo stderr >&2"`)
                @test String(take!(stdout)) == "stdout\n";
                @test String(take!(stderr)) == "stderr\n";
            end
        end

        @testset "ignorestatus()" begin
            config = SandboxConfig(Dict("/" => rootfs_dir))
            with_executor(executor) do exe
                @test_throws ProcessFailedException run(exe, config, `/bin/sh -c "false"`)
                @test !success(exe, config, ignorestatus(`/bin/sh -c "false"`))
            end
        end

        @testset "environment passing" begin
            # Ensure all those pesky "special" variables make it through
            env = Dict(
                "PATH" => "for",
                "LD_LIBRARY_PATH" => "science",
                "DYLD_LIBRARY_PATH" => "you",
                "SHELL" => "monster",
            )
            stdout = IOBuffer()
            config = SandboxConfig(
                Dict("/" => rootfs_dir),
                Dict{String,String}(),
                env;
                stdout,
            )
            user_cmd = `/bin/sh -c "echo \$PATH \$LD_LIBRARY_PATH \$DYLD_LIBRARY_PATH \$SHELL"`
            with_executor(executor) do exe
                @test success(exe, config, user_cmd)
                @test String(take!(stdout)) == "for science you monster\n";
            end

            # Test that setting some environment onto `user_cmd` can override the `config` env:
            user_cmd = setenv(user_cmd, "DYLD_LIBRARY_PATH" => "my", "SHELL" => "friend")
            with_executor(executor) do exe
                @test success(exe, config, user_cmd)
                @test String(take!(stdout)) == "for science my friend\n";
            end
        end

        @testset "reading from maps" begin
            mktempdir() do dir
                open(joinpath(dir, "note.txt"), write=true) do io
                    write(io, "great success")
                end
                stdout = IOBuffer()
                config = SandboxConfig(
                    Dict("/" => rootfs_dir, "/glados" => dir);
                    stdout,
                )
                with_executor(executor) do exe
                    @test success(exe, config, `/bin/sh -c "cat /glados/note.txt"`)
                    @test String(take!(stdout)) == "great success";
                end
            end
        end

        @testset "writing to workspaces" begin
            mktempdir() do dir
                stdout = IOBuffer()
                config = SandboxConfig(
                    Dict("/" => rootfs_dir),
                    Dict("/glados" => dir);
                )
                @test success(executor(), config, `/bin/sh -c "echo aperture > /glados/science.txt"`)
                @test isfile(joinpath(dir, "science.txt"))
                @test String(read(joinpath(dir, "science.txt"))) == "aperture\n"
            end
        end

        @testset "pipelining" begin
            pipe = PipeBuffer()
            stdout = IOBuffer()
            first_config = SandboxConfig(
                Dict("/" => rootfs_dir),
                stdout = pipe,
            )
            second_config = SandboxConfig(
                Dict("/" => rootfs_dir),
                stdin = pipe,
                stdout = stdout,
            )
            @test success(executor(), first_config, `/bin/sh -c "echo 'ignore me'; echo 'pick this up foo'; echo 'ignore me as well'"`)
            @test success(executor(), second_config, `/bin/sh -c "grep foo"`)
            @test String(take!(stdout)) == "pick this up foo\n";
        end

        @testset "read-only mounts are really read-only" begin
            mktempdir() do dir
                read_only_dir = joinpath(dir, "read_only")
                read_write_dir = joinpath(dir, "read_write")
                mkdir(read_only_dir)
                mkdir(read_write_dir)
                stdout = IOBuffer()
                stderr = IOBuffer()
                config = SandboxConfig(
                    Dict("/" => rootfs_dir, "/read_only" => read_only_dir),
                    Dict("/read_write" => read_write_dir),
                    stdout = stdout,
                    stderr = stderr,
                    persist = false,
                )
                # Modifying the rootfs works, and is temporary; for docker containers this is modifying
                # the rootfs image, for userns this is all mounted within an overlay backed by a tmpfs,
                # because we have `persist` set to `false`.
                with_executor(executor) do exe
                    @test success(exe, config, `/bin/sh -c "echo aperture >> /bin/science && cat /bin/science"`)
                    @test String(take!(stdout)) == "aperture\n";
                    @test print_if_nonempty(take!(stderr))
                    @test success(exe, config, `/bin/sh -c "echo aperture >> /bin/science && cat /bin/science"`)
                    @test String(take!(stdout)) == "aperture\n";
                    @test print_if_nonempty(take!(stderr))

                    # An actual read-only mount will not allow writing, because it's truly read-only
                    @test !success(exe, config, ignorestatus(`/bin/sh -c "echo aperture >> /read_only/science && cat /read_only/science"`))
                    @test occursin("Read-only file system", String(take!(stderr)))

                    # A read-write mount, on the other hand, will be permanent
                    @test success(exe, config, `/bin/sh -c "echo aperture >> /read_write/science && cat /read_write/science"`)
                    @test String(take!(stdout)) == "aperture\n";
                    @test print_if_nonempty(take!(stderr))
                    @test success(exe, config, `/bin/sh -c "echo aperture >> /read_write/science && cat /read_write/science"`)
                    @test String(take!(stdout)) == "aperture\naperture\n";
                    @test print_if_nonempty(take!(stderr))
                end
            end
        end

        @testset "entrypoint" begin
            mktempdir() do dir
                read_only_dir = joinpath(dir, "read_only")
                mkdir(read_only_dir)
                stdout = IOBuffer()
                stderr = IOBuffer()
                config = SandboxConfig(
                    Dict("/" => rootfs_dir, "/read_only" => read_only_dir),
                    entrypoint = "/read_only/entrypoint",
                    stdout = stdout,
                    stderr = stderr,
                )

                # Generate an `entrypoint` script that mounts a tmpfs-backed overlayfs over our read-only mounts
                # Allowing us to write to those read-only mounts, but the changes are temporary
                open(joinpath(read_only_dir, "entrypoint"), write=true) do io
                    write(io, """
                    #!/bin/sh

                    echo entrypoint activated

                    mkdir /overlay_workdir
                    mount -t tmpfs -osize=1G tmpfs /overlay_workdir
                    mkdir -p /overlay_workdir/upper
                    mkdir -p /overlay_workdir/work
                    mount -t overlay overlay -olowerdir=/read_only -oupperdir=/overlay_workdir/upper -oworkdir=/overlay_workdir/work /read_only

                    exec "\$@"
                    """)
                end
                chmod(joinpath(read_only_dir, "entrypoint"), 0o755)

                # Modifying the read-only files now works, and is temporary
                with_executor(executor) do exe
                    @test success(exe, config, `/bin/sh -c "echo aperture >> /read_only/science && cat /read_only/science"`)
                    @test String(take!(stdout)) == "entrypoint activated\naperture\n";
                    @test print_if_nonempty(take!(stderr))
                    @test success(exe, config, `/bin/sh -c "echo aperture >> /read_only/science && cat /read_only/science"`)
                    @test String(take!(stdout)) == "entrypoint activated\naperture\n";
                    @test print_if_nonempty(take!(stderr))
                end
            end
        end

        @testset "persistence" begin
            mktempdir() do dir
                stdout = IOBuffer()
                stderr = IOBuffer()
                config = SandboxConfig(
                    Dict("/" => rootfs_dir),
                    stdout = stdout,
                    stderr = stderr,
                    persist = true,
                )

                # Modifying the read-only files is persistent within a single executor
                cmd = `/bin/sh -c "echo aperture >> /bin/science && cat /bin/science"`
                with_executor(executor) do exe
                    @test success(exe, config, cmd)
                    @test String(take!(stdout)) == "aperture\n";
                    @test print_if_nonempty(take!(stderr))
                    @test success(exe, config, cmd)
                    @test String(take!(stdout)) == "aperture\naperture\n";
                    @test print_if_nonempty(take!(stderr))
                end

                with_executor(executor) do exe
                    @test success(exe, config, cmd)
                    @test String(take!(stdout)) == "aperture\n";
                    @test print_if_nonempty(take!(stderr))
                end
            end
        end

        @testset "explicit user and group" begin
            for (uid,gid) in [(0,0), (999,0), (0,999), (999,999)]
                stdout = IOBuffer()

                config = SandboxConfig(
                    Dict("/" => rootfs_dir);
                    stdout, uid, gid
                )
                with_executor(executor) do exe
                    @test success(exe, config, `/usr/bin/id`)
                    str = String(take!(stdout))
                    @test contains(str, "uid=$(uid)")
                    @test contains(str, "gid=$(gid)")
                end
            end
        end

        # If we have the docker executor available (necessary to do the initial pull),
        # let's test launching off of a docker image
        if executor_available(DockerExecutor)
            julia_rootfs = Sandbox.pull_docker_image("julia:alpine")
            @testset "launch from docker image" begin
                stdout = IOBuffer()
                stderr = IOBuffer()
                config = SandboxConfig(
                    Dict("/" => julia_rootfs),
                    Dict{String,String}(),
                    # Add the path to `julia` onto the path, then use `sh` to process the PATH
                    Dict("PATH" => "/usr/local/julia/bin:/usr/local/bin:/usr/bin:/bin");
                    stdout = stdout,
                    stderr = stderr,
                )

                with_executor(executor) do exe
                    @test success(exe, config, `/bin/sh -c "julia -e 'println(\"Hello, Julia!\")'"`)
                    @test String(take!(stdout)) == "Hello, Julia!\n";
                    @test print_if_nonempty(take!(stderr))
                end
            end
        end

        @testset "Internet access" begin
            mktempdir() do rw_dir
                ro_mappings = Dict(
                    "/" => rootfs_dir,
                )

                # Mount in `/etc/resolv.conf` as a read-only mount if using a UserNS executor, so that we have DNS
                if executor <: UserNamespacesExecutor && isfile("/etc/resolv.conf")
                    resolv_conf = joinpath(rw_dir, "resolv.conf")
                    cp("/etc/resolv.conf", resolv_conf; follow_symlinks=true)
                    ro_mappings["/etc/resolv.conf"] = resolv_conf
                end

                config = SandboxConfig(
                    ro_mappings,
                    Dict("/tmp/rw_dir" => rw_dir),
                )

                # Test that we can use `wget` (née busybox) within the alpine rootfs to download something
                socrates_url = "https://github.com/staticfloat/small_bin/raw/master/socrates.tar.xz"
                socrates_hash = "61bcf109fcb749ee7b6a570a6057602c08c836b6f81091eab7aa5f5870ec6475"
                with_executor(executor) do exe
                    @test success(exe, config, `/bin/sh -c "wget -q $(socrates_url) -O /tmp/rw_dir/$(basename(socrates_url))"`)
                end

                socrates_path = joinpath(rw_dir, basename(socrates_url))
                @test isfile(socrates_path)
                @test open(io -> bytes2hex(sha256(io)), socrates_path) == socrates_hash
                rm(socrates_path; force=true)

                # Do another test with the debian rootfs where we try to use `apt`
                ro_mappings["/"] = Sandbox.debian_rootfs()
                config = SandboxConfig(
                    ro_mappings,
                    Dict("/tmp/rw_dir" => rw_dir),
                    Dict("HOME" => "/root"),
                )
                with_executor(executor) do exe
                    @test success(exe, config, `/bin/sh -c "apt update && apt install -y curl && curl -L $(socrates_url) -o /tmp/rw_dir/$(basename(socrates_url))"`)
                end
                @test isfile(socrates_path)
                @test open(io -> bytes2hex(sha256(io)), socrates_path) == socrates_hash
            end
        end
    end
end

@testset "default executor" begin
    stdout = IOBuffer()
    stderr = IOBuffer()
    config = SandboxConfig(
        Dict("/" => rootfs_dir);
        stdout,
        stderr,
    )
    with_executor() do exe
        @test success(exe, config, `/bin/sh -c "echo stdout; echo stderr >&2"`)
        @test String(take!(stdout)) == "stdout\n";
        @test String(take!(stderr)) == "stderr\n";
    end
end


text:
using Test
using WebMSISE00

# insert tests using @Test macro

    #Test 1 (tests ReadMSISE)
    testinput = Dict(
        "year" => "2017",
        "month" => "01",
        "day" => "01",
        "step" => "25.",
        "vars" => ["05","11"]
    )
    @test ReadMSISE(testinput)[4,2] == 2.773e-08

    #Test 2 (tests WriteMSISEData, using the call within ReadMSISE)
    ReadMSISE(testinput, "testoutput")
    @test isfile("testoutput.jld2")

    #Test 3 (tests ReadMSISEData)
    frontmatter, output = ReadMSISEData("testoutput")
    @test output[4,2] == 2.773e-08


text:
mutable struct DataSlice
    metadata
    y0
    data
end
Base.show(io::IO, col::DataSlice) = print(io, "DataSlice(...)")

mutable struct DataColumn
    metadata
    ys
    ysymbol
    data
    touched
end
DataColumn(metadata) = DataColumn(Float64[], metadata)
DataColumn(ys, metadata) = DataColumn(ys, nothing, metadata)
DataColumn(ys, ysymbol, metadata) = DataColumn(metadata, collect(ys), ysymbol, fill!(Vector(undef, length(ys)), NamedTuple()), fill(false, length(ys)))

function initialize!(col::DataColumn, ys, ysymbol)
    col.ys = ys
    col.ysymbol = ysymbol
    col.data = fill!(Vector(undef, length(ys)), NamedTuple())
    col.touched = fill(false, length(ys))
    return col
end

function Base.Vector{DataColumn}(xs::AbstractVector)
    self = Vector{DataColumn}(undef, length(xs))
    for (i, x) in enumerate(xs)
        self[i] = DataColumn((x=x,))
    end
    return self
end

function Base.Vector{DataColumn}(xsymbol, xs::AbstractVector)
    self = Vector{DataColumn}(undef, length(xs))
    for (i, x) in enumerate(xs)
        self[i] = DataColumn((xsymbol=xsymbol, x=x))
    end
    return self
end

Base.setindex!(col::DataColumn, value, ys...) = setindex!(col.data, map(indexsnap, ys))
Base.copy(col::DataColumn) = DataColumn(col.metadata, col.ys, col.ysymbol, copy(col.data), col.touched)
Base.show(io::IO, col::DataColumn) = print(io, "DataColumn(...)")

@export struct DataScatter end

function DataScatter(f, cols::Vector{DataColumn})
    xs = mapreduce(col -> [col.metadata.x for _ in col.ys], vcat, cols)
    ys = mapreduce(col -> col.ys, vcat, cols)
    zs = mapreduce(col -> map(f, col.data), vcat, cols)
    return xs, ys, zs
end

function indexsnap(xs, x0)
    x1, x2 = x0 .- inv.(extrema(inv.(x0 .- xs)))
    x0 = abs(x2 - x0) > abs(x1 - x0) ? x1 : x2
    return findfirst(x -> x == x0, xs)
end

@export function datamap(f, cols::Vector{DataColumn})
    ys = mapreduce(a -> collect(a.ys), hcat, cols)
    xs = mapreduce(a -> a.metadata.x, vcat, cols)
    xs = [x for _ in 1:size(ys, 1), x in xs]
    zs = mapreduce(a -> map(f, a.data), hcat, cols)
    return xs, ys, zs
end

function datamap(f, slices::Vector{DataSlice})
    xs = mapreduce(a -> a.metadata.x, vcat, slices)
    ys = mapreduce(a -> f(a.data), vcat, slices)
    return xs, ys
end

function energy_bands(cols::Vector{DataColumn}; step=1)
    eigvalues = mapreduce(col -> col.metadata.sim.eig.values, hcat, cols)'
    energy_range = range(floor(Int, minimum(eigvalues)), ceil(Int, maximum(eigvalues)), step=step)
    return eigvalues, energy_range
end

function energy_bounds(cols::Vector{DataColumn})
    gmin, gmax = 0.0, 0.0
    for col in cols
        gmin, gmax = energy_bounds(col)
    end
    return gmin, gmax
end

function energy_bounds(col::DataColumn)
    gmin = min(gmin, floor(Int, minimum(col.metadata.sim.eig.values)))
    gmax = max(gmax, ceil(Int, maximum(col.metadata.sim.eig.values)))
    return gmin, gmax
end

function ranges(cols::Vector{DataColumn})
    xs = mapreduce(a -> a.metadata.x, vcat, cols)
    ys = collect(cols[1].ys)
    return xs, ys
end

function Base.range(slices::Vector{DataSlice})
    return mapreduce(a -> a.metadata.x, vcat, slices)
end

function atpoint(
    f,
    x,
    y,
    args...;
    xsymbol,
    ysymbol,
    calc = calc_data1,
    v = Dict(),
    kwargs...
)
    sim = LiteSimulation(args...; (xsymbol => x,)..., kwargs...)
    return f(calc(sim; v..., (ysymbol => y,)...))
end

gaussian(x, x0, σ) = exp(-(x - x0)^2 / (2σ^2))
box(x, x0, σ) = abs(x - x0) < σ ? 1.0 : 0.0

function find_crossing(
    x0,
    y0,
    args...;
    xsymbol,
    threshold = 1e-12,
    max_iterations = 1e1,
    δx = 1e-6,
    attenuation = 1e-2,
    rounding = :average,
    kwargs...
)
    function optim(x, y)
        sim = LiteSimulation(args...; kwargs..., (xsymbol => x,)...)
        eigvals, _ = nearest_eigenstates(sim.eig, y, n=2)
        d = abs(eigvals[1] - eigvals[2])
        y = (eigvals[1] + eigvals[2])/2
        return d, y
    end

    x = x0
    _, y = optim(x, y0)
    for _ in 1:max_iterations
        (d, y), (d_, _) = optim(x, y), optim(x + δx, y)
        δd = d_ - d
        abs(d) < threshold && return x, y
        x = x - clamp(d*δx/δd, -attenuation, attenuation)
    end

    if rounding in (:upper, :lower, :both)
        sim = LiteSimulation(args...; kwargs..., (xsymbol => x,)...)
        eigvals, _ = nearest_eigenstates(sim.eig, y, n=2)
        rounding == :lower && return (x, minimum(eigvals))
        rounding == :upper && return (x, maximum(eigvals))
        rounding == :both && return (x, minimum(eigvals), maximum(eigvals))
    end

    return x, y
end

@export function track_crossing_length(
    points,
    args...;
    N0,
    pinned = true,
    N_lower = 2,
    N_upper = 52,
    N_step = 2,
    threshold = 0.001,
    f = prefactor,
    kwargs...
)
    Ns = vcat(N0:-N_step:N_lower, N0:N_step:N_upper)
    Ns_ordered = N_lower:N_step:N_upper
    indices = indexin(Ns, Ns_ordered)
    dat = fill!(Matrix{NamedTuple}(undef, length(Ns_ordered), length(points)), NamedTuple())
    points0 = copy(points)
    @showprogress 1 "" for (i, N) in zip(indices, Ns), (j, (x,y)) in enumerate(points)
        if N == N0 && !pinned
            x, y = points0[j]
        end
        x, y = find_crossing(x, y, N, threshold=threshold)
        if !pinned
            points[j] = (x, y)
        end

        a, b, c = atpoint(f, x, y; N = N, kwargs...)
        dat[i,j] = (x = x, y = y, p = a*b/c)
    end
    return dat
end

@export function load_columns(dirname)
    list = readdir(joinpath("data", dirname))
    cols = Vector{DataColumn}(undef, length(list))
    @showprogress 1 "" for (i, filename) in enumerate(list)
        @load joinpath("data", dirname, filename) col
        cols[i] = col
    end
    return cols
end

@export function gen_bands(
    args...;
    xsymbol,
    bounds,
    nsamples = 50,
    xs = range(bounds..., length=nsamples),
    kwargs...
)
    gen_bands!(Vector{DataColumn}(xsymbol, xs), args...; xs = xs, xsymbol = xsymbol, kwargs...)
end

function gen_bands!(
    cols::Vector{DataColumn},
    args...;
    xsymbol,
    xs,
    save = false,
    dirname = "$(now())_gen_bands()",
    kwargs...
)
    save && mkpath(joinpath("data", dirname))

    @showprogress 1 "" for (idx,col) in enumerate(cols)
        sim = LiteSimulation(args...; kwargs..., (xsymbol => col.metadata.x,)...)
        col.metadata = (col.metadata..., sim = sim, xlims=extrema(xs))
        save && @save joinpath("data", dirname, "col-$(string(idx, pad=6)).bson") col
    end

    return cols
end

@export function gen_on_bands!(
    cols;
    bounds = energy_bounds(cols),
    save = false,
    dirname = "$(now())_gen_on_bands()",
    kwargs...
)
    save && mkpath(joinpath("data", dirname))

    @showprogress 1 "" for (idx,col) in enumerate(cols)
        ys = filter(y -> bounds[1] <= y <= bounds[2], col.metadata.sim.eig.values)
        gen_col!(col; bounds=bounds, kwargs..., ys = ys, _progress_dt=Inf)
        save && @save joinpath("data", dirname, "col-$(string(idx, pad=6)).bson") col
    end

    return cols
end

@export function gen_near_bands!(
    cols;
    save = false,
    dirname = "$(now())_gen_near_bands()",
    kwargs...
)
    save && mkpath(joinpath("data", dirname))

    @showprogress 1 "" for (idx, col) in enumerate(cols)
        gen_col!(col; kwargs..., _progress_dt=Inf)
        save && @save joinpath("data", dirname, "col-$(string(idx, pad=6)).bson") col
    end

    return cols
end

@export function gen_col!(
    col::DataColumn;
    ysymbol,
    bounds = energy_bounds(col),
    nsamples = 50,
    ys = range(bounds..., length=nsamples),
    threshold = nothing,
    f = calc_data1,
    cond = (sim, y) -> isnothing(threshold) ? true : any(abs.(y .- sim.eig.values) .< threshold),
    clear = true,
    _progress_dt = 1,
    kwargs...

)
    col.metadata = (col.metadata..., ylims=extrema(ys))
    sim = col.metadata.sim
    if clear || col.ys != ys || col.ysymbol != ysymbol
        initialize!(col, ys, ysymbol)
    end
    @showprogress _progress_dt for (i, y) in enumerate(ys)
        if cond(sim, y) && !col.touched[i]
            col.touched[i] = true
            col.data[i] = f(sim; kwargs..., (ysymbol => y,)...)
        end
    end
    return col
end

function first_order_perturbation(sim::Simulation; E=sim.μ, α=DEFAULT_α, λ=DEFAULT_λ)
    γL = α*sim.γL
    ΓL = α*sim.ΓL
    ΓR = α*sim.ΓR

    G = propagator(sim, E=E, Γ=ΓL+ΓR)
    X = G*γL*G'
    t = 2real(dot(X, ΓR))
    s = map(L -> 4λ*dot(X, ΓR*G*L), sim.L)

    return (E=E, α=α, s=s, t=t)
end

function calc_data1(sim::Simulation; E=sim.μ, α=DEFAULT_α, λ=DEFAULT_λ, n=2)
    G = propagator(sim, E=E)
    eigvals, U = nearest_eigenstates(sim.eig, E, n=n)

    X = G*sim.γL*G'
    t = 2real(dot(X, sim.ΓR))
    s = map(L -> 4λ*dot(X, sim.ΓR*G*L), sim.L)

    return (
        E=E, α=α, n=n,

        s = s,
        t = t,
        eigvals = eigvals,
        G = U'G*U,
        γL = U'sim.γL*U,
        ΓL = U'sim.ΓL*U,
        ΓR = U'sim.ΓR*U,
        L = map(Li -> U'Li*U, sim.L)
    )
end

function calc_data2(sim::Simulation; E=sim.μ, α=DEFAULT_α, λ=DEFAULT_λ)
    G = propagator(sim, E=E)
    carbon_atoms = collect(filter(x -> x isa Carbon, sim.mol.atoms))

    Ls = collect(zip(
        (angularmomentum(:x, sim.mol, atom) for atom in carbon_atoms),
        (angularmomentum(:y, sim.mol, atom) for atom in carbon_atoms),
        (angularmomentum(:z, sim.mol, atom) for atom in carbon_atoms)
    ))

    eigvals, U = nearest_eigenstates(sim.eig, E)

    ss = NTuple{3,Complex{Float64}}[]
    ts = Float64[]

    for L in Ls
        s, t = calculate_s_and_t(G, sim.γL, sim.ΓR, L, λ=λ)
        push!(ss, v)
        push!(ts, t)
    end

    return (
        E=E, α=α, n=n,

        ss = ss,
        ts = ts,
        eigvals = eigvals,
        G = U'G*U,
        γL = U'sim.γL*U,
        ΓL = U'sim.ΓL*U,
        ΓR = U'sim.ΓR*U,
        Ls = [map(Li -> U'Li*U, L) for L in Ls]
    )
end

# Calculate the reduced

function calc_data3(sim::Simulation; E=sim.μ, α=DEFAULT_α, λ=DEFAULT_λ, n=2, nmin=1)
    G = propagator(sim, E=E)
    Gfull = fullpropagator(sim, E=E, λ=λ)
    eigvals, U = nearest_eigenstates(sim.eig, E, n=n, nmin=nmin)
    Ufull = U ⊗ σ0

    s, t = calculate_s_and_t(G, sim.γL, sim.ΓR, sim.L, λ=λ)

    return (
        E=E, α=α, λ=λ, n=n,

        s = s,
        t = t,
        eigvals = eigvals,

        G = U'G*U,
        Gfull = Ufull'Gfull*Ufull,
        γL = U'sim.γL*U,
        ΓL = U'sim.ΓL*U,
        ΓR = U'sim.ΓR*U,
        L = map(Li -> U'Li*U, sim.L),
    )
end

function calc_data4(sim::Simulation; E=sim.μ, α=DEFAULT_α, λ=DEFAULT_λ, n=2)
    G = propagator(sim, E=E)
    eigvals, U, V = nearest_eigenstates(sim.eig, E, n=n)

    s, t = calculate_s_and_t(G, sim.γL, sim.ΓR, sim.L, λ=λ)

    return (
        E=E, α=α, λ=λ, n=n,

        s = s,
        t = t,
        eigvals = eigvals,
        G = G,
        U = U,
        V = V,
        γL = sim.γL,
        ΓL = sim.ΓL,
        ΓR = sim.ΓR,
        L = sim.L
    )
end

function calc_data5(sim::Simulation; E=sim.μ, α=DEFAULT_α, λ=DEFAULT_λ, n=2, Γτ=1.0, γL=sim.γL)
    G = propagator(sim, E=E, ΓL=I / (Γτ*α*λ))
    eigvals, U = nearest_eigenstates(sim.eig, E, n=n)
    s, t = calculate_s_and_t(G, γL ./ (2π*Γτ), sim.ΓR, sim.L, λ=λ)

    return (
        E=E, α=α, n=n,

        s = s,
        t = t,
        eigvals = eigvals,
        G = U'G*U,
        γL = U'sim.γL*U,
        ΓL = U'sim.ΓL*U,
        ΓR = U'sim.ΓR*U,
        L = map(Li -> U'Li*U, sim.L)
    )
end

function calc_data6(sim::Simulation; E=sim.μ, α=DEFAULT_α, λ=DEFAULT_λ, c=4, cL=1.0)
    Γ = α/2 * sim.ΓR ⊗ σ0
    ΔΓ = α/2 * sim.ΓR * (c - 1) / (c + 1) ⊗ σ[:z]
    γL = sim.γL ⊗ σ0
    ΓL = α * sim.ΓL ⊗ σ0

    Gup = fullpropagator(
        sim,
        E = E,
        λ = λ,
        Γ = Γ + ΔΓ+ cL*ΓL
    )
    Gdown = fullpropagator(
        sim,
        E = E,
        λ = λ,
        Γ = Γ - ΔΓ + cL*ΓL
    )

    t_up = tr(γL*Gup'ΓL*Gup)
    t_down = tr(γL*Gdown'ΓL*Gdown)

    return (
        E=E, α=α, λ=λ,
        t_up = t_up,
        t_down = t_down,
        spintransmission = (t_up - t_down) / 2,
        transmission = (t_up + t_down) / 2,
    )
end

function simple_transport(sim::Simulation; E=sim.μ, α=DEFAULT_α, λ=DEFAULT_λ)
    ΓL = sim.ΓL ⊗ σ0
    ΓR = sim.ΓR ⊗ σ0

    G = fullpropagator(sim, E=E, λ=λ, Γ=ΓL+ΓR)
    transmission = tr(ΓL*G'*ΓR*G)

    return (E=E, α=α, λ=λ, transmission=transmission)
end

@export percentage(x) = 100x

@export function transmission(x::NamedTuple; default=0.0)
    return real(get(x, :transmission, get(x, :t, default)))
end

@export function spintransmission(x::NamedTuple)
    return real.(get(x, :spintransmission, get(x, :s, [0.0, 0.0, 0.0])))
end
spintransmission(i::Int; kwargs...) = (x::NamedTuple) -> spintransmission(x, i; kwargs...)
spintransmission(x::NamedTuple, i; kwargs...) = spintransmission(x; kwargs...)[i]

@export polarization(x::NamedTuple; kwargs...) = spintransmission(x; kwargs...) / transmission(x; default=1e-16, kwargs...)
polarization(x::NamedTuple, i; kwargs...) = spintransmission(x, i; kwargs...) / transmission(x; default=1e-16, kwargs...)
polarization(i::Int; kwargs...) = (x::NamedTuple) -> polarization(x, i; kwargs...)

@export function precession(x::NamedTuple)
    return imag.(get(x, :s, [0.0, 0.0, 0.0])) / transmission(x; default=1e-16)
end
precession(x::NamedTuple, i; kwargs...) = precession(x; kwargs...)[i]
precession(i::Int; kwargs...) = (x::NamedTuple) -> precession(x, i; kwargs...)

@export function transmission_reduced(x::NamedTuple; α=get(x, :α, DEFAULT_α), λ=get(x, :λ, DEFAULT_λ))
    G = get(x, :G, nothing)
    isnothing(G) && return 0.0

    γL, ΓR = (α*λ)*x[:γL], (α*λ)*x[:ΓR]
    return 2real(dot(γL, G'ΓR*G))
end

@export function spintransmission_reduced(x::NamedTuple, i=nothing; α=get(x, :α, DEFAULT_α), λ=get(x, :λ, DEFAULT_λ))
    G = get(x, :G, nothing)
    isnothing(G) && return (i == nothing ? [0.0, 0.0, 0.0] : 0.0)
    Ls, γL, ΓR = x[:L], (α*λ)*x[:γL], (α*λ)*x[:ΓR]

    X = G*γL
    Y = ΓR*G
    s = map(L -> 4real(dot(X, Y*L*G)), Ls)
    return (i == nothing ? s : s[i]) * λ
end
spintransmission_reduced(i::Int; kwargs...) = (x::NamedTuple) -> spintransmission_reduced(x, i; kwargs...)

@export function polarization_reduced(x::NamedTuple, i=nothing; α=get(x, :α, DEFAULT_α), λ=get(x, :λ, DEFAULT_λ))
    G = get(x, :G, nothing)
    isnothing(G) && return (i == nothing ? [0.0, 0.0, 0.0] : 0.0)
    Ls, γL, ΓR = x[:L], (α*λ)*x[:γL], (α*λ)*x[:ΓR]

    X = G*γL
    Y = ΓR*G
    s = map(L -> 4real(dot(X, Y*L*G)), Ls)
    t = 2real(dot(X, Y))
    return (i == nothing ? s : s[i]) * λ / t
end
polarization_reduced(i::Int; kwargs...) = (x::NamedTuple) -> polarization_reduced(x, i; kwargs...)

@export function precession_reduced(x::NamedTuple, i=nothing; α=get(x, :α, DEFAULT_α), λ=get(x, :λ, DEFAULT_λ))
    G = get(x, :G, nothing)
    isnothing(G) && return (i == nothing ? [0.0, 0.0, 0.0] : 0.0)
    Ls, γL, ΓR = x[:L], (α*λ)*x[:γL], (α*λ)*x[:ΓR]

    X = G*γL
    Y = ΓR*G
    s = map(L -> 4imag(dot(X, Y*L*G)), Ls)
    t = 2real(dot(X, Y))
    return (i == nothing ? s : s[i]) * λ / t
end
precession_reduced(i::Int; kwargs...) = (x::NamedTuple) -> precession_reduced(x, i; kwargs...)

@export function fulltransmission_reduced(x::NamedTuple; α=get(x, :α, DEFAULT_α), λ=get(x, :λ, DEFAULT_λ))
    G = get(x, :Gfull, fill(0.0, 4, 4))
    iszero(G) && return 0.0
    γL, ΓR = (α*λ)*x[:γL] ⊗ σ0, (α*λ)*x[:ΓR] ⊗ σ0

    return real(dot(γL, G'ΓR*G))
end

@export function fullspintransmission_reduced(x::NamedTuple, i=nothing; α=get(x, :α, DEFAULT_α), λ=get(x, :λ, DEFAULT_λ))
    G = get(x, :Gfull, nothing)
    isnothing(G) && return 0.0
    γL, ΓR = (α*λ)*x[:γL] ⊗ σ0, (α*λ)*x[:ΓR] ⊗ σ0
    M = Matrix(1.0I, size(G, 1) ÷ 2, size(G, 2) ÷ 2)

    s = map(σi -> real(dot(γL, G'ΓR*(M ⊗ σi)*G)), collect(σ))
    return (i == nothing ? s : s[i])
end
fullspintransmission_reduced(i::Int; kwargs...) = (x::NamedTuple) -> fullspintransmission_reduced(x, i; kwargs...)

@export function fullpolarization_reduced(x::NamedTuple, i=nothing; α=get(x, :α, DEFAULT_α), λ=get(x, :λ, DEFAULT_λ))
    G = get(x, :Gfull, nothing)
    isnothing(G) && return 0.0
    γL, ΓR = (α*λ)*x[:γL] ⊗ σ0, (α*λ)*x[:ΓR] ⊗ σ0
    M = Matrix(1.0I, size(G, 1) ÷ 2, size(G, 2) ÷ 2)

    s = map(σi -> real(dot(γL, G'ΓR*(M ⊗ σi)*G)), collect(σ))
    t = real(dot(γL, G'ΓR*G))
    return (i == nothing ? s : s[i]) / t
end
fullpolarization_reduced(i::Int; kwargs...) = (x::NamedTuple) -> fullpolarization_reduced(x, i; kwargs...)

@export function smoothen(f, cols::Vector{DataColumn}; kwargs...)
    out = Vector{DataColumn}(undef, length(cols))
    @showprogress 1 "" for (i, col) in enumerate(cols)
        out[i] = smoothen(f, col; kwargs...)
    end
    return out
end

function smoothen(f, cols::Vector{DataColumn}, y0; kwargs...)
    out = Vector{DataSlice}(undef, length(cols))
    @showprogress 1 "" for (i, col) in enumerate(cols)
        out[i] = smoothen(f, col, y0; kwargs...)
    end
    return out
end

function smoothen(f, col::DataColumn; kwargs...)
    out = copy(col)
    for (i, y0) in enumerate(col.ys)
        out.data[i] = smoothen(f, col, y0; kwargs...).data
    end
    return out
end

function smoothen(fs::NamedTuple, col::DataColumn, y0; σ = 0.1, w = gaussian)
    ws = w.(col.ys, y0, σ)
    slice = DataSlice(col.metadata, y0, map(f -> sum(x -> f(x[1]) * x[2], zip(col.data, ws)), fs))
    return slice
end

function smoothen(f, col::DataColumn, y0; σ = 0.1, w = gaussian)
    ws = w.(col.ys, y0, σ)
    slice = DataSlice(col.metadata, y0, (result = sum(f.(col.data) .* ws),))
    return slice
end

Λ12(x::NamedTuple; λ=8e-3) = 2*imag(λ*get(x, :L, fill(0.0, 2, 2))[1,2])
function prefactor(x::NamedTuple; i=nothing, α=get(x, :α, DEFAULT_α), λ=get(x, :λ, DEFAULT_λ))
    G = get(x, :G, nothing)
    isnothing(G) && return (i == nothing ? [0.0, 0.0, 0.0] : 0.0)
    Ls, γL, ΓR = x[:L], (α*λ)*x[:γL], (α*λ)*x[:ΓR]

    Λ12 = λ .* map(L -> L[1,2], Ls)
    s = 2 * (G'*(γL*G*ΓR - ΓR*G*γL)*G')[2,1]
    t = real(tr(γL*G'ΓR*G))
    return imag(i == nothing ? Λ12 : Λ12[i]), s / t

end

function polarization_prefactor(x::NamedTuple)
    a, b, c = prefactor(x)
    return a*b/c
end

function annotate_crossings!(f::Function, points; N=14, fontsize=6, xtransform=identity, ztransform=identity, kwargs...)
    for (x,y) in points
        x, y = find_crossing(x, y, N, threshold=1e-6)
        a, b, c = atpoint(f, x, y; N = N, kwargs...)
        a, b = sign(b)*a, ztransform(abs(b))
        data = "\\($(ScientificNotation.string(a / 1e-3, backend=:latex, digits=1, lower=-2, upper=2)), $(ScientificNotation.string(b/c * 1e-3, backend=:latex, digits=1, lower=-2, upper=2))\\)"
        Plots.annotate!([(xtransform(x), y, Plots.text(data, fontsize, :center))])
    end
    Plots.plot!()
end

@export function yslice(cols::Vector{DataColumn}, y0)
    idx = indexsnap(cols[1].ys, y0)
    return [DataSlice(col.metadata, y0, col.data[idx]) for col in cols]
end


text:
module Ledger

using Transducers

abstract type AbstractLedger end

struct SubLedger <: AbstractLedger
    name
    contents
end

struct GeneralLedger <: AbstractLedger
    assets
    liabilities
    equity
end

function GeneralLedger()
    return GeneralLedger([],[],[])
end

function addAsset!(gl::GeneralLedger,a)
    push!(gl.assets,a)
end

function addLiability!(gl::GeneralLedger,l)
    push!(gl.liabilities,l)
end

struct Balance
    assets
    liabilities
    equity
end

abstract type ValuationBasis end

abstract type Asset end

abstract type Liability end

function value(basis,obj)
    return obj
end

function Balance(basis::ValuationBasis,l::GeneralLedger)
    val = Map(x -> value(basis,x))
    a = tcopy(val,l.assets)
    l = tcopy(val,l.liabilities)
    a_sum = length(a) == 0 ? 0.0 : reduce(+,a)
    l_sum = length(l) == 0 ? 0.0 : reduce(+,l)
    eq = a_sum - l_sum

    return Balance(a,l,eq)
end

export value, Asset, Liability, Balance, GeneralLedger,
        addAsset!,addLiability!

end # module

max_stars_repo_name: alecloudenback/Ledger

max_issues_repo_name: alecloudenback/Ledger

max_forks_repo_name: alecloudenback/Ledger


text:
#
# Maybe
#

"""
    Maybe{T}

Option type, either a [`Just{T}`](@ref) or [`None{T}`](@ref)
"""
abstract type Maybe{T} end

"""
    None{T} <: Maybe{T}
    None(T=Any)

Indicate the lack of a meaningful value (ie nothing when `::T` is expected)
"""
struct None{T} <: Maybe{T} end

None(T::Type=Any) = None{T}()
None(::T) where T = None(T)
None(s::Some) = None(typeof(something(s)))

"""
    Just{T} <: Maybe{T}
    Just(v::T)
    Just(s::Some{T})

Indicate a meaningful value.
"""
struct Just{T} <: Maybe{T}
    v::T
end

Just(s::Some) = Just(something(s))

Base.eltype(::Maybe{T}) where {T} = T

value(j::Just) = j.v
value(::Nothing) = nothing

isnone(::None) = true
isnone(_) = false

isjust(::Just) = true
isjust(_) = false

Base.join(n::None) = n
Base.join(j::Just{<:Just}) = join(value(j))
Base.join(j::Just{<:None}) = value(j)
Base.join(j::Just) = j

"""
    map(f, m::Either, S=eltype(m))

Return `Just(f(value(e)))` if `m::Just`, else return `None(S)`
"""
Base.map(f, m::Maybe) = map(f, m, eltype(m))
Base.map(_, ::None, T::Type) = None(T)
Base.map(f, j::Just, _) = Just(f(value(j)))

Base.promote_rule(::Type{Maybe{T1}}, ::Type{Maybe{T2}}) where {T1,T2} =
        Maybe{promote_type(T1, T2)}

Base.convert(::Type{None{T}}, ::None) where {T} = None(T)
Base.convert(::Type{Just{T}}, j::Just) where {T} = Just{T}(value(j))

Base.convert(::Type{Maybe{T}}, v) where {T} = Just{T}(v)
Base.convert(::Type{Maybe{T}}, ::Nothing) where {T} = None{T}()

Base.show(io::IO, j::Just) = print(io, "Just($(value(j)))")
Base.show(io::IO, n::None) = print(io, "None(::$(eltype(n)))")


text:
int main() {
    boolean b=false;
    while(b) return 0;
}

max_stars_repo_name: carlostome/Javalette-Compiler

max_issues_repo_name: carlostome/Javalette-Compiler

max_forks_repo_name: carlostome/Javalette-Compiler


text:
using MPIReco, Documenter

makedocs(
    format = Documenter.HTML(prettyurls = false),
    modules = [MPIReco],
    sitename = "MPI Reconstruction",
    authors = "Tobias Knopp,...",
    pages = [
        "Home" => "index.md",
        "Getting Started" => "overview.md",
        "Basic Reconstruction" => "basicReconstruction.md",
        "Parameters" => "parameters.md",
        "Results" => "recoResults.md",
        "Multi-Contrast" => "multiContrast.md",
        "Multi-Patch" => "multiPatch.md",
        "Compression" => "matrixCompression.md"
    ],
)

deploydocs(repo   = "github.com/MagneticParticleImaging/MPIReco.jl.git",
           target = "build")


text:
# Inverse 32-bit Shift-And-Xor transform

function xorshift_left(value::UInt32, n_shift::Integer, and_mask::UInt32 = 0xFFFF_FFFF)::UInt32
    value ⊻ ((value << n_shift) & and_mask)
end

function xorshift_right(value::UInt32, n_shift::Integer, and_mask::UInt32 = 0xFFFF_FFFF)::UInt32
    value ⊻ ((value >> n_shift) & and_mask)
end

function reverse_xorshift_left(value::UInt32, n_shift::Int, and_mask::UInt32 = 0xFFFF_FFFF)::UInt32
    if n_shift == 0
        error("`n_shift` should not be 0")
    end

    n_remains::Int = 32 - n_shift
    mask = (UInt32(1) << n_shift) - UInt32(1)
    while n_remains > 0
        value ⊻= ((value & mask) << n_shift) & and_mask
        n_remains -= n_shift
        mask <<= n_shift
    end
    value
end

function reverse_xorshift_right(value::UInt32, n_shift::Int, and_mask::UInt32 = 0xFFFF_FFFF)::UInt32
    if n_shift == 0
        error("`n_shift` should not be 0")
    end

    n_remains::Int = 32 - n_shift
    mask = ~((UInt32(1) << n_remains) - UInt32(1))
    while n_remains > 0
        value ⊻= ((value & mask) >> n_shift) & and_mask
        n_remains -= n_shift
        mask >>= n_shift
    end
    value
end

# Let `b[i] = (value >> (n_shift * i)) & ((1 << n_shift) - 1)` (0-based), after the $j$-th xor
# operations, we have
#
#     T(b[i], j) == b[i] ⊻ b[i - 2 ^ j],  if i - 2 ^ j >= 0
#     T(b[i], j) == b[i],  otherwise

function reverse_xorshift_left_fast(value::UInt32, n_shift::Int)::UInt32
    if n_shift == 0
        error("`n_shift` should not be 0")
    end

    while n_shift < 32
        value ⊻= value << n_shift
        n_shift *= 2
    end
    value
end

function reverse_xorshift_right_fast(value::UInt32, n_shift::Int)::UInt32
    if n_shift == 0
        error("`n_shift` should not be 0")
    end

    while n_shift < 32
        value ⊻= value >> n_shift
        n_shift *= 2
    end
    value
end

#===== Unit Tests =====#

using Test
using Random: seed!

@testset "Inverse Xorshift" begin
    n = 1024
    seed!()
    x_arr = rand(UInt32, n)
    n_shift_arr = rand(1:32, n)
    and_mask_arr = rand(UInt32, n)

    x_left_arr = xorshift_left.(x_arr, n_shift_arr, and_mask_arr)
    x_right_arr = xorshift_right.(x_arr, n_shift_arr, and_mask_arr)
    x_left_arr_inv = reverse_xorshift_left.(x_left_arr, n_shift_arr, and_mask_arr)
    x_right_arr_inv = reverse_xorshift_right.(x_right_arr, n_shift_arr, and_mask_arr)
    @test x_arr == x_left_arr_inv == x_right_arr_inv

    x_left_arr = xorshift_left.(x_arr, n_shift_arr)
    x_right_arr = xorshift_right.(x_arr, n_shift_arr)
    x_left_arr_inv = reverse_xorshift_left_fast.(x_left_arr, n_shift_arr)
    x_right_arr_inv = reverse_xorshift_right_fast.(x_right_arr, n_shift_arr)
    @test x_arr == x_left_arr_inv == x_right_arr_inv
end

max_stars_repo_name: gyk/TrivialSolutions

max_issues_repo_name: gyk/TrivialSolutions

max_forks_repo_name: gyk/TrivialSolutions


text:
module TestStacks

using EventTracker.Implementations: EventID, IntervalTree, _interval_trees
using Test

const IntervalEntry = NamedTuple{(:eventid, :start, :stop),Tuple{EventID,Int64,Int64}}

function example_itnerval_trees()
    prev = Ref(UInt64(0))
    iota() = EventID(prev[] += 1)
    interval_data = [
        (iota(), 555_0000_000, 555_0000_100),
        (iota(), 555_0000_001, 555_0000_010),
        (iota(), 555_0000_002, 555_0000_003),
        (iota(), 555_0000_004, 555_0000_005),
        (iota(), 555_0000_006, 555_0000_009),
        (iota(), 555_0000_007, 555_0000_008),
        (iota(), 555_0000_020, 555_0000_099),
        (iota(), 555_0000_021, 555_0000_098),
        (iota(), 555_0000_022, 555_0000_097),
        (iota(), 555_0000_023, 555_0000_096),
    ]
    intervals = IntervalEntry.(interval_data)
    return _interval_trees(intervals)
end

function test_example()
    expected = [
        IntervalTree(
            EventID(0x001),
            [
                IntervalTree(
                    EventID(0x002),
                    [
                        IntervalTree(EventID(0x003), nothing, 0),
                        IntervalTree(EventID(0x004), nothing, 0),
                        IntervalTree(
                            EventID(0x005),
                            [IntervalTree(EventID(0x006), nothing, 0)],
                            1,
                        ),
                    ],
                    2,
                ),
                IntervalTree(
                    EventID(0x007),
                    [
                        IntervalTree(
                            EventID(0x008),
                            [
                                IntervalTree(
                                    EventID(0x009),
                                    [IntervalTree(EventID(0x00a), nothing, 0)],
                                    1,
                                ),
                            ],
                            2,
                        ),
                    ],
                    3,
                ),
            ],
            4,
        ),
    ]
    @test example_itnerval_trees() == expected
end

function withcontext(block)
    previd = Ref(UInt64(0))
    prevtime = Ref(0)
    newid() = EventID(previd[] += 1)
    newtime() = prevtime[] += 1
    intervals = IntervalEntry[]
    stack = [IntervalTree(EventID(0), [], -1)]

    function apply(f, args...; kwargs...)
        # Recording an interval
        eventid = newid()
        start = newtime()
        begin
            # Recording a frame in a stack
            push!(stack, IntervalTree(eventid, [], -1))
            begin
                y = f(apply, args...; kwargs...)
            end
            tree = pop!(stack)
            push!(stack[end].branches, IntervalTree(eventid, tree.branches))
        end
        stop = newtime()
        push!(intervals, (eventid = eventid, start = start, stop = stop))

        return y
    end

    let y = block(apply)
        @assert length(stack) == 1
        sort!(intervals; by = i -> i.start)
        return intervals, stack[end].branches, y
    end
end

just_apply(f, args...; kwargs...) = f(just_apply, args...; kwargs...)

function fib(apply, n)
    n <= 1 && return n
    a = apply(fib, n - 1)
    b = apply(fib, n - 2)
    return a + b
end

tarai(apply, x, y, z) =
    if y < x
        apply(
            tarai,
            apply(tarai, x - 1, y, z),
            apply(tarai, y - 1, z, x),
            apply(tarai, z - 1, x, y),
        )
    else
        y
    end

generate_fib(n) = withcontext(apply -> apply(fib, n))
generate_tarai(x, y, z) = withcontext(apply -> apply(tarai, x, y, z))

function test_fib(n)
    intervals, trees, result = generate_fib(n)
    @test result == just_apply(fib, n)
    @test _interval_trees(intervals) == trees
end

function test_fib()
    @testset for n in 0:10
        test_fib(n)
    end
end

function test_tarai(x, y, z)
    intervals, trees, result = generate_tarai(x, y, z)
    @test result == just_apply(tarai, x, y, z)
    @test _interval_trees(intervals) == trees
end

function test_tarai()
    @testset for x in 2:4
        test_tarai(x, 1, 10)
    end
end

end  # module


text:
using Test, GenericLinearAlgebra, LinearAlgebra, Quaternions
Base.isreal(q::Quaternion) = q.v1 == q.v2 == q.v3 == 0

@testset "The selfadjoint eigen problem" begin
    n = 50
    @testset "SymTridiagonal" begin
        # Should automatically dispatch to method defined in this
        # package since a BigFloat methods isn't defined in
        # LinearAlgebra
        T = SymTridiagonal(big.(randn(n)), big.(randn(n - 1)))
        vals, vecs  = eigen(T)
        @testset "default" begin
            @test (vecs'*T)*vecs ≈ Diagonal(vals)
            @test eigvals(T) ≈ vals
            @test vecs'vecs ≈ Matrix(I, n, n)
        end

        @testset "eigen2" begin
            vals2, vecs2 = GenericLinearAlgebra.eigen2(T)
            @test vals ≈ vals2
            @test vecs[[1,n],:] == vecs2
            @test vecs2*vecs2' ≈ Matrix(I, 2, 2)
        end

        @testset "QR version (QL is default)" begin
            vals, vecs = GenericLinearAlgebra.eigQR!(copy(T), vectors = Matrix{eltype(T)}(I, n, n))
            @test (vecs'*T)*vecs ≈ Diagonal(vals)
            @test eigvals(T) ≈ vals
            @test vecs'vecs ≈ Matrix(I, n, n)
        end
    end

    @testset "(full) Symmetric" for uplo in (:L, :U)
        A = Hermitian(big.(randn(n, n)), uplo)
        vals, vecs = eigen(A)
        @testset "default" begin
            @test vecs'*A*vecs ≈ diagm(0 => vals)
            @test eigvals(A) ≈ vals
            @test vecs'vecs ≈ Matrix(I, n, n)
        end

        @testset "eigen2" begin
            vals2, vecs2 = GenericLinearAlgebra.eigen2(A)
            @test vals ≈ vals2
            @test vecs[[1,n],:] ≈ vecs2
            @test vecs2*vecs2'  ≈ Matrix(I, 2, 2)
        end
    end

    @testset "(full) Quaternion Hermitian using :$uplo" for uplo in (:L, :U)
        V = qr([Quaternion(randn(4)...) for i in 1:n, j in 1:n]).Q
        λ = 10 .^ range(-8, stop=0, length=n)
        A = Hermitian(V*Diagonal(λ)*V' |> t -> (t + t')/2, uplo)
        vals, vecs = eigen(A)
        @testset "default" begin
            if uplo == :L # FixMe! Probably an conjugation is off somewhere. Don't have time to check now.
                @test_broken vecs'*A*vecs ≈ diagm(0=> vals)
            else
                @test vecs'*A*vecs ≈ diagm(0 => vals)
            end
            @test eigvals(A)   ≈ vals
            @test vals         ≈ λ rtol=1e-13*n
            @test vecs'vecs    ≈ Matrix(I, n, n)
        end

        @testset "eigen2" begin
            vals2, vecs2 = GenericLinearAlgebra.eigen2(A)
            @test vals ≈ vals2
            @test vecs[[1,n],:] ≈ vecs2
            @test vecs2*vecs2'  ≈ Matrix(I, 2, 2)
        end
    end

    @testset "big Hermitian{<:Complex}" begin
        # This one used to cause an ambiguity error. See #35
        A = complex.(randn(4,4), randn(4,4))
        @test Float64.(eigen(Hermitian(big.(A))).values) ≈ eigen(Hermitian(copy(A))).values
        @test Float64.(eigvals(Hermitian(big.(A))))      ≈ eigvals(Hermitian(copy(A)))
    end

    @testset "generic Givens" begin
        x, y = randn(2)
        c, s, r = invoke(LinearAlgebra.givensAlgorithm, Tuple{Real,Real}, x, y)
        @test c*x + s*y ≈ r
        @test c*y ≈ s*x
    end

    @testset "out-of-bounds issue in 1x1 case" begin
        @test GenericLinearAlgebra._eigvals!(SymTridiagonal([1.0], Float64[])) == [1.0]
        @test GenericLinearAlgebra._eigen!(SymTridiagonal([1.0], Float64[])).values == [1.0]
        @test GenericLinearAlgebra._eigen!(SymTridiagonal([1.0], Float64[])).vectors == fill(1.0, 1, 1)
    end

    # Issue #52
    @testset "convergence criterion when diagonal has zeros" begin
        M1 = Hermitian(zeros(3, 3))
        M1[1,1] = 0.01
        M2 = Hermitian(zeros(3, 3))
        M2[3, 3] = 0.01
        @test eigvals(M1) == GenericLinearAlgebra._eigvals!(copy(M1))
        @test eigvals(M2) == GenericLinearAlgebra._eigvals!(copy(M2))
        @test eigen(M1).values == GenericLinearAlgebra._eigen!(copy(M1)).values
        @test eigen(M2).values == GenericLinearAlgebra._eigen!(copy(M2)).values
    end
end


text:
function heavy_chain_plot!(fig, chain::Chain, xmin::Number, xmax::Number, t::Number)
  chain_length = chain.x_coords[end]
  const basewidth = 0.2 #width of the car
  const baseheight = 0.1 #height of the car

  #plot
  plot!(fig, ratio=:equal, xlim = (xmin, xmax), ylim = (-chain_length*1.1, chain_length*0.05+baseheight/2), title = "t=$(round(t, 1))", lab = "")

  #plot zero line
  plot!(fig, [xmin, xmax], [0.0, 0.0], c=:black, l=:dot, lab = "", grid = false)

  #plot base
  base(x) = Plots.Shape(x+[-basewidth/2, basewidth/2, basewidth/2, -basewidth/2, -basewidth/2], [-baseheight/2, -baseheight/2, baseheight/2, baseheight/2, -baseheight/2])
  plot!(fig, base(chain.w[1]), c=:orange, lab = "")

  #project x_coords to be consistent with the chain length
  x_new = Array{Float64}(length(chain.x_coords))
  x_new[1] = 0.0
  for i = 2:length(x_new)
    x_new[i] = x_new[i-1]+sqrt( (chain.x_coords[i]-chain.x_coords[i-1])^2 - (chain.w[i]-chain.w[i-1])^2 )
  end

  #plot chain
  plot!(fig, chain.w, -x_new, c = :black, lw = 2, marker = :circle, ms = 4, lab = "")
end

max_stars_repo_name: NikonPic/REINFORCEMENT-JULIA

max_issues_repo_name: NikonPic/REINFORCEMENT-JULIA

max_forks_repo_name: NikonPic/REINFORCEMENT-JULIA


text:
__precompile__()

module DPMMSubClusters

using Distributed
using DistributedArrays
using StatsBase
using Distributions
using SpecialFunctions
using LinearAlgebra
using JLD2
using Clustering

import Random:seed!

include("ds.jl")

#Priors:
include("priors/niw.jl")
include("priors/multinomial_prior.jl")

#Distributions:
include("distributions/mv_gaussian.jl")
include("distributions/multinomial_dist.jl")

include("utils.jl")
include("shared_actions.jl")
include("local_clusters_actions.jl")
include("global_params.jl")
include("dp-parallel-sampling.jl")
include("data_generators.jl")

export generate_gaussian_data, generate_mnmm_data, dp_parallel_sampling, dp_parallel, run_model_from_checkpoint, save_model, calculate_posterior, fit, get_labels_histogram,predict

end # module