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

"""
    associate_domain(acm_certificate_arn, domain_name, fleet_arn)
    associate_domain(acm_certificate_arn, domain_name, fleet_arn, params::Dict{String,<:Any})

Specifies a domain to be associated to Amazon WorkLink.

# Arguments
- `acm_certificate_arn`: The ARN of an issued ACM certificate that is valid for the domain
  being associated.
- `domain_name`: The fully qualified domain name (FQDN).
- `fleet_arn`: The Amazon Resource Name (ARN) of the fleet.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DisplayName"`: The name to display.
"""
associate_domain(AcmCertificateArn, DomainName, FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/associateDomain", Dict{String, Any}("AcmCertificateArn"=>AcmCertificateArn, "DomainName"=>DomainName, "FleetArn"=>FleetArn); aws_config=aws_config)
associate_domain(AcmCertificateArn, DomainName, FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/associateDomain", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("AcmCertificateArn"=>AcmCertificateArn, "DomainName"=>DomainName, "FleetArn"=>FleetArn), params)); aws_config=aws_config)

"""
    associate_website_authorization_provider(authorization_provider_type, fleet_arn)
    associate_website_authorization_provider(authorization_provider_type, fleet_arn, params::Dict{String,<:Any})

Associates a website authorization provider with a specified fleet. This is used to
authorize users against associated websites in the company network.

# Arguments
- `authorization_provider_type`: The authorization provider type.
- `fleet_arn`: The ARN of the fleet.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DomainName"`: The domain name of the authorization provider. This applies only to
  SAML-based authorization providers.
"""
associate_website_authorization_provider(AuthorizationProviderType, FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/associateWebsiteAuthorizationProvider", Dict{String, Any}("AuthorizationProviderType"=>AuthorizationProviderType, "FleetArn"=>FleetArn); aws_config=aws_config)
associate_website_authorization_provider(AuthorizationProviderType, FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/associateWebsiteAuthorizationProvider", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("AuthorizationProviderType"=>AuthorizationProviderType, "FleetArn"=>FleetArn), params)); aws_config=aws_config)

"""
    associate_website_certificate_authority(certificate, fleet_arn)
    associate_website_certificate_authority(certificate, fleet_arn, params::Dict{String,<:Any})

Imports the root certificate of a certificate authority (CA) used to obtain TLS
certificates used by associated websites within the company network.

# Arguments
- `certificate`: The root certificate of the CA.
- `fleet_arn`: The ARN of the fleet.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DisplayName"`: The certificate name to display.
"""
associate_website_certificate_authority(Certificate, FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/associateWebsiteCertificateAuthority", Dict{String, Any}("Certificate"=>Certificate, "FleetArn"=>FleetArn); aws_config=aws_config)
associate_website_certificate_authority(Certificate, FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/associateWebsiteCertificateAuthority", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Certificate"=>Certificate, "FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Creates a fleet. A fleet consists of resources and the configuration that delivers
associated websites to authorized users who download and set up the Amazon WorkLink app.

# Arguments
- `fleet_name`: A unique name for the fleet.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DisplayName"`: The fleet name to display.
- `"OptimizeForEndUserLocation"`: The option to optimize for better performance by routing
  traffic through the closest AWS Region to users, which may be outside of your home Region.
- `"Tags"`:  The tags to add to the resource. A tag is a key-value pair.
"""
create_fleet(FleetName; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/createFleet", Dict{String, Any}("FleetName"=>FleetName); aws_config=aws_config)
create_fleet(FleetName, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/createFleet", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetName"=>FleetName), params)); aws_config=aws_config)

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

Deletes a fleet. Prevents users from accessing previously associated websites.

# Arguments
- `fleet_arn`: The ARN of the fleet.

"""
delete_fleet(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/deleteFleet", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
delete_fleet(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/deleteFleet", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Describes the configuration for delivering audit streams to the customer account.

# Arguments
- `fleet_arn`: The ARN of the fleet.

"""
describe_audit_stream_configuration(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeAuditStreamConfiguration", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
describe_audit_stream_configuration(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeAuditStreamConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Describes the networking configuration to access the internal websites associated with the
specified fleet.

# Arguments
- `fleet_arn`: The ARN of the fleet.

"""
describe_company_network_configuration(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeCompanyNetworkConfiguration", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
describe_company_network_configuration(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeCompanyNetworkConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

"""
    describe_device(device_id, fleet_arn)
    describe_device(device_id, fleet_arn, params::Dict{String,<:Any})

Provides information about a user's device.

# Arguments
- `device_id`: A unique identifier for a registered user's device.
- `fleet_arn`: The ARN of the fleet.

"""
describe_device(DeviceId, FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeDevice", Dict{String, Any}("DeviceId"=>DeviceId, "FleetArn"=>FleetArn); aws_config=aws_config)
describe_device(DeviceId, FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeDevice", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DeviceId"=>DeviceId, "FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Describes the device policy configuration for the specified fleet.

# Arguments
- `fleet_arn`: The ARN of the fleet.

"""
describe_device_policy_configuration(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeDevicePolicyConfiguration", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
describe_device_policy_configuration(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeDevicePolicyConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Provides information about the domain.

# Arguments
- `domain_name`: The name of the domain.
- `fleet_arn`: The ARN of the fleet.

"""
describe_domain(DomainName, FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeDomain", Dict{String, Any}("DomainName"=>DomainName, "FleetArn"=>FleetArn); aws_config=aws_config)
describe_domain(DomainName, FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeDomain", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Provides basic information for the specified fleet, excluding identity provider,
networking, and device configuration details.

# Arguments
- `fleet_arn`: The Amazon Resource Name (ARN) of the fleet.

"""
describe_fleet_metadata(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeFleetMetadata", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
describe_fleet_metadata(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeFleetMetadata", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Describes the identity provider configuration of the specified fleet.

# Arguments
- `fleet_arn`: The ARN of the fleet.

"""
describe_identity_provider_configuration(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeIdentityProviderConfiguration", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
describe_identity_provider_configuration(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeIdentityProviderConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

"""
    describe_website_certificate_authority(fleet_arn, website_ca_id)
    describe_website_certificate_authority(fleet_arn, website_ca_id, params::Dict{String,<:Any})

Provides information about the certificate authority.

# Arguments
- `fleet_arn`: The ARN of the fleet.
- `website_ca_id`: A unique identifier for the certificate authority.

"""
describe_website_certificate_authority(FleetArn, WebsiteCaId; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeWebsiteCertificateAuthority", Dict{String, Any}("FleetArn"=>FleetArn, "WebsiteCaId"=>WebsiteCaId); aws_config=aws_config)
describe_website_certificate_authority(FleetArn, WebsiteCaId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/describeWebsiteCertificateAuthority", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn, "WebsiteCaId"=>WebsiteCaId), params)); aws_config=aws_config)

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

Disassociates a domain from Amazon WorkLink. End users lose the ability to access the
domain with Amazon WorkLink.

# Arguments
- `domain_name`: The name of the domain.
- `fleet_arn`: The ARN of the fleet.

"""
disassociate_domain(DomainName, FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/disassociateDomain", Dict{String, Any}("DomainName"=>DomainName, "FleetArn"=>FleetArn); aws_config=aws_config)
disassociate_domain(DomainName, FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/disassociateDomain", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "FleetArn"=>FleetArn), params)); aws_config=aws_config)

"""
    disassociate_website_authorization_provider(authorization_provider_id, fleet_arn)
    disassociate_website_authorization_provider(authorization_provider_id, fleet_arn, params::Dict{String,<:Any})

Disassociates a website authorization provider from a specified fleet. After the
disassociation, users can't load any associated websites that require this authorization
provider.

# Arguments
- `authorization_provider_id`: A unique identifier for the authorization provider.
- `fleet_arn`: The ARN of the fleet.

"""
disassociate_website_authorization_provider(AuthorizationProviderId, FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/disassociateWebsiteAuthorizationProvider", Dict{String, Any}("AuthorizationProviderId"=>AuthorizationProviderId, "FleetArn"=>FleetArn); aws_config=aws_config)
disassociate_website_authorization_provider(AuthorizationProviderId, FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/disassociateWebsiteAuthorizationProvider", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("AuthorizationProviderId"=>AuthorizationProviderId, "FleetArn"=>FleetArn), params)); aws_config=aws_config)

"""
    disassociate_website_certificate_authority(fleet_arn, website_ca_id)
    disassociate_website_certificate_authority(fleet_arn, website_ca_id, params::Dict{String,<:Any})

Removes a certificate authority (CA).

# Arguments
- `fleet_arn`: The ARN of the fleet.
- `website_ca_id`: A unique identifier for the CA.

"""
disassociate_website_certificate_authority(FleetArn, WebsiteCaId; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/disassociateWebsiteCertificateAuthority", Dict{String, Any}("FleetArn"=>FleetArn, "WebsiteCaId"=>WebsiteCaId); aws_config=aws_config)
disassociate_website_certificate_authority(FleetArn, WebsiteCaId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/disassociateWebsiteCertificateAuthority", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn, "WebsiteCaId"=>WebsiteCaId), params)); aws_config=aws_config)

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

Retrieves a list of devices registered with the specified fleet.

# Arguments
- `fleet_arn`: The ARN of the fleet.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of results to be included in the next page.
- `"NextToken"`: The pagination token used to retrieve the next page of results for this
  operation. If this value is null, it retrieves the first page.
"""
list_devices(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/listDevices", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
list_devices(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/listDevices", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Retrieves a list of domains associated to a specified fleet.

# Arguments
- `fleet_arn`: The ARN of the fleet.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of results to be included in the next page.
- `"NextToken"`: The pagination token used to retrieve the next page of results for this
  operation. If this value is null, it retrieves the first page.
"""
list_domains(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/listDomains", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
list_domains(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/listDomains", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Retrieves a list of fleets for the current account and Region.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of results to be included in the next page.
- `"NextToken"`: The pagination token used to retrieve the next page of results for this
  operation. If this value is null, it retrieves the first page.
"""
list_fleets(; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/listFleets"; aws_config=aws_config)
list_fleets(params::AbstractDict{String, Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/listFleets", params; aws_config=aws_config)

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

Retrieves a list of tags for the specified resource.

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

"""
list_tags_for_resource(ResourceArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("GET", "/tags/$(ResourceArn)"; aws_config=aws_config)
list_tags_for_resource(ResourceArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("GET", "/tags/$(ResourceArn)", params; aws_config=aws_config)

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

Retrieves a list of website authorization providers associated with a specified fleet.

# Arguments
- `fleet_arn`: The ARN of the fleet.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of results to be included in the next page.
- `"NextToken"`: The pagination token to use to retrieve the next page of results for this
  operation. If this value is null, it retrieves the first page.
"""
list_website_authorization_providers(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/listWebsiteAuthorizationProviders", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
list_website_authorization_providers(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/listWebsiteAuthorizationProviders", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Retrieves a list of certificate authorities added for the current account and Region.

# Arguments
- `fleet_arn`: The ARN of the fleet.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of results to be included in the next page.
- `"NextToken"`: The pagination token used to retrieve the next page of results for this
  operation. If this value is null, it retrieves the first page.
"""
list_website_certificate_authorities(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/listWebsiteCertificateAuthorities", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
list_website_certificate_authorities(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/listWebsiteCertificateAuthorities", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Moves a domain to ACTIVE status if it was in the INACTIVE status.

# Arguments
- `domain_name`: The name of the domain.
- `fleet_arn`: The ARN of the fleet.

"""
restore_domain_access(DomainName, FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/restoreDomainAccess", Dict{String, Any}("DomainName"=>DomainName, "FleetArn"=>FleetArn); aws_config=aws_config)
restore_domain_access(DomainName, FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/restoreDomainAccess", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Moves a domain to INACTIVE status if it was in the ACTIVE status.

# Arguments
- `domain_name`: The name of the domain.
- `fleet_arn`: The ARN of the fleet.

"""
revoke_domain_access(DomainName, FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/revokeDomainAccess", Dict{String, Any}("DomainName"=>DomainName, "FleetArn"=>FleetArn); aws_config=aws_config)
revoke_domain_access(DomainName, FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/revokeDomainAccess", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "FleetArn"=>FleetArn), params)); aws_config=aws_config)

"""
    sign_out_user(fleet_arn, username)
    sign_out_user(fleet_arn, username, params::Dict{String,<:Any})

Signs the user out from all of their devices. The user can sign in again if they have valid
credentials.

# Arguments
- `fleet_arn`: The ARN of the fleet.
- `username`: The name of the user.

"""
sign_out_user(FleetArn, Username; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/signOutUser", Dict{String, Any}("FleetArn"=>FleetArn, "Username"=>Username); aws_config=aws_config)
sign_out_user(FleetArn, Username, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/signOutUser", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn, "Username"=>Username), params)); aws_config=aws_config)

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

Adds or overwrites one or more tags for the specified resource, such as a fleet. Each tag
consists of a key and an optional value. If a resource already has a tag with the same key,
this operation updates its value.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the fleet.
- `tags`: The tags to add to the resource. A tag is a key-value pair.

"""
tag_resource(ResourceArn, Tags; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/tags/$(ResourceArn)", Dict{String, Any}("Tags"=>Tags); aws_config=aws_config)
tag_resource(ResourceArn, Tags, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/tags/$(ResourceArn)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Tags"=>Tags), params)); aws_config=aws_config)

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

Removes one or more tags from the specified resource.

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

"""
untag_resource(ResourceArn, tagKeys; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("DELETE", "/tags/$(ResourceArn)", Dict{String, Any}("tagKeys"=>tagKeys); aws_config=aws_config)
untag_resource(ResourceArn, tagKeys, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("DELETE", "/tags/$(ResourceArn)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("tagKeys"=>tagKeys), params)); aws_config=aws_config)

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

Updates the audit stream configuration for the fleet.

# Arguments
- `fleet_arn`: The ARN of the fleet.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"AuditStreamArn"`: The ARN of the Amazon Kinesis data stream that receives the audit
  events.
"""
update_audit_stream_configuration(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/updateAuditStreamConfiguration", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
update_audit_stream_configuration(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/updateAuditStreamConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

"""
    update_company_network_configuration(fleet_arn, security_group_ids, subnet_ids, vpc_id)
    update_company_network_configuration(fleet_arn, security_group_ids, subnet_ids, vpc_id, params::Dict{String,<:Any})

Updates the company network configuration for the fleet.

# Arguments
- `fleet_arn`: The ARN of the fleet.
- `security_group_ids`: The security groups associated with access to the provided subnets.
- `subnet_ids`: The subnets used for X-ENI connections from Amazon WorkLink rendering
  containers.
- `vpc_id`: The VPC with connectivity to associated websites.

"""
update_company_network_configuration(FleetArn, SecurityGroupIds, SubnetIds, VpcId; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/updateCompanyNetworkConfiguration", Dict{String, Any}("FleetArn"=>FleetArn, "SecurityGroupIds"=>SecurityGroupIds, "SubnetIds"=>SubnetIds, "VpcId"=>VpcId); aws_config=aws_config)
update_company_network_configuration(FleetArn, SecurityGroupIds, SubnetIds, VpcId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/updateCompanyNetworkConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn, "SecurityGroupIds"=>SecurityGroupIds, "SubnetIds"=>SubnetIds, "VpcId"=>VpcId), params)); aws_config=aws_config)

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

Updates the device policy configuration for the fleet.

# Arguments
- `fleet_arn`: The ARN of the fleet.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DeviceCaCertificate"`: The certificate chain, including intermediate certificates and
  the root certificate authority certificate used to issue device certificates.
"""
update_device_policy_configuration(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/updateDevicePolicyConfiguration", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
update_device_policy_configuration(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/updateDevicePolicyConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Updates domain metadata, such as DisplayName.

# Arguments
- `domain_name`: The name of the domain.
- `fleet_arn`: The ARN of the fleet.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DisplayName"`: The name to display.
"""
update_domain_metadata(DomainName, FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/updateDomainMetadata", Dict{String, Any}("DomainName"=>DomainName, "FleetArn"=>FleetArn); aws_config=aws_config)
update_domain_metadata(DomainName, FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/updateDomainMetadata", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("DomainName"=>DomainName, "FleetArn"=>FleetArn), params)); aws_config=aws_config)

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

Updates fleet metadata, such as DisplayName.

# Arguments
- `fleet_arn`: The ARN of the fleet.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DisplayName"`: The fleet name to display. The existing DisplayName is unset if null is
  passed.
- `"OptimizeForEndUserLocation"`: The option to optimize for better performance by routing
  traffic through the closest AWS Region to users, which may be outside of your home Region.
"""
update_fleet_metadata(FleetArn; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/UpdateFleetMetadata", Dict{String, Any}("FleetArn"=>FleetArn); aws_config=aws_config)
update_fleet_metadata(FleetArn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/UpdateFleetMetadata", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn), params)); aws_config=aws_config)

"""
    update_identity_provider_configuration(fleet_arn, identity_provider_type)
    update_identity_provider_configuration(fleet_arn, identity_provider_type, params::Dict{String,<:Any})

Updates the identity provider configuration for the fleet.

# Arguments
- `fleet_arn`: The ARN of the fleet.
- `identity_provider_type`: The type of identity provider.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"IdentityProviderSamlMetadata"`: The SAML metadata document provided by the customer’s
  identity provider. The existing IdentityProviderSamlMetadata is unset if null is passed.
"""
update_identity_provider_configuration(FleetArn, IdentityProviderType; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/updateIdentityProviderConfiguration", Dict{String, Any}("FleetArn"=>FleetArn, "IdentityProviderType"=>IdentityProviderType); aws_config=aws_config)
update_identity_provider_configuration(FleetArn, IdentityProviderType, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = worklink("POST", "/updateIdentityProviderConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("FleetArn"=>FleetArn, "IdentityProviderType"=>IdentityProviderType), params)); aws_config=aws_config)


text:
#
# This file is a part of MolecularGraph.jl
# Licensed under the MIT License http://opensource.org/licenses/MIT
#

export
    PERIODIC_TABLE, H_WEIGHT,
    SDFileAtom, SmilesAtom, SmartsAtom,
    setcharge,
    atomsymbol, atomnumber, atomname, atomweight

const PERIODIC_TABLE = YAML.load(open(
    joinpath(dirname(@__FILE__), "..", "..", "assets", "const", "periodictable.yaml")
))
const H_WEIGHT = PERIODIC_TABLE["H"]["std_weight"]

struct SDFileAtom <: Atom
    symbol::Symbol
    charge::Int
    multiplicity::Int
    mass::Union{Float64, Nothing}
    coords::Union{Vector{Float64}, Nothing}

    function SDFileAtom(sym, chg, multi, mass, coords)
        if !(string(sym) in keys(PERIODIC_TABLE))
            throw(ErrorException("unsupported symbol: $(sym)"))
        end
        new(sym, chg, multi, mass, coords)
    end
end

SDFileAtom() = SDFileAtom(:C, 0, 1, nothing, nothing)
SDFileAtom(sym) = SDFileAtom(sym, 0, 1, nothing, nothing)
SDFileAtom(sym, chg) = SDFileAtom(sym, chg, 1, nothing, nothing)

setcharge(a, chg
    ) = SDFileAtom(a.symbol, chg, a.multiplicity, a.mass, a.coords)

struct SmilesAtom <: Atom
    symbol::Symbol
    charge::Int
    multiplicity::Int
    mass::Union{Float64, Nothing}
    isaromatic::Union{Bool, Nothing}
    stereo::Union{Int, Nothing}

    function SmilesAtom(sym, chg, multi, mass, aromatic, stereo)
        if !(string(sym) in keys(PERIODIC_TABLE))
            throw(ErrorException("unsupported symbol: $(sym)"))
        end
        new(sym, chg, multi, mass, aromatic, stereo)
    end
end

SmilesAtom() = SmilesAtom(:C, 0, 1, nothing, nothing, nothing)
SmilesAtom(sym) = SmilesAtom(sym, 0, 1, nothing, nothing, nothing)
SmilesAtom(sym, chg) = SmilesAtom(sym, chg, 1, nothing, nothing, nothing)

setcharge(a::SmilesAtom, chg) = SmilesAtom(
    a.symbol, chg, a.multiplicity, a.mass, a.isaromatic, a.stereo)

struct SmartsAtom <: QueryAtom
    query::Pair
end

function atomsymbol(number::Int)
    for (sym, atom) in PERIODIC_TABLE
        if atom["number"] == number
            return Symbol(sym)
        end
    end
    throw(ErrorException("invalid atomic number $(number)"))
end

atomnumber(symbol::Symbol) = PERIODIC_TABLE[string(symbol)]["number"]
atomnumber(atom::Atom) = PERIODIC_TABLE[string(atom.symbol)]["number"]

atomname(symbol::Symbol) = PERIODIC_TABLE[string(symbol)]["name"]
atomname(atom::Atom) = PERIODIC_TABLE[string(atom.symbol)]["name"]

function atomweight(atom::Atom)
    stdweight = PERIODIC_TABLE[string(atom.symbol)]["std_weight"]
    atom.mass === nothing ? stdweight : atom.mass
end

ext: jl


text:
## Functions to provide oversampled grids for FrameFun approximations.

equispacedgrid(domain::AbstractInterval, smpl_par::Int) =
    EquispacedGrid(smpl_par, infimum(domain), supremum(domain))

equispacedgrid(domain::ProductDomain, smpl_par::Tuple) =
    cartesianproduct(map(equispacedgrid, components(domain), smpl_par))

equispacedgrid(domain::Domain, smpl_par::Tuple) = subgrid(equispacedgrid(boundingbox(domain), smpl_par), domain)

function oversampling_grid(dict::Dictionary, smpl_par)
    if hasinterpolationgrid(dict)
        try
            return resize(interpolation_grid(dict), smpl_par)
        catch
            return interpolation_grid(resize(dict, smpl_par))
        end
    else
        # If the dictionary does not have an associated grid, we compute an
        # equispaced grid on its support.
        equispacedgrid(support(dict), smpl_par)
    end
end

oversampling_grid(dict::TensorProductDict, smpl_par) = ProductGrid(map(oversampling_grid, components(dict), smpl_par)...)
oversampling_grid(dict::TensorProductDict, smpl_par::CartesianIndex) = oversampling_grid(dict, smpl_par.I)
oversampling_grid(dict::TensorProductDict, smpl_par::Int) = error("Expects a tuple or a CartesianIndex")

oversampling_grid(dict::BasisFunctions.CompositeDict, smpl_par) = oversampling_grid(component(dict,1), smpl_par)

oversampling_grid(dict::WeightedDict, smpl_par) = oversampling_grid(superdict(dict), smpl_par)

oversampling_grid(dict::MappedDict, smpl_par) = apply_map(oversampling_grid(superdict(dict), smpl_par), forward_map(dict))

oversampling_grid(dict::OperatedDict, smpl_par) = oversampling_grid(superdict(dict), smpl_par)

# Make an initial guess for the sampling parameter smpl_par. The problem is that we have to
# determine the type of smpl_par. We try to infer this from the dimension of the dictionary and/or
# of its support.
initialguess(ap, M) = initialguess(dictionary(ap), M)
initialguess(dict::Dictionary1d, M::Int) = M
initialguess(dict::BasisFunctions.CompositeDict, M) = initialguess(component(dict,1), M)
initialguess(dict::BasisFunctions.CompositeDict, M::Int) = initialguess(component(dict,1), M)
initialguess(dict::Dictionary, M) = _initialguess(dict, M, support(dict), size(dict))
_initialguess(dict::Dictionary, M, domain::Domain, size) = size
_initialguess(dict::Dictionary, M, domain::Domain1d, size::Tuple{Int}) = M
function _initialguess(dict::Dictionary, M, domain::Domain2d, size::Tuple{Int})
    n = round(Int,sqrt(size[1]))
    (n,n)
end

match_and_correct_sampling_parameter(platform::Platform, plt_par, M; dict=dictionary(platform, plt_par), options...) =
    match_and_correct_sampling_parameter(platform, plt_par, M, initialguess(dict, M); dict=dict, options...)
match_and_correct_sampling_parameter(dict::Dictionary, M; options...) =
    match_and_correct_sampling_parameter(dict, M, initialguess(dict, M); options...)

function match_and_correct_sampling_parameter(platform::Platform, plt_par, M, smpl_par_init; dict=dictionary(platform, plt_par), options...)
    smpl_par_trial = match_sampling_parameter(dict, M, smpl_par_init)
    # The above does not always return a suitable smpl_par since it does not account for the platform/Dictionary
    # correct the result to a suitable one if necesarry
    correct_sampling_parameter(platform, plt_par, smpl_par_trial; dict=dict, options...)
end

function match_and_correct_sampling_parameter(dict::Dictionary, M, smpl_par_init; options...)
    smpl_par_trial = match_sampling_parameter(dict, M, smpl_par_init)
    # The above does not always return a suitable smpl_par since it does not account for the platform/Dictionary
    # correct the result to a suitable one if necesarry
    correct_sampling_parameter(dict, smpl_par_trial; options...)
end

correct_sampling_parameter(dict::Dictionary, smpl_par_trial; options...) = smpl_par_trial
correct_sampling_parameter(platform::Platform, plt_par, smpl_par_trial; options...) = smpl_par_trial
correct_sampling_parameter(p::ProductPlatform, plt_par, smpl_par; options...) =
    tuple(map(x->correct_sampling_parameter(x...; options...), zip(components(p), plt_par, smpl_par))...)

function match_sampling_parameter(samplingobject::Dictionary, M, smpl_par_init)
    objective(smpl_par) = length(oversampling_grid(samplingobject, smpl_par))-M
    monotonic_bisect(objective, smpl_par_init)
end

struct BisectionType end
Base.broadcastable(bt::BisectionType) = Ref(bt)

bisect_smaller(::BisectionType, L::Int) = L>>1
bisect_smaller(::BisectionType, L::Number) = L/2
bisect_larger(::BisectionType, L::Number) = 2L

bisect_average(bt::BisectionType, L1, L2) = bisect_average(bt, promote(L1,L2)...)
bisect_average(::BisectionType, L1::Int, L2::Int) = ceil(Int, (L1+L2)/2)
bisect_average(::BisectionType, L1::T, L2::T) where {T} = convert(T, (L1+L2)/2)

bisect_smaller(bt::BisectionType, L::Tuple) = bisect_smaller.(bt, L)
bisect_larger(bt::BisectionType, L::Tuple) = bisect_larger.(bt, L)
bisect_average(bt::BisectionType, L1::Tuple, L2::Tuple) = bisect_average.(bt, L1, L2)

bisect_small(l1) = bisect_smaller(BisectionType(), l1)
bisect_larger(l1) = bisect_larger(BisectionType(), l2)
bisect_average(l1, l2) = bisect_average(BisectionType(), l1, l2)

"""
Find the root of a monotonically increasing function with a given starting value
`L_init` and using bisection.

The value is increased or decreased first (using `bisect_larger` and
`bisect_smaller`) until an interval is found for which the objective function
switches sign. Next, the smallest value of `L` for which the objective function
becomes positive is located using bisection (with `bisect_average` to average out
two values of `L`).

The user can optionally supply an argument `bt`, which will be passed as the
first argument to the `bisect_X` routines. Thus, the variable `L` can have any
type as long as making it larger/smaller or computing averages can be meaningfully
defined.

The bisection is run until convergence. This ensures that if `L` has a discrete
nature, the optimal solution is always found exactly, in finite time.
"""
function monotonic_bisect(objective, L_init; maxiterations = 20, bt = BisectionType())
    local L1
    Z = objective(L_init)
    if Z ≈ 0
        return L_init
    end
    iterations = 0
    if Z > 0
        while (Z > 0) && (iterations < maxiterations)
            iterations += 1
            L1 = L_init
            L_init = bisect_smaller(bt, L1)
            Z = objective(L_init)
        end
        iterations == maxiterations && error("Maximal number of iterations reached in monotonic_bisect.")
        monotonic_bisect(objective, L_init, L1, bt)
    else
        while (Z < 0) && (iterations <  maxiterations)
            iterations += 1
            L1 = L_init
            L_init = bisect_larger(bt, L1)
            Z = objective(L_init)
        end
        iterations == maxiterations && error("Maximal number of iterations reached in monotonic_bisect.")
        monotonic_bisect(objective, L1, L_init, bt)
    end
end

function monotonic_bisect(objective, Lmin, Lmax, bt)
    Lmin, Lmax, bt
    Lmid = bisect_average(bt, Lmin, Lmax)
    if (Lmid == Lmax) || (Lmid == Lmin)
        return Lmid
    end
    Z = objective(Lmid)
    if Z ≈ 0
        return Lmid
    elseif Z > 0
        monotonic_bisect(objective, Lmin, Lmid, bt)
    else
        monotonic_bisect(objective, Lmid, Lmax, bt)
    end
end


text:
module Bracket

include("genebracket.jl")

function side_effect(n)
    if n == 1
        println("Function 1")
    else
        println("Other ",n)
    end
end

function main(prog)
    println("Start Gene Bracket")
    vm = Vm(side_effect)
    #load prelude
    #vm.bra = load_file(vm,"prelude.clj")
    #eval_bra(vm)

    vm.bra = load_file(vm,prog)
    printBra(vm, vm.bra)
    vm.ket = NIL

    @time eval_bra(vm)

    printKet(vm, vm.ket)
    println("done")
end

function main()
    println("Start Bracket")
    vm = Vm(side_effect)
    #reset!(vm)
    #vm.env = cons(vm,NIL,NIL)
    #load prelude
    vm.bra = load_file(vm,"prelude.clj")
    #vm.ket = NIL
    eval_bra(vm)

    # repl(vm)    # repl should run in depth 0
    #vm.depth = 1  # normal programs start in depth 1

    #vm.ket = NIL

    #str = "1 3 foo [bar 4 dup]"
    #str = "eval [ rec gt 0 dup add 1 print dup] -20 trace 0"
    #str = "eval [ rec gt 0 dup add 1 ] -50000000"  # 5e7  # 2.8 sec
    #str = "eval [ rec gt 0 dup add 1 ] -500000000"  # 5e8  # 16-17.6sec

     # ***************************

    #str = "ack 3 10 def ack' \\[m n]
    # [eval if eq 0 m
    #    [+ n 1]
    # [eval if eq 0 n
    #     [ack - m 1 1]
    # [ack - m 1 ack m - n 1] ]] " # "125")

     # bench
     # ack 3 4 --> 0.028
     # ack 3 5 --> 0.038
     # ack 3 6 --> 0.086
     # ack 3 7 --> 0.26
     # ack 3 8 --> 0.92
     # ack 3 9 --> 2.87
     # ack 3 10 --> 10.7

     # ***************************

    #str = " x eval [x def x' 2] x def x' 1 trace 1"
    #str = "foo def x' 3 def foo' [x` def x'] 4"
    #str = "rnd 3 rnd 3 rnd 3 rnd 3 rnd 3 rnd 3 rnd 3 rnd 3"
    #str = "rnd [1 2 3] rnd [1 2 3] rnd [1 2 3] rnd [1 2 3] rnd [1 2 3] rnd [1 2 3] rnd [1 2 3] "
    #= str = "ack 3 10 def ack' \\[m n]
      [cond
        [ [ack - m 1 ack m - n 1]
          [ack - m 1 1]  [eq 0 n]
          [+ n 1]  [eq 0 m]] ]"
    =#

    #=str = "ack 3 11 def ack' \\[m n]
        [eval if
            [+ n 1]
            [ eval if
                [ack - m 1 1]
                [ack - m 1 ack m - n 1]
                eq 0 n
            ]
            eq 0 m
        ]"
    =#

    #str = "eval [rec gt 0 dup add 1 dup] -5"
    str  = "typ 20 trace 1"

    vm.bra = make_bra(vm, str)

    #vm.bra = cons(vm, boxInt(3), cons(vm,boxInt(4), boxInt(5)))
    #vm.bra = cons(vm, boxInt(2), vm.bra)
    #vm.bra = cons(vm, boxInt(3), cons(vm,DEF, NIL))
    #vm.bra = cons(vm, VAL, cons(vm,DEF, boxPrim(2)))
    #vm.bra = load_file("test.clj",vm)

    printBra(vm, vm.bra)
    #vm.bra = cons(box_int(1), NIL, vm)
    vm.ket = NIL

    @time eval_bra(vm)

    printKet(vm, vm.ket)
    println("done")

end

@time main("play.clj")

end # end module


text:
#=
Taken from https://github.com/JuliaPlots/StatsMakie.jl/blob/master/src/typerecipes/distribution.jl
The StatMakie.jl package is licensed under the MIT "Expat" License:
    Copyright (c) 2018: Pietro Vertechi. =#

# pick a nice default x range given a distribution
function default_range(dist::Distribution, alpha=0.0001)
    minval = isfinite(minimum(dist)) ? minimum(dist) : quantile(dist, alpha)
    maxval = isfinite(maximum(dist)) ? maximum(dist) : quantile(dist, 1 - alpha)
    minval..maxval
end

isdiscrete(::Distribution) = false
isdiscrete(::Distribution{<:VariateForm,<:Discrete}) = true

support(dist::Distribution) = default_range(dist)
support(dist::Distribution{<:VariateForm,<:Discrete}) = UnitRange(endpoints(default_range(dist))...)

convert_arguments(P::PlotFunc, dist::Distribution) = convert_arguments(P, support(dist), dist)

function convert_arguments(P::PlotFunc, x::Union{Interval,AbstractVector}, dist::Distribution)
    default_ptype = isdiscrete(dist) ? ScatterLines : Lines
    ptype = plottype(P, default_ptype)
    to_plotspec(ptype, convert_arguments(ptype, x, x -> pdf(dist, x)))
end
# -----------------------------------------------------------------------------
# qqplots (M. K. Borregaard implementation from StatPlots)

"""
    qqplot(x, y; kwargs...)
Draw a Q-Q plot, comparing quantiles of two distributions. `y` must be a list of
samples, i.e., `AbstractVector{<:Real}`, whereas `x` can be
- a list of samples,
- an abstract distribution, e.g. `Normal(0, 1)`,
- a distribution type, e.g. `Normal`.
In the last case, the distribution type is fitted to the data `y`.

The attribute `qqline` (defaults to `:none`) determines how to compute a fit line for the Q-Q plot.
Possible values are the following.
- `:identity` draws the identity line.
- `:fit` computes a least squares line fit of the quantile pairs.
- `:fitrobust` computes the line that passes through the first and third quartiles of the distributions.
- `:none` omits drawing the line.
Broadly speaking, `qqline = :identity` is useful to see if `x` and `y` follow the same distribution,
whereas `qqline = :fit` and `qqline = :fitrobust` are useful to see if the distribution of `y` can be
obtained from the distribution of `x` via an affine transformation.

Graphical attributes are
- `color` to control color of both line and markers (if `markercolor` is not specified)
- `linestyle`
- `linewidth`
- `markercolor`
- `strokecolor`
- `strokewidth`
- `marker`
- `markersize`
"""
@recipe(QQPlot) do scene
    s_theme = default_theme(scene, Scatter)
    l_theme = default_theme(scene, Lines)
    Attributes(
        color = l_theme.color,
        linestyle = l_theme.linestyle,
        linewidth = l_theme.linewidth,
        markercolor = automatic,
        markersize = s_theme.markersize,
        strokecolor = s_theme.strokecolor,
        strokewidth = s_theme.strokewidth,
        marker = s_theme.marker,
        inspectable = theme(scene, :inspectable),
        cycle = [:color],
    )
end

"""
    qqnorm(y; kwargs...)

Shorthand for `qqplot(Normal(0,1), y)`, i.e., draw a Q-Q plot of `y` against the
standard normal distribution. See `qqplot` for more details.
"""
@recipe(QQNorm) do scene
    default_theme(scene, QQPlot)
end

# Compute points and line for the qqplot
function fit_qqplot(x, y; qqline = :none)
    if !(qqline in (:identity, :fit, :fitrobust, :none))
        msg = "valid values for qqline are :identity, :fit, :fitrobust or :none, " *
            "encountered " * repr(qqline)
        throw(ArgumentError(msg))
    end
    h = qqbuild(x, y)
    points = Point2f.(h.qx, h.qy)
    qqline == :none && return points, Point2f[]
    xs = collect(extrema(h.qx))
    if qqline == :identity
        ys = xs
    elseif qqline == :fit
        itc, slp = hcat(fill!(similar(h.qx), 1), h.qx) \ h.qy
        ys = @. slp * xs + itc
    else # if qqline == :fitrobust
        quantx, quanty = quantile(x, [0.25, 0.75]), quantile(y, [0.25, 0.75])
        slp = (quanty[2] - quanty[1]) / (quantx[2] - quantx[1])
        ys = @. quanty + slp * (xs - quantx)
    end
    return points, Point2f.(xs, ys)
end

# Fit distribution type, otherwise leave first argument unchanged
maybefit(D::Type{<:Distribution}, y) = Distributions.fit(D, y)
maybefit(x, _) = x

function convert_arguments(::Type{<:QQPlot}, x′, y; qqline = :none)
    x = maybefit(x′, y)
    points, line = fit_qqplot(x, y; qqline = qqline)
    return PlotSpec{QQPlot}(points, line)
end

convert_arguments(::Type{<:QQNorm}, y; qqline = :none) =
    convert_arguments(QQPlot, Distributions.Normal(0, 1), y; qqline = qqline)

used_attributes(::Type{<:QQNorm}, y) = (:qqline,)
used_attributes(::Type{<:QQPlot}, x, y) = (:qqline,)

function Makie.plot!(p::QQPlot)

    points, line = p[1], p[2]
    real_markercolor = Observable{RGBColors}()

    map!(real_markercolor, p.color, p.markercolor) do color, markercolor
        return to_color(markercolor === automatic ? color : markercolor)
    end

    scatter!(p, points;
        color = real_markercolor,
        strokecolor = p.strokecolor,
        strokewidth = p.strokewidth,
        marker = p.marker,
        markersize = p.markersize,
        inspectable = p.inspectable
    )
    linesegments!(p, line;
        color = p.color,
        linestyle = p.linestyle,
        linewidth = p.linewidth,
        inspectable = p.inspectable
    )
end


text:
using Nemo, GibbsTypePriors, JLD

grid_k = [collect(1:25:1000); 1000]

Pkn_numerical_accuracy = GibbsTypePriors.Pkn_NGG_arb.(grid_k, 1000, 1.2, 0.6) |> x -> accuracy_bits.(x)
save("test/graphical_tests/saves_for_graphical_tests/accuracy_Pkn_1000.jld", "Pkn_numerical_accuracy", Pkn_numerical_accuracy)

max_stars_repo_name: konkam/GibbsTypePriors

max_issues_repo_name: konkam/GibbsTypePriors

max_forks_repo_name: konkam/GibbsTypePriors


text:
# This file contains functions to return DataFrame with boolean for tags

"""
    function get_tags()

"""
function get_tags(vector_wyscout_data::Vector{WyscoutData})::Vector{WyscoutData}

    for i in eachindex(vector_wyscout_data)
        tags = WyscoutEventTags()

        for j in eachindex(vector_wyscout_data[i].event.tags)
            tag = vector_wyscout_data[i].event.tags[j]["id"]

            if tag == 101 tags.goal = true end
            if tag == 102 tags.own_goal = true end
            if tag == 301 tags.assist = true end
            if tag == 302 tags.key_pass = true end
            if tag == 1901 tags.counter_attack = true end
            if tag == 401 tags.left_foot = true end
            if tag == 402 tags.right_foot = true end
            if tag == 403 tags.head_body = true end
            if tag == 1101 tags.direct = true end
            if tag == 1102 tags.indirect = true end
            if tag == 2001 tags.dangerous_ball_lost = true end
            if tag == 2101 tags.blocked = true end
            if tag == 801 tags.high = true end
            if tag == 802 tags.low = true end
            if tag == 1401 tags.interception = true end
            if tag == 1501 tags.clearance = true end
            if tag == 201 tags.opportunity = true end
            if tag == 1301 tags.feint = true end
            if tag == 1302 tags.missed_ball = true end
            if tag == 501 tags.free_space_right = true end
            if tag == 502 tags.free_space_left = true end
            if tag == 503 tags.take_on_left = true end
            if tag == 504 tags.take_on_right = true end
            if tag == 1601 tags.sliding_tackle = true end
            if tag == 601 tags.anticipated = true end
            if tag == 602 tags.anticipation = true end
            if tag == 1701 tags.red_card = true end
            if tag == 1702 tags.yellow_card = true end
            if tag == 1703 tags.second_yellow_card = true end
            if tag == 1201 tags.position_goal_low_center = true end
            if tag == 1202 tags.position_goal_low_right = true end
            if tag == 1203 tags.position_goal_mid_center = true end
            if tag == 1204 tags.position_goal_mid_left = true end
            if tag == 1205 tags.position_goal_low_left = true end
            if tag == 1206 tags.position_goal_mid_right = true end
            if tag == 1207 tags.position_goal_high_center = true end
            if tag == 1208 tags.position_goal_high_left = true end
            if tag == 1209 tags.position_goal_high_right = true end
            if tag == 1210 tags.position_out_low_right = true end
            if tag == 1211 tags.position_out_mid_left = true end
            if tag == 1212 tags.position_out_low_left = true end
            if tag == 1213 tags.position_out_mid_rights = true end
            if tag == 1214 tags.position_out_high_center = true end
            if tag == 1215 tags.position_out_high_left = true end
            if tag == 1216 tags.position_out_high_right = true end
            if tag == 1217 tags.position_post_low_right = true end
            if tag == 1218 tags.position_post_mid_left = true end
            if tag == 1219 tags.position_post_low_left = true end
            if tag == 1220 tags.position_post_mid_right = true end
            if tag == 1221 tags.position_post_high_center = true end
            if tag == 1222 tags.position_post_high_left = true end
            if tag == 1223 tags.position_post_high_right = true end
            if tag == 901 tags.through = true end
            if tag == 1001 tags.fairplay = true end
            if tag == 701 tags.lost = true end
            if tag == 702 tags.neutral = true end
            if tag == 703 tags.won = true end
            if tag == 1801 tags.accurate = true end
            if tag == 1802 tags.not_accurate = true end

        end

        vector_wyscout_data[i].tags = tags
    end

    return vector_wyscout_data
end


text:
using JuMP
using Gurobi
using Plasmo
using PlasmoAlgorithms

##Place MP and SP into ModelGraph
mp = Model(solver = GurobiSolver(OutputFlag=0))
sp = Model(solver = GurobiSolver(OutputFlag=0))

@variable(mp,y>=0)
@objective(mp,Min,2y)

@variable(sp,x[1:2]>=0)
@variable(sp,y>=0)
@constraint(sp,c1,2x[1]-x[2]+3y>=4)
@constraint(sp,x[1]+2x[2]+y>=3)
@objective(sp,Min,2x[1]+3x[2])

## Plasmo Graph
g = ModelGraph()
setsolver(g, GurobiSolver(OutputFlag=0))
n1 = add_node(g)
setmodel(n1,mp)
n2 = add_node(g)
setmodel(n2,sp)

##Set n2 as a child node of n1
edge = Plasmo.add_edge(g,n1,n2)

## Linking constraints between MP and SP
@linkconstraint(g, n1[:y] == n2[:y])

r = bendersolve(g, max_iterations=5)


text:
module SuperFastGraphs

using LightGraphs
using DataStructures

export sampleDistance
export iFub
export ccSample
export triangleCountingDegree
export triangleForward
export prunedBFS
export preProcess
export topKcc

function sampleDistance(g::AbstractGraph, precision::Int64 )
	numV = nv(g)
	distApp = 0
	k = convert(Int64, floor(log(numV) * precision)) # precision = 100 per precisione allo 0.1
	k = k < numV ? k : numV # il sottoinsieme preso puo essere al massimo grande quanto quello originale
	vertexSample = randKVector(vertices(g), k)

	for v in vertexSample
		distApp = distApp + sum(gdistances(g, v))
	end
	agvApp = distApp / (k * (numV - 1))
	return agvApp
end

# Given a vector the function returns a random subvector with k diffent elements
function randKVector(v::UnitRange{Int64}, k::Int64)
	kv = zeros(Int64, length(v))
	for i = 1:k
		elem = v[rand(1:end)]
		while kv[elem] != 0
			elem = v[rand(1:end)]
		end
		kv[elem] = elem
	end
	return filter(x -> x != 0, kv)
end

function iFub(g::AbstractGraph)
	return iFub(g, findmax(degree_centrality(g, normalize=false))[2])
end

# u : starting vertex
function iFub(g::AbstractGraph, u::Int64)
		dist = gdistances(g, u)
		lb = eccentricity(g, u)
	# println(u)
		ub = 2 * lb
		i = lb
		nodeCounter = 1
		while (ub > lb)
				biu = lb
				for v in vertices(g)
						if (dist[v] == i)
								e = eccentricity(g, v)
				# println(nodeCounter, "  " , v)
				# nodeCounter = nodeCounter + 1
								if (e > biu)
										biu = e
								end
								if (biu == ub)
										break
								end
						end
				end
				if (biu > 2 * (i - 1))
						ub = biu
						lb = biu
				else
						lb = biu
						ub = 2 * (i - 1)
				end
				i = i - 1
		end
		return ub
end

# k : sample size
# u : vertex for cc
function ccSample(g::AbstractGraph, k::Int64, u::Int64)
	ccSample = 0
	tempCC = 0
	vertexSample = randKVector(vertices(g), k)
	n = nv(g)
	dists = gdistances(g, u)
	for i in 1:length(vertexSample)
		tempCC = tempCC + (dists[vertexSample[i]] * n) / (k * (n - 1))
	end
	ccSample = 1 / tempCC
	return ccSample
end

function triangleForward(g::AbstractGraph)
	listT = Array{Array{Int}}(nv(g))
	for i in 1:length(listT)
		listT[i] = []
	end
	sortedV = sort!(collect(1:nv(g)), by = x -> -degree(g, x))
	nTriangles = 0
	for s in sortedV
		vNeighbors = neighbors(g, s)
		for t in vNeighbors
			if degree(g, s) < degree(g, t) || (degree(g, s) == degree(g, t) && s < t)
				nTriangles = nTriangles + length(intersect(listT[s], listT[t]))
			else
				push!(listT[t], s)
			end
		end
	end
	return nTriangles
end

function triangleCountingDegree(g::AbstractGraph)
	t = zeros(Int64, nv(g))
	dv, du, dw = 0, 0, 0
	for v in vertices(g)
		vNeighbors = neighbors(g, v)
		dv = degree(g, v)
		for u in vNeighbors
			du = degree(g, u)
			if (dv < du || ((dv == du && v < u)))
				for w in vNeighbors
					w >= u && break
					dw = degree(g, w)
					if ((dv < dw || ((dv == dw && v < w))) && has_edge(g, u, w))
						t[v] = t[v] + 1
						t[u] = t[u] + 1
						t[w] = t[w] + 1
					end
				end
			end
		end
	end
	# println(t)
	# println(triangleNumber)
	return t
end

function prunedBFS(g::AbstractGraph, v::Int64, x::Float64, preProcessData)
	q = Queue(Int64)
	visited = zeros(Int64, nv(g)) #0: not visited, 1:visited, 2:completely explored
	enqueue!(q, v)
	f = Int64[]
	push!(f, v)
	depth = 0
	timeToDepthIncrease = 1
	elementsToDepthIncrease = 0
	nodeAtDepth = Int64[]
	fdValue = 0
	nodeExplored = 0
	ccV = 1
	#gamma_d1 = degree(g, v)
	while !in(v, preProcessData[1][ccV]) #trovo la componente connessa di v
		ccV = ccV + 1
	end
	# println("---VERTICE ", v,": ")
	root  = true
	while length(q)>0
		e = dequeue!(q)
		push!(nodeAtDepth, e)
		visited[e] = 2
		neighborhood = neighbors(g, e)
		elementsToDepthIncrease = elementsToDepthIncrease + length(neighborhood)
		if (!is_directed(g) && root == true)
			elementsToDepthIncrease = elementsToDepthIncrease - 1
			root = false
		end
		timeToDepthIncrease = timeToDepthIncrease - 1
		if timeToDepthIncrease == 0
			n = length(vertices(g))
			fdValue = fdValue + (length(nodeAtDepth)*depth)

			nodeExplored = nodeExplored + length(nodeAtDepth)

			gamma_d1 = sum(degree(g, nodeAtDepth)) - length(nodeAtDepth)

			fdTildeValueAlpha = fdValue - gamma_d1 + (depth+2)*(preProcessData[2][ccV] - nodeExplored)
			fdTildeValueOmega = fdValue - gamma_d1 + (depth+2)*(preProcessData[3][ccV] - nodeExplored)
			# println("R(V): ", preProcessData[2][ccV])
			a = ((preProcessData[2][ccV]-1)^2) / fdTildeValueAlpha
			b = ((preProcessData[3][ccV]-1)^2) / fdTildeValueOmega
			bound = max( a, b ) / (n-1)
			#println("fdValue: ",fdValue)
			#println("n_d: ", nodeExplored)
			#println("gamma_d1: ",gamma_d1)
			#println("depth: ", depth)
			#println("bound: ", bound)
			#println("alpha: ", preProcessData[2][ccV]," omega: ",preProcessData[3][ccV] )
			#println("fdtilde: ",fdTildeValueAlpha, " ", fdTildeValueOmega)
			if (x > bound )
				#println("v: ", v, " bound: ", bound, " NON TOPK")
				return 0 #il nodo non è tra i topk
			end
			timeToDepthIncrease = elementsToDepthIncrease
			elementsToDepthIncrease = 0
			depth = depth + 1
			nodeAtDepth = Int64[]
			gamma_d1 = 0
		end
		for neighbor in neighborhood
			if visited[neighbor] == 0
				visited[neighbor] = 1
				#gamma_d1 = gamma_d1 + degree(g, neighbor)
				#print(gamma_d1, " ")
				enqueue!(q, neighbor)
				push!(f,neighbor)
			end
		end
	end

	#println("RITORNO VALORE->")
	#println("fvalue: ", fdValue)
	#println("rv: ", preProcessData[1][ccV])
	d = dijkstra_shortest_paths(g,v).dists
	δ = filter(x->x != typemax(x), d)
	# println("PreProcess[1][", ccV,"]: ", preProcessData[1][ccV])
	#return ((length(preProcessData[1][ccV]) - 1 )^2)/((nv(g)-1)*sum(δ))
	return ((length(d) - 1 )^2)/((nv(g)-1)*sum(δ))
end

function preProcess(g::AbstractGraph) #preprocess for compute upper boud of closeness centrality
	if (is_directed(g) && is_strongly_connected(g))
		return ([collect(vertices(g))], [nv(g)], [nv(g)])
	elseif (!is_directed(g) && is_connected(g))
		return ([collect(vertices(g))], [nv(g)], [nv(g)])
	elseif (!is_directed(g) && !is_connected(g))
		ccg = connected_components(g)
		lenccg = Int64[]
		for cc in ccg
			push!(lenccg, length(cc))
		end
		return (ccg, lenccg, lenccg)
	elseif (is_directed(g) && !is_strongly_connected(g) && is_weakly_connected(g))
		ccg = strongly_connected_components(g)
		condensationGraph = condensation(g)
		ccDAGTopologicalSorted = topological_sort_by_dfs(condensationGraph)
		ccgTopologicalSorted = Array{Array{Int64}}(length(ccg))

		alpha = zeros(Int64, length(ccDAGTopologicalSorted))
		omega = zeros(Int64, length(ccDAGTopologicalSorted))
		c = ccg[ccDAGTopologicalSorted[end]]
		omega[end] = length(c)
		alpha[end] = length(c)
		maxAlpha = alpha[end]
		ccgTopologicalSorted[end] = c
		for i in length(ccg)-1:-1:1 #dynamic programming
			c = ccg[ccDAGTopologicalSorted[i]]
			# println(i,": ",c," -> ", length(c))
			ccgTopologicalSorted[i] = c
			omega[i] = length(c)+sum(omega)
			alpha[i] = maxAlpha + length(c)
			if (alpha[i] > maxAlpha)
				maxAlpha = alpha[i]
			end
		end
		return (ccgTopologicalSorted, alpha, omega)
	end
end

function topKcc(g::AbstractGraph, k::Int64)
	preprocessData = preProcess(g)
	# println("Dati PreProcess: ", preprocessData)
	xk = 0.0
	topK = PriorityQueue{Int64,Float64}()
	for v in vertices(g)
		if (degree(g, v) != 0)
			t_xk = prunedBFS(g, v, xk, preprocessData)
			t_xk = prunedBFS(g, v, 0.0, preprocessData)
			# println(v," --- analizzato --->", t_xk)
			if t_xk != 0
				if (length(topK) < k)
					enqueue!(topK, v, t_xk)
					# println(topK)
					# println(v," --- trovato top k --->", t_xk)
					if length(topK) == k
						xk = peek(topK)[2]
						# println("valore di xk piu piccolo con coda piena ", xk)
					end
				elseif (length(topK) == k && peek(topK)[2] <= t_xk)
					dequeue!(topK)
					enqueue!(topK, v, t_xk)
					xk = peek(topK)[2]
					# println("valore di xk piu piccolo con dequeue ", xk)
					# println(topK)
					# println(v," --- trovato top k --->", t_xk)
				end
			end
		end
	end
	return priorityQueueToList(topK)
end

function priorityQueueToList(q::PriorityQueue)
	list = []
	for i in 1:length(q)
		push!(list,  peek(q))
		dequeue!(q)
	end
	return list
end

end # module

max_stars_repo_name: mameli/SuperFastGraphs

max_issues_repo_name: mameli/SuperFastGraphs

max_forks_repo_name: mameli/SuperFastGraphs


text:
using ApproxFun, LinearAlgebra, Plots

x = Fun(-20 .. 20)
V = abs(x)
D = Derivative()
S = ApproxFun.canonicalspace(space(V))
B = [Dirichlet(S); continuity(S,0:1)]
λ, v = ApproxFun.eigs(B, -D^2 + V, 500,tolerance=1E-10)

p = plot(V; legend=false)
    for k=1:20
        plot!(real(v[k]/norm(v[k]) + λ[k]))
    end
    p

max_stars_repo_path: ODEs/Quantum states.jl

max_issues_repo_path: ODEs/Quantum states.jl

max_forks_repo_path: ODEs/Quantum states.jl


text:
# define the interface here..Todo mainly

abstract FdrEstimator
abstract LocalFdrEstimator <: FdrEstimator

# fit(pvalues, fdrestimator)     -> returns FdrFit object (or LocalFdrFit)

abstract FdrFit
abstract LocalFdrFit <: FdrFit

# In principle 1-1 correspondende between FdrEstimator and FdrFit types..
# E.g. GrenanderEstimator and GrenanderLocalFdrFit
# can we make use the type system to reflect this???

#FdrFit should implement

# pvalues(fdrfit) -> return p-values based on which fit was calculated
# tailfdr(fdrfit) -> return all estimated tailfdrs
# tailfdr(fdrfit, x) -> estimate tailfdr at x, where x might not have been one of the original pvals

# nulldistribution(fdrfit)
# nulldistribution(fdrfit, x)

# distribution(fdrfit)
# distribution(fdrfit,x)

# pi0(fdrfit)

# LocalFdrFit should also implement

# nulldensity
# density
# localfdr


text:
struct DensityConvergence{FT <: Real, MT <: AbstractMatrix{FT}} <: StopCriteria
    ϵ::FT
    ρ_old::MT
    ρ::MT
end
function should_stop!(stop_criteria::DensityConvergence, q, f_in)
    nx, ny = size(stop_criteria.ρ_old)
    for x_idx in nx, y_idx in ny
        stop_criteria.ρ_old[x_idx, y_idx] = stop_criteria.ρ[x_idx, y_idx]
        stop_criteria.ρ[x_idx, y_idx] = density(q, f_in[x_idx, y_idx, :])
    end

    δρ = norm(stop_criteria.ρ - stop_criteria.ρ_old)

    # Stop procesing if the density converged or the method seems to be diverging
    return δρ < stop_criteria.ϵ || δρ > 100.0
end


text:
function frag_face_channel(in_chan, out_chan, V, EV, FE, sp_idx)
    run_loop = true
    while run_loop
        sigma = take!(in_chan)
        if sigma != -1
            put!(out_chan, frag_face(V, EV, FE, sp_idx, sigma))
        else
            run_loop = false
        end
    end
end
function frag_face(V, EV, FE, sp_idx, sigma)
    vs_num = size(V, 1)

    sigmavs = (abs.(FE[sigma:sigma,:])*abs.(EV))[1,:].nzind
    sV = V[sigmavs, :]
    sEV = EV[FE[sigma, :].nzind, sigmavs]

    M = submanifold_mapping(sV)
    tV = ([V ones(vs_num)]*M)[:, 1:3]

    sV = tV[sigmavs, :]

    for i in sp_idx[sigma]
        tmpV, tmpEV = face_int(tV, EV, FE[i, :])

        sV, sEV = LinearAlgebraicRepresentation.skel_merge(sV, sEV, tmpV, tmpEV)
    end

    sV = sV[:, 1:2]

    nV, nEV, nFE = planar_arrangement(sV, sEV, sparsevec(ones(Int8, length(sigmavs))))

    if nV == nothing
        return [], spzeros(Int8, 0,0), spzeros(Int8, 0,0)
    end

    nvsize = size(nV, 1)
    nV = [nV zeros(nvsize) ones(nvsize)]*inv(M)[:, 1:3]
    return nV, nEV, nFE
end

function merge_vertices(V::LinearAlgebraicRepresentation.Points, EV::LinearAlgebraicRepresentation.ChainOp, FE::LinearAlgebraicRepresentation.ChainOp, err=1e-4)
    vertsnum = size(V, 1)
    edgenum = size(EV, 1)
    facenum = size(FE, 1)
    newverts = zeros(Int, vertsnum)
    # KDTree constructor needs an explicit array of Float64
    V = Array{Float64,2}(V)
    kdtree = KDTree(V')

    todelete = []

    i = 1
    for vi in 1:vertsnum
        if !(vi in todelete)
            nearvs = LinearAlgebraicRepresentation.inrange(kdtree, V[vi, :], err)

            newverts[nearvs] = i

            nearvs = setdiff(nearvs, vi)
            todelete = union(todelete, nearvs)

            i = i + 1
        end
    end

    nV = V[setdiff(collect(1:vertsnum), todelete), :]

    edges = Array{Tuple{Int, Int}, 1}(edgenum)
    oedges = Array{Tuple{Int, Int}, 1}(edgenum)

    for ei in 1:edgenum
        v1, v2 = EV[ei, :].nzind

        edges[ei] = Tuple{Int, Int}(sort([newverts[v1], newverts[v2]]))
        oedges[ei] = Tuple{Int, Int}(sort([v1, v2]))

    end
    nedges = union(edges)
    nedges = filter(t->t[1]!=t[2], nedges)

    nedgenum = length(nedges)
    nEV = spzeros(Int8, nedgenum, size(nV, 1))

    etuple2idx = Dict{Tuple{Int, Int}, Int}()

    for ei in 1:nedgenum
        nEV[ei, collect(nedges[ei])] = 1
        etuple2idx[nedges[ei]] = ei
    end

    faces = [[
        map(x->newverts[x], FE[fi, ei] > 0 ? oedges[ei] : reverse(oedges[ei]))
        for ei in FE[fi, :].nzind
    ] for fi in 1:facenum]

    visited = []
    function filter_fn(face)

        verts = []
        map(e->verts = union(verts, collect(e)), face)
        verts = Set(verts)

        if !(verts in visited)
            push!(visited, verts)
            return true
        end
        return false
    end

    nfaces = filter(filter_fn, faces)

    nfacenum = length(nfaces)
    nFE = spzeros(Int8, nfacenum, size(nEV, 1))

    for fi in 1:nfacenum
        for edge in nfaces[fi]
            ei = etuple2idx[Tuple{Int, Int}(sort(collect(edge)))]
            nFE[fi, ei] = sign(edge[2] - edge[1])
        end
    end

    return LinearAlgebraicRepresentation.Points(nV), nEV, nFE
end

"""
    spatial_arrangement(V::Points, EV::ChainOp, FE::ChainOp; [multiproc::Bool])

Compute the arrangement on the given cellular complex 2-skeleton in 3D.

A cellular complex is arranged when the intersection of every possible pair of cell
of the complex is empty and the union of all the cells is the whole Euclidean space.
The function returns the full arranged complex as a list of vertices V and a chain of borders EV, FE, CF.

## Additional arguments:
- `multiproc::Bool`: Runs the computation in parallel mode. Defaults to `false`.
"""
function spatial_arrangement(V::LinearAlgebraicRepresentation.Points, EV::LinearAlgebraicRepresentation.ChainOp, FE::LinearAlgebraicRepresentation.ChainOp, multiproc::Bool=false)

    fs_num = size(FE, 1)
    sp_idx = spatial_index(V, EV, FE)

    rV = LinearAlgebraicRepresentation.Points(0,3)
    rEV = spzeros(Int8,0,0)
    rFE = spzeros(Int8,0,0)

    if (multiproc == true)
        in_chan = RemoteChannel(()->Channel{Int64}(0))
        out_chan = RemoteChannel(()->Channel{Tuple}(0))

        @schedule begin
            for sigma in 1:fs_num
                put!(in_chan, sigma)
            end
            for p in workers()
                put!(in_chan, -1)
            end
        end

        for p in workers()
            @async Base.remote_do(
                frag_face_channel, p, in_chan, out_chan, V, EV, FE, sp_idx)
        end

        for sigma in 1:fs_num
            rV, rEV, rFE = LinearAlgebraicRepresentation.skel_merge(rV, rEV, rFE, take!(out_chan)...)
        end

    else
        for sigma in 1:fs_num
            # print(sigma, "/", fs_num, "\r")
            nV, nEV, nFE = frag_face(V, EV, FE, sp_idx, sigma)
            rV, rEV, rFE = LinearAlgebraicRepresentation.skel_merge(rV, rEV, rFE, nV, nEV, nFE)
        end

    end

    rV, rEV, rFE = merge_vertices(rV, rEV, rFE)

    rCF = minimal_3cycles(rV, rEV, rFE)

    return rV, rEV, rFE, rCF
end


text:
export Semicircle

"""
Wigner semicircle distribution

By default, creates a standardized distribution
with mean 0 and variance 1 (radius 2)
"""
immutable Semicircle{T<:Real} <: ContinuousUnivariateDistribution
    mean::T
    radius::T
    Semicircle(μ::T,r::T) = new(μ,r)
end
Semicircle{T<:Real}(μ::T=0.0, r::T=2.0) = r > 0 ? Semicircle{T}(μ, r) :
    throw(ArgumentError("radius r must be positive, got $r"))

# Distribution function methods
###############################

# cumulative distribution function
function cdf{T<:Real}(d::Semicircle{T}, x::T)
    r, a = d.mean, d.radius
    if insupport(d, x)
        return 0.5 + (x-a)/(π*r^2) * √(r^2 - (x-a)^2) + asin((x-a)/r)/π
    elseif x ≥ a
        return one(T)
    else
	return zero(T)
    end
end

# probability density function
function pdf{T<:Real}(d::Semicircle{T}, x::T)
    r, a = d.mean, d.radius
    if insupport(d, x)
        return 2/(π*r^2) * √(r^2 - (x-a)^2)
    else
	return zero(T)
    end
end

# predicate is x in the support of the distribution?
insupport{T<:Real}(d::Semicircle{T}, x::T)=abs(x)<d.radius

#Entropy methods
################

# entropy of distribution in nats
entropy(X::Semicircle)=log(π*X.radius) - 0.5

#Measures of central tendency methods
#####################################

# mean of distribution
mean(X::Semicircle)=X.mean

# median of distribution
median(X::Semicircle)=X.mean

# mode(s) of distribution as vector
modes{T}(X::Semicircle{T})=T[X.mean]

# kurtosis of the distribution
kurtosis{T}(X::Semicircle{T})=T(2)

# skewness of the distribution
skewness{T}(X::Semicircle{T})=T(0)

# standard deviation of distribution
std(X::Semicircle)=X.radius/2

# variance of distribution
var(X::Semicircle)=std(X)^2

# moment of distribution
function moment{T<:Real}(X::Semicircle{T}, order::Integer)
    a, r = X.mean, X.radius
    if X.mean != 0
        return a^n*hypergeom([(1-n)/2, -n/2], 2, (r/a)^2)
    elseif iseven(order)
        return (0.5*r)^(2order) * T(catalannum(order÷2))
    else
	return zero(T)
    end
end

# cumulant of distribution
function cumulant{T<:Real}(d::Semicircle{T}, order::Integer)
    if d.mean != 0
        throw(ArgumentError("Non-central Semicircle not supported"))
    end

    if order==0
	return one(T)
    elseif iseven(order)
        return (0.5*d.radius)^(2order) * T(lassallenum(order÷2))
    else
        return zero(T)
    end
end

# free cumulant of distribution
function freecumulant{T<:Real}(d::Semicircle{T}, order::Int)
    if order == 0
        return one(T)
    elseif order == 1
        return mean(X)
    elseif order == 2
        return var(X)
    else
        return zero(T)
    end
end

#Generating function methods
############################

# characteristic function
function cf(d::Semicircle, t::Real)
  r = t / d.mean
  2 * besselj(1, r)/r
end

# moment generating function
function mgf(d::Semicircle, t::Real)
  r = t * d.mean
  2 * besseli(1, r)/r
end

#Sampling methods
#################

# random sampler
# Use relationship with beta distribution
function rand(X::Semicircle)
    Y = rand(Beta(1.5, 1.5))
    X.mean + 2 * X.radius * Y - X.radius
end


text:
@testset "getproperty" begin
    ds = KeyedDataset(
        :val1 => KeyedArray(
            rand(4, 3, 2);
            time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
            loc=1:3,
            obj=[:a, :b],
        ),
        :val2 => KeyedArray(
            rand(4, 3, 2) .+ 1.0;
            time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
            loc=1:3,
            obj=[:x, :y],
        );
        constraints=Pattern[(:__, :time), (:__, :loc)],
    )

    @test getproperty(ds, :constraints) == getfield(ds, :constraints)
    @test getproperty(ds, :data) == getfield(ds, :data)
    @test ds.val1 == ds.data[(:val1,)]
    @test ds.time == ds.data[(:val1,)].time
    @test_throws ArgumentError ds.obj
    @test_throws ArgumentError ds.foobar

    @testset "ReadOnly" begin
        # Test that mutating data properties directly errors
        @test isa(ds.time, ReadOnlyArray)
        @test isa(ds.val1.time, ReadOnlyArray)

        @test_throws ErrorException ds.time[3] = DateTime(2020, 1, 1)
        @test_throws ErrorException ds.val1.time[3] = DateTime(2020, 1, 1)

        # Test that we can still modify non-shared keys
        ds.val1.obj[2] = :d
        @test ds.val1.obj[2] === :d
    end
end

@testset "getindex" begin
    @testset "depth = 1" begin
        ds = KeyedDataset(
            :a => KeyedArray(
                allowmissing(rand(4, 3, 2));
                time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
                loc=1:3,
                obj=[:a, :b],
            ),
            :b => KeyedArray(
                rand(4, 2);
                time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
                label=["x", "y"],
            ),
        )

        @test ds[:a] == ds[(:a,)]
        @test isa(ds[:a], KeyedArray)
    end

    @testset "depth > 1" begin
        ds = KeyedDataset(
            flatten([
                :group1 => [
                    :a => KeyedArray(
                        allowmissing(rand(4, 3, 2));
                        time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
                        loc=1:3,
                        obj=[:a, :b],
                    ),
                ],
                :group2 => [
                    :b => KeyedArray(
                        rand(4, 2) .+ 1.0;
                        time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
                        label=["x", "y"],
                    ),
                ],
            ])...
        )

        grp1a = ds[(:group1, :a)]
        @test isa(grp1a, KeyedArray)

        grp2b = ds[(:group2, :b)]
        @test isa(grp2b, KeyedArray)

        @test_throws KeyError ds[(:group1, :)]
        @test_throws KeyError ds[:group1]
        @test_throws KeyError ds[:a]
    end
end

@testset "setindex!" begin
    ds = KeyedDataset(
        :a => KeyedArray(
            allowmissing(rand(4, 3, 2));
            time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
            loc=1:3,
            obj=[:a, :b],
        ),
        :b => KeyedArray(
            rand(4, 2);
            time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
            label=["x", "y"],
        ),
    )

    init_constraints = deepcopy(ds.constraints)
    @test length(init_constraints) == 4

    ds[:c] = KeyedArray(
        rand(4, 2);
        time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
        label=["x", "y"],
    )
    @test ds.constraints == init_constraints

    ds[:c] = KeyedArray(rand(5); id=100:100:500)
    @test ds.constraints != init_constraints
    @test length(ds.constraints) == 5

    # Test validation error if we try to add a component with a mismatched dimension
    # relative to our existing dimensions / constraints
    @test_throws KeyAlignmentError setindex!(ds, KeyedArray(rand(2); id=[1, 2]), :d)
end

@testset "lookup" begin
    ds = KeyedDataset(
        flatten([
            :group1 => [
                :a => KeyedArray(
                    allowmissing(rand(4, 3, 2));
                    time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
                    loc=1:3,
                    obj=[:a, :b],
                ),
                :b => KeyedArray(
                    rand(4, 2);
                    time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
                    label=["x", "y"],
                )
            ],
            :group2 => [
                :a => KeyedArray(
                    rand(4, 3, 2) .+ 1.0;
                    time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
                    loc=1:3,
                    obj=[:a, :b],
                ),
                :b => KeyedArray(
                    rand(4, 2) .+ 1.0;
                    time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
                    label=["x", "y"],
                )
            ]
        ])...
    )

    a = ds(:_, :a)
    @test isa(a, KeyedDataset)
    @test issetequal([(:group1, :a), (:group2, :a)], keys(a.data))

    grp1 = ds(:group1, :__)
    @test isa(grp1, KeyedDataset)
    @test issetequal([(:group1, :a), (:group1, :b)], keys(grp1.data))

    @test_throws KeyError ds(:group1)
    @test_throws KeyError ds(:a)

    # Test custom filter
    custom = ds(k -> any(startswith("gr"), string.(k)))
    @test custom == ds
end

@testset "mixed key types" begin
    ds = KeyedDataset(
        flatten([
            :group1 => [
                "a" => KeyedArray(
                    allowmissing(rand(4, 3, 2));
                    time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
                    loc=1:3,
                    obj=[:a, :b],
                ),
                "b" => KeyedArray(
                    rand(4, 2);
                    time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
                    label=["x", "y"],
                )
            ],
            :group2 => [
                "a" => KeyedArray(
                    rand(4, 3, 2) .+ 1.0;
                    time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
                    loc=1:3,
                    obj=[:a, :b],
                ),
                "b" => KeyedArray(
                    rand(4, 2) .+ 1.0;
                    time=DateTime(2021, 1, 1, 11):Hour(1):DateTime(2021, 1, 1, 14),
                    label=["x", "y"],
                )
            ]
        ])...
    )

    grp1a = ds[(:group1, "a")]
    @test isa(grp1a, KeyedArray)

    grp2b = ds[(:group2, "b")]
    @test isa(grp2b, KeyedArray)

    a = ds(:_, "a")
    @test isa(a, KeyedDataset)
    @test issetequal([(:group1, "a"), (:group2, "a")], keys(a.data))

    grp1 = ds(:group1, :__)
    @test isa(grp1, KeyedDataset)
    @test issetequal([(:group1, "a"), (:group1, "b")], keys(grp1.data))
end


text:
# Random Fourier Features
# from: Rahimi,Recht, "Random Features for Large-Scale Kernel Machines", NIPS 2007
#
# Danny Perry (dperry@cs.utah.edu)
# Oct 2014
#
# compare to Gaussian kernel:

using PyPlot
using RDatasets
using MAT

using RandomFourierFeatures
using Kernel
using Debug

X = []
Labels = []

#name = "iris"
#name = "baseball"
#name = "cpu"
name = "synthetic"
#name = "mnist"

if name == "iris"
	iris = dataset("datasets","iris")

	X = [ convert(Array{Float64,1}, iris[1]) convert(Array{Float64,1}, iris[2]) convert(Array{Float64,1}, iris[3]) convert(Array{Float64,1}, iris[4]) ]
	n = size(X,1)
	println("X: ", size(X))
	Labels = ASCIIString[]
	for i=1:n
		push!(Labels, iris[5][i])
	end
elseif name == "mnist"

	f = matopen("mnist/nitish/mnist/train.mat")
	X = read(f, "train")
	close(f)
	f = matopen("mnist/nitish/mnist/test.mat")
	Xtest = read(f, "test")
	close(f)

	if true
		n = 1000
		nt = 100

		Xtmp = X
		X =Xtmp[1:n,:]
		for i=n+1:size(Xtmp,1)
			r = int(ceil(rand()*i))
			if r <= n
				X[r,:] = Xtmp[i,:]
			end
		end
		Xtmp = Xtest
		Xtest =Xtmp[1:nt,:]
		for i=nt+1:size(Xtmp,1)
			r = int(ceil(rand()*i))
			if r <= nt
				Xtest[r,:] = Xtmp[i,:]
			end
		end

		X = [X; Xtest]
	end

	#Xtest = X[1:n/2,:]
	#X = X[n/2+1:end,:]

	println("X: ", size(X))
	#println("Xtest: ", size(Xtest))

elseif name == "cpu"

	f = matopen("nystrom_rff_paper/cpu/cpu.mat")
	X = read(f, "Xtrain")
	X = X'

	if true
		#n = 1021
		#n = 3000 * 2
		n = 1200
		#n = 121*2
		Xtmp = X
		X = zeros(n, size(Xtmp,2))
		for i=1:n
			X[i,:] = Xtmp[i,:]
		end
		for i=n+1:size(Xtmp,1)
			r = int(ceil(rand()*i))
			if r <= n
				X[r,:] = Xtmp[i,:]
			end
		end
	end

	#Xtest = X[1:n/2,:]
	#X = X[n/2+1:end,:]

	println("X: ", size(X))
	#println("Xtest: ", size(Xtest))

elseif name == "synthetic"

	#f = matopen("SDU_20000_1000_500_10.mat")
	f = matopen("SDU_1000_100_50_10.mat")
	X = read(f, "data")
	#Xtest = X[end-1000:end,:]
	#X = X[1:end-1000-1,:]

	n = 1000

	if n > 0
		Xtmp = X
		X = Xtmp[1:n,:]
		for i=n+1:size(Xtmp,1)
			r = int(ceil(rand()*i))
			if r <= n
				X[r,:] = Xtmp[i,:]
			end
		end
	end

	nt = 0
	if nt > 0
		Xtmp = Xtest
		Xtest = Xtmp[1:nt,:]
		for i=n+1:size(Xtmp,1)
			r = int(ceil(rand()*i))
			if r <= n
				Xtest[r,:] = Xtmp[i,:]
			end
		end
	end

	println("X: ", size(X))

else

	baseball = dataset("plyr","baseball")

	numerical_cols = [1,4,8,9,10,11,12,13,17]
	X = zeros(size(baseball,1),length(numerical_cols))

	for i=1:length(numerical_cols)
		println(i,": ",numerical_cols[i])
		X[:,i] = convert(Array{Float64,1}, baseball[numerical_cols[i]])
	end

end

n = size(X,1)
X_centered = X .- (ones(n,1)*mean(X,1))

# compute neighborhood distances to inform choice of sigma:
#sig2 = 1e9
#sig2 = 10
sig2 = 10 # TODO: try some different data sets with varying sigma...
if true

	sigma = 0
	for i=1:n
		sigma += sum( sqrt( sum( (X .- ones(n,1)*X[i,:]).^2, 2 ) ) )
	end
	sigma /= n^2

	sig2 = sigma^2

	figure()
	for i=1:n
		x = X[i,:]
		d2 = sum((X - ones(n,1)*x).^2,2)
		#println(i,": ", sort(vec(d2))[end-4:end])
		plot(1:length(d2),sort(vec(d2)),"--")
		hold(:on)
	end
	plot(1:n,sig2*ones(n),".-")
	title("distance squared to other points")
	ylabel("distance squared")
	xlabel("sorted neighbors")
end

# generate the standard guassian kernel:
#sigma = sqrt(sig2) * 1e-2
paramstr = @sprintf("s=%.1f",sigma)

# now generate a kernel matrix from the approximate space:
function comparison(X,Xtest,sigma)

	println("computing kernel matrix for param: ",paramstr," ...")
	K = GaussianKernel(Xtest,Xtest,sigma)
	Ktrain = GaussianKernel(X,Xtest,sigma)

	println("starting comparison")

	inputdim = size(X,2)
	dims = Int64[]
	errs = Float64[]
	errs2 = Float64[]
	maxerrs = Float64[]
	minerrs = Float64[]
	errs_ff = Float64[]
	errs_nystrom = Float64[]
	maxerrs_nystrom = Float64[]
	minerrs_nystrom = Float64[]
	#figure()
	#for dim=10:100:1000
	for l=10:10:100
		dim = inputdim*l
		#dim = l
		println("dim: ",dim)
		err = 0
		err2 = 0
		maxerr = 0
		minerr = 0
		err_ff = 0
		err_nystrom = 0
		maxerr_nystrom = 0
		minerr_nystrom = 0
		samples = 10
		for i=1:samples
			# random fourier features
			rffs = GenerateFunctionsGaussian(typeof(Xtest[1,1]), sigma, inputdim, dim)
			rffs2 = GenerateFunctionsGaussianSinCos(typeof(Xtest[1,1]), sigma, inputdim, dim)
			Xp = RFFProject( Xtest, rffs )
			Xp2 = RFFProjectSinCos( Xtest, rffs2 )
			Kp = Xp * Xp'
			Kp2 = Xp2 * Xp2'
			#absdiff = abs(K[:] .- Kp[:])
			#absdiff2 = abs(K[:] .- Kp2[:])
			absdiff = vecnorm(K - Kp) #/ length(K)
			absdiff2 = vecnorm(K - Kp2) #/ length(K)
			err += absdiff
			err2 += absdiff2
			maxerr += maximum(absdiff)
			minerr += minimum(absdiff)
			# fast food features
			ffs = GenerateFastFood(Float64, dim, inputdim)
			Xff = FFProject( Xtest', ffs, sigma )
			Kff = Xff' * Xff
			err_ff += vecnorm(K-Kff)

			# random sub matrix (Nystrom method)
			# reservoir subsample:
			nystrom_num = min(size(X,1), dim)
			if false
				subset = [1:nystrom_num]
				for j=nystrom_num+1:size(X,1)
					r = ceil(rand()*j)
					if r <= nystrom_num
						subset[r] = j
					end
				end
			else
				subset = int(ceil(rand(nystrom_num) * size(X,1)))
			end
			K_subset = GaussianKernel(X[subset,:], sigma)
			#K_all = GaussianKernel(X, X_subset, sigma)
			K_all = Ktrain[subset,:]
			if cond(K_subset) > 1e10
				UU,SS,VV = svd(K_subset)
				SS = diagm(SS) + 1e-10*eye(length(SS))
				K_subset = UU*SS*VV'
			end
			K_nystrom = K_all' * (K_subset \ K_all)
			absdiff_nystrom = vecnorm(K - K_nystrom) #/ length(K)
			err_nystrom += mean(absdiff_nystrom)
			maxerr_nystrom += maximum(absdiff_nystrom)
			minerr_nystrom += minimum(absdiff_nystrom)

		end
		err /= samples
		err2 /= samples
		maxerr /= samples
		minerr /= samples

		err_ff /= samples

		err_nystrom /= samples
		maxerr_nystrom /= samples
		minerr_nystrom /= samples
		#println("avg err: ", err )

		push!(dims, dim)
		push!(errs, err)
		push!(errs2, err2)
		push!(minerrs, minerr)
		push!(maxerrs, maxerr)

		push!(errs_ff, err_ff)

		push!(errs_nystrom, err_nystrom)
		push!(minerrs_nystrom, minerr_nystrom)
		push!(maxerrs_nystrom, maxerr_nystrom)

	end

	figure()
	plot(dims,errs,"r-")
	hold(:on)
	plot(dims,errs2,"b-")
	plot(dims,errs_ff,"g:")
	plot(dims,errs_nystrom,"k-")
	legend(["RFF avg err","RFF 2 avg err", "FF avg err", "Nys avg err"],loc="upper right")
	title("RR dim vs avg error")

	figure()
	plot(dims,errs,"r-")
	hold(:on)
	plot(dims,errs2,"b-")
	plot(dims,errs_ff,"g:")
	plot(dims,errs_nystrom,"k-")
	xscale("log")
	yscale("log")
	legend(["RFF avg err","RFF 2 avg err", "FF avg err", "Nys avg err"],loc="lower left")
	title("Log scale: RR dim vs avg error")

	PyPlot.plt[:show]()
	#@bp

end

comparison(X_centered[1:end-100,:], X_centered[end-100+1:end,:], sigma)


text:
# Author: Youngjun Kim, youngjun@stanford.edu
# Date: 06/25/2014

module SISLES

export
    CorrAEM,
    LLAEM,
    CorrAEMDBN,
    StarDBN,
    SideOnDBN,
    PairwiseCorrAEMDBN,
    SimplePilotResponse,
    StochasticLinearPR,
    LLDetPR,
    SimpleADM,
    LLADM,
    AirSpace,
    SimpleTCASSensor,
    ACASXSensor,
    GenericCoord,
    SimpleTCAS,
    CoordSimpleTCAS,
    ACASX_CCAS,
    ACASX_ADD,
    TCASSimulator,
    SimpleTCAS_EvU, #deprecated
    SimpleTCAS_EvE, #deprecated
    ACASX_GM,

    addObserver,
    clearObservers!,
    initialize,
    update,
    outputGFormatString,

    # Encounter
    getTrajectory,
    setInitialDistributions,
    validate,
    getInitialSample,

    # Simulator
    simulate

PACKAGE_PATH = Pkg.dir("SISLES", "src")

push!(LOAD_PATH, "$PACKAGE_PATH/include")
push!(LOAD_PATH, "$PACKAGE_PATH/common")
push!(LOAD_PATH, "$PACKAGE_PATH/Encounter")
push!(LOAD_PATH, "$PACKAGE_PATH/Encounter/CorrAEMImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/Encounter/LLAEMImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/EncounterDBN")
push!(LOAD_PATH, "$PACKAGE_PATH/EncounterDBN/CorrAEMDBNImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/EncounterDBN/StarDBNImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/EncounterDBN/SideOnDBNImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/EncounterDBN/PairwiseCorrAEMDBNImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/PilotResponse")
push!(LOAD_PATH, "$PACKAGE_PATH/PilotResponse/SimplePilotResponseImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/PilotResponse/StochasticLinearPRImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/PilotResponse/LLDetPRImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/DynamicModel")
push!(LOAD_PATH, "$PACKAGE_PATH/DynamicModel/SimpleADMImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/DynamicModel/LLADMImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/WorldModel")
push!(LOAD_PATH, "$PACKAGE_PATH/WorldModel/AirSpaceImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/Sensor")
push!(LOAD_PATH, "$PACKAGE_PATH/Sensor/SimpleTCASSensorImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/Sensor/ACASXSensorImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/CASCoordination")
push!(LOAD_PATH, "$PACKAGE_PATH/CASCoordination/GenericCoordImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/CollisionAvoidanceSystem")
push!(LOAD_PATH, "$PACKAGE_PATH/CollisionAvoidanceSystem/SimpleTCASImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/CollisionAvoidanceSystem/CoordSimpleTCASImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/CollisionAvoidanceSystem/ACASXCommonImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/CollisionAvoidanceSystem/ACASX_CCAS_Impl")
push!(LOAD_PATH, "$PACKAGE_PATH/CollisionAvoidanceSystem/ACASX_ADD_Impl")
push!(LOAD_PATH, "$PACKAGE_PATH/Simulator")
push!(LOAD_PATH, "$PACKAGE_PATH/Simulator/TCASSimulatorImpl")
push!(LOAD_PATH, "$PACKAGE_PATH/GenerativeModel")
push!(LOAD_PATH, "$PACKAGE_PATH/GenerativeModel/SimpleTCAS_EvU_Impl")
push!(LOAD_PATH, "$PACKAGE_PATH/GenerativeModel/SimpleTCAS_EvE_Impl")
push!(LOAD_PATH, "$PACKAGE_PATH/GenerativeModel/ACASX_GM_Impl")
push!(LOAD_PATH, "$PACKAGE_PATH/GenerativeModel/common")

using CommonInterfaces
using Util
using Encounter
using EncounterDBN
using PilotResponse
using DynamicModel
using WorldModel
using Sensor
using CASCoordination
using CollisionAvoidanceSystem
using Simulator
using GenerativeModel

end

max_stars_repo_name: sisl/RLES-SISLES

max_issues_repo_name: sisl/RLES-SISLES

max_forks_repo_name: sisl/RLES-SISLES


text:
module SBA

include("indices.jl")
include("core.jl")

end # module


text:
using EmpiricalRiskMinimization
using Convex, SCS, ECOS
using Base.Test

TOL = 1e-3

# Setting a seed
srand(1234)
@test true

# Squared Loss tests
# n = 1000; d = 200;
# X = randn(n, d); y = randn(n);
# loss_ERM = EmpiricalRiskMinimization.minimize(SquaredLoss(), L1Reg(2.5), X, y)[2][end]
# theta = Variable(d)
# cvx_objective = sumsquares(X*theta - y) + 2.5*norm(theta, 1)
# cvx_problem = Convex.minimize(cvx_objective)
# solve!(cvx_problem, SCSSolver(verbose=false, max_iters=10000, eps=1e-9), verbose=false)
# loss_CVX = cvx_problem.optval
# println("Convex: $loss_CVX, ERM: $loss_ERM")
# @test abs(loss_CVX - loss_ERM) < TOL

# n = 1000; d = 200;
# X = randn(n, d); y = randn(n);
# loss_ERM = EmpiricalRiskMinimization.minimize(SquaredLoss(), L1L2Reg(0.5, 1), X, y)[2][end]
# theta = Variable(d)
# cvx_objective = sumsquares(X*theta - y) + 0.5*norm(theta, 1) + sumsquares(theta)
# cvx_problem = Convex.minimize(cvx_objective)
# solve!(cvx_problem, SCSSolver(verbose=false, max_iters=10000, eps=1e-9), verbose=false)
# loss_CVX = cvx_problem.optval
# println("Convex: $loss_CVX, ERM: $loss_ERM")
# @test abs(loss_CVX - loss_ERM) < TOL

# n = 1000; d = 200;
# X = randn(n, d); y = randn(n);
# loss_ERM = EmpiricalRiskMinimization.minimize(SquaredLoss(), L2Reg(0.5), X, y)[2][end]
# cvx_objective = sumsquares(X*theta - y) + 0.5*sumsquares(theta)
# cvx_problem = Convex.minimize(cvx_objective)
# solve!(cvx_problem, SCSSolver(verbose=false, max_iters=10000, eps=1e-9), verbose=false)
# loss_CVX = cvx_problem.optval
# # Use closed form solution for ridge regression
# theta_opt = inv(X'*X + 0.5*eye(d))*X'*y
# loss_RR= norm(X*theta_opt - y, 2)^2 + 0.5*norm(theta_opt, 2)^2
# println("Ridge regression: $loss_RR, ERM: $loss_ERM, (Convex: $loss_CVX)")
# @test abs(loss_RR - loss_ERM) < TOL

# # L1 loss tests
# L1_tol = 1
# n = 300; d = 50;
# X = randn(n, d); y = randn(n); lambd = rand();
# loss_ERM = EmpiricalRiskMinimization.minimize(AbsoluteLoss(), L2Reg(lambd), X, y,
#                                               max_iters=100000, verbose=false, tol=1e-5)[2][end]
# theta = Variable(d)
# cvx_objective = norm(X*theta - y, 1) + lambd*norm(theta, 2)^2
# cvx_problem = Convex.minimize(cvx_objective)
# solve!(cvx_problem, ECOSSolver(verbose=false, max_iters=10000, eps=1e-9), verbose=true)
# loss_CVX = cvx_problem.optval
# println("Convex: $loss_CVX, ERM: $loss_ERM")
# @test abs(loss_CVX - loss_ERM) < L1_tol

# # Logistic regression test
# n = 2000; d = 350;
# X = randn(n, d); X = randn(n, d); y = (sign.(randn(n) - 0.5) + 1)/2; lambd = rand();
# model = Model(LogisticLoss(), L2Reg(lambd), fit_intercept=true);
# fit!(model, X, y)
# status(model);
# final_risk(model);
# weights = parameters(model);
# # predictions
# y_tild = sigm.(X*weights[1:d] + weights[d + 1])
# y_pred = 1.0 * (y_tild .>= 0.5)
# acc_ERM = sum(1.0*(y_pred .== y))/n
# # compare w/ cvx
# theta = Variable(d + 1)
# X_tild = [X ones(n)]
# cvx_problem = Convex.minimize(logisticloss(-y.*(X_tild*theta)))
# solve!(cvx_problem,  SCSSolver(verbose=false, max_iters=10000), verbose=false)
# theta = theta.value
# y_hat_CVX = 1.0*((sigm.(X_tild*theta)) .>= 0.5)
# acc_CVX = sum(1.0*(y_hat_CVX .== y))/n
# println("Convex: $acc_CVX, ERM: $acc_ERM")
# @test abs(acc_CVX - acc_ERM) < TOL

# # Matrix factorization test
# println("Testing matrix factorization")

# # SVD Test
# unsupervised_model = Model(FrobeniusLoss(), NoReg(), fit_intercept=false)
# X = randn(n, d); k = 1

# # ERM
# theta_X, theta_Y, losses = EmpiricalRiskMinimization.minimize_unsupervised(FrobeniusLoss(), NoReg(), X, k)
# loss_ERM = losses[end]

# # PCA by singular value decomposition
# U, S, V = svd(X)

# X_pca = U[:,1:k]*diagm(S)[1:k, 1:k]*V[:,1:k]'
# loss_SVD = vecnorm(X - X_pca)^2
# println("SVD: $(loss_SVD), ERM: $(loss_ERM)")
# @test abs(loss_SVD - loss_ERM) < TOL


text:
struct SRS <: Imputor
    rng::AbstractRNG
    context::AbstractContext
end

"""
    SRS(; rng=Random.GLOBAL_RNG, context=Context())

Simple Random Sampling (SRS) imputation is a method for imputing both continuous and categorical
variables. Furthermore, it completes imputation while preserving the distributional
properties of the variables (e.g., mean, standard deviation).

The basic idea is that for a given variable, `x`, with missing data, we randomly draw
from the observed values of `x` to impute the missing elements. Since the random draws
from `x` for imputation are done in proportion to the frequency distribution of the values
in `x`, the univariate distributional properties are generally not impacted; this is true
for both categorical and continuous data.

# Keyword Arguments
* `rng::AbstractRNG`: A random number generator to use for observation selection
* `context::AbstractContext`: A context which keeps track of missing data
  summary information

# Example
"""

SRS(; rng=Random.GLOBAL_RNG, context=Context()) = SRS(rng, context)

function impute!(data::AbstractVector, imp::SRS)
    imp.context() do c
        obs_values = Impute.dropobs(data)
        if !isempty(obs_values)
            for i in eachindex(data)
                if ismissing!(c, data[i])
                    data[i] = rand(imp.rng, obs_values)
                end
            end
        end

        return data
    end
end


text:
typealias SCIP_Status Int8

SCIP_STATUS_UNKNOWN        = int8(  0)
SCIP_STATUS_USERINTERRUPT  = int8(  1)
SCIP_STATUS_NODELIMIT      = int8(  2)
SCIP_STATUS_TOTALNODELIMIT = int8(  3)
SCIP_STATUS_STALLNODELIMIT = int8(  4)
SCIP_STATUS_TIMELIMIT      = int8(  5)
SCIP_STATUS_MEMLIMIT       = int8(  6)
SCIP_STATUS_GAPLIMIT       = int8(  7)
SCIP_STATUS_SOLLIMIT       = int8(  8)
SCIP_STATUS_BESTSOLLIMIT   = int8(  9)
SCIP_STATUS_OPTIMAL        = int8( 10)
SCIP_STATUS_INFEASIBLE     = int8( 11)
SCIP_STATUS_UNBOUNDED      = int8( 12)
SCIP_STATUS_INFORUNBD      = int8( 13)

SCIP_STATUS = Dict{SCIP_Status, String}()
SCIP_STATUS[SCIP_STATUS_UNKNOWN]        = "the solving status is not yet known"
SCIP_STATUS[SCIP_STATUS_USERINTERRUPT]  = "the user interrupted the solving process (by pressing CTRL-C)"
SCIP_STATUS[SCIP_STATUS_NODELIMIT]      = "the solving process was interrupted because the node limit was reached"
SCIP_STATUS[SCIP_STATUS_TOTALNODELIMIT] = "the solving process was interrupted because the total node limit was reached (incl. restarts)"
SCIP_STATUS[SCIP_STATUS_STALLNODELIMIT] = "the solving process was interrupted because the stalling node limit was reached (no inprovement w.r.t. primal bound)"
SCIP_STATUS[SCIP_STATUS_TIMELIMIT]      = "the solving process was interrupted because the time limit was reached"
SCIP_STATUS[SCIP_STATUS_MEMLIMIT]       = "the solving process was interrupted because the memory limit was reached"
SCIP_STATUS[SCIP_STATUS_GAPLIMIT]       = "the solving process was interrupted because the gap limit was reached"
SCIP_STATUS[SCIP_STATUS_SOLLIMIT]       = "the solving process was interrupted because the solution limit was reached"
SCIP_STATUS[SCIP_STATUS_BESTSOLLIMIT]   = "the solving process was interrupted because the solution improvement limit was reached"
SCIP_STATUS[SCIP_STATUS_OPTIMAL]        = "the problem was solved to optimality, an optimal solution is available"
SCIP_STATUS[SCIP_STATUS_INFEASIBLE]     = "the problem was proven to be infeasible"
SCIP_STATUS[SCIP_STATUS_UNBOUNDED]      = "the problem was proven to be unbounded"
SCIP_STATUS[SCIP_STATUS_INFORUNBD]      = "the problem was proven to be either infeasible or unbounded"


text:
export timeseries, timehist
function map_n(m::AbstractMarkovMap,x::Number,n::Integer)
  y = copy(x)
  for i = 1:n
    y = m(x)*(1+randn()*eps(prectype(m)))
  end
  y
end

function timeseries_initialvalue(m::AbstractMarkovMap,n::Integer,xinit::T) where T
  @assert domain(m) == rangedomain(m)
  @compat x_ts = Array{T}(undef,n)#randn(n)*eps(T)
  x_ts[1] = xinit
  x = copy(xinit)
  for i = 2:n
    x = m(x)#*(1+x_ts[i])
    x_ts[i] = x
  end
  x_ts
end
timeseries(m::AbstractMarkovMap,n::Integer;x0=map_n(m,rand(domain(m)),10^4)) = timeseries_initialvalue(m,n,x0)
samplable(ρ::Fun) = isa(domain(ρ),AbstractInterval) ? ρ : Fun(ρ,Space(Interval(domain(ρ))))
        # probably Interval(..) should be a convert routine but that's how ApproxFun has it...
timeseries(m::AbstractMarkovMap,n::Integer,ρ::Fun) = timeseries_initialvalue(m,n,sample(samplable(ρ)))

function timehist_initialvalue(m::AbstractMarkovMap,n::Integer,nbins::Integer,xinit::T) where T
  @assert domain(m) == rangedomain(m)
  bin_start = leftendpoint(domain(m))
  bin_step = (rightendpoint(domain(m))-bin_start)/nbins
  x_hist = zeros(Int,nbins)
  x = copy(xinit)
  for i = 1:n
    x = m(x)#*(1+randn()*eps(T))
    x_hist[min(nbins,max(1,convert(Int,ceil((x-bin_start)/bin_step))))] += 1
  end

  range(bin_start,stop=rightendpoint(domain(m)),length=nbins+1),x_hist
end
timehist(m::AbstractMarkovMap,n::Integer,nbins::Integer;x0=map_n(m,rand(domain(m)),10^4)) = timehist_initialvalue(m,n,nbins,x0)
timehist(m::AbstractMarkovMap,n::Integer,nbins::Integer,ρ::Fun) = timehist_initialvalue(m,n,nbins,sample(samplable(ρ)))