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

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

Instantiates an autoscaling virtual server based on the selected file transfer protocol in
AWS. When you make updates to your file transfer protocol-enabled server or when you work
with users, use the service-generated ServerId property that is assigned to the newly
created server.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Certificate"`: The Amazon Resource Name (ARN) of the AWS Certificate Manager (ACM)
  certificate. Required when Protocols is set to FTPS. To request a new public certificate,
  see Request a public certificate in the  AWS Certificate Manager User Guide. To import an
  existing certificate into ACM, see Importing certificates into ACM in the  AWS Certificate
  Manager User Guide. To request a private certificate to use FTPS through private IP
  addresses, see Request a private certificate in the  AWS Certificate Manager User Guide.
  Certificates with the following cryptographic algorithms and key sizes are supported:
  2048-bit RSA (RSA_2048)   4096-bit RSA (RSA_4096)   Elliptic Prime Curve 256 bit
  (EC_prime256v1)   Elliptic Prime Curve 384 bit (EC_secp384r1)   Elliptic Prime Curve 521
  bit (EC_secp521r1)    The certificate must be a valid SSL/TLS X.509 version 3 certificate
  with FQDN or IP address specified and information about the issuer.
- `"Domain"`:
- `"EndpointDetails"`: The virtual private cloud (VPC) endpoint settings that are
  configured for your server. When you host your endpoint within your VPC, you can make it
  accessible only to resources within your VPC, or you can attach Elastic IPs and make it
  accessible to clients over the internet. Your VPC's default security groups are
  automatically assigned to your endpoint.
- `"EndpointType"`: The type of VPC endpoint that you want your server to connect to. You
  can choose to connect to the public internet or a VPC endpoint. With a VPC endpoint, you
  can restrict access to your server and resources only within your VPC.  It is recommended
  that you use VPC as the EndpointType. With this endpoint type, you have the option to
  directly associate up to three Elastic IPv4 addresses (BYO IP included) with your server's
  endpoint and use VPC security groups to restrict traffic by the client's public IP address.
  This is not possible with EndpointType set to VPC_ENDPOINT.
- `"HostKey"`: The RSA private key as generated by the ssh-keygen -N \"\" -m PEM -f
  my-new-server-key command.  If you aren't planning to migrate existing users from an
  existing SFTP-enabled server to a new server, don't update the host key. Accidentally
  changing a server's host key can be disruptive.  For more information, see Change the host
  key for your SFTP-enabled server in the AWS Transfer Family User Guide.
- `"IdentityProviderDetails"`: Required when IdentityProviderType is set to API_GATEWAY.
  Accepts an array containing all of the information required to call a customer-supplied
  authentication API, including the API Gateway URL. Not required when IdentityProviderType
  is set to SERVICE_MANAGED.
- `"IdentityProviderType"`: Specifies the mode of authentication for a server. The default
  value is SERVICE_MANAGED, which allows you to store and access user credentials within the
  AWS Transfer Family service. Use the API_GATEWAY value to integrate with an identity
  provider of your choosing. The API_GATEWAY setting requires you to provide an API Gateway
  endpoint URL to call for authentication using the IdentityProviderDetails parameter.
- `"LoggingRole"`: Allows the service to write your users' activity to your Amazon
  CloudWatch logs for monitoring and auditing purposes.
- `"Protocols"`: Specifies the file transfer protocol or protocols over which your file
  transfer protocol client can connect to your server's endpoint. The available protocols
  are:    SFTP (Secure Shell (SSH) File Transfer Protocol): File transfer over SSH    FTPS
  (File Transfer Protocol Secure): File transfer with TLS encryption    FTP (File Transfer
  Protocol): Unencrypted file transfer    If you select FTPS, you must choose a certificate
  stored in AWS Certificate Manager (ACM) which will be used to identify your server when
  clients connect to it over FTPS. If Protocol includes either FTP or FTPS, then the
  EndpointType must be VPC and the IdentityProviderType must be API_GATEWAY. If Protocol
  includes FTP, then AddressAllocationIds cannot be associated. If Protocol is set only to
  SFTP, the EndpointType can be set to PUBLIC and the IdentityProviderType can be set to
  SERVICE_MANAGED.
- `"SecurityPolicyName"`: Specifies the name of the security policy that is attached to the
  server.
- `"Tags"`: Key-value pairs that can be used to group and search for servers.
"""
create_server(; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("CreateServer"; aws_config=aws_config)
create_server(params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("CreateServer", params; aws_config=aws_config)

"""
    create_user(role, server_id, user_name)
    create_user(role, server_id, user_name, params::Dict{String,<:Any})

Creates a user and associates them with an existing file transfer protocol-enabled server.
You can only create and associate users with servers that have the IdentityProviderType set
to SERVICE_MANAGED. Using parameters for CreateUser, you can specify the user name, set the
home directory, store the user's public key, and assign the user's AWS Identity and Access
Management (IAM) role. You can also optionally add a scope-down policy, and assign metadata
with tags that can be used to group and search for users.

# Arguments
- `role`: The IAM role that controls your users' access to your Amazon S3 bucket. The
  policies attached to this role will determine the level of access you want to provide your
  users when transferring files into and out of your Amazon S3 bucket or buckets. The IAM
  role should also contain a trust relationship that allows the server to access your
  resources when servicing your users' transfer requests.
- `server_id`: A system-assigned unique identifier for a server instance. This is the
  specific server that you added your user to.
- `user_name`: A unique string that identifies a user and is associated with a as specified
  by the ServerId. This user name must be a minimum of 3 and a maximum of 100 characters
  long. The following are valid characters: a-z, A-Z, 0-9, underscore '_', hyphen '-', period
  '.', and at sign '@'. The user name can't start with a hyphen, period, or at sign.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"HomeDirectory"`: The landing directory (folder) for a user when they log in to the
  server using the client. An example is  your-Amazon-S3-bucket-name>/home/username .
- `"HomeDirectoryMappings"`: Logical directory mappings that specify what Amazon S3 paths
  and keys should be visible to your user and how you want to make them visible. You will
  need to specify the \"Entry\" and \"Target\" pair, where Entry shows how the path is made
  visible and Target is the actual Amazon S3 path. If you only specify a target, it will be
  displayed as is. You will need to also make sure that your IAM role provides access to
  paths in Target. The following is an example.  '[ \"/bucket2/documentation\", { \"Entry\":
  \"your-personal-report.pdf\", \"Target\":
  \"/bucket3/customized-reports/{transfer:UserName}.pdf\" } ]'  In most cases, you can use
  this value instead of the scope-down policy to lock your user down to the designated home
  directory (\"chroot\"). To do this, you can set Entry to '/' and set Target to the
  HomeDirectory parameter value.  If the target of a logical directory entry does not exist
  in Amazon S3, the entry will be ignored. As a workaround, you can use the Amazon S3 API to
  create 0 byte objects as place holders for your directory. If using the CLI, use the s3api
  call instead of s3 so you can use the put-object operation. For example, you use the
  following: aws s3api put-object --bucket bucketname --key path/to/folder/. Make sure that
  the end of the key name ends in a '/' for it to be considered a folder.
- `"HomeDirectoryType"`: The type of landing directory (folder) you want your users' home
  directory to be when they log into the server. If you set it to PATH, the user will see the
  absolute Amazon S3 bucket paths as is in their file transfer protocol clients. If you set
  it LOGICAL, you will need to provide mappings in the HomeDirectoryMappings for how you want
  to make Amazon S3 paths visible to your users.
- `"Policy"`: A scope-down policy for your user so you can use the same IAM role across
  multiple users. This policy scopes down user access to portions of their Amazon S3 bucket.
  Variables that you can use inside this policy include {Transfer:UserName},
  {Transfer:HomeDirectory}, and {Transfer:HomeBucket}.  For scope-down policies, AWS Transfer
  Family stores the policy as a JSON blob, instead of the Amazon Resource Name (ARN) of the
  policy. You save the policy as a JSON blob and pass it in the Policy argument. For an
  example of a scope-down policy, see Creating a scope-down policy. For more information, see
  AssumeRole in the AWS Security Token Service API Reference.
- `"PosixProfile"`:
- `"SshPublicKeyBody"`: The public portion of the Secure Shell (SSH) key used to
  authenticate the user to the server.
- `"Tags"`: Key-value pairs that can be used to group and search for users. Tags are
  metadata attached to users for any purpose.
"""
create_user(Role, ServerId, UserName; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("CreateUser", Dict{String, Any}("Role"=>Role, "ServerId"=>ServerId, "UserName"=>UserName); aws_config=aws_config)
create_user(Role, ServerId, UserName, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("CreateUser", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Role"=>Role, "ServerId"=>ServerId, "UserName"=>UserName), params)); aws_config=aws_config)

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

Deletes the file transfer protocol-enabled server that you specify. No response returns
from this operation.

# Arguments
- `server_id`: A unique system-assigned identifier for a server instance.

"""
delete_server(ServerId; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("DeleteServer", Dict{String, Any}("ServerId"=>ServerId); aws_config=aws_config)
delete_server(ServerId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("DeleteServer", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ServerId"=>ServerId), params)); aws_config=aws_config)

"""
    delete_ssh_public_key(server_id, ssh_public_key_id, user_name)
    delete_ssh_public_key(server_id, ssh_public_key_id, user_name, params::Dict{String,<:Any})

Deletes a user's Secure Shell (SSH) public key. No response is returned from this operation.

# Arguments
- `server_id`: A system-assigned unique identifier for a file transfer protocol-enabled
  server instance that has the user assigned to it.
- `ssh_public_key_id`: A unique identifier used to reference your user's specific SSH key.
- `user_name`: A unique string that identifies a user whose public key is being deleted.

"""
delete_ssh_public_key(ServerId, SshPublicKeyId, UserName; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("DeleteSshPublicKey", Dict{String, Any}("ServerId"=>ServerId, "SshPublicKeyId"=>SshPublicKeyId, "UserName"=>UserName); aws_config=aws_config)
delete_ssh_public_key(ServerId, SshPublicKeyId, UserName, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("DeleteSshPublicKey", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ServerId"=>ServerId, "SshPublicKeyId"=>SshPublicKeyId, "UserName"=>UserName), params)); aws_config=aws_config)

"""
    delete_user(server_id, user_name)
    delete_user(server_id, user_name, params::Dict{String,<:Any})

Deletes the user belonging to a file transfer protocol-enabled server you specify. No
response returns from this operation.  When you delete a user from a server, the user's
information is lost.

# Arguments
- `server_id`: A system-assigned unique identifier for a server instance that has the user
  assigned to it.
- `user_name`: A unique string that identifies a user that is being deleted from a server.

"""
delete_user(ServerId, UserName; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("DeleteUser", Dict{String, Any}("ServerId"=>ServerId, "UserName"=>UserName); aws_config=aws_config)
delete_user(ServerId, UserName, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("DeleteUser", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ServerId"=>ServerId, "UserName"=>UserName), params)); aws_config=aws_config)

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

Describes the security policy that is attached to your file transfer protocol-enabled
server. The response contains a description of the security policy's properties. For more
information about security policies, see Working with security policies.

# Arguments
- `security_policy_name`: Specifies the name of the security policy that is attached to the
  server.

"""
describe_security_policy(SecurityPolicyName; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("DescribeSecurityPolicy", Dict{String, Any}("SecurityPolicyName"=>SecurityPolicyName); aws_config=aws_config)
describe_security_policy(SecurityPolicyName, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("DescribeSecurityPolicy", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("SecurityPolicyName"=>SecurityPolicyName), params)); aws_config=aws_config)

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

Describes a file transfer protocol-enabled server that you specify by passing the ServerId
parameter. The response contains a description of a server's properties. When you set
EndpointType to VPC, the response will contain the EndpointDetails.

# Arguments
- `server_id`: A system-assigned unique identifier for a server.

"""
describe_server(ServerId; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("DescribeServer", Dict{String, Any}("ServerId"=>ServerId); aws_config=aws_config)
describe_server(ServerId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("DescribeServer", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ServerId"=>ServerId), params)); aws_config=aws_config)

"""
    describe_user(server_id, user_name)
    describe_user(server_id, user_name, params::Dict{String,<:Any})

Describes the user assigned to the specific file transfer protocol-enabled server, as
identified by its ServerId property. The response from this call returns the properties of
the user associated with the ServerId value that was specified.

# Arguments
- `server_id`: A system-assigned unique identifier for a server that has this user assigned.
- `user_name`: The name of the user assigned to one or more servers. User names are part of
  the sign-in credentials to use the AWS Transfer Family service and perform file transfer
  tasks.

"""
describe_user(ServerId, UserName; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("DescribeUser", Dict{String, Any}("ServerId"=>ServerId, "UserName"=>UserName); aws_config=aws_config)
describe_user(ServerId, UserName, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("DescribeUser", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ServerId"=>ServerId, "UserName"=>UserName), params)); aws_config=aws_config)

"""
    import_ssh_public_key(server_id, ssh_public_key_body, user_name)
    import_ssh_public_key(server_id, ssh_public_key_body, user_name, params::Dict{String,<:Any})

Adds a Secure Shell (SSH) public key to a user account identified by a UserName value
assigned to the specific file transfer protocol-enabled server, identified by ServerId. The
response returns the UserName value, the ServerId value, and the name of the SshPublicKeyId.

# Arguments
- `server_id`: A system-assigned unique identifier for a server.
- `ssh_public_key_body`: The public key portion of an SSH key pair.
- `user_name`: The name of the user account that is assigned to one or more servers.

"""
import_ssh_public_key(ServerId, SshPublicKeyBody, UserName; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("ImportSshPublicKey", Dict{String, Any}("ServerId"=>ServerId, "SshPublicKeyBody"=>SshPublicKeyBody, "UserName"=>UserName); aws_config=aws_config)
import_ssh_public_key(ServerId, SshPublicKeyBody, UserName, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("ImportSshPublicKey", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ServerId"=>ServerId, "SshPublicKeyBody"=>SshPublicKeyBody, "UserName"=>UserName), params)); aws_config=aws_config)

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

Lists the security policies that are attached to your file transfer protocol-enabled
servers.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: Specifies the number of security policies to return as a response to the
  ListSecurityPolicies query.
- `"NextToken"`: When additional results are obtained from the ListSecurityPolicies
  command, a NextToken parameter is returned in the output. You can then pass the NextToken
  parameter in a subsequent command to continue listing additional security policies.
"""
list_security_policies(; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("ListSecurityPolicies"; aws_config=aws_config)
list_security_policies(params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("ListSecurityPolicies", params; aws_config=aws_config)

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

Lists the file transfer protocol-enabled servers that are associated with your AWS account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: Specifies the number of servers to return as a response to the
  ListServers query.
- `"NextToken"`: When additional results are obtained from the ListServers command, a
  NextToken parameter is returned in the output. You can then pass the NextToken parameter in
  a subsequent command to continue listing additional servers.
"""
list_servers(; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("ListServers"; aws_config=aws_config)
list_servers(params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("ListServers", params; aws_config=aws_config)

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

Lists all of the tags associated with the Amazon Resource Number (ARN) you specify. The
resource can be a user, server, or role.

# Arguments
- `arn`: Requests the tags associated with a particular Amazon Resource Name (ARN). An ARN
  is an identifier for a specific AWS resource, such as a server, user, or role.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: Specifies the number of tags to return as a response to the
  ListTagsForResource request.
- `"NextToken"`: When you request additional results from the ListTagsForResource
  operation, a NextToken parameter is returned in the input. You can then pass in a
  subsequent command to the NextToken parameter to continue listing additional tags.
"""
list_tags_for_resource(Arn; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("ListTagsForResource", Dict{String, Any}("Arn"=>Arn); aws_config=aws_config)
list_tags_for_resource(Arn, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("ListTagsForResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Arn"=>Arn), params)); aws_config=aws_config)

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

Lists the users for a file transfer protocol-enabled server that you specify by passing the
ServerId parameter.

# Arguments
- `server_id`: A system-assigned unique identifier for a server that has users assigned to
  it.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: Specifies the number of users to return as a response to the ListUsers
  request.
- `"NextToken"`: When you can get additional results from the ListUsers call, a NextToken
  parameter is returned in the output. You can then pass in a subsequent command to the
  NextToken parameter to continue listing additional users.
"""
list_users(ServerId; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("ListUsers", Dict{String, Any}("ServerId"=>ServerId); aws_config=aws_config)
list_users(ServerId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("ListUsers", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ServerId"=>ServerId), params)); aws_config=aws_config)

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

Changes the state of a file transfer protocol-enabled server from OFFLINE to ONLINE. It has
no impact on a server that is already ONLINE. An ONLINE server can accept and process file
transfer jobs. The state of STARTING indicates that the server is in an intermediate state,
either not fully able to respond, or not fully online. The values of START_FAILED can
indicate an error condition. No response is returned from this call.

# Arguments
- `server_id`: A system-assigned unique identifier for a server that you start.

"""
start_server(ServerId; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("StartServer", Dict{String, Any}("ServerId"=>ServerId); aws_config=aws_config)
start_server(ServerId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("StartServer", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ServerId"=>ServerId), params)); aws_config=aws_config)

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

Changes the state of a file transfer protocol-enabled server from ONLINE to OFFLINE. An
OFFLINE server cannot accept and process file transfer jobs. Information tied to your
server, such as server and user properties, are not affected by stopping your server.
Stopping the server will not reduce or impact your file transfer protocol endpoint billing;
you must delete the server to stop being billed.  The state of STOPPING indicates that the
server is in an intermediate state, either not fully able to respond, or not fully offline.
The values of STOP_FAILED can indicate an error condition. No response is returned from
this call.

# Arguments
- `server_id`: A system-assigned unique identifier for a server that you stopped.

"""
stop_server(ServerId; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("StopServer", Dict{String, Any}("ServerId"=>ServerId); aws_config=aws_config)
stop_server(ServerId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("StopServer", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ServerId"=>ServerId), params)); aws_config=aws_config)

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

Attaches a key-value pair to a resource, as identified by its Amazon Resource Name (ARN).
Resources are users, servers, roles, and other entities. There is no response returned from
this call.

# Arguments
- `arn`: An Amazon Resource Name (ARN) for a specific AWS resource, such as a server, user,
  or role.
- `tags`: Key-value pairs assigned to ARNs that you can use to group and search for
  resources by type. You can attach this metadata to user accounts for any purpose.

"""
tag_resource(Arn, Tags; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("TagResource", Dict{String, Any}("Arn"=>Arn, "Tags"=>Tags); aws_config=aws_config)
tag_resource(Arn, Tags, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("TagResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Arn"=>Arn, "Tags"=>Tags), params)); aws_config=aws_config)

"""
    test_identity_provider(server_id, user_name)
    test_identity_provider(server_id, user_name, params::Dict{String,<:Any})

If the IdentityProviderType of a file transfer protocol-enabled server is API_Gateway,
tests whether your API Gateway is set up successfully. We highly recommend that you call
this operation to test your authentication method as soon as you create your server. By
doing so, you can troubleshoot issues with the API Gateway integration to ensure that your
users can successfully use the service.

# Arguments
- `server_id`: A system-assigned identifier for a specific server. That server's user
  authentication method is tested with a user name and password.
- `user_name`: The name of the user account to be tested.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ServerProtocol"`: The type of file transfer protocol to be tested. The available
  protocols are:   Secure Shell (SSH) File Transfer Protocol (SFTP)   File Transfer Protocol
  Secure (FTPS)   File Transfer Protocol (FTP)
- `"SourceIp"`: The source IP address of the user account to be tested.
- `"UserPassword"`: The password of the user account to be tested.
"""
test_identity_provider(ServerId, UserName; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("TestIdentityProvider", Dict{String, Any}("ServerId"=>ServerId, "UserName"=>UserName); aws_config=aws_config)
test_identity_provider(ServerId, UserName, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("TestIdentityProvider", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ServerId"=>ServerId, "UserName"=>UserName), params)); aws_config=aws_config)

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

Detaches a key-value pair from a resource, as identified by its Amazon Resource Name (ARN).
Resources are users, servers, roles, and other entities. No response is returned from this
call.

# Arguments
- `arn`: The value of the resource that will have the tag removed. An Amazon Resource Name
  (ARN) is an identifier for a specific AWS resource, such as a server, user, or role.
- `tag_keys`: TagKeys are key-value pairs assigned to ARNs that can be used to group and
  search for resources by type. This metadata can be attached to resources for any purpose.

"""
untag_resource(Arn, TagKeys; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("UntagResource", Dict{String, Any}("Arn"=>Arn, "TagKeys"=>TagKeys); aws_config=aws_config)
untag_resource(Arn, TagKeys, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("UntagResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Arn"=>Arn, "TagKeys"=>TagKeys), params)); aws_config=aws_config)

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

Updates the file transfer protocol-enabled server's properties after that server has been
created. The UpdateServer call returns the ServerId of the server you updated.

# Arguments
- `server_id`: A system-assigned unique identifier for a server instance that the user
  account is assigned to.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Certificate"`: The Amazon Resource Name (ARN) of the AWS Certificate Manager (ACM)
  certificate. Required when Protocols is set to FTPS. To request a new public certificate,
  see Request a public certificate in the  AWS Certificate Manager User Guide. To import an
  existing certificate into ACM, see Importing certificates into ACM in the  AWS Certificate
  Manager User Guide. To request a private certificate to use FTPS through private IP
  addresses, see Request a private certificate in the  AWS Certificate Manager User Guide.
  Certificates with the following cryptographic algorithms and key sizes are supported:
  2048-bit RSA (RSA_2048)   4096-bit RSA (RSA_4096)   Elliptic Prime Curve 256 bit
  (EC_prime256v1)   Elliptic Prime Curve 384 bit (EC_secp384r1)   Elliptic Prime Curve 521
  bit (EC_secp521r1)    The certificate must be a valid SSL/TLS X.509 version 3 certificate
  with FQDN or IP address specified and information about the issuer.
- `"EndpointDetails"`: The virtual private cloud (VPC) endpoint settings that are
  configured for your server. With a VPC endpoint, you can restrict access to your server to
  resources only within your VPC. To control incoming internet traffic, you will need to
  associate one or more Elastic IP addresses with your server's endpoint.
- `"EndpointType"`: The type of endpoint that you want your server to connect to. You can
  choose to connect to the public internet or a VPC endpoint. With a VPC endpoint, you can
  restrict access to your server and resources only within your VPC.  It is recommended that
  you use VPC as the EndpointType. With this endpoint type, you have the option to directly
  associate up to three Elastic IPv4 addresses (BYO IP included) with your server's endpoint
  and use VPC security groups to restrict traffic by the client's public IP address. This is
  not possible with EndpointType set to VPC_ENDPOINT.
- `"HostKey"`: The RSA private key as generated by ssh-keygen -N \"\" -m PEM -f
  my-new-server-key.  If you aren't planning to migrate existing users from an existing
  server to a new server, don't update the host key. Accidentally changing a server's host
  key can be disruptive.  For more information, see Change the host key for your SFTP-enabled
  server in the AWS Transfer Family User Guide.
- `"IdentityProviderDetails"`: An array containing all of the information required to call
  a customer's authentication API method.
- `"LoggingRole"`: Changes the AWS Identity and Access Management (IAM) role that allows
  Amazon S3 events to be logged in Amazon CloudWatch, turning logging on or off.
- `"Protocols"`: Specifies the file transfer protocol or protocols over which your file
  transfer protocol client can connect to your server's endpoint. The available protocols
  are:   Secure Shell (SSH) File Transfer Protocol (SFTP): File transfer over SSH   File
  Transfer Protocol Secure (FTPS): File transfer with TLS encryption   File Transfer Protocol
  (FTP): Unencrypted file transfer    If you select FTPS, you must choose a certificate
  stored in AWS Certificate Manager (ACM) which will be used to identify your server when
  clients connect to it over FTPS. If Protocol includes either FTP or FTPS, then the
  EndpointType must be VPC and the IdentityProviderType must be API_GATEWAY. If Protocol
  includes FTP, then AddressAllocationIds cannot be associated. If Protocol is set only to
  SFTP, the EndpointType can be set to PUBLIC and the IdentityProviderType can be set to
  SERVICE_MANAGED.
- `"SecurityPolicyName"`: Specifies the name of the security policy that is attached to the
  server.
"""
update_server(ServerId; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("UpdateServer", Dict{String, Any}("ServerId"=>ServerId); aws_config=aws_config)
update_server(ServerId, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("UpdateServer", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ServerId"=>ServerId), params)); aws_config=aws_config)

"""
    update_user(server_id, user_name)
    update_user(server_id, user_name, params::Dict{String,<:Any})

Assigns new properties to a user. Parameters you pass modify any or all of the following:
the home directory, role, and policy for the UserName and ServerId you specify. The
response returns the ServerId and the UserName for the updated user.

# Arguments
- `server_id`: A system-assigned unique identifier for a server instance that the user
  account is assigned to.
- `user_name`: A unique string that identifies a user and is associated with a server as
  specified by the ServerId. This user name must be a minimum of 3 and a maximum of 100
  characters long. The following are valid characters: a-z, A-Z, 0-9, underscore '_', hyphen
  '-', period '.', and at sign '@'. The user name can't start with a hyphen, period, or at
  sign.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"HomeDirectory"`: Specifies the landing directory (folder) for a user when they log in
  to the server using their file transfer protocol client. An example is
  your-Amazon-S3-bucket-name>/home/username.
- `"HomeDirectoryMappings"`: Logical directory mappings that specify what Amazon S3 paths
  and keys should be visible to your user and how you want to make them visible. You will
  need to specify the \"Entry\" and \"Target\" pair, where Entry shows how the path is made
  visible and Target is the actual Amazon S3 path. If you only specify a target, it will be
  displayed as is. You will need to also make sure that your IAM role provides access to
  paths in Target. The following is an example.  '[ \"/bucket2/documentation\", { \"Entry\":
  \"your-personal-report.pdf\", \"Target\":
  \"/bucket3/customized-reports/{transfer:UserName}.pdf\" } ]'  In most cases, you can use
  this value instead of the scope-down policy to lock your user down to the designated home
  directory (\"chroot\"). To do this, you can set Entry to '/' and set Target to the
  HomeDirectory parameter value.  If the target of a logical directory entry does not exist
  in Amazon S3, the entry will be ignored. As a workaround, you can use the Amazon S3 API to
  create 0 byte objects as place holders for your directory. If using the CLI, use the s3api
  call instead of s3 so you can use the put-object operation. For example, you use the
  following: aws s3api put-object --bucket bucketname --key path/to/folder/. Make sure that
  the end of the key name ends in a / for it to be considered a folder.
- `"HomeDirectoryType"`: The type of landing directory (folder) you want your users' home
  directory to be when they log into the server. If you set it to PATH, the user will see the
  absolute Amazon S3 bucket paths as is in their file transfer protocol clients. If you set
  it LOGICAL, you will need to provide mappings in the HomeDirectoryMappings for how you want
  to make Amazon S3 paths visible to your users.
- `"Policy"`: Allows you to supply a scope-down policy for your user so you can use the
  same IAM role across multiple users. The policy scopes down user access to portions of your
  Amazon S3 bucket. Variables you can use inside this policy include {Transfer:UserName},
  {Transfer:HomeDirectory}, and {Transfer:HomeBucket}.  For scope-down policies, AWS Transfer
  Family stores the policy as a JSON blob, instead of the Amazon Resource Name (ARN) of the
  policy. You save the policy as a JSON blob and pass it in the Policy argument. For an
  example of a scope-down policy, see Creating a scope-down policy. For more information, see
  AssumeRole in the AWS Security Token Service API Reference.
- `"PosixProfile"`:
- `"Role"`: The IAM role that controls your users' access to your Amazon S3 bucket. The
  policies attached to this role will determine the level of access you want to provide your
  users when transferring files into and out of your Amazon S3 bucket or buckets. The IAM
  role should also contain a trust relationship that allows the server to access your
  resources when servicing your users' transfer requests.
"""
update_user(ServerId, UserName; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("UpdateUser", Dict{String, Any}("ServerId"=>ServerId, "UserName"=>UserName); aws_config=aws_config)
update_user(ServerId, UserName, params::AbstractDict{String, <:Any}; aws_config::AbstractAWSConfig=global_aws_config()) = transfer("UpdateUser", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ServerId"=>ServerId, "UserName"=>UserName), params)); aws_config=aws_config)


text:
# Path that the walk takes
function path(
    u,
    w::Walker2D,
    timesteps::Int64,
    rate::Float64,
    width::Int=1,
    length::Int=1)
# W is a type parameter
ws = [position(w)]

for i in 1:timesteps
    w = u(w, step(rate),width,length)
    push!(ws, position(w))
end
return ws
end

# Create local functions
function period_path(t,r,l,w)
    path(
        updateperiod,
        Walker2D(0,0),
        Int(round(t,digits=0)),
        r,w,l)
end

function period_path_df(t,r,l,w)
    DataFrame(
        reduce(
            vcat,
            [[i[1] i[2]] for i in period_path(t,r,l,w)]),
        [:x, :y])
end

# Taking more than one path
function paths(
Nwalks::Int,
u,
w::Walker2D,
timesteps::Int64,
rate::Float64,
width::Int=1,
length::Int=1)
displace = []

for k in 1:Nwalks
    t = path(
                u,w,timesteps,rate,width,length)
    tup = endpoint(t)
    data = WalkersData(
        Nwalks,
        timesteps,
        rate,
        width,
        length,
        tup.x,
        tup.y)

    push!(displace,data)
end
return displace
end

# Last point in a path
function endpoint(t)
    return Walker2D(t[end][1],t[end][2])
end

function paths_df(
    paramRange::Int,
    largestTime::Int,
    Nwalks::Int,
    updateRule,
    w::Walker2D,
    width::Int=1,
    length::Int=1
    )
timesteps = range(1,largestTime,length=paramRange)
rate = range(0.001, 0.25, length=paramRange)
dis_vec = []
for i in 1:paramRange,j in 1:paramRange
Walks = paths(
    Nwalks,
    updateRule,
    w,
    Int(round(timesteps[i],digits=0)),
    rate[j],
    width,
    length)
push!(dis_vec,Walks)
end
df = WalkersData2DataFram(dis_vec)

df.taxcabdisplacement = abs.(df.x) .+ abs.(df.y)
df.taxcabdisplacement² = abs.(df.x).^2 .+ abs.(df.y).^2
df.sqrttaxcabdisplacement² = sqrt.(df.taxcabdisplacement²)

return df
end

ext: jl


text:
# This file is a part of BAT.jl, licensed under the MIT License (MIT).

"""
    abstract type AbstractDensity

Subtypes of `AbstractDensity` must be implement the function

* `DensityInterface.logdensityof(density::SomeDensity, v)`

For likelihood densities this is typically sufficient, since BAT can infer
variate shape and bounds from the prior.

!!! note

    If `DensityInterface.logdensityof` is called with an argument that is out
    of bounds, the behavior is undefined. The result for arguments that are
    not within bounds is *implicitly* `-Inf`, but it is the caller's
    responsibility to handle these cases.

Densities with a known variate shape may also implement

* `ValueShapes.varshape`

Densities with known variate bounds may also implement

* `BAT.var_bounds`

!!! note

    The function `BAT.var_bounds` is not part of the stable public BAT-API,
    it's name and arguments may change without deprecation.
"""
abstract type AbstractDensity end
export AbstractDensity

Base.convert(::Type{AbstractDensity}, density::AbstractDensity) = density
Base.convert(::Type{AbstractDensity}, density::Any) = convert(WrappedNonBATDensity, density)

DensityInterface.isdensitytype(::Type{<:AbstractDensity}) = true

@inline ValueShapes.varshape(f::Base.Fix1{typeof(DensityInterface.logdensityof),<:AbstractDensity}) = varshape(f.x)
@inline ValueShapes.unshaped(f::Base.Fix1{typeof(DensityInterface.logdensityof),<:AbstractDensity}) = logdensityof(unshaped(f.x))

"""
    BAT.eval_logval_unchecked(density::AbstractDensity, v::Any)

**DEPRECATED** use/overload `DensityInterface.logdensityof` instead.
"""
const eval_logval_unchecked = logdensityof

show_value_shape(io::IO, vs::AbstractValueShape) = show(io, vs)
function show_value_shape(io::IO, vs::NamedTupleShape)
    print(io, Base.typename(typeof(vs)).name, "(")
    show(io, propertynames(vs))
    print(io, "}(…)")
end

function Base.show(io::IO, d::AbstractDensity)
    print(io, Base.typename(typeof(d)).name, "(objectid = ")
    show(io, objectid(d))
    vs = varshape(d)
    if !ismissing(vs)
        print(io, ", varshape = ")
        show_value_shape(io, vs)
    end
    print(io, ")")
end

"""
    struct DensityEvalException <: Exception

Constructors:

* ```$(FUNCTIONNAME)(func::Function, density::AbstractDensity, v::Any, ret::Any)```

Fields:

$(TYPEDFIELDS)
"""
struct DensityEvalException{F<:Function,D<:AbstractDensity,V,C} <: Exception
    "Density evaluation function that failed."
    func::F

    "Density being evaluated."
    density::D

    "Variate at which the evaluation of `density` (applying `f` to `d` at `v`) failed."
    v::V

    "Cause of failure, either the invalid return value of `f` on `d` at `v`, or another expection (on rethrow)."
    ret::C
end

function Base.showerror(io::IO, err::DensityEvalException)
    print(io, "Density evaluation with $(err.func) failed at ")
    show(io, value_for_msg(err.v))
    if err.ret isa Exception
        print(io, " due to exception ")
        showerror(io, err.ret)
    else
        print(io, ", must not evaluate to ")
        show(io, value_for_msg(err.ret))
    end
    print(io, ", density is ")
    show(io, err.density)
end

"""
    var_bounds(
        density::AbstractDensity
    )::Union{AbstractVarBounds,Missing}

*BAT-internal, not part of stable public API.*

Get the parameter bounds of `density`. See [`AbstractDensity`](@ref) for the
implications and handling of bounds.
"""
var_bounds(density::AbstractDensity) = missing

"""
    ValueShapes.totalndof(density::AbstractDensity)::Union{Int,Missing}

Get the number of degrees of freedom of the variates of `density`. May return
`missing`, if the shape of the variates is not fixed.
"""
function ValueShapes.totalndof(density::AbstractDensity)
    shape = varshape(density)
    ismissing(shape) ? missing : ValueShapes.totalndof(shape)
end

"""
    ValueShapes.varshape(
        density::AbstractDensity
    )::Union{ValueShapes.AbstractValueShape,Missing}

    ValueShapes.varshape(
        density::DistLikeDensity
    )::ValueShapes.AbstractValueShape

Get the shapes of the variates of `density`.

For prior densities, the result must not be `missing`, but may be `nothing` if
the prior only supports unshaped variate/parameter vectors.
"""
ValueShapes.varshape(density::AbstractDensity) = missing

bat_sampler(d::AbstractDensity) = Distributions.sampler(d)

"""
    checked_logdensityof(density::AbstractDensity, v::Any, T::Type{<:Real})

*BAT-internal, not part of stable public API.*

Evaluates density log-value via `DensityInterface.logdensityof` and performs
additional checks.

Throws a `BAT.DensityEvalException` on any of these conditions:

* The variate shape of `density` (if known) does not match the shape of `v`.
* The return value of `DensityInterface.logdensityof` is `NaN`.
* The return value of `DensityInterface.logdensityof` is an equivalent of positive
  infinity.
"""
function checked_logdensityof end

@inline checked_logdensityof(density::AbstractDensity) = Base.Fix1(checked_logdensityof, density)

@inline ValueShapes.varshape(f::Base.Fix1{typeof(checked_logdensityof),<:AbstractDensity}) = varshape(f.x)
@inline ValueShapes.unshaped(f::Base.Fix1{typeof(checked_logdensityof),<:AbstractDensity}) = checked_logdensityof(unshaped(f.x))

@inline DensityInterface.logfuncdensity(f::Base.Fix1{typeof(checked_logdensityof)}) = f.x

function checked_logdensityof(density::AbstractDensity, v::Any)
    check_variate(varshape(density), v)

    logval = try
        logdensityof(density, v)
    catch err
        @rethrow_logged DensityEvalException(logdensityof, density, v, err)
    end

    _check_density_logval(density, v, logval)

    #R = density_valtype(density, v_shaped)
    #return convert(R, logval)::R
    return logval
end

ZygoteRules.@adjoint checked_logdensityof(density::AbstractDensity, v::Any) = begin
    check_variate(varshape(density), v)
    logval, back = try
        ZygoteRules.pullback(logdensityof(density), v)
    catch err
        @rethrow_logged DensityEvalException(logdensityof, density, v, err)
    end
    _check_density_logval(density, v, logval)
    eval_logval_pullback(logval::Real) = (nothing, first(back(logval)))
    (logval, eval_logval_pullback)
end

function _check_density_logval(density::AbstractDensity, v::Any, logval::Real)
    if isnan(logval) || !(logval < float(typeof(logval))(+Inf))
        throw(DensityEvalException(logdensityof, density, v, logval))
    end
    nothing
end

value_for_msg(v::Real) = v
# Strip dual numbers to make errors more readable:
value_for_msg(v::ForwardDiff.Dual) = ForwardDiff.value(v)
value_for_msg(v::AbstractArray) = value_for_msg.(v)
value_for_msg(v::NamedTuple) = map(value_for_msg, v)

"""
    BAT.density_valtype(density::AbstractDensity, v::Any)

*BAT-internal, not part of stable public API.*

Determine a suitable return type for the (log-)density value
of the given density for the given variate.
"""
function density_valtype end

@inline function density_valtype(density::AbstractDensity, v::Any)
    T = float(getnumtype(v))
    promote_type(T, default_val_numtype(density))
end

function ChainRulesCore.rrule(::typeof(density_valtype), density::AbstractDensity, v::Any)
    result = density_valtype(density, v)
    _density_valtype_pullback(ΔΩ) = (NoTangent(), NoTangent(), ZeroTangent())
    return result, _density_valtype_pullback
end

"""
    BAT.default_var_numtype(density::AbstractDensity)

*BAT-internal, not part of stable public API.*

Returns the default/preferred underlying numerical type for (elements of)
variates of `density`.
"""
function default_var_numtype end
default_var_numtype(density::AbstractDensity) = Float64

"""
    BAT.default_val_numtype(density::AbstractDensity)

*BAT-internal, not part of stable public API.*

Returns the default/preferred numerical type (log-)density values of
`density`.
"""
function default_val_numtype end
default_val_numtype(density::AbstractDensity) = Float64

"""
    BAT.log_zero_density(T::Type{<:Real})

log-density value to assume for regions of implicit zero density, e.g.
outside of variate/parameter bounds/support.

Returns an equivalent of negative infinity.
"""
log_zero_density(T::Type{<:Real}) = float(T)(-Inf)

"""
    BAT.is_log_zero(x::Real, T::Type{<:Real} = typeof(x)}

*BAT-internal, not part of stable public API.*

Check if x is an equivalent of log of zero, resp. negative infinity,
in respect to type `T`.
"""
function is_log_zero(x::Real, T::Type{<:Real} = typeof(x))
    U = typeof(x)

    FT = float(T)
    FU = float(U)

    x_notnan = !isnan(x)
    x_isinf = !isfinite(x)
    x_isneg = x < zero(x)
    x_notgt1 = !(x > log_zero_density(FT))
    x_notgt2 = !(x > log_zero_density(FU))
    x_iseq1 = x ≈ log_zero_density(FT)
    x_iseq2 = x ≈ log_zero_density(FU)

    x_notnan && ((x_isinf && x_isneg) | x_notgt1 | x_notgt2 | x_iseq1 | x_iseq1)
end

"""
    abstract type DistLikeDensity <: AbstractDensity

A density that implements part of the `Distributions.Distribution` interface.
Such densities are suitable for use as a priors.

Typically, custom priors should be implemented as subtypes of
`Distributions.Distribution`. BAT will automatically wrap them in a subtype of
`DistLikeDensity`.

Subtypes of `DistLikeDensity` are required to support more functionality
than an [`AbstractDensity`](@ref), but less than a
`Distribution{Multivariate,Continuous}`.

A `d::Distribution{Multivariate,Continuous}` can be converted into (wrapped
in) an `DistLikeDensity` via `conv(DistLikeDensity, d)`.

The following functions must be implemented for subtypes:

* `DensityInterface.logdensityof`

* `ValueShapes.varshape`

* `Distributions.sampler`

* `Statistics.cov`

* `BAT.var_bounds`

!!! note

    The function `BAT.var_bounds` is not part of the stable public BAT-API
    and subject to change without deprecation.
"""
abstract type DistLikeDensity <: AbstractDensity end
export DistLikeDensity

"""
    var_bounds(density::DistLikeDensity)::AbstractVarBounds

*BAT-internal, not part of stable public API.*

Get the parameter bounds of `density`. Must not be `missing`.
"""
function var_bounds end

"""
    ValueShapes.totalndof(density::DistLikeDensity)::Int

Get the number of degrees of freedom of the variates of `density`. Must not be
`missing`, a `DistLikeDensity` must have a fixed variate shape.
"""
ValueShapes.totalndof(density::DistLikeDensity) = totalndof(var_bounds(density))

"""
    BAT.AnyDensityLike = Union{...}

Union of all types that BAT will accept as a probability density, resp. that
`convert(AbstractDensity, d)` supports:

* [`AbstractDensity`](@ref)
* `DensityInterface.LogFuncDensity`
* `Distributions.Distribution`
"""
const AnyDensityLike = Union{
    AbstractDensity,
    DensityInterface.LogFuncDensity,
    Distributions.ContinuousDistribution
}
export AnyDensityLike

"""
    BAT.AnySampleable = Union{...}

Union of all types that BAT can sample from:

* [`AbstractDensity`](@ref)
* [`DensitySampleVector`](@ref)
* `DensityInterface.LogFuncDensity`
* `Distributions.Distribution`
"""
const AnySampleable = Union{
    AbstractDensity,
    DensitySampleVector,
    DensityInterface.LogFuncDensity,
    Distributions.Distribution
}
export AnySampleable

"""
    BAT.AnyIIDSampleable = Union{...}

Union of all distribution/density-like types that BAT can draw i.i.d.
(independent and identically distributed) samples from:

* [`DistLikeDensity`](@ref)
* `Distributions.Distribution`
"""
const AnyIIDSampleable = Union{
    DistLikeDensity,
    Distributions.Distribution
}
export AnyIIDSampleable

"""
    struct BAT.WrappedNonBATDensity{F<:Base.Callable}

*BAT-internal, not part of stable public API.*

Wraps a log-density function `log_f`.
"""
struct WrappedNonBATDensity{D} <: AbstractDensity
    _d::D

    function WrappedNonBATDensity{D}(density::D) where D
        @argcheck isdensitytype(D)
        new{D}(density)
    end

    WrappedNonBATDensity(density::D) where D = WrappedNonBATDensity{D}(density)
end

Base.convert(::Type{WrappedNonBATDensity}, density::Any) = WrappedNonBATDensity(density)

@inline Base.parent(density::WrappedNonBATDensity) = density._d

@inline DensityInterface.logdensityof(density::WrappedNonBATDensity, x) = logdensityof(parent(density), x)
@inline DensityInterface.logdensityof(density::WrappedNonBATDensity) = logdensityof(parent(density))

ValueShapes.varshape(density::WrappedNonBATDensity) = varshape(parent(density))

function Base.show(io::IO, density::WrappedNonBATDensity)
    print(io, Base.typename(typeof(density)).name, "(")
    show(io, parent(density))
    print(io, ")")
end


text:
############################
## grossMomentsLogMoments ##
############################

function grossRetMomentsToLogRetMoments(mu::Float64, sigma::Float64)
    ## arithmetic moments R to r^{log}

    ## calculate log variance
    varLog = log(1 + sigma^2/mu^2)
    muLog = log(mu) - 0.5*varLog
    sigmaLog = sqrt(varLog)

    return muLog, sigmaLog
end

function logRetMomentsToGrossRetMoments(muLog::Float64,
                                        sigmaLog::Float64)
    ## logarithmic moments r^{log} to R
    mu = exp(muLog + 0.5*sigmaLog^2)
    varGross = (exp(sigmaLog^2) - 1)*exp(2*muLog + sigmaLog^2)

    return mu, sqrt(varGross)
end

#######################
## scaling functions ##
#######################

## Note: initialized without any scaling by now
## Problem: mus should not be scaled linearly, as discrete returns may
## not be aggregated over time linearly. A better way might be to make
## a distributional assumption (log-normal) and scale geometric means
## (or arithmetic means for log returns)

function defaultMuSigmaScaling(mu::Float64, sigma::Float64;
                               scalingFactor = 52)
    ## - annualized arithmetic mean and sigma shown
    ## - via annualized log moments
    ## - percentage values
    ## Assumptions:
    ## - log-normality to get log moments
    ## - independence over time for square-root-of-time scaling
    ## - constant weights over time
    ## - constant moments over time

    ## net to gross
    muGross = mu + 1

    ## get log moments
    muLog, sigmaLog = grossRetMomentsToLogRetMoments(muGross, sigma)

    ## annualize log moments
    muLogAnnual = muLog*scalingFactor
    sigmaLogAnnual = sqrt(scalingFactor)*sigmaLog

    ## translate to gross moments
    muGrossAnnual, sigmaAnnual =
        logRetMomentsToGrossRetMoments(muLogAnnual,
                                       sigmaLogAnnual)

    ## translate to net returns
    muNetAnnual = muGrossAnnual - 1

    ## translate to percentages
    muNetAnnualPercent = muNetAnnual * 100
    sigmaAnnualPercent = sigmaAnnual * 100

    return muNetAnnualPercent, sigmaAnnualPercent
end

## applied to vectors
function defaultMuSigmaScaling(mus::Array{Float64, 1},
                               sigmas::Array{Float64, 1};
                               scalingFactor = 52)
    ## preallocation
    nMoments = size(mus, 1)
    scaledMus = ones(nMoments)
    scaledSigmas = ones(nMoments)

    for ii=1:nMoments
        thisMu, thisSigma =
            defaultMuSigmaScaling(mus[ii], sigmas[ii])
        scaledMus[ii] = thisMu
        scaledSigmas[ii] = thisSigma
    end
    return scaledMus, scaledSigmas
end

##########################################
## symbol / string conversion functions ##
##########################################

function symbToStr(symbs::Array{Symbol, 1})
    return UTF8String[string(symb) for symb in symbs]
end

function symbToStr(symbs::DataArray{Symbol, 1})
    return UTF8String[string(symb) for symb in symbs]
end

function strToSymb(strs::Array{UTF8String, 1})
    return Symbol[symbol(xx) for xx in strs]
end

function strToSymb(strs::DataArray{UTF8String, 1})
    return Symbol[symbol(xx) for xx in strs]
end

function strToSymb(strs::DataArray{String, 1})
    return Symbol[symbol(xx) for xx in strs]
end

#######################
## calculate moments ##
#######################

## single portfolio, single universe
function getPMean(wgts::Array{Float64, 1}, mus::Array{Float64, 1})
    return (wgts'*mus)[1]
end

## multiple portfolios, single universe
function getPMean(wgts::Array{Float64, 2}, mus::Array{Float64, 1})
    nPfs = size(wgts, 1)
    pfMus = ones(nPfs)
    for ii=1:nPfs
        pfMus[ii] = getPMean(wgts[ii, :][:], mus)
    end
    return pfMus
end

## single portfolio, single universe
function getPVar(wgts::Array{Float64, 1}, covMatr::Array{Float64, 2})
    return (wgts'*covMatr*wgts)[1]
end

## multiple portfolios, single universe
function getPVar(wgts::Array{Float64, 2}, covMatr::Array{Float64, 2})
    nPfs = size(wgts, 1)
    pfVariances = ones(nPfs)
    for ii=1:nPfs
        pfVariances[ii] = getPVar(wgts[ii, :][:], covMatr)
    end
    return pfVariances
end

####################################
## statistic functions DataFrames ##
####################################

import Base.mean
function mean(df::DataFrame, int::Integer)
    if int==2
        error("for row-wise mean, use rowmean instead")
    else
        mus = DataFrame(mean(array(df), 1), names(df))
    end
end

import Base.cov
function cov(df::DataFrame)
    return DataFrame(cov(array(df)), names(df))
end

function corrcov(covMatr::DataFrame)
    d = diagm(1/sqrt(diag(array(covMatr))))
    return DataFrame(d*array(covMatr)*d, names(covMatr))
end

##################################
## create random weights matrix ##
##################################

## function randWgts(nObs::Int, nAss::Int)
##     ## create random weights
##     ##
##     ## Output:
##     ## 	nObs x nAss Array{Float64,2} containing portfolio weights in
##     ## 	each row

##     simVals = rand(nObs, nAss)
##     rowsums = sum(simVals, 2)
##     wgts = simVals ./ repmat(rowsums, 1, nAss)
## end

##################################################
## normalize matrix values to represent weights ##
##################################################

function makeWeights(matr::Array{Float64, 2})
    ## normalize matrix to have row sums of 1
    nObs = size(matr, 1)
    for ii=1:nObs
        matr[ii, :] = matr[ii, :]./sum(matr[ii, :])
    end
    return matr
end

#################################
## download interest rate data ##
#################################

function getTBill()
    ## get Federal funds effective rate

    tbillsURL =
        "http://www.federalreserve.gov/datadownload/Output.aspx?rel=H15&series=646250c87b1afd04cc6774796fc0cec8&lastObs=&from=&to=&filetype=csv&label=include&layout=seriescolumn"

    rawSplitted = download(tbillsURL) |>
    readall |>
    s -> split(s,"\r\n") |> # get individual lines
    s -> map(l -> split(l, ","), s)     # decompose each line into
                                        # dates and rates

    maxNumberDates = length(rawSplitted)
    dats = Array(Date{ISOCalendar}, maxNumberDates)
    intRatesStr = Array(String, maxNumberDates)
    skipLines = rep(false, maxNumberDates)

    for ii=1:maxNumberDates
        try
            dats[ii] = date(rawSplitted[ii][1])
            intRatesStr[ii] = rawSplitted[ii][2]
            if intRatesStr[ii] == "ND"
                skipLines[ii] = true
                println("line ", ii, " skipped: no observation")
            end
        catch
            println("line ", ii, " skipped: no date in line")
            skipLines[ii] = true
            continue
        end
    end

    intRatesValid = intRatesStr[!skipLines]
    intRates = Array(Float64, length(intRatesValid))
    for ii=1:length(intRatesValid)
        intRates[ii] = parsefloat(intRatesValid[ii])
    end

    intRatesDf = DataFrame(FEDrate = intRates)
    return Timematr(intRatesDf, dats[!skipLines])
end


text:
function testdata_provider()
    n_customers = 36
    demand = [16, 18, 1, 13, 8, 23, 7, 27, 1, 3, 6, 24, 19, 2, 5, 16, 7, 4, 22, 7, 23, 16, 2, 2, 9, 2, 12, 1, 9, 23, 6, 19, 7, 7, 20, 20]
    capacity = 100
    edge_tail = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 35, 35, 36]
    edge_head = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 29, 30, 31, 32, 33, 34, 35, 36, 37, 30, 31, 32, 33, 34, 35, 36, 37, 31, 32, 33, 34, 35, 36, 37, 32, 33, 34, 35, 36, 37, 33, 34, 35, 36, 37, 34, 35, 36, 37, 35, 36, 37, 36, 37, 37]
    edge_x = [1.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0]
    n_edges = length(edge_head)
    max_n_cuts = 10
    integrality_tolerance = 1e-6

    return demand, capacity, edge_head, edge_tail, edge_x
end


text:
# Helpers to aid in constructing class definitions
struct ClassId end

mutable struct ClassConstructor
  statements
  param_defs
  method_defs
  new_args
  arguments
  ClassConstructor() = new([],[],[],[],:undef)
end

mutable struct ClassInfo
  constructor::ClassConstructor
  parameters
  undefined
  nonfunctions
  ClassInfo() = new(ClassConstructor(), [], [], [])
end

function make_constructor(name, info, constructor_info::ClassConstructor)
  args  = constructor_info.arguments
  stats = constructor_info.statements

  statements  = args == :undef ? map(make_def, info.undefined) : stats
  arguments   = args == :undef ? info.undefined : args
  param_defs  = constructor_info.param_defs
  method_defs = constructor_info.method_defs
  new_args    = constructor_info.new_args

  :(function $name($(arguments...))
      this = $name(ClassId())
      $(param_defs...)
      $(method_defs...)
      $(statements...)
      this
    end)
end

# unrelated to the metadispatch part of the definition

abstract type Object end

struct Method{T <: Object}
  func  :: Function
end
(m::Method)(args...) = m.func(args...)

class_field_values(obj) =
  filter(x->!isa(x, Method), map(x->getfield(obj, x), fieldnames(obj)))

function Base.show(io::IO, obj::T) where T<:Object
  print("$T(")

  fields = class_field_values(obj)
  for i in eachindex(fields)
  	print(fields[i])
  	if i != length(fields)
  	  print(",")
  	end
  end

  print(")")
end


text:
### A Pluto.jl notebook ###
# v0.17.2

# using Markdown
# using InteractiveUtils

# ╔═╡ 74975885-9a4e-4857-8135-9e4f69061caf
begin
	using DocStringExtensions
	using StaticArrays
	using LinearAlgebra
end

# ╔═╡ c0a30957-4c7b-4d7b-bfa9-c2fb691a077b
#=╠═╡ notebook_exclusive
begin
	using PlutoUtils
	using PlotlyBase
	using BenchmarkTools
end
  ╠═╡ notebook_exclusive =#

# ╔═╡ 379613ec-0973-4000-ae8c-d7c33ddca18e
#=╠═╡ notebook_exclusive
md"""
# Packages
"""
  ╠═╡ notebook_exclusive =#

# ╔═╡ 736b0cf6-bec2-4226-8ef4-70f6a865d34a
#=╠═╡ notebook_exclusive
ToC()
  ╠═╡ notebook_exclusive =#

# ╔═╡ f8243a65-9f5e-464e-bb06-0bb4f5131b8b
#=╠═╡ notebook_exclusive
md"""
# Exports
"""
  ╠═╡ notebook_exclusive =#

# ╔═╡ 8660a7c4-eb78-4e7c-966b-d759df7f3dfa
#=╠═╡ notebook_exclusive
md"""
# Lattice Functions
"""
  ╠═╡ notebook_exclusive =#

# ╔═╡ 71163795-9695-4f11-acc2-6e3838c8a158
#=╠═╡ notebook_exclusive
md"""
## generate\_regular_lattice
"""
  ╠═╡ notebook_exclusive =#

# ╔═╡ da97848f-a7ff-4f2d-b98d-e8bf1ccc3038
function lattice_generator(dx::T, dy::T, ds::T;x0::T = T(0), y0::T = T(0), M::Int = 70,N::Int = M) where T<:Real
	# Function to generate x position as function of row,column number m,n
	x(m, n) = m * dx + n * ds + x0
	# Function to generate y position as function of row,column number m,n
	y(n) = n * dy + y0
	# Generate the elements. For each row, shift the columns to always have the search domain around x=0
	gen = ((x(m - round(Int,n * ds / dx), n), y(n)) for n in -N:N,m in -M:M)
	return gen
end

# ╔═╡ f8a53711-e07f-4b6b-84ea-803679496571
"""
Generate a regular lattice of points
$(TYPEDSIGNATURES)

# Arguments
- `dx` → element spacing on the x axis
- `dy` → element spacing on the y axis
- `ds` → displacement along x between rows of elements
- `f_cond::Function` → function of two arguments (`f(x,y) = ...`) returning `true` if element at position `x,y` must be kept and `false` otherwise

# Keyord Arguments
- `x0 = 0` → x coordinate of the origin of the lattice
- `y0 = 0` → y coordinate of the origin of the lattice
- `M::Int = 70` → Number of elements to generate per row of points before appliying the filtering function `f_cond`
- `N::Int = M` → Number of rows of points to generate before appliying the filtering function `f_cond`
"""
function generate_regular_lattice(dx::T, dy::T, ds::T, f_cond::Function = (x, y) -> true;x0::T = T(0), y0::T = T(0), M::Int = 70,N::Int = M) where T<:Real
	gen = lattice_generator(dx, dy, ds; x0, y0, M, N)
	return [x for x ∈ gen if f_cond(x...)]
end

# ╔═╡ ce22b91e-6bba-4312-a89b-1a78f84034d3
function regular_lattice_nelements(dx::T, dy::T, ds::T, f_cond::Function = (x, y) -> true;x0::T = T(0), y0::T = T(0), M::Int = 70,N::Int = M) where T<:Real
	gen = lattice_generator(dx, dy, ds; x0, y0, M, N)
	sum(x -> f_cond(x...), gen)
end

# ╔═╡ 0eb5d19d-b535-4cda-a89b-26ba295e2711
generate_regular_lattice(dx::Real,dy::Real,ds::Real,args...;kwargs...) = generate_regular_lattice(promote(dx,dy,ds)...,args...;kwargs...)

# ╔═╡ 2ba73b51-ecb9-4632-9f39-bdaeb8c5bd34
#=╠═╡ notebook_exclusive
@benchmark generate_square_lattice(1, (x,y) -> x^2 + y^2 < 100)
  ╠═╡ notebook_exclusive =#

# ╔═╡ f0834b38-8efe-4e77-b0f9-47e5b7595191
#=╠═╡ notebook_exclusive
md"""
## generate\_rect_lattice
"""
  ╠═╡ notebook_exclusive =#

# ╔═╡ 9e5db472-f96a-4acb-96ae-024b5c73a93d
"""
    generate_rect_lattice(spacing_x::Real,spacing_y::Real[,f_cond];kwargs...)
# Summary
Generate a rectangular lattice of points (with different spacing among x and y directions)
# Arguments
- `spacing_x` → spacing between points on the x axis
- `spacing_y` → spacing between points on the y axis

See [`generate_regular_lattice`](@ref) for a description of `f_cond` and of  the keyword arguments
"""
generate_rect_lattice(spacing_x::Real,spacing_y::Real,args...;kwargs...) = generate_regular_lattice(spacing_x,spacing_y,0,args...;kwargs...)

# ╔═╡ c41f9f41-d8bd-4001-98cb-2ab788404b1b
#=╠═╡ notebook_exclusive
md"""
## generate\_square\_lattice
"""
  ╠═╡ notebook_exclusive =#

# ╔═╡ 8787134f-9d14-4329-8dda-72557e3175b8
"""
`generate_square_lattice(spacing::Real[,f_cond];kwargs...)`
# Summary
Generate a square lattice of points (with equal spacing among x and y directions)
# Arguments
- `spacing` → spacing between points on both x and y axis

See [`generate_regular_lattice`](@ref) for a description of `f_cond` and of  the keyword arguments
"""
generate_square_lattice(spacing::Real,args...;kwargs...) = generate_regular_lattice(spacing,spacing,0,args...;kwargs...)

# ╔═╡ f589306c-919d-468a-a0fd-9367acc36a7b
#=╠═╡ notebook_exclusive
md"""
## generate\_hex\_lattice
"""
  ╠═╡ notebook_exclusive =#

# ╔═╡ 6ca05079-4c0d-4c45-8486-a4291310189d
"""
`generate_hex_lattice(spacing::Real[,f_cond];kwargs...)`
# Summary
Generate a hexagonal lattice of points (with equal distance between neighboring points).
The hexagonal lattice generated by this function has distance between points on the same
column √3 times greater than the distance between points on the same row.
# Arguments
- `spacing` → spacing between points

See [`generate_regular_lattice`](@ref) for a description of `f_cond` and of  the keyword arguments
"""
generate_hex_lattice(spacing::Real,args...;kwargs...) = generate_regular_lattice(spacing .* (1,√3/2,.5)...,args...;kwargs...)

# ╔═╡ 243621c4-245a-4267-9bb4-568e673450fa
#=╠═╡ notebook_exclusive
generate_hex_lattice(1;M=20, x0 = .5) |> x -> scatter(x; mode="markers") |> Plot
  ╠═╡ notebook_exclusive =#

# ╔═╡ 059045e0-9acc-438d-b3f5-602f8d5892f7
#=╠═╡ notebook_exclusive
md"""
# Misc Functions
"""
  ╠═╡ notebook_exclusive =#

# ╔═╡ 2f1f02c5-3ea5-40c1-8fae-704d150036e6
# Get the conversion from linear to db and viceversa
"""
$(TYPEDSIGNATURES)
Convert a number from linear to dB
"""
lin2db(x::Real) = 10log10(x)

# ╔═╡ 5be397fe-a531-423c-8be0-5d31df79dd2f
"""
$(TYPEDSIGNATURES)
Convert a number from dB to linear
"""
db2lin(x::Real) = 10^(x/10)

# ╔═╡ b2e80c33-bbfe-43ca-8795-c9d8d6fa52a9
# Convert between frequency and wavelength
"""
$(TYPEDSIGNATURES)
Get the wavelength (in m) starting from the frequency (in Hz)
"""
f2λ(f::Real) = c₀/f

# ╔═╡ 9165c4d4-69b5-456c-813c-4725feeb5b52
"""
$(TYPEDSIGNATURES)
Get the frequency (in Hz) starting from the wavelength (in m)
"""
λ2f(λ::Real) = c₀/λ

# ╔═╡ a5ca5a8a-8497-41e2-9af0-92db5db9ce73
#=╠═╡ notebook_exclusive
md"""
# Generate Colors
"""
  ╠═╡ notebook_exclusive =#

# ╔═╡ 3f2a31d4-0fa8-40fa-9dc4-bd6a26d2ddc9
# Initialize the vector that contains the matrix to compute the beam coloring. We limit ourselves at 500 colors to start
const F_reuse_matrix = (square = SMatrix{2,2,Float64,4}[], triangular = SMatrix{2,2,Float64,4}[])

# ╔═╡ 6b9beb62-dc7e-4b8b-9b7c-8fee5b1da98f
function _coloring_inner_bruteforce!(T_mat, rot_mat, grid_max)
    max_colours = length(T_mat)
    check_vec = fill((typemax(Int),typemax(Int)),max_colours)
    @inline norm2(x) = sum(abs2.(x))
    @inbounds for x1 = 0:grid_max, y1 = 0:grid_max, x2 = -grid_max:grid_max, y2 = 0:grid_max
        mat = @SMatrix [x1 y1;x2 y2]
        # Compute the determinant
        t_det = Int(det(mat))
        # Skip points which are not likely to give useful results
        if (t_det < 1)  || (t_det > max_colours) || (t_det > grid_max^2) || (maximum(abs.(mat)) > ceil(sqrt(t_det) + 3))
            continue
        end
        # Compute the angle between the basis vectors identified by [x1,y1] and [x2,y2]
        angle = abs(atan(y1,x1) - atan(y2,x2))
        # Skip cases where the angle between vectors is either too acute or too obtuse
        if abs(π/2-angle) > π/4
            continue
        end
        # Create temp variables for computation of the minimum distance
        dmat = mat*rot_mat
        # Compute frobenius norm and minimum squared distance for the candidate lattice generating matrix
        frobe = round(Int,norm2(dmat))
        # display(frobe)
        # Minimum squared distance is either the modulo of one of the vectors or the modulo of sum or difference of them
        dmin = round(Int,minimum((norm2(dmat[1,:]), norm2(dmat[2,:]), norm2(sum(dmat;dims=1)), norm2(diff(dmat;dims=1)))))
        # Check if the current realization is better than the saved one
        if isless((-dmin,frobe),check_vec[t_det])
            # Update the check_vec
            check_vec[t_det] = (-dmin,frobe)
            # Update the vector containing the generating matrices
            T_mat[t_det] = mat'
        end
    end
end

# ╔═╡ 14cb2a0b-2ea8-471b-987f-1647f1516992
## Here we have the functions for the coloring computation
function compute_F_cell(max_colours::Int;grid_max::Int=25)
    #=
    This function is used to compute all the possible 2x2 lattice generating matrices for possible coloring schemes up to 'max_colours' colors
    Computation is done with a brute-force approach, generating all possible 2x1 vectors with maximum elements up to grid_max
    =#

    # Find the current length of the pre-computed vector
    current_length = length(F_reuse_matrix.square)
    if current_length >= max_colours
        # We already computed the function for the required number of colors
        return
    end
    n_missing = max_colours - current_length
    append!(F_reuse_matrix.square,Vector{SMatrix{2,2,Float64,4}}(undef,n_missing))
    append!(F_reuse_matrix.triangular,Vector{SMatrix{2,2,Float64,4}}(undef,n_missing))
    # Compute the matrix for the square lattice
    _coloring_inner_bruteforce!(F_reuse_matrix.square,I,grid_max)
    # Compute the matrix for the triangular lattice
    _coloring_inner_bruteforce!(F_reuse_matrix.triangular,@SMatrix([1 0;cosd(60) sind(60)]),grid_max)
end

# ╔═╡ 1d44cf1c-11a5-4366-94f3-85b695c6ca12
function generate_F_reuse_matrix(lattice_type::Symbol=:triangular,N_Colours::Int=4;max_colours::Int=max(10,N_Colours))
    compute_F_cell(max_colours)
    return getproperty(F_reuse_matrix,lattice_type)[N_Colours]
end

# ╔═╡ 7e68054e-4268-424e-b413-ef18baf832ac
"""
    generate_colors(BeamCenters::AbstractVector,N_Colours::Int=4;lattice_type::Symbol=:triangular)

Provide a the coloring breakdown for a given set of lattice points.
# Arguments
- `BeamCenters` → Vector of Tuple or StaticVectors expressing the U-V coordinates of each point in the lattice for which the coloring is being computed
- `N_Colours` → Number of colors to divide the lattice in. Defaults to `4`

# keyword Arguments
- `lattice_type` → Symbol that can either be `:triangular` or `:square`, idenifying the type of lattice. Defaults to `:triangular`
"""
function generate_colors(BeamCenters::AbstractVector,N_Colours::Int=4;first_color_coord=nothing,first_color_idx=nothing,precision_digits::Int=7,lattice_type::Symbol=:triangular)
    #=
    **************************************************************************
       Generate frequency colouring file
    **************************************************************************

     References:
     [1]   "On the frequency allocation for mobile radio telephone systems", C. de
           Almeida; R. Palazzo, Proceedings of 6th International Symposium on
           Personal, Indoor and Mobile Radio Communications, Year: 1995, Volume: 1, Pages: 96 - 99 vol.1
     [2]   P. Angeletti, "Simple implementation of vectorial modulo operation based
           on fundamental parallelepiped," in Electronics Letters, vol. 48, no. 3, pp. 159-160,
           February 2 2012. doi: 10.1049/el.2011.3667

     Authors: Alberto Mengali, 2020, European Space Agency

    Input Arguments:
    BeamCenters:         A vector containing the U,V coordinates of the beam centers as tuples or staticvectors
    N_Colours:           An integer number specifying the number of colors to generate in the association
    first_color_coord:   A tuple or static vector containing the U,V coordinates of the beam that will have the first color
    first_color_idx:     The beam index of the beam containing the first color, either this variable of first_order_coord can be specified, not together
    precision_digits:    The number of digits to be used in the flooring operation
    =#

    # Check if either the first color coordinates or first color idx are given
    if first_color_coord === nothing
        if first_color_idx === nothing
            # Initialize to coorinates of the first beam
            first_color_idx = 1;
        end
        first_color_coord = BeamCenters[first_color_idx]
    else
        if first_color_idx !== nothing
            @warn "Both first_color_idx and first_color_coord were given, disregarding the idx variable"
        end
    end
    if lattice_type ∉ (:triangular, :square)
        @error "The specified lattice type ($lattice_type) is not recognized, it should be either :triangular or :square"
    end

    n_beams = length(BeamCenters)

    # If only 1 color is requested, simply return the trivial result
    if N_Colours == 1
        Colours = ones(n_beams)
        nbeams_per_color = n_beams
        idxs = fill(fill(true,nbeams))
    end

    # Find the minimum distance in U and V
    minU_dist = minimum(diff(sort(first.(BeamCenters)) |> x -> unique!(y -> round(y;digits=precision_digits),x)))
    minV_dist = minimum(diff(sort(last.(BeamCenters)) |> x -> unique!(y -> round(y;digits=precision_digits),x)))
    if lattice_type === :triangular
        beamU_spacing = 2minU_dist
        beamV_spacing = 2minV_dist
        # Matrix to normalize the grid points in u-v into a integer grid with y(v) axis not pointing north but north-east with 60° inclination
        D = @SMatrix [1 -1/2;0 1]
    elseif lattice_type === :square
        beamU_spacing = minU_dist
        beamV_spacing = minV_dist
        D = @SMatrix [1 0;0 1]
    end
    # Get the coloring generating matrix
    F_reuse_matrix = generate_F_reuse_matrix(lattice_type,N_Colours)
    # Create the set that will contain the unique results
    unique_colors_vecs = SVector{2,Int}[]
    # Initialize the colors vector
    Colors = similar(BeamCenters, Int)
    @inbounds for (n,p₀) ∈ enumerate(BeamCenters)
        # Compute the integer beam centers
        p₀_normalized = p₀ ./ SA_F64[beamU_spacing, minV_dist]
        # Transform the beam centers from u-v coordinates in radians into integer indexes
        beam_index_vector = round.(Int,D*p₀_normalized);
        # Find the values of the beam indexes modulo F_reuse_matrix
        unique_beam_index = round.(Int,beam_index_vector .- (F_reuse_matrix*floor.(round.(inv(F_reuse_matrix)*beam_index_vector,digits=precision_digits))))
        # Check if this color has already been assigned/registered
        idx = findfirst(x -> x == unique_beam_index,unique_colors_vecs)
        if idx isa Nothing
            push!(unique_colors_vecs, unique_beam_index)
            cidx = length(unique_colors_vecs)
        else
            cidx = idx
        end
        Colors[n] = cidx
    end

    return Colors
end

# ╔═╡ d8584d03-8eb4-4864-b646-a6a0656a2e12
begin
	export generate_regular_lattice, generate_square_lattice, generate_hex_lattice, generate_rect_lattice
	export generate_colors
	export f2λ, λ2f, db2lin, lin2db
end

# ╔═╡ 8160086a-6349-447c-87ae-880b02fa97f5
#=╠═╡ notebook_exclusive
md"""
# Tests
"""
  ╠═╡ notebook_exclusive =#

# ╔═╡ 3ea0415c-af14-430c-bf7c-2c7d71b7a333
#=╠═╡ notebook_exclusive
let
	N_colors = 6
	lat = generate_hex_lattice(1; M = 10)
	colors = generate_colors(lat,N_colors)
	data = scatter(lat;mode="markers", marker_color = colors)
	Plot(data)
end
  ╠═╡ notebook_exclusive =#

# ╔═╡ 65b74f4a-e2af-4caf-8719-5a59c6349bb9
#=╠═╡ notebook_exclusive
let
	N_colors = 4
	lat = generate_square_lattice(1; M = 10)
	colors = generate_colors(lat,N_colors; lattice_type = :square)
	data = scatter(lat;mode="markers", marker_color = colors)
	Plot(data)
end
  ╠═╡ notebook_exclusive =#

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5"
PlutoUtils = "ed5d0301-4775-4676-b788-cf71e66ff8ed"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

[compat]
BenchmarkTools = "~1.2.0"
DocStringExtensions = "~0.8.6"
PlotlyBase = "~0.8.18"
PlutoUtils = "~0.4.13"
StaticArrays = "~1.2.13"
"""

# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised

julia_version = "1.7.0-rc2"
manifest_format = "2.0"

[[deps.AbstractPlutoDingetjes]]
deps = ["Pkg"]
git-tree-sha1 = "0bc60e3006ad95b4bb7497698dd7c6d649b9bc06"
uuid = "6e696c72-6542-2067-7265-42206c756150"
version = "1.1.1"

[[deps.ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"

[[deps.Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"

[[deps.Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[deps.BenchmarkTools]]
deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"]
git-tree-sha1 = "61adeb0823084487000600ef8b1c00cc2474cd47"
uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
version = "1.2.0"

[[deps.Chain]]
git-tree-sha1 = "cac464e71767e8a04ceee82a889ca56502795705"
uuid = "8be319e6-bccf-4806-a6f7-6fae938471bc"
version = "0.4.8"

[[deps.ColorSchemes]]
deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"]
git-tree-sha1 = "a851fec56cb73cfdf43762999ec72eff5b86882a"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.15.0"

[[deps.ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.0"

[[deps.Colors]]
deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.12.8"

[[deps.CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"

[[deps.Crayons]]
git-tree-sha1 = "3f71217b538d7aaee0b69ab47d9b7724ca8afa0d"
uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
version = "4.0.4"

[[deps.DataAPI]]
git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.9.0"

[[deps.DataValueInterfaces]]
git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
version = "1.0.0"

[[deps.Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[deps.DelimitedFiles]]
deps = ["Mmap"]
uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"

[[deps.DocStringExtensions]]
deps = ["LibGit2"]
git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b"
uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
version = "0.8.6"

[[deps.Downloads]]
deps = ["ArgTools", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"

[[deps.FileWatching]]
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"

[[deps.FixedPointNumbers]]
deps = ["Statistics"]
git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
version = "0.8.4"

[[deps.Formatting]]
deps = ["Printf"]
git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8"
uuid = "59287772-0a20-5a39-b81b-1366585eb4c0"
version = "0.4.2"

[[deps.Glob]]
git-tree-sha1 = "4df9f7e06108728ebf00a0a11edee4b29a482bb2"
uuid = "c27321d9-0574-5035-807b-f59d2c89b15c"
version = "1.3.0"

[[deps.Hyperscript]]
deps = ["Test"]
git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9"
uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
version = "0.0.4"

[[deps.HypertextLiteral]]
git-tree-sha1 = "2b078b5a615c6c0396c77810d92ee8c6f470d238"
uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
version = "0.9.3"

[[deps.IOCapture]]
deps = ["Logging", "Random"]
git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a"
uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
version = "0.2.2"

[[deps.InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[deps.IteratorInterfaceExtensions]]
git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856"
uuid = "82899510-4779-5014-852e-03e436cf321d"
version = "1.0.0"

[[deps.JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.2"

[[deps.LaTeXStrings]]
git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.3.0"

[[deps.LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"

[[deps.LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"

[[deps.LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"

[[deps.LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"

[[deps.Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[deps.LinearAlgebra]]
deps = ["Libdl", "libblastrampoline_jll"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

[[deps.Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"

[[deps.MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.9"

[[deps.Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[[deps.MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"

[[deps.Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[deps.MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"

[[deps.NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"

[[deps.OpenBLAS_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"

[[deps.OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"

[[deps.Parameters]]
deps = ["OrderedCollections", "UnPack"]
git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe"
uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
version = "0.12.3"

[[deps.Parsers]]
deps = ["Dates"]
git-tree-sha1 = "ae4bbcadb2906ccc085cf52ac286dc1377dceccc"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.1.2"

[[deps.Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

[[deps.PlotlyBase]]
deps = ["ColorSchemes", "Dates", "DelimitedFiles", "DocStringExtensions", "JSON", "LaTeXStrings", "Logging", "Parameters", "Pkg", "REPL", "Requires", "Statistics", "UUIDs"]
git-tree-sha1 = "180d744848ba316a3d0fdf4dbd34b77c7242963a"
uuid = "a03496cd-edff-5a9b-9e67-9cda94a718b5"
version = "0.8.18"

[[deps.PlutoDevMacros]]
deps = ["MacroTools", "PlutoHooks"]
git-tree-sha1 = "7392720177703062cb2e2a0115efb77dc5dc818c"
uuid = "a0499f29-c39b-4c5c-807c-88074221b949"
version = "0.3.7"

[[deps.PlutoHooks]]
deps = ["FileWatching", "InteractiveUtils", "Markdown", "UUIDs"]
git-tree-sha1 = "f297787f7d7507dada25f6769fe3f08f6b9b8b12"
uuid = "0ff47ea0-7a50-410d-8455-4348d5de0774"
version = "0.0.3"

[[deps.PlutoTest]]
deps = ["HypertextLiteral", "InteractiveUtils", "Markdown", "Test"]
git-tree-sha1 = "92b8ae1eee37c1b8f70d3a8fb6c3f2d81809a1c5"
uuid = "cb4044da-4d16-4ffa-a6a3-8cad7f73ebdc"
version = "0.2.0"

[[deps.PlutoUI]]
deps = ["AbstractPlutoDingetjes", "Base64", "Dates", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "UUIDs"]
git-tree-sha1 = "e071adf21e165ea0d904b595544a8e514c8bb42c"
uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
version = "0.7.19"

[[deps.PlutoUtils]]
deps = ["Chain", "Glob", "HypertextLiteral", "InteractiveUtils", "Markdown", "PlutoDevMacros", "PlutoHooks", "PlutoTest", "PlutoUI", "PrettyTables", "Reexport", "Requires", "UUIDs"]
git-tree-sha1 = "3d3856ecfea340b4ee0c77e5c3228dd1b4478ae1"
uuid = "ed5d0301-4775-4676-b788-cf71e66ff8ed"
version = "0.4.13"

[[deps.PrettyTables]]
deps = ["Crayons", "Formatting", "Markdown", "Reexport", "Tables"]
git-tree-sha1 = "d940010be611ee9d67064fe559edbb305f8cc0eb"
uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
version = "1.2.3"

[[deps.Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[[deps.Profile]]
deps = ["Printf"]
uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"

[[deps.REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[[deps.Random]]
deps = ["SHA", "Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[deps.Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"

[[deps.Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.1.3"

[[deps.SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"

[[deps.Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

[[deps.Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"

[[deps.SparseArrays]]
deps = ["LinearAlgebra", "Random"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[[deps.StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "3c76dde64d03699e074ac02eb2e8ba8254d428da"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.13"

[[deps.Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[[deps.TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"

[[deps.TableTraits]]
deps = ["IteratorInterfaceExtensions"]
git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39"
uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
version = "1.0.1"

[[deps.Tables]]
deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"]
git-tree-sha1 = "fed34d0e71b91734bf0a7e10eb1bb05296ddbcd0"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.6.0"

[[deps.Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"

[[deps.Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[[deps.UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[[deps.UnPack]]
git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b"
uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
version = "1.0.2"

[[deps.Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[[deps.Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"

[[deps.libblastrampoline_jll]]
deps = ["Artifacts", "Libdl", "OpenBLAS_jll"]
uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"

[[deps.nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"

[[deps.p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
"""

# ╔═╡ Cell order:
# ╟─379613ec-0973-4000-ae8c-d7c33ddca18e
# ╠═74975885-9a4e-4857-8135-9e4f69061caf
# ╠═c0a30957-4c7b-4d7b-bfa9-c2fb691a077b
# ╠═736b0cf6-bec2-4226-8ef4-70f6a865d34a
# ╟─f8243a65-9f5e-464e-bb06-0bb4f5131b8b
# ╠═d8584d03-8eb4-4864-b646-a6a0656a2e12
# ╟─8660a7c4-eb78-4e7c-966b-d759df7f3dfa
# ╟─71163795-9695-4f11-acc2-6e3838c8a158
# ╠═f8a53711-e07f-4b6b-84ea-803679496571
# ╠═ce22b91e-6bba-4312-a89b-1a78f84034d3
# ╠═da97848f-a7ff-4f2d-b98d-e8bf1ccc3038
# ╠═0eb5d19d-b535-4cda-a89b-26ba295e2711
# ╠═2ba73b51-ecb9-4632-9f39-bdaeb8c5bd34
# ╟─f0834b38-8efe-4e77-b0f9-47e5b7595191
# ╠═9e5db472-f96a-4acb-96ae-024b5c73a93d
# ╟─c41f9f41-d8bd-4001-98cb-2ab788404b1b
# ╠═8787134f-9d14-4329-8dda-72557e3175b8
# ╟─f589306c-919d-468a-a0fd-9367acc36a7b
# ╠═6ca05079-4c0d-4c45-8486-a4291310189d
# ╠═243621c4-245a-4267-9bb4-568e673450fa
# ╟─059045e0-9acc-438d-b3f5-602f8d5892f7
# ╠═2f1f02c5-3ea5-40c1-8fae-704d150036e6
# ╠═5be397fe-a531-423c-8be0-5d31df79dd2f
# ╠═b2e80c33-bbfe-43ca-8795-c9d8d6fa52a9
# ╠═9165c4d4-69b5-456c-813c-4725feeb5b52
# ╟─a5ca5a8a-8497-41e2-9af0-92db5db9ce73
# ╠═3f2a31d4-0fa8-40fa-9dc4-bd6a26d2ddc9
# ╠═14cb2a0b-2ea8-471b-987f-1647f1516992
# ╠═6b9beb62-dc7e-4b8b-9b7c-8fee5b1da98f
# ╠═1d44cf1c-11a5-4366-94f3-85b695c6ca12
# ╠═7e68054e-4268-424e-b413-ef18baf832ac
# ╟─8160086a-6349-447c-87ae-880b02fa97f5
# ╠═3ea0415c-af14-430c-bf7c-2c7d71b7a333
# ╠═65b74f4a-e2af-4caf-8719-5a59c6349bb9
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


text:
import DielectricUpdateTechique as DUTCH
using Test

nCells = [30,33,61];
res = [1f-3,1f-3,1f-3];

r = DUTCH._create_grid_Greens_function(nCells,res);

@test size(r) == (64,128,128)
@test r[33,65,65] == 0
@test r[34,66,66] == sqrt(res[1]^2 + res[2]^2 + res[3]^2)
@test r[33,66,66] == sqrt(res[2]^2 + res[3]^2)
@test r[1,66,66] == sqrt((32*res[1])^2 + res[2]^2 + res[3]^2)

G = DUTCH._create_Greens_function(r,6.4,res[1]/2f0);

@test size(G) == size(r)
@test maximum(abs.(G)) == abs(G[1,1,1])

Gdv = DUTCH.create_Greens_function(nCells,res,6.4);

@test Gdv[1,1,1] == G[1,1,1]*prod(res)


text:
import Splittings: UniformMesh, RectMesh2D, meshgrid, poisson!

@testset "Poisson 2D on rectangular grid" begin

    mesh = RectMesh2D( UniformMesh(0, 2π, 64), UniformMesh( 0, 2π, 128))
    x = range(mesh.x1min, stop=mesh.x1max, length=mesh.n1+1)[1:end-1]
    y = range(mesh.ymin, stop=mesh.ymax, length=mesh.n2+1)[1:end-1]

    X, Y = meshgrid(x,y)

    ex   = zeros(Complex{Float64}, (mesh.n1, mesh.n2))
    ey   = zeros(Complex{Float64}, (mesh.n1, mesh.n2))
    ρ    = zeros(Complex{Float64}, (mesh.n1, mesh.n2))

    ρ   .= - 2 * sin.(X) .* cos.(Y);
    poisson!( ρ, mesh, ex, ey)
    @test maximum(abs.( ex .- (cos.(X) .* cos.(Y)))) ≈ 0.0 atol = 1e-15
    @test maximum(abs.( ey .+ (sin.(X) .* sin.(Y)))) ≈ 0.0 atol = 1e-15

end