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

"""
    change_server_life_cycle_state(life_cycle, source_server_id)
    change_server_life_cycle_state(life_cycle, source_server_id, params::Dict{String,<:Any})

Allows the user to set the SourceServer.LifeCycle.state property for specific Source Server
IDs to one of the following: READY_FOR_TEST or READY_FOR_CUTOVER. This command only works
if the Source Server is already launchable (dataReplicationInfo.lagDuration is not null.)

# Arguments
- `life_cycle`: The request to change the source server migration lifecycle state.
- `source_server_id`: The request to change the source server migration lifecycle state by
  source server ID.

"""
function change_server_life_cycle_state(
    lifeCycle, sourceServerID; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/ChangeServerLifeCycleState",
        Dict{String,Any}("lifeCycle" => lifeCycle, "sourceServerID" => sourceServerID);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function change_server_life_cycle_state(
    lifeCycle,
    sourceServerID,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/ChangeServerLifeCycleState",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "lifeCycle" => lifeCycle, "sourceServerID" => sourceServerID
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_replication_configuration_template(associate_default_security_group, bandwidth_throttling, create_public_ip, data_plane_routing, default_large_staging_disk_type, ebs_encryption, replication_server_instance_type, replication_servers_security_groups_ids, staging_area_subnet_id, staging_area_tags, use_dedicated_replication_server)
    create_replication_configuration_template(associate_default_security_group, bandwidth_throttling, create_public_ip, data_plane_routing, default_large_staging_disk_type, ebs_encryption, replication_server_instance_type, replication_servers_security_groups_ids, staging_area_subnet_id, staging_area_tags, use_dedicated_replication_server, params::Dict{String,<:Any})

Creates a new ReplicationConfigurationTemplate.

# Arguments
- `associate_default_security_group`: Request to associate the default Application
  Migration Service Security group with the Replication Settings template.
- `bandwidth_throttling`: Request to configure bandwidth throttling during Replication
  Settings template creation.
- `create_public_ip`: Request to create Public IP during Replication Settings template
  creation.
- `data_plane_routing`: Request to configure data plane routing during Replication Settings
  template creation.
- `default_large_staging_disk_type`: Request to configure the Staging Disk EBS volume type
  to \"gp2\" during Replication Settings template creation.
- `ebs_encryption`: Request to configure EBS enryption during Replication Settings template
  creation.
- `replication_server_instance_type`: Request to configure the Replication Server instance
  type during Replication Settings template creation.
- `replication_servers_security_groups_ids`: Request to configure the Replication Server
  Secuirity group ID during Replication Settings template creation.
- `staging_area_subnet_id`: Request to configure the Staging Area subnet ID during
  Replication Settings template creation.
- `staging_area_tags`: Request to configure Staiging Area tags during Replication Settings
  template creation.
- `use_dedicated_replication_server`: Request to use Dedicated Replication Servers during
  Replication Settings template creation.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ebsEncryptionKeyArn"`: Request to configure an EBS enryption key during Replication
  Settings template creation.
- `"tags"`: Request to configure tags during Replication Settings template creation.
"""
function create_replication_configuration_template(
    associateDefaultSecurityGroup,
    bandwidthThrottling,
    createPublicIP,
    dataPlaneRouting,
    defaultLargeStagingDiskType,
    ebsEncryption,
    replicationServerInstanceType,
    replicationServersSecurityGroupsIDs,
    stagingAreaSubnetId,
    stagingAreaTags,
    useDedicatedReplicationServer;
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/CreateReplicationConfigurationTemplate",
        Dict{String,Any}(
            "associateDefaultSecurityGroup" => associateDefaultSecurityGroup,
            "bandwidthThrottling" => bandwidthThrottling,
            "createPublicIP" => createPublicIP,
            "dataPlaneRouting" => dataPlaneRouting,
            "defaultLargeStagingDiskType" => defaultLargeStagingDiskType,
            "ebsEncryption" => ebsEncryption,
            "replicationServerInstanceType" => replicationServerInstanceType,
            "replicationServersSecurityGroupsIDs" => replicationServersSecurityGroupsIDs,
            "stagingAreaSubnetId" => stagingAreaSubnetId,
            "stagingAreaTags" => stagingAreaTags,
            "useDedicatedReplicationServer" => useDedicatedReplicationServer,
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_replication_configuration_template(
    associateDefaultSecurityGroup,
    bandwidthThrottling,
    createPublicIP,
    dataPlaneRouting,
    defaultLargeStagingDiskType,
    ebsEncryption,
    replicationServerInstanceType,
    replicationServersSecurityGroupsIDs,
    stagingAreaSubnetId,
    stagingAreaTags,
    useDedicatedReplicationServer,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/CreateReplicationConfigurationTemplate",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "associateDefaultSecurityGroup" => associateDefaultSecurityGroup,
                    "bandwidthThrottling" => bandwidthThrottling,
                    "createPublicIP" => createPublicIP,
                    "dataPlaneRouting" => dataPlaneRouting,
                    "defaultLargeStagingDiskType" => defaultLargeStagingDiskType,
                    "ebsEncryption" => ebsEncryption,
                    "replicationServerInstanceType" => replicationServerInstanceType,
                    "replicationServersSecurityGroupsIDs" =>
                        replicationServersSecurityGroupsIDs,
                    "stagingAreaSubnetId" => stagingAreaSubnetId,
                    "stagingAreaTags" => stagingAreaTags,
                    "useDedicatedReplicationServer" => useDedicatedReplicationServer,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deletes a single Job by ID.

# Arguments
- `job_id`: Request to delete Job from service by Job ID.

"""
function delete_job(jobID; aws_config::AbstractAWSConfig=global_aws_config())
    return mgn(
        "POST",
        "/DeleteJob",
        Dict{String,Any}("jobID" => jobID);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_job(
    jobID, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/DeleteJob",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("jobID" => jobID), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deletes a single Replication Configuration Template by ID

# Arguments
- `replication_configuration_template_id`: Request to delete Replication Configuration
  Template from service by Replication Configuration Template ID.

"""
function delete_replication_configuration_template(
    replicationConfigurationTemplateID; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/DeleteReplicationConfigurationTemplate",
        Dict{String,Any}(
            "replicationConfigurationTemplateID" => replicationConfigurationTemplateID
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_replication_configuration_template(
    replicationConfigurationTemplateID,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/DeleteReplicationConfigurationTemplate",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "replicationConfigurationTemplateID" =>
                        replicationConfigurationTemplateID,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deletes a single source server by ID.

# Arguments
- `source_server_id`: Request to delete Source Server from service by Server ID.

"""
function delete_source_server(
    sourceServerID; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/DeleteSourceServer",
        Dict{String,Any}("sourceServerID" => sourceServerID);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_source_server(
    sourceServerID,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/DeleteSourceServer",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("sourceServerID" => sourceServerID), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves detailed Job log with paging.

# Arguments
- `job_id`: Request to describe Job log job ID.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: Request to describe Job log item maximum results.
- `"nextToken"`: Request to describe Job log next token.
"""
function describe_job_log_items(jobID; aws_config::AbstractAWSConfig=global_aws_config())
    return mgn(
        "POST",
        "/DescribeJobLogItems",
        Dict{String,Any}("jobID" => jobID);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function describe_job_log_items(
    jobID, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/DescribeJobLogItems",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("jobID" => jobID), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Returns a list of Jobs. Use the JobsID and fromDate and toData filters to limit which jobs
are returned. The response is sorted by creationDataTime - latest date first. Jobs are
normaly created by the StartTest, StartCutover, and TerminateTargetInstances APIs. Jobs are
also created by DiagnosticLaunch and TerminateDiagnosticInstances, which are APIs available
only to *Support* and only used in response to relevant support tickets.

# Arguments
- `filters`: Request to describe Job log filters.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: Request to describe Job log by max results.
- `"nextToken"`: Request to describe Job logby next token.
"""
function describe_jobs(filters; aws_config::AbstractAWSConfig=global_aws_config())
    return mgn(
        "POST",
        "/DescribeJobs",
        Dict{String,Any}("filters" => filters);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function describe_jobs(
    filters, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/DescribeJobs",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("filters" => filters), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Lists all ReplicationConfigurationTemplates, filtered by Source Server IDs.

# Arguments
- `replication_configuration_template_ids`: Request to describe Replication Configuration
  template by template IDs.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: Request to describe Replication Configuration template by max results.
- `"nextToken"`: Request to describe Replication Configuration template by next token.
"""
function describe_replication_configuration_templates(
    replicationConfigurationTemplateIDs; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/DescribeReplicationConfigurationTemplates",
        Dict{String,Any}(
            "replicationConfigurationTemplateIDs" => replicationConfigurationTemplateIDs
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function describe_replication_configuration_templates(
    replicationConfigurationTemplateIDs,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/DescribeReplicationConfigurationTemplates",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "replicationConfigurationTemplateIDs" =>
                        replicationConfigurationTemplateIDs,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves all SourceServers or multiple SourceServers by ID.

# Arguments
- `filters`: Request to filter Source Servers list.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: Request to filter Source Servers list by maximum results.
- `"nextToken"`: Request to filter Source Servers list by next token.
"""
function describe_source_servers(filters; aws_config::AbstractAWSConfig=global_aws_config())
    return mgn(
        "POST",
        "/DescribeSourceServers",
        Dict{String,Any}("filters" => filters);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function describe_source_servers(
    filters, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/DescribeSourceServers",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("filters" => filters), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Disconnects specific Source Servers from Application Migration Service. Data replication is
stopped immediately. All AWS resources created by Application Migration Service for
enabling the replication of these source servers will be terminated / deleted within 90
minutes. Launched Test or Cutover instances will NOT be terminated. If the agent on the
source server has not been prevented from communciating with the Application Migration
Service service, then it will receive a command to uninstall itself (within approximately
10 minutes). The following properties of the SourceServer will be changed immediately:
dataReplicationInfo.dataReplicationState will be set to DISCONNECTED; The totalStorageBytes
property for each of dataReplicationInfo.replicatedDisks will be set to zero;
dataReplicationInfo.lagDuration and dataReplicationInfo.lagDurationwill be nullified.

# Arguments
- `source_server_id`: Request to disconnect Source Server from service by Server ID.

"""
function disconnect_from_service(
    sourceServerID; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/DisconnectFromService",
        Dict{String,Any}("sourceServerID" => sourceServerID);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function disconnect_from_service(
    sourceServerID,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/DisconnectFromService",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("sourceServerID" => sourceServerID), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Finalizes the cutover immediately for specific Source Servers. All AWS resources created by
Application Migration Service for enabling the replication of these source servers will be
terminated / deleted within 90 minutes. Launched Test or Cutover instances will NOT be
terminated. The AWS Replication Agent will receive a command to uninstall itself (within 10
minutes). The following properties of the SourceServer will be changed immediately:
dataReplicationInfo.dataReplicationState will be to DISCONNECTED; The
SourceServer.lifeCycle.state will be changed to CUTOVER; The totalStorageBytes property fo
each of dataReplicationInfo.replicatedDisks will be set to zero;
dataReplicationInfo.lagDuration and dataReplicationInfo.lagDurationwill be nullified.

# Arguments
- `source_server_id`: Request to finalize Cutover by Soure Server ID.

"""
function finalize_cutover(sourceServerID; aws_config::AbstractAWSConfig=global_aws_config())
    return mgn(
        "POST",
        "/FinalizeCutover",
        Dict{String,Any}("sourceServerID" => sourceServerID);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function finalize_cutover(
    sourceServerID,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/FinalizeCutover",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("sourceServerID" => sourceServerID), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Lists all LaunchConfigurations available, filtered by Source Server IDs.

# Arguments
- `source_server_id`: Request to get Launch Configuration information by Source Server ID.

"""
function get_launch_configuration(
    sourceServerID; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/GetLaunchConfiguration",
        Dict{String,Any}("sourceServerID" => sourceServerID);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_launch_configuration(
    sourceServerID,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/GetLaunchConfiguration",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("sourceServerID" => sourceServerID), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Lists all ReplicationConfigurations, filtered by Source Server ID.

# Arguments
- `source_server_id`: Request to get Replication Configuaration by Source Server ID.

"""
function get_replication_configuration(
    sourceServerID; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/GetReplicationConfiguration",
        Dict{String,Any}("sourceServerID" => sourceServerID);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_replication_configuration(
    sourceServerID,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/GetReplicationConfiguration",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("sourceServerID" => sourceServerID), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Initialize Application Migration Service.

"""
function initialize_service(; aws_config::AbstractAWSConfig=global_aws_config())
    return mgn(
        "POST", "/InitializeService"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function initialize_service(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/InitializeService",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

List all tags for your Application Migration Service resources.

# Arguments
- `resource_arn`: List tags for resource request by ARN.

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

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

Archives specific Source Servers by setting the SourceServer.isArchived property to true
for specified SourceServers by ID. This command only works for SourceServers with a
lifecycle.state which equals DISCONNECTED or CUTOVER.

# Arguments
- `source_server_id`: Mark as archived by Source Server ID.

"""
function mark_as_archived(sourceServerID; aws_config::AbstractAWSConfig=global_aws_config())
    return mgn(
        "POST",
        "/MarkAsArchived",
        Dict{String,Any}("sourceServerID" => sourceServerID);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function mark_as_archived(
    sourceServerID,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/MarkAsArchived",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("sourceServerID" => sourceServerID), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Causes the data replication initiation sequence to begin immediately upon next Handshake
for specified SourceServer IDs, regardless of when the previous initiation started. This
command will not work if the SourceServer is not stalled or is in a DISCONNECTED or STOPPED
state.

# Arguments
- `source_server_id`: Retry data replication for Source Server ID.

"""
function retry_data_replication(
    sourceServerID; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/RetryDataReplication",
        Dict{String,Any}("sourceServerID" => sourceServerID);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function retry_data_replication(
    sourceServerID,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/RetryDataReplication",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("sourceServerID" => sourceServerID), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Launches a Cutover Instance for specific Source Servers. This command starts a LAUNCH job
whose initiatedBy property is StartCutover and changes the SourceServer.lifeCycle.state
property to CUTTING_OVER.

# Arguments
- `source_server_ids`: Start Cutover by Source Server IDs.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"tags"`: Start Cutover by Tags.
"""
function start_cutover(sourceServerIDs; aws_config::AbstractAWSConfig=global_aws_config())
    return mgn(
        "POST",
        "/StartCutover",
        Dict{String,Any}("sourceServerIDs" => sourceServerIDs);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function start_cutover(
    sourceServerIDs,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/StartCutover",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("sourceServerIDs" => sourceServerIDs), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Lauches a Test Instance for specific Source Servers. This command starts a LAUNCH job whose
initiatedBy property is StartTest and changes the SourceServer.lifeCycle.state property to
TESTING.

# Arguments
- `source_server_ids`: Start Test for Source Server IDs.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"tags"`: Start Test by Tags.
"""
function start_test(sourceServerIDs; aws_config::AbstractAWSConfig=global_aws_config())
    return mgn(
        "POST",
        "/StartTest",
        Dict{String,Any}("sourceServerIDs" => sourceServerIDs);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function start_test(
    sourceServerIDs,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/StartTest",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("sourceServerIDs" => sourceServerIDs), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Adds or overwrites only the specified tags for the specified Application Migration Service
resource or resources. When you specify an existing tag key, the value is overwritten with
the new value. Each resource can have a maximum of 50 tags. Each tag consists of a key and
optional value.

# Arguments
- `resource_arn`: Tag resource by ARN.
- `tags`: Tag resource by Tags.

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

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

Starts a job that terminates specific launched EC2 Test and Cutover instances. This command
will not work for any Source Server with a lifecycle.state of TESTING, CUTTING_OVER, or
CUTOVER.

# Arguments
- `source_server_ids`: Terminate Target instance by Source Server IDs.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"tags"`: Terminate Target instance by Tags.
"""
function terminate_target_instances(
    sourceServerIDs; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/TerminateTargetInstances",
        Dict{String,Any}("sourceServerIDs" => sourceServerIDs);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function terminate_target_instances(
    sourceServerIDs,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/TerminateTargetInstances",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("sourceServerIDs" => sourceServerIDs), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deletes the specified set of tags from the specified set of Application Migration Service
resources.

# Arguments
- `resource_arn`: Untag resource by ARN.
- `tag_keys`: Untag resource by Keys.

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

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

Updates multiple LaunchConfigurations by Source Server ID.

# Arguments
- `source_server_id`: Update Launch configuration by Source Server ID request.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"copyPrivateIp"`: Update Launch configuration copy Private IP request.
- `"copyTags"`: Update Launch configuration copy Tags request.
- `"launchDisposition"`: Update Launch configuration launch disposition request.
- `"licensing"`: Update Launch configuration licensing request.
- `"name"`: Update Launch configuration name request.
- `"targetInstanceTypeRightSizingMethod"`: Update Launch configuration Target instance
  right sizing request.
"""
function update_launch_configuration(
    sourceServerID; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/UpdateLaunchConfiguration",
        Dict{String,Any}("sourceServerID" => sourceServerID);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_launch_configuration(
    sourceServerID,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/UpdateLaunchConfiguration",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("sourceServerID" => sourceServerID), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Allows you to update multiple ReplicationConfigurations by Source Server ID.

# Arguments
- `source_server_id`: Update replication configuration Source Server ID request.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"associateDefaultSecurityGroup"`: Update replication configuration associate default
  Application Migration Service Security group request.
- `"bandwidthThrottling"`: Update replication configuration bandwidth throttling request.
- `"createPublicIP"`: Update replication configuration create Public IP request.
- `"dataPlaneRouting"`: Update replication configuration data plane routing request.
- `"defaultLargeStagingDiskType"`: Update replication configuration use default large
  Staging Disk type request.
- `"ebsEncryption"`: Update replication configuration EBS encryption request.
- `"ebsEncryptionKeyArn"`: Update replication configuration EBS encryption key ARN request.
- `"name"`: Update replication configuration name request.
- `"replicatedDisks"`: Update replication configuration replicated disks request.
- `"replicationServerInstanceType"`: Update replication configuration Replication Server
  instance type request.
- `"replicationServersSecurityGroupsIDs"`: Update replication configuration Replication
  Server Security Groups IDs request.
- `"stagingAreaSubnetId"`: Update replication configuration Staging Area subnet request.
- `"stagingAreaTags"`: Update replication configuration Staging Area Tags request.
- `"useDedicatedReplicationServer"`: Update replication configuration use dedicated
  Replication Server request.
"""
function update_replication_configuration(
    sourceServerID; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/UpdateReplicationConfiguration",
        Dict{String,Any}("sourceServerID" => sourceServerID);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_replication_configuration(
    sourceServerID,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/UpdateReplicationConfiguration",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("sourceServerID" => sourceServerID), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Updates multiple ReplicationConfigurationTemplates by ID.

# Arguments
- `replication_configuration_template_id`: Update replication configuration template
  template ID request.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"arn"`: Update replication configuration template ARN request.
- `"associateDefaultSecurityGroup"`: Update replication configuration template associate
  default Application Migration Service Security group request.
- `"bandwidthThrottling"`: Update replication configuration template bandwidth throttling
  request.
- `"createPublicIP"`: Update replication configuration template create Public IP request.
- `"dataPlaneRouting"`: Update replication configuration template data plane routing
  request.
- `"defaultLargeStagingDiskType"`: Update replication configuration template use default
  large Staging Disk type request.
- `"ebsEncryption"`: Update replication configuration template EBS encryption request.
- `"ebsEncryptionKeyArn"`: Update replication configuration template EBS encryption key ARN
  request.
- `"replicationServerInstanceType"`: Update replication configuration template Replication
  Server instance type request.
- `"replicationServersSecurityGroupsIDs"`: Update replication configuration template
  Replication Server Security groups IDs request.
- `"stagingAreaSubnetId"`: Update replication configuration template Staging Area subnet ID
  request.
- `"stagingAreaTags"`: Update replication configuration template Staging Area Tags request.
- `"useDedicatedReplicationServer"`: Update replication configuration template use
  dedicated Replication Server request.
"""
function update_replication_configuration_template(
    replicationConfigurationTemplateID; aws_config::AbstractAWSConfig=global_aws_config()
)
    return mgn(
        "POST",
        "/UpdateReplicationConfigurationTemplate",
        Dict{String,Any}(
            "replicationConfigurationTemplateID" => replicationConfigurationTemplateID
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_replication_configuration_template(
    replicationConfigurationTemplateID,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return mgn(
        "POST",
        "/UpdateReplicationConfigurationTemplate",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "replicationConfigurationTemplateID" =>
                        replicationConfigurationTemplateID,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end


text:
let sys = DenseSystem(test_params...),
    beta = 12.34,
    P = 256,
    num_samples = 100,
    sampling_sys = DiagonalSystem(test_params_sampling...)

    # Only testing that it runs to completion.
    @test_nowarn SamplingPrimitiveThermodynamic(sys, beta, P, num_samples; progress_output=devnull)
    @test_nowarn SamplingPrimitiveThermodynamic(sys, beta, P, num_samples; sampling_sys=sampling_sys, progress_output=devnull)
end

ext: jl


text:
# Example below has benn taken from https://diffeq.sciml.ai/stable/tutorials/advanced_ode_example/#Declaring-Jacobian-Functions
using DifferentialEquations
function rober(du,u,p,t)
  y₁,y₂,y₃ = u
  k₁,k₂,k₃ = p
  du[1] = -k₁*y₁+k₃*y₂*y₃
  du[2] =  k₁*y₁-k₂*y₂^2-k₃*y₂*y₃
  du[3] =  k₂*y₂^2
  nothing
end
prob = ODEProblem(rober,[1.0,0.0,0.0],(0.0,1e5),(0.04,3e7,1e4))
sol = solve(prob)


text:
# Julia wrapper for header: libssh2_sftp.h
# Automatically generated using Clang.jl

function libssh2_sftp_init(session)
    ccall((:libssh2_sftp_init, libssh2), Ptr{LIBSSH2_SFTP}, (Ptr{LIBSSH2_SESSION},), session)
end

function libssh2_sftp_shutdown(sftp)
    ccall((:libssh2_sftp_shutdown, libssh2), Cint, (Ptr{LIBSSH2_SFTP},), sftp)
end

function libssh2_sftp_last_error(sftp)
    ccall((:libssh2_sftp_last_error, libssh2), Culong, (Ptr{LIBSSH2_SFTP},), sftp)
end

function libssh2_sftp_get_channel(sftp)
    ccall((:libssh2_sftp_get_channel, libssh2), Ptr{LIBSSH2_CHANNEL}, (Ptr{LIBSSH2_SFTP},), sftp)
end

function libssh2_sftp_open_ex(sftp, filename, filename_len, flags, mode, open_type)
    ccall((:libssh2_sftp_open_ex, libssh2), Ptr{LIBSSH2_SFTP_HANDLE}, (Ptr{LIBSSH2_SFTP}, Cstring, UInt32, Culong, Clong, Cint), sftp, filename, filename_len, flags, mode, open_type)
end

function libssh2_sftp_read(handle, buffer, buffer_maxlen)
    ccall((:libssh2_sftp_read, libssh2), ssize_t, (Ptr{LIBSSH2_SFTP_HANDLE}, Cstring, Csize_t), handle, buffer, buffer_maxlen)
end

function libssh2_sftp_readdir_ex(handle, buffer, buffer_maxlen, longentry, longentry_maxlen, attrs)
    ccall((:libssh2_sftp_readdir_ex, libssh2), Cint, (Ptr{LIBSSH2_SFTP_HANDLE}, Cstring, Csize_t, Cstring, Csize_t, Ptr{LIBSSH2_SFTP_ATTRIBUTES}), handle, buffer, buffer_maxlen, longentry, longentry_maxlen, attrs)
end

function libssh2_sftp_write(handle, buffer, count)
    ccall((:libssh2_sftp_write, libssh2), ssize_t, (Ptr{LIBSSH2_SFTP_HANDLE}, Cstring, Csize_t), handle, buffer, count)
end

function libssh2_sftp_fsync(handle)
    ccall((:libssh2_sftp_fsync, libssh2), Cint, (Ptr{LIBSSH2_SFTP_HANDLE},), handle)
end

function libssh2_sftp_close_handle(handle)
    ccall((:libssh2_sftp_close_handle, libssh2), Cint, (Ptr{LIBSSH2_SFTP_HANDLE},), handle)
end

function libssh2_sftp_seek(handle, offset)
    ccall((:libssh2_sftp_seek, libssh2), Cvoid, (Ptr{LIBSSH2_SFTP_HANDLE}, Csize_t), handle, offset)
end

function libssh2_sftp_seek64(handle, offset)
    ccall((:libssh2_sftp_seek64, libssh2), Cvoid, (Ptr{LIBSSH2_SFTP_HANDLE}, libssh2_uint64_t), handle, offset)
end

function libssh2_sftp_tell(handle)
    ccall((:libssh2_sftp_tell, libssh2), Csize_t, (Ptr{LIBSSH2_SFTP_HANDLE},), handle)
end

function libssh2_sftp_tell64(handle)
    ccall((:libssh2_sftp_tell64, libssh2), libssh2_uint64_t, (Ptr{LIBSSH2_SFTP_HANDLE},), handle)
end

function libssh2_sftp_fstat_ex(handle, attrs, setstat)
    ccall((:libssh2_sftp_fstat_ex, libssh2), Cint, (Ptr{LIBSSH2_SFTP_HANDLE}, Ptr{LIBSSH2_SFTP_ATTRIBUTES}, Cint), handle, attrs, setstat)
end

function libssh2_sftp_rename_ex(sftp, source_filename, srouce_filename_len, dest_filename, dest_filename_len, flags)
    ccall((:libssh2_sftp_rename_ex, libssh2), Cint, (Ptr{LIBSSH2_SFTP}, Cstring, UInt32, Cstring, UInt32, Clong), sftp, source_filename, srouce_filename_len, dest_filename, dest_filename_len, flags)
end

function libssh2_sftp_unlink_ex(sftp, filename, filename_len)
    ccall((:libssh2_sftp_unlink_ex, libssh2), Cint, (Ptr{LIBSSH2_SFTP}, Cstring, UInt32), sftp, filename, filename_len)
end

function libssh2_sftp_fstatvfs(handle, st)
    ccall((:libssh2_sftp_fstatvfs, libssh2), Cint, (Ptr{LIBSSH2_SFTP_HANDLE}, Ptr{LIBSSH2_SFTP_STATVFS}), handle, st)
end

function libssh2_sftp_statvfs(sftp, path, path_len, st)
    ccall((:libssh2_sftp_statvfs, libssh2), Cint, (Ptr{LIBSSH2_SFTP}, Cstring, Csize_t, Ptr{LIBSSH2_SFTP_STATVFS}), sftp, path, path_len, st)
end

function libssh2_sftp_mkdir_ex(sftp, path, path_len, mode)
    ccall((:libssh2_sftp_mkdir_ex, libssh2), Cint, (Ptr{LIBSSH2_SFTP}, Cstring, UInt32, Clong), sftp, path, path_len, mode)
end

function libssh2_sftp_rmdir_ex(sftp, path, path_len)
    ccall((:libssh2_sftp_rmdir_ex, libssh2), Cint, (Ptr{LIBSSH2_SFTP}, Cstring, UInt32), sftp, path, path_len)
end

function libssh2_sftp_stat_ex(sftp, path, path_len, stat_type, attrs)
    ccall((:libssh2_sftp_stat_ex, libssh2), Cint, (Ptr{LIBSSH2_SFTP}, Cstring, UInt32, Cint, Ptr{LIBSSH2_SFTP_ATTRIBUTES}), sftp, path, path_len, stat_type, attrs)
end

function libssh2_sftp_symlink_ex(sftp, path, path_len, target, target_len, link_type)
    ccall((:libssh2_sftp_symlink_ex, libssh2), Cint, (Ptr{LIBSSH2_SFTP}, Cstring, UInt32, Cstring, UInt32, Cint), sftp, path, path_len, target, target_len, link_type)
end


text:
module SingleHouseholdCalculations

#
# This module drives all the calculations for single household and a single set of parameters.
#

using ScottishTaxBenefitModel

using .Definitions

using .RunSettings:
    Settings

using .Results:
    IndividualResult,
    BenefitUnitResult,
    HouseholdResult,
    init_household_result,
    aggregate!

using .STBParameters:
    TaxBenefitSystem

using .ModelHousehold:
    BenefitUnit,
    BenefitUnits,
    BUAllocation,
    Household,
    People_Dict,
    PeopleArray,
    Person,
    default_bu_allocation,
    get_benefit_units,
    get_head,
    get_spouse,
    num_people,
    printpids

# using .LegacyMeansTestedBenefits

using .NonMeansTestedBenefits:
    calc_pre_tax_non_means_tested!,
    calc_post_tax_non_means_tested!

using .IncomeTaxCalculations:
    calc_income_tax!

using .NationalInsuranceCalculations:
    calculate_national_insurance!

using .STBIncomes

using .Intermediate:
    MTIntermediate,
    make_intermediate

using .Results:
    BenefitUnitResult,
    HouseholdResult,
    IndividualResult,
    ITResult,
    NIResult

using .LocalLevelCalculations:
    calc_council_tax

using .LegacyMeansTestedBenefits:
    calc_legacy_means_tested_benefits!

using .UniversalCredit:
    calc_universal_credit!

using .BenefitCap:
    apply_benefit_cap!

using .UCTransition: route_to_uc_or_legacy!

using .ScottishBenefits:
    calc_scottish_child_payment!,
    calc_bedroom_tax_mitigation!

using .UBI: calc_UBI!, make_ubi_post_adjustments!

export do_one_calc

"""
One complete calculation for a single household and tb system.
"""
function do_one_calc(
    hh :: Household{T},
    sys :: TaxBenefitSystem{T},
    settings :: Settings = Settings() ) :: HouseholdResult{T} where T
    # hh = deepcopy( mhh ) # for minwage and so on

    bus = get_benefit_units( hh )
    hres :: HouseholdResult{T} = init_household_result(hh)
    intermed = make_intermediate(
        hh,
        sys.hours_limits,
        sys.age_limits,
        sys.child_limits )

    hd :: BigInt = get_head( hh ).pid
    calc_pre_tax_non_means_tested!(
        hres,
        hh,
        sys.nmt_bens,
        sys.hours_limits,
        sys.age_limits )
    calc_UBI!(
        hres,
        hh,
        sys.ubi )
    buno = 1
    for bu in bus

        # income tax, with some nonsense for
        # what remains of joint taxation..
        head = get_head( bu )
        spouse = get_spouse( bu )
        calc_income_tax!(
            hres.bus[buno],
            head,
            spouse,
            sys.it )
        for chno in bu.children
            child = bu.people[chno]
            calc_income_tax!(
                hres.bus[buno].pers[child.pid],
                child,
                sys.it )
        end
        for (pid,pers) in bu.people
            if pers.age >= 16 # must be 16+
                calculate_national_insurance!(
                    hres.bus[buno].pers[pers.pid],
                    pers,
                    sys.ni )
                end
        end
        buno += 1
    end # bus loop
    calc_post_tax_non_means_tested!(
        hres,
        hh,
        sys.nmt_bens,
        sys.age_limits )

    hres.bus[1].pers[hd].income[LOCAL_TAXES] =
        calc_council_tax( hh, intermed.hhint, sys.loctax.ct )

    calc_legacy_means_tested_benefits!(
        hres,
        hh,
        intermed,
        sys.lmt,
        sys.age_limits,
        sys.hours_limits,
        sys.nmt_bens,
        sys.hr )

    calc_universal_credit!(
        hres,
        hh,
        intermed,
        sys.uc,
        sys.age_limits,
        sys.hours_limits,
        sys.child_limits,
        sys.hr,
        sys.minwage
    )

    route_to_uc_or_legacy!(
        hres,
        settings,
        hh,
        intermed )

    for buno in eachindex( bus )
        calc_scottish_child_payment!(
            hres.bus[buno],
            bus[buno],
            intermed.buint[buno],
            sys.scottish_child_payment )

        apply_benefit_cap!(
            hres.bus[buno],
            hh.region,
            bus[buno],
            intermed.buint[buno],
            sys.bencap,
            hres.bus[buno].route )
    end
    # do this after the benefit cap
    # since the DISCRESIONARY_HOUSING_PAYMENT must be <= hb/uc housing costs
    calc_bedroom_tax_mitigation!( hres, hh )
    if ! sys.ubi.abolished
        make_ubi_post_adjustments!( hres, sys.ubi )
    end
    aggregate!( hh, hres )
    return hres
end

end # module

max_stars_repo_name: grahamstark/ScottishTaxBenefitModel

max_issues_repo_name: grahamstark/ScottishTaxBenefitModel

max_forks_repo_name: grahamstark/ScottishTaxBenefitModel


text:
"""
A simple output that stores each step of the simulation in a vector of arrays.

### Arguments:
- `frames`: Single init array or vector of arrays
- `length`: The length of the output.
"""
@Output mutable struct ArrayOutput{} <: Output{T} end

ArrayOutput(init, length::Integer; kwargs...) = begin
    frames = [deepcopy(init)]
    append!(frames, zeroframes(init, length-1))
    ArrayOutput(; frames=frames, kwargs...)
end


text:
#--------------------------------------------------------------------
# Spacetime Discretization methods in Julia
# Soham 01-2018
#--------------------------------------------------------------------

function distribute{T<:Integer}(fbndr::Function, fbndc::Function, frhs::Function, Nx::T, Ny::T, M::T)::Dict{Array{Int,1}, Patch}
    dop = derivOP(Nx, Ny)/M^4
    bop = boundaryOP(Nx, Ny)
    dbase  = Dict{Array{Int, 1}, Patch}()
    for i in 2:2M, k in i-min(i-1,M):min(i-1,M)
        loc  = [k, i-k]
        rhs  = RHS(frhs, Nx, Ny, M, loc)
        bndx = (loc[2]==1) ? (getPatchIC(fbndr, 0, Nx, M, loc[1])) : (getPatchBnd(dbase[loc-[0,1]], 0))
        bndy = (loc[1]==1) ? (getPatchIC(fbndc, 1, Ny, M, loc[2])) : (getPatchBnd(dbase[loc-[1,0]], 1))
        dbase[loc] = calcPatch(bndx, bndy, rhs, dop, bop, loc)
    end
    return dbase
end


text:
#! /usr/bin/julia

# Rosetta Code, Web scraping

using Requests

function getusnotime()
    const url = "http://tycho.usno.navy.mil/timer.pl"
    s = try
        get(url)
        catch err
        @sprintf "get(%s)\n   => %s" url err
    end
    isa(s, Requests.Response) || return (s, false)
    t = match(r"<BR>(.*UTC)", s.data)
    isa(t, RegexMatch) || return (@sprintf("raw html:\n %s", s.data), false)
    return (t.captures[1], true)
end

(t, issuccess) = getusnotime()

if issuccess
    println("The USNO time is ", t)
else
    println("Failed to fetch UNSO time:\n", t)
end

max_stars_repo_name: MichaeLeroy/rosetta-code

max_issues_repo_name: MichaeLeroy/rosetta-code

max_forks_repo_name: MichaeLeroy/rosetta-code


text:
# /* ----------------------------------------------------------------------
#    compute Bi by summing conj(Ui)*Zi
# ------------------------------------------------------------------------- */

function compute_bi(snap::SNAPParams, runtime_arrays::RuntimeArrays)
    #   // for j1 = 0,...,twojmax
    #   //   for j2 = 0,twojmax
    #   //     for j = |j1-j2|,Min(twojmax,j1+j2),2
    #   //        b(j1,j2,j) = 0
    #   //        for mb = 0,...,jmid
    #   //          for ma = 0,...,j
    #   //            b(j1,j2,j) +=
    #   //              2*Conj(u(j,ma,mb))*z(j1,j2,j,ma,mb)

    num_elements = snap.prebuilt_arrays.num_elements
    # n_elements = length(snap.elements)
    for ielem = 1:num_elements
        itriple = 0;
        idouble = 0;
        for elem1 = 0:(num_elements-1)
            for elem2 = 0:(num_elements-1)
                zptr_r = runtime_arrays.zlist_r[(idouble*snap.prebuilt_arrays.idxz_max+1):end];
                zptr_i = runtime_arrays.zlist_i[(idouble*snap.prebuilt_arrays.idxz_max+1):end];

                for elem3 = 0:(num_elements-1)
                    for jjb = 0:(snap.prebuilt_arrays.idxb_max-1)
                        j1 = snap.prebuilt_arrays.idxb[jjb+1].j1;
                        j2 = snap.prebuilt_arrays.idxb[jjb+1].j2;
                        j  = snap.prebuilt_arrays.idxb[jjb+1].j;

                        jjz = snap.prebuilt_arrays.idxz_block[j1+1,j2+1,j+1];
                        jju = snap.prebuilt_arrays.idxu_block[j+1];
                        sumzu = 0.0
                        mb = 0

                        while 2*mb < j
                            for ma = 0:j
                                sumzu += (runtime_arrays.ulisttot_r[elem3*snap.prebuilt_arrays.idxu_max+jju+1] * zptr_r[jjz+1] +
                                        runtime_arrays.ulisttot_i[elem3*snap.prebuilt_arrays.idxu_max+jju+1] * zptr_i[jjz+1])
                                jjz+=1
                                jju+=1
                            end
                            mb +=1;
                        end # loop over ma, mb
                        # // For j even, handle middle column
                        if (j % 2 == 0)
                            mb = j ÷ 2;
                            ma = 0
                            # Strict inequality
                            while ma < mb
                                sumzu += runtime_arrays.ulisttot_r[elem3*snap.prebuilt_arrays.idxu_max+jju+1] * zptr_r[jjz+1] +
                                        runtime_arrays.ulisttot_i[elem3*snap.prebuilt_arrays.idxu_max+jju+1] * zptr_i[jjz+1];
                                jjz+=1;
                                jju+=1;
                                ma+=1
                            end
                            sumzu += 0.5 * (runtime_arrays.ulisttot_r[elem3*snap.prebuilt_arrays.idxu_max+jju+1] * zptr_r[jjz+1] +
                                        runtime_arrays.ulisttot_i[elem3*snap.prebuilt_arrays.idxu_max+jju+1] * zptr_i[jjz+1]);

                        end # if jeven

                        runtime_arrays.blist[itriple*snap.prebuilt_arrays.idxb_max+jjb+1] = 2.0 * sumzu;
                    end
                    itriple+=1;
                end
                idouble+=1;
            end
        end

        # // apply bzero shift

        if (snap.bzero_flag)
            if (~snap.wselfall_flag)
                itriple = (ielem-1)*( num_elements+1)*num_elements+(ielem-1);
                for jjb = 0:(snap.prebuilt_arrays.idxb_max-1)
                    j = snap.prebuilt_arrays.idxb[jjb+1].j;
                    runtime_arrays.blist[itriple*snap.prebuilt_arrays.idxb_max+jjb+1] -= snap.prebuilt_arrays.bzero[j+1];
                end # loop over JJ
            else
                itriple = 0;
                for elem1=0:(num_elements-1)
                    for elem2 = 0:(num_elements-1)
                        for elem3 = 0:(num_elements-1)
                            for jjb = 0:(snap.prebuilt_arrays.idxb_max-1)
                                j = snap.prebuilt_arrays.idxb[jjb+1].j;
                                runtime_arrays.blist[itriple*snap.prebuilt_arrays.idxb_max+jjb+1] -= snap.prebuilt_arrays.bzero[j+1];
                            end # loop over JJ
                            itriple+=1;
                        end # loop over elem3
                    end # loop over elem1,elem2
                end
            end
        end
    end
end

# /* ----------------------------------------------------------------------
#    calculate derivative of Bi w.r.t. atom j
#    variant using indexlist for j1,j2,j
#    variant using symmetry relation
# ------------------------------------------------------------------------- */

function compute_dbidrj(jelem::Int, snap::SNAPParams, runtime_arrays::RuntimeArrays)

    # // for j1 = 0,...,twojmax
    # //   for j2 = 0,twojmax
    # //     for j = |j1-j2|,Min(twojmax,j1+j2),2
    # //        zdb = 0
    # //        for mb = 0,...,jmid
    # //          for ma = 0,...,j
    # //            zdb +=
    # //              Conj(dudr(j,ma,mb))*z(j1,j2,j,ma,mb)
    # //        dbdr(j1,j2,j) += 2*zdb
    # //        zdb = 0
    # //        for mb1 = 0,...,j1mid
    # //          for ma1 = 0,...,j1
    # //            zdb +=
    # //              Conj(dudr(j1,ma1,mb1))*z(j,j2,j1,ma1,mb1)
    # //        dbdr(j1,j2,j) += 2*zdb*(j+1)/(j1+1)
    # //        zdb = 0
    # //        for mb2 = 0,...,j2mid
    # //          for ma2 = 0,...,j2
    # //            zdb +=
    # //              Conj(dudr(j2,ma2,mb2))*z(j1,j,j2,ma2,mb2)
    # //        dbdr(j1,j2,j) += 2*zdb*(j+1)/(j2+1)

    n_rows, n_cols = size(runtime_arrays.dblist)
    for row = 1:n_rows
        for col = 1:n_cols
            runtime_arrays.dblist[row, col] = 0.0
        end
    end

    # elem3 = elem_duarray;
    # n_elements = length(snap.elements)
    num_elements = snap.prebuilt_arrays.num_elements

    if snap.chem_flag
        elem3 = jelem-1;
    else
        elem3 = 0
    end

    for jjb = 0:(snap.prebuilt_arrays.idxb_max-1)
        j1 = snap.prebuilt_arrays.idxb[jjb+1].j1;
        j2 = snap.prebuilt_arrays.idxb[jjb+1].j2;
        j  = snap.prebuilt_arrays.idxb[jjb+1].j;

        # // Sum terms Conj(dudr(j,ma,mb))*z(j1,j2,j,ma,mb)

        for elem1 = 0:(num_elements-1)
            for elem2 = 0:(num_elements-1)

                jjz = snap.prebuilt_arrays.idxz_block[j1+1,j2+1,j+1];
                jju = snap.prebuilt_arrays.idxu_block[j+1];
                idouble = elem1*num_elements+elem2;
                itriple = (elem1*num_elements+elem2)*num_elements+elem3;
                zptr_r = runtime_arrays.zlist_r[idouble*snap.prebuilt_arrays.idxz_max+1:end];
                zptr_i = runtime_arrays.zlist_i[idouble*snap.prebuilt_arrays.idxz_max+1:end];
                sumzdu_r = zeros(3)

                mb = 0
                while 2*mb < j
                    for ma = 0:j
                        dudr_r = runtime_arrays.dulist_r[jju+1, :];
                        dudr_i = runtime_arrays.dulist_i[jju+1, :];
                        for k = 1:3
                            sumzdu_r[k] +=
                                dudr_r[k] * zptr_r[jjz+1] +
                                dudr_i[k] * zptr_i[jjz+1];
                        end
                        jjz+=1;
                        jju+=1;
                    end # loop over ma mb
                    mb+=1;
                end

                # // For j even, handle middle column

                if (j % 2 == 0)
                    mb = j ÷ 2;
                    for ma = 0:(mb-1)
                        dudr_r = runtime_arrays.dulist_r[jju+1, :];
                        dudr_i = runtime_arrays.dulist_i[jju+1, :];
                        for k = 1:3
                            sumzdu_r[k] +=
                                dudr_r[k] * zptr_r[jjz+1] +
                                dudr_i[k] * zptr_i[jjz+1];
                        end
                        jjz+=1;
                        jju+=1;
                    end

                    dudr_r = runtime_arrays.dulist_r[jju+1, :];
                    dudr_i = runtime_arrays.dulist_i[jju+1, :];
                    for k = 1:3
                        sumzdu_r[k] +=
                            (dudr_r[k] * zptr_r[jjz+1] +
                            dudr_i[k] * zptr_i[jjz+1]) * 0.5;
                    end
                    # // jjz++;
                    # // jju++;
                end # if jeven

                for k = 1:3
                    runtime_arrays.dblist[itriple*snap.prebuilt_arrays.idxb_max+jjb+1, k] = 2.0 * sumzdu_r[k]
                end

                # // Sum over Conj(dudr(j1,ma1,mb1))*z(j,j2,j1,ma1,mb1)
                j1fac   = (j + 1) / (j1 + 1.0);
                idouble = elem1*num_elements+elem2;
                itriple = (elem3*num_elements+elem2)*num_elements+elem1;
                jjz     = snap.prebuilt_arrays.idxz_block[j+1,j2+1,j1+1];
                jju     = snap.prebuilt_arrays.idxu_block[j1+1];
                zptr_r  = runtime_arrays.zlist_r[idouble*snap.prebuilt_arrays.idxz_max+1:end];
                zptr_i  = runtime_arrays.zlist_i[idouble*snap.prebuilt_arrays.idxz_max+1:end];

                for k = 1:3
                    sumzdu_r[k] = 0.0;
                end

                mb = 0
                while 2*mb < j1
                    for ma = 0:j1
                        dudr_r = runtime_arrays.dulist_r[jju+1, :];
                        dudr_i = runtime_arrays.dulist_i[jju+1, :];
                        for k = 1:3
                            sumzdu_r[k] +=
                                dudr_r[k] * zptr_r[jjz+1] +
                                dudr_i[k] * zptr_i[jjz+1];
                        end
                        jjz+=1;
                        jju+=1;
                    end
                    mb+=1
                end # loop over ma mb

                # // For j1 even, handle middle column

                if (j1 % 2 == 0)
                    mb = j1 ÷ 2;
                    for ma = 0:(mb-1)
                        dudr_r = runtime_arrays.dulist_r[jju+1, :];
                        dudr_i = runtime_arrays.dulist_i[jju+1, :];
                        for k = 1:3
                            sumzdu_r[k] +=
                                dudr_r[k] * zptr_r[jjz+1] +
                                dudr_i[k] * zptr_i[jjz+1];
                        end
                        jjz+=1;
                        jju+=1;
                    end

                    dudr_r = runtime_arrays.dulist_r[jju+1, :];
                    dudr_i = runtime_arrays.dulist_i[jju+1, :];
                    for k = 1:3
                        sumzdu_r[k] +=
                            (dudr_r[k] * zptr_r[jjz+1] +
                            dudr_i[k] * zptr_i[jjz+1]) * 0.5;
                    end
                    # // jjz++;
                    # // jju++;
                end # if j1even

                for k = 1:3
                    if (snap.bnorm_flag)
                        runtime_arrays.dblist[itriple*snap.prebuilt_arrays.idxb_max+jjb+1, k] += 2.0 * sumzdu_r[k]
                    else
                        runtime_arrays.dblist[itriple*snap.prebuilt_arrays.idxb_max+jjb+1, k] += 2.0 * sumzdu_r[k] * j1fac;
                    end
                end

                # // Sum over Conj(dudr(j2,ma2,mb2))*z(j,j1,j2,ma2,mb2)

                j2fac = (j + 1) / (j2 + 1.0);

                idouble = elem2*num_elements+elem1;
                itriple = (elem1*num_elements+elem3)*num_elements+elem2;
                jjz = snap.prebuilt_arrays.idxz_block[j+1,j1+1,j2+1];
                jju = snap.prebuilt_arrays.idxu_block[j2+1];
                zptr_r = runtime_arrays.zlist_r[idouble*snap.prebuilt_arrays.idxz_max+1:end];
                zptr_i = runtime_arrays.zlist_i[idouble*snap.prebuilt_arrays.idxz_max+1:end];

                for k = 1:3
                    sumzdu_r[k] = 0.0;
                end

                mb = 0
                while 2*mb < j2
                    for ma = 0:j2
                        dudr_r = runtime_arrays.dulist_r[jju+1, :];
                        dudr_i = runtime_arrays.dulist_i[jju+1, :];
                        for k = 1:3
                            sumzdu_r[k] +=
                                dudr_r[k] * zptr_r[jjz+1] +
                                dudr_i[k] * zptr_i[jjz+1];
                        end
                        jjz+=1;
                        jju+=1;
                    end
                    mb +=1;
                end # loop over ma mb

                # // For j2 even, handle middle column

                if (j2 % 2 == 0)
                    mb =  j2 ÷ 2;
                    for ma = 0:(mb-1)
                        dudr_r = runtime_arrays.dulist_r[jju+1, :];
                        dudr_i = runtime_arrays.dulist_i[jju+1, :];
                        for k = 1:3
                            sumzdu_r[k] +=
                                dudr_r[k] * zptr_r[jjz+1] +
                                dudr_i[k] * zptr_i[jjz+1];
                        end
                        jjz+=1;
                        jju+=1;
                    end
                    dudr_r = runtime_arrays.dulist_r[jju+1, :];
                    dudr_i = runtime_arrays.dulist_i[jju+1, :];
                    for k = 1:3
                        sumzdu_r[k] +=
                            (dudr_r[k] * zptr_r[jjz+1] +
                            dudr_i[k] * zptr_i[jjz+1]) * 0.5;
                    end
                    # // jjz++;
                    # // jju++;
                end # if j2even

                for k = 1:3
                    if (snap.bnorm_flag)
                        runtime_arrays.dblist[itriple*snap.prebuilt_arrays.idxb_max+jjb+1, k] += 2.0 * sumzdu_r[k]
                    else
                        runtime_arrays.dblist[itriple*snap.prebuilt_arrays.idxb_max+jjb+1, k] += 2.0 * sumzdu_r[k] * j2fac;
                    end
                end
            end
        end
    end

end


text:
# this file depends on jacobi.jl from JuliaOptics/OpticsPolynomials that
# should be found in the same directory

export zernike
export zernike_series
export zernike_sum
export zernike_norm
export zernike_nm_to_fringe
export zernike_nm_to_ansi_j
export zernike_ansi_j_to_nm
export zernike_noll_to_nm
export zernike_fringe_to_nm
export zernike_zero_separation

export apply_weights

"""
    apply_weights(data, weights)

Given data of arbitrary dimensionality with multiple realizations or modes along
the final dimension, weight the final dimension by weights and return the sum.

Will have one fewer dimension than the input data.
"""
function apply_weights(data, weights)
    shape = size(data)
    prod = reshape(data, (:, shape[end])) * weights
    return reshape(prod, shape[1: end-1])
end

function kronecker(i,j)
    return i==j ? 1 : 0
end

"""
    zernike_norm(n, m)

Norm of Zernike polynomial of radial order n, azimuthal order m.

The norm is the average squared distance to zero.  By multiplying a zernike
value by the norm, the term is given unit stdev or RMS.
"""
function zernike_norm(n::Integer, m::Integer)
    return √(2 * (n+1)) / (1 + kronecker(m, 0))
end

"""
    zernike_nm_to_fringe(n, m)

Map (n,m) ANSI indices to a single fringe index.
"""
function zernike_nm_to_fringe(n::Integer, m::Integer)
    term1 = (1 + (n + abs(m))/2)^2
    term2 = 2 * abs(m)
    term3 = (1 + sign(m)) / 2
    return Int(trunc(term1 - term2 - term3)) + 1
end

"""
    zernike_nm_to_ansi_j(n, m)

Map (n,m) ANSI indices to a single ANSI j index.

See also:
    - [`zernike_ansi_j_to_nm`](@ref) (reciprocal of this function)
"""
function zernike_nm_to_ansi_j(n::Integer, m::Integer)
    return (n * (n + 2) + m) ÷ 2
end

"""
    zernike_ansi_to_ansi_j(n, m)

Map (n,m) ANSI indices to a single ANSI j index.

See also:
    - [`zernike_nm_to_ansi_j`](@ref) (reciprocal of this function)
"""
function zernike_ansi_j_to_nm(j::Integer)
    n = (-3 + √(9 + 8j))÷2
    m = 2j - n * (n + 2)
    return Int(n), Int(m)
end

"""
    zernike_noll_to_nm(j)

Map j Noll index to ANSI (n,m) indices.
"""
function zernike_noll_to_nm(j::Integer)
    n = ceil(Int, (-1 + √(1 + 8j))/2 - 1)
    if n == 0
        m = 0
    else
        nseries = (n+1) * (n+2) ÷ 2
        residual = j - nseries

        if isodd(j)
            sign = -1
        else
            sign = 1
        end

        if isodd(n)
            ms = [1,1]
        else
            ms = [0]
        end

        for i=0:(n÷2)-1
            push!(ms, ms[end]+2)
            push!(ms, ms[end])
        end

        m = ms[end+residual] * sign
    end
    return n, Int(m)
end

"""
    zernike_fringe_to_nm(j)

Map j Fringe index to ANSI (n,m) indices.
"""
function zernike_fringe_to_nm(j::Integer)
    m_n = 2 * (ceil(Int, √j) - 1)
    g_s = (m_n ÷ 2)^2 + 1
    n = m_n ÷ 2 + (j-g_s)÷2
    m = (m_n - n) * (1 - mod(j-g_s, 2) * 2)
    return n, m
end

"""
    zernike_zero_separation(n)

Minimum zero separation of Zernike polynomial of radial order n.  Useful for
computing sample count requirements.
"""
function zernike_zero_separation(n::Integer)
    return 1 / n^2
end

"""
    zernike(n, m, ρ, θ[; norm])

Zernike polynomial of radial order n and azimuthal order m, evaluated at the
point (ρ, θ).  No normalization is required of (ρ, θ), though the polynomials
are orthogonal only over the unit disk.

norm is a boolean flag indicating whether the result should be orthonormalized
(scaled to unit RMS) or not.

The zernike polynomials' radial basis is a special case of the Jacobi
polynomials under the transformation n_jacobi = (n-m)/2, α=0, β=|m|, x=2ρ^2-1.

See also: [`zernike_series`](@ref), [`zernike_sum`](@ref).
"""
function zernike(n::Integer, m::Integer, ρ, θ; norm::Bool=true)
    x = 2 .* ρ.^2 .- 1
    am = abs(m)
    n_j = (n - am) ÷ 2
    out = jacobi(n_j, 0, am, x)
    if m != 0
        if m < 0
            out .*= (ρ.^am .* sin.(m.*θ))
        else
            out .*= (ρ.^am .* cos.(m.*θ))
        end

    end
	if norm
		out .*= zernike_norm(n,m)
	end
    return out
end

"""
    zernike_series(nms, ρ, θ[; norm])

Compute a series of Zernike polynomials of orders (n,m).
Returns an array with shape (size(ρ)..., length(nms)).
That is, the _final_ dimension contains the modes and the first dimension(s)
are spatial.

See also: [`zernike`](@ref), [`zernike_sum`](@ref)
"""
function zernike_series(nms, ρ, θ; norm::Bool=true)
    # 1.  Calculate a lookup table of Jacobi polynomials for the unique elements combinations of $|m|$ and $n_j$.
    # 2.  Calculate a lookup table of $\rho^{|m|}$ for each unique $|m|$
    # 3.  Calculate a lookup table of $\sin{m\theta}$ and $\cos{m\theta}$ for each unique $m$.
    # 4.  For each input $n, m$ look up the appropriate elements and compute the Zernike polynomial.
	x = 2 .* ρ.^2 .- 1
    n_j_list = [((n - abs(m)) ÷ 2, abs(m)) for (n,m) in nms]
    abs_m_type = typeof(n_j_list[1][2])
    dtype = eltype(ρ)
    jacobi_sequences_mnj = Dict{abs_m_type,Array{typeof(n_j_list[1][1]), 1}}()
	for (nj, am) in n_j_list
		a = get!(jacobi_sequences_mnj, am) do
			Array{abs_m_type, 1}()
		end
		push!(a, nj)
	end
	for key in keys(jacobi_sequences_mnj)
		# sort may not be needed.  Inherently sorted
		# but not sure if unique guarantees not shuffling
		# input
		sort!(unique!(jacobi_sequences_mnj[key]))
	end
    # jacobi sequences_mnj now maps |m| => max n_j
    # this is step 1 at the top of the function
    jacobi_sequences = Dict{abs_m_type,Array{dtype,ndims(ρ)+1}}()
    for k in keys(jacobi_sequences_mnj)
        njs = jacobi_sequences_mnj[k]
        jacobi_sequences[k] = jacobi_series(njs, 0., dtype(k), x)
    end

    # jacobi_sequences now maps |m| => arrays with n_j along the last dimension
    # powers_of_rho is now ρ^|m| for each unique |m|
    plane_idx = ndims(ρ)+1
    sines = Dict{abs_m_type, typeof(ρ)}()
    cosines = Dict{abs_m_type, typeof(ρ)}()
    powers_of_rho = Dict{abs_m_type, typeof(ρ)}()
    out = Array{eltype(ρ), ndims(ρ)+1}(undef, size(ρ)..., length(nms))
    for i in eachindex(nms)
        n, m = nms[i]
        absm = abs(m)

        out_view = selectdim(out, plane_idx, i)
		n_j = (n-abs(m))÷2
		jac_plane = first(searchsorted(jacobi_sequences_mnj[absm], n_j))
        jacobi_piece = selectdim(jacobi_sequences[absm], plane_idx, jac_plane)
        if m == 0
            if norm
                norm_val = zernike_norm(n, m)
                out_view .= norm_val .* jacobi_piece
            else
                out_view .= jacobi_piece
            end
        else
            if m < 0
				# these evaluate the sin/cosine only as needed,
				# the do block is only called if get! would error
                azpiece = get!(sines, m) do
					sin.(m .* θ)
				end
            else
                azpiece = get!(cosines, m) do
					cos.(m .* θ)
				end
            end
            radialpiece = get!(powers_of_rho, absm) do
				ρ .^ absm
			end

            if norm
                norm_val = zernike_norm(n, m)
                out_view .= norm_val .* jacobi_piece .* radialpiece .* azpiece
            else
                out_view .= jacobi_piece .* radialpiece .* azpiece
            end
        end
    end
    return out
end

"""
    zernike_sum(nms, weights, ρ, θ[; norm])

Compute a sum of Zernike polynomials of orders (n,m) weighted by weights.

See also: [`zernike`](@ref), [`zernike_series`](@ref)
"""
function zernike_sum(nms, weights, ρ, θ, norm::Bool=true)
    data = zernike_series(nms, ρ, θ, norm=norm)
    return apply_weights(data, weights)
end


text:
function add_get!(func::Function, app::App, path::AbstractString)
    if contains(path, ':')
        paths = URIs.splitpath(path)
        new_paths = map(paths) do str
            startswith(str, ':') ? "*" : str
        end
        new_path = joinpath(new_paths...)

        handler = (request::HTTP.Request, body::BodyTypes) -> begin
            params = createparams(request, path)
            query = createquery(request)
            req = Req(request.method, path, params, query, body)
            return func(req)
        end

        HTTP.@register(app.router, "GET", new_path, handler)
    else
        handler = (request::HTTP.Request, body::BodyTypes) -> begin
            params = Params()
            query = createquery(request)
            req = Req(request.method, request.target, params, query, body)
            return func(req)
        end

        HTTP.@register(app.router, "GET", path, handler)
    end

    push!(app.routelist["GET"], path)
    return nothing
end

function add_post!(func::Function, app::App, path::AbstractString)
    if contains(path, ':')
        paths = URIs.splitpath(path)
        new_paths = map(paths) do str
            startswith(str, ':') ? "*" : str
        end
        new_path = joinpath(new_paths...)

        handler = (request::HTTP.Request, body::BodyTypes) -> begin
            params = createparams(request, path)
            query = createquery(request)
            req = Req(request.method, path, params, query, body)
            return func(req)
        end

        HTTP.@register(app.router, "POST", new_path, handler)
    else
        handler = (request::HTTP.Request, body::BodyTypes) -> begin
            params = Params()
            query = createquery(request)
            req = Req(request.method, request.target, params, query, body)
            return func(req)
        end

        HTTP.@register(app.router, "POST", path, handler)
    end

    push!(app.routelist["POST"], path)
    return nothing
end

function add_put!(func::Function, app::App, path::AbstractString)
    if contains(path, ':')
        paths = URIs.splitpath(path)
        new_paths = map(paths) do str
            startswith(str, ':') ? "*" : str
        end
        new_path = joinpath(new_paths...)

        handler = (request::HTTP.Request, body::BodyTypes) -> begin
            params = createparams(request, path)
            query = createquery(request)
            req = Req(request.method, path, params, query, body)
            return func(req)
        end

        HTTP.@register(app.router, "PUT", new_path, handler)
    else
        handler = (request::HTTP.Request, body::BodyTypes) -> begin
            params = Params()
            query = createquery(request)
            req = Req(request.method, request.target, params, query, body)
            return func(req)
        end

        HTTP.@register(app.router, "PUT", path, handler)
    end

    push!(app.routelist["PUT"], path)
    return nothing
end

function add_patch!(func::Function, app::App, path::AbstractString)
    if contains(path, ':')
        paths = URIs.splitpath(path)
        new_paths = map(paths) do str
            startswith(str, ':') ? "*" : str
        end
        new_path = joinpath(new_paths...)

        handler = (request::HTTP.Request, body::BodyTypes) -> begin
            params = createparams(request, path)
            query = createquery(request)
            req = Req(request.method, path, params, query, body)
            return func(req)
        end

        HTTP.@register(app.router, "PATCH", new_path, handler)
    else
        handler = (request::HTTP.Request, body::BodyTypes) -> begin
            params = Params()
            query = createquery(request)
            req = Req(request.method, request.target, params, query, body)
            return func(req)
        end

        HTTP.@register(app.router, "PATCH", path, handler)
    end

    push!(app.routelist["PATCH"], path)
    return nothing
end

function add_delete!(func::Function, app::App, path::AbstractString)
    if contains(path, ':')
        paths = URIs.splitpath(path)
        new_paths = map(paths) do str
            startswith(str, ':') ? "*" : str
        end
        new_path = joinpath(new_paths...)

        handler = (request::HTTP.Request, body::BodyTypes) -> begin
            params = createparams(request, path)
            query = createquery(request)
            req = Req(request.method, path, params, query, body)
            return func(req)
        end

        HTTP.@register(app.router, "DELETE", new_path, handler)
    else
        handler = (request::HTTP.Request, body::BodyTypes) -> begin
            params = Params()
            query = createquery(request)
            req = Req(request.method, request.target, params, query, body)
            return func(req)
        end

        HTTP.@register(app.router, "DELETE", path, handler)
    end

    push!(app.routelist["DELETE"], path)
    return nothing
end


text:
@testset "Equilibria" begin
tolerances = Dict(Float16 => 1e-3, Float32 => 1e-5, Float64 => 1e-7, Real => 1e-7)
    @testset "One dimension -velocity -gravity" begin
        N = 10
        # Generate test moments and a test distribution
        typelist = [Float16 Float32 Float64 Real]
        for type in typelist
            testmoments = JuSwalbe.Macroquant{Vector{type}, Vector{type}}(ones(type,N),zeros(type,N),zeros(type,N),zeros(type,N))
            equilibria = calc_equilibrium_distribution(testmoments)
            # Push them in a dictonary to easily loop through the keys (fields)
            test_dict = struct2dict(equilibria)
            # Test types and lengths
            @test isa(equilibria, JuSwalbe.DistributionD1Q3)
            @test length(keys(test_dict)) == 3
            # Test the
            for key in keys(test_dict)
                @test isa(test_dict[key], Array{type,1})
                @test length(test_dict[key]) == N
                # Check if the values are actually consistent
                if key == :f0
                    for value in test_dict[key]
                        @test value == 1.0
                    end
                else
                    for value in test_dict[key]
                        @test value == 0.0
                    end
                end
            end
        end
    end
    @testset "One dimension -velocity +gravity" begin
        N = 10
        # Generate test moments and a test distribution
        typelist = [Float16 Float32 Float64 Real]
        for type in typelist
            testmoments = JuSwalbe.Macroquant{Vector{type}, Vector{type}}(ones(type,N),zeros(type,N),zeros(type,N),zeros(type,N))
            equilibria = calc_equilibrium_distribution(testmoments; gravity=type(0.1))
            # Push them in a dictonary to easily loop through the keys (fields)
            test_dict = struct2dict(equilibria)
            # Test types and lengths
            @test isa(equilibria, JuSwalbe.DistributionD1Q3)
            @test length(keys(test_dict)) == 3
            # Test the
            for key in keys(test_dict)
                @test isa(test_dict[key], Array{type,1})
                @test length(test_dict[key]) == N
                # Check if the values are actually consistent
                if key == :f0
                    for value in test_dict[key]
                        @test value == type(0.95)
                    end
                else
                    for value in test_dict[key]
                        @test value == type(1.0/40.0)
                    end
                end
            end
        end
    end
    @testset "One dimension +velocity +gravity" begin
        N = 10
        # Generate test moments and a test distribution
        typelist = [Float16 Float32 Float64 Real]
        for type in typelist
            test_velocity = ones(type, N) * type(0.1)
            testmoments = JuSwalbe.Macroquant{Vector{type}, Vector{type}}(ones(type,N),test_velocity,zeros(type,N),zeros(type,N))
            equilibria = calc_equilibrium_distribution(testmoments; gravity=type(0.1))
            # Push them in a dictonary to easily loop through the keys (fields)
            test_dict = struct2dict(equilibria)
            # Test types and lengths
            @test isa(equilibria, JuSwalbe.DistributionD1Q3)
            @test length(keys(test_dict)) == 3
            # Test the
            for key in keys(test_dict)
                @test isa(test_dict[key], Array{type,1})
                @test length(test_dict[key]) == N
                # Check if the values are actually consistent
                if key == :f0
                    for value in test_dict[key]
                        @test value - type(1 - 1.0/20.0 - 0.01) ≈ type(0.0) atol=tolerances[type]
                    end
                elseif key == :f1
                    for value in test_dict[key]
                        @test value - type(1.0/40.0 + 1.0/20.0 + 1.0/200.0) ≈ type(0.0) atol=tolerances[type]
                    end
                elseif key == :f2
                    for value in test_dict[key]
                        @test value - type(1.0/40.0 - 1.0/20.0 + 1.0/200.0) ≈ type(0.0) atol=tolerances[type]
                    end
                end
            end
        end
    end
    @testset "One dimension +velocity -gravity" begin
        N = 10
        # Generate test moments and a test distribution
        typelist = [Float16 Float32 Float64 Real]
        for type in typelist
            test_velocity = ones(type, N) * type(0.1)
            testmoments = JuSwalbe.Macroquant{Vector{type}, Vector{type}}(ones(type,N),test_velocity,zeros(type,N),zeros(type,N))
            equilibria = calc_equilibrium_distribution(testmoments)
            # Push them in a dictonary to easily loop through the keys (fields)
            test_dict = struct2dict(equilibria)
            # Test types and lengths
            @test isa(equilibria, JuSwalbe.DistributionD1Q3)
            @test length(keys(test_dict)) == 3
            # Test the
            for key in keys(test_dict)
                @test isa(test_dict[key], Array{type,1})
                @test length(test_dict[key]) == N
                # Check if the values are actually consistent
                if key == :f0
                    for value in test_dict[key]
                        @test value ≈ type(1 - 0.01) atol = 1e-3
                    end
                elseif key == :f1
                    for value in test_dict[key]
                        @test value ≈ type(1.0/20.0 + 1.0/200.0) atol = 1e-3
                    end
                elseif key == :f2
                    for value in test_dict[key]
                        @test value ≈ type(- 1.0/20.0 + 1.0/200.0) atol = 1e-3
                    end
                end
            end
        end
    end

    @testset "Two dimension -velocity -gravity" begin
        N = 3
        M = 2
        # Generate test moments and a test distribution
        typelist = [Float16 Float32 Float64]
        for type in typelist
            testvelocity_x = zeros(type, (N,M))
            testvelocity_y = zeros(type, (N,M))
            test_vel = JuSwalbe.Twovector(x=testvelocity_x, y=testvelocity_y)
            testmoments = JuSwalbe.Macroquant(height=ones(type,(N,M)), velocity=test_vel, pressure=zeros(type,(N,M)), energy=zeros(type,(N,M)))
            equilibria = calc_equilibrium_distribution(testmoments, gravity=type(0.0))
            # Push them in a dictonary to easily loop through the keys (fields)
            test_dict = struct2dict(equilibria)
            # Test types and lengths
            @test isa(equilibria, JuSwalbe.DistributionD2Q9)
            @test length(keys(test_dict)) == 9
            # Test the
            for key in keys(test_dict)
                @test isa(test_dict[key], Array{type,2})
                @test size(test_dict[key]) == (N,M)
                @test size(test_dict[key],1) == N
                @test size(test_dict[key],2) == M
                # Check if the values are actually consistent
                if key == :f0
                    for value in test_dict[key]
                        @test value == type(1)
                    end
                else
                    for value in test_dict[key]
                        @test value == type(0)
                    end
                end
            end
        end
    end

    @testset "Two dimension -velocity +gravity" begin
        N = 3
        M = 2
        weights = [4/9, 1/9, 1/9, 1/9, 1/9, 1/36, 1/36, 1/36, 1/36]
        typelist = [Float16 Float32 Float64]
        for type in typelist
            # I use dicts as they are easier to iterate over
            weightsdict = Dict()
            # For type correction
            weightcorrected = Array{type,1}(undef, 9)
            for (dist, weight) in enumerate(weights)
                weightcorrected[dist] = weights[dist]
                weightsdict[Symbol("f$(dist-1)")] = weightcorrected[dist]
            end
            # Generate test moments and a test distribution
            testvelocity_x = zeros(type, (N,M))
            testvelocity_y = zeros(type, (N,M))
            test_vel = JuSwalbe.Twovector(testvelocity_x, testvelocity_y)
            testmoments = JuSwalbe.Macroquant{Matrix{type}, JuSwalbe.Twovector{Matrix{type}}}(ones(type,(N,M)), test_vel, zeros(type,(N,M)), zeros(type,(N,M)))
            equilibria = calc_equilibrium_distribution(testmoments; gravity=type(0.1))
            # Push them in a dictonary to easily loop through the keys (fields)
            test_dict = struct2dict(equilibria)
            # Test types and lengths
            @test isa(equilibria, JuSwalbe.DistributionD2Q9)
            @test length(keys(test_dict)) == 9
            # Test the
            for key in keys(test_dict)
                @test isa(test_dict[key], Array{type,2})
                @test size(test_dict[key]) == (N,M)
                @test size(test_dict[key],1) == N
                @test size(test_dict[key],2) == M
                # Check if the values are actually consistent
                if key == :f0
                    for value in test_dict[key]
                        @test value - type(1 - 1/12) ≈ type(0.0) atol = tolerances[type]
                    end
                else
                    for value in test_dict[key]
                        @test value ≈ type(3/2*0.1 * weightsdict[key]) atol = 1e-3
                    end
                end
            end
        end
    end

    @testset "Two dimension +velocity +gravity" begin
        N = 3
        M = 2
        weights = [4/9, 1/9, 1/9, 1/9, 1/9, 1/36, 1/36, 1/36, 1/36]
        lattice_vel = [0 0; 1 0; 0 1; -1 0; 0 -1; 1 1; -1 1; -1 -1; 1 -1]
        # I use dicts as they are easier to iterate over
        weightsdict = Dict()
        latticeveldict = Dict()
        typelist = [Float16 Float32 Float64]
        for type in typelist
            # For type correction
            weightcorrected = Array{type,1}(undef, 9)
            for (dist, weight) in enumerate(weights)
                weightcorrected[dist] = weights[dist]
                weightsdict[Symbol("f$(dist-1)")] = weightcorrected[dist]
                latticeveldict[Symbol("f$(dist-1)")]=lattice_vel[dist,:]
            end
            # Generate test moments and a test distribution
            testvelocity_x = ones(type, (N,M)) * type(0.1)
            testvelocity_y = ones(type, (N,M)) * type(0.2)
            test_vel = JuSwalbe.Twovector(testvelocity_x, testvelocity_y)
            testmoments = JuSwalbe.Macroquant{Matrix{type}, JuSwalbe.Twovector{Matrix{type}}}(ones(type,(N,M)), test_vel, zeros(type,(N,M)), zeros(type,(N,M)))
            equilibria = calc_equilibrium_distribution(testmoments; gravity=type(0.1))
            # Push them in a dictonary to easily loop through the keys (fields)
            test_dict = struct2dict(equilibria)
            # Test types and lengths
            @test isa(equilibria, JuSwalbe.DistributionD2Q9)
            @test length(keys(test_dict)) == 9
            # Test the
            for key in keys(test_dict)
                @test isa(test_dict[key], Array{type,2})
                @test size(test_dict[key]) == (N,M)
                @test size(test_dict[key],1) == N
                @test size(test_dict[key],2) == M
                # Check if the values are actually consistent
                if key == :f0
                    for value in test_dict[key]
                        @test value - type(1 - 7/60) ≈ type(0) atol=tolerances[type]
                    end
                else
                    for value in test_dict[key]
                        @test value ≈ type(weightsdict[key] * (3.0/2.0 * 0.1 + 3 * (latticeveldict[key][1]*0.1 + latticeveldict[key][2]*0.2)
                                                        + 9.0/2.0 * (latticeveldict[key][1]*0.1 + latticeveldict[key][2]*0.2)^2
                                                        - 3.0/2.0 * 1.0/20.0)) atol = 1e-3
                    end
                end
            end
        end
    end

    @testset "Two dimension +velocity -gravity" begin
        N = 3
        M = 2
        weights = [4/9, 1/9, 1/9, 1/9, 1/9, 1/36, 1/36, 1/36, 1/36]
        lattice_vel = [0 0; 1 0; 0 1; -1 0; 0 -1; 1 1; -1 1; -1 -1; 1 -1]
        # I use dicts as they are easier to iterate over
        weightsdict = Dict()
        latticeveldict = Dict()
        typelist = [Float16 Float32 Float64]
        for type in typelist
            # For type correction
            weightcorrected = Array{type,1}(undef, 9)
            for (dist, weight) in enumerate(weights)
                weightcorrected[dist] = weights[dist]
                weightsdict[Symbol("f$(dist-1)")] = weightcorrected[dist]
                latticeveldict[Symbol("f$(dist-1)")]=lattice_vel[dist,:]
            end
            # Generate test moments and a test distribution
            testvelocity_x = ones(type, (N,M)) * type(0.1)
            testvelocity_y = ones(type, (N,M)) * type(0.2)
            test_vel = JuSwalbe.Twovector(testvelocity_x, testvelocity_y)
            testmoments = JuSwalbe.Macroquant{Matrix{type}, JuSwalbe.Twovector{Matrix{type}}}(ones(type,(N,M)), test_vel, zeros(type,(N,M)), zeros(type,(N,M)))
            equilibria = calc_equilibrium_distribution(testmoments, gravity=type(0.0))
            # Push them in a dictonary to easily loop through the keys (fields)
            test_dict = struct2dict(equilibria)
            # Test types and lengths
            @test isa(equilibria, JuSwalbe.DistributionD2Q9)
            @test length(keys(test_dict)) == 9
            # Test the
            for key in keys(test_dict)
                @test isa(test_dict[key], Array{type,2})
                @test size(test_dict[key]) == (N,M)
                @test size(test_dict[key],1) == N
                @test size(test_dict[key],2) == M
                # Check if the values are actually consistent
                if key == :f0
                    for value in test_dict[key]
                        @test value - type(1 - 1.0/30.0) ≈ type(0.0) atol=tolerances[type]
                    end
                else
                    for value in test_dict[key]
                        @test value ≈ type(weightsdict[key] * (3 * (latticeveldict[key][1]*0.1 + latticeveldict[key][2]*0.2)
                                                        + 9.0/2.0 * (latticeveldict[key][1]*0.1 + latticeveldict[key][2]*0.2)^2
                                                        - 3.0/2.0 * 1.0/20.0)) atol = 1e-3
                    end
                end
            end
        end
    end
end

max_stars_repo_name: Zitzeronion/JuSwalbe

max_issues_repo_name: Zitzeronion/JuSwalbe


text:
### Basic components and subtypes ###

abstract type Species end
abstract type SpeciesProperty{S<:Species} end
abstract type SpeciesDynamics{F<:Species} end
abstract type Ion <: Species end
abstract type PseudoIon <: Ion end

"""
Not including voltage in tagging ion channels. Flows are all charged particles. So they will always include voltage.
"""

struct Voltage <: Species end
struct Sodium <: Ion end
struct Potassium <: Ion end
struct Calcium <: Ion end
struct Proton <: Ion end
struct Leak <: PseudoIon end

abstract type Reversal{I<:Ion} <: SpeciesProperty{I} end
abstract type Current{I<:Ion} <: SpeciesProperty{I} end
abstract type Conductance{I<:Ion} <: SpeciesProperty{I} end
abstract type mRNA{I<:Ion} <: SpeciesProperty{I} end

shorthand_name(::Type{Voltage}) = :V
shorthand_name(::Type{Sodium}) = :Na
shorthand_name(::Type{Potassium}) = :K
shorthand_name(::Type{Calcium}) = :Ca
shorthand_name(::Type{Proton}) = :H
shorthand_name(::Type{Leak}) = :Leak
shorthand_name(::Type{Reversal{T}}) where {T} = Symbol(:E, shorthand_name(T))
shorthand_name(::Type{Current{T}}) where {T} = Symbol(:I, shorthand_name(T))
shorthand_name(::Type{Conductance{T}}) where {T} = Symbol(:g, shorthand_name(T))
shorthand_name(::Type{mRNA{T}}) where {T} = Symbol(:mRNA_, shorthand_name(T))
shorthand_name(x::Type{Tuple{T,R}}) where {T,R} = shorthand_name.(x.types)


text:
using Swarm
using Test


text:
"""
    RDPG(N::BinaryNetwork; rank::Integer=3)

Given a binary network `N`, `RDPG(N)` returns a probabilistic network with the
same number of species, where every interaction happens with a probability equal
to the dot product of species representation in the network `N`'s RDPG space of
rank `rank`.

Because the pairwise dot product obtained by the matrix multiplication of the
two spaces `Left * Right` are not granted to be bounded between 0 and 1 (for
numerical and theoric reasons), we bound the entries to be in the `[0,1]` range.

#### References

Dalla Riva, G.V. and Stouffer, D.B., 2016. Exploring the evolutionary signature
of food webs' backbones using functional traits. Oikos, 125(4), pp.446-456.
https://doi.org/10.1111/oik.02305

"""
function RDPG(N::T; rank::Integer=3) where {T<:BinaryNetwork}
  L, R = svd_truncated(N; rank=rank)
  ardpg = L * R
  ardp[ardpg .< 0.] .= 0.
  ardpg[ardpg .> 1.] .= 1.
  ReturnType = typeof(N) <: AbstractBipartiteNetwork ? BipartiteProbabilisticNetwork : UnipartiteProbabilisticNetwork
  return ReturnType(ardpg, EcologicalNetworks.species_objects(N)...)
end


text:
conTRUE() = (println("Condition is evaluated and is TRUE"); true)
conFALSE() = (println("Condition is evaluated and is FALSE"); false)

# Short Circuit &&
conTRUE() && conTRUE()
conTRUE() && conFALSE()
conFALSE() && conTRUE()
conFALSE() && conFALSE()

# Short Circuit ||
conTRUE() || conTRUE()
conTRUE() || conFALSE()
conFALSE() || conTRUE()
conFALSE() || conFALSE()

# Ternary

x = 5
x >= 0 || println("x less than 0")

x = -1
x >= 0 || println("x less than 0")

max_stars_repo_name: cadamsmith/julia-programming

max_issues_repo_name: cadamsmith/julia-programming

max_forks_repo_name: cadamsmith/julia-programming


text:
importall Bukdu

type WelcomeController <: ApplicationController
end

index(::WelcomeController) = "hello world"

Router() do
    get("/", WelcomeController, index)
end

Endpoint() do
    plug(Plug.Logger)
    plug(Router)
end

using Base.Test
@test Bukdu.Logger.level_debug == Bukdu.Logger.settings[:level]

Logger.have_color(false)

let oldout = STDERR
   rdout, wrout = redirect_stdout()

conn = (Router)(get, "/")
@test_throws NoRouteError (Router)(get, "/strange")
@test_throws NoRouteError (Endpoint)("/strange")

   reader = @async readstring(rdout)
   redirect_stdout(oldout)
   close(wrout)

str = wait(reader)
@test "DEBUG GET /                         index(::WelcomeController)\nWARN  GET /strange\nWARN  | /strange\n" == str
end


text:
module DemoPackagePM

print_greeting() = print("Hello, world!")

end


text:
abstract type LogLikelihood{T} end

struct GaussianLogLikelihood{T, V<:AbstractVector{T}, S<:AbstractMatrix{T}} <: LogLikelihood{T}
    μ::V
    Σ::S
end

Base.copy(logf::GaussianLogLikelihood) = GaussianLogLikelihood(copy(logf.μ), copy(logf.Σ))

function (logf::GaussianLogLikelihood{T})(x::V) where {T, V<:AbstractVector{T}}
    T(-0.5)*dot(x-logf.μ, logf.Σ\(x-logf.μ))
end
(logf::GaussianLogLikelihood)(x, ::Val{:v}) = logf(x)
(logf::GaussianLogLikelihood)(x, ::Val{:g}) = -logf.Σ\(x - logf.μ)
function (logf::GaussianLogLikelihood{T})(x::V, ::Val{:vg}) where {T, V<:AbstractVector{T}}
    invΣx = logf.Σ\(x - logf.μ)
    return T(-0.5)*dot(x - logf.μ, invΣx), -invΣx
end

struct RLogLikelihood{T, V <: LogLikelihood{T}, W <: AbstractMatrix{T}} <: LogLikelihood{T}
    orglogf::V
    R::W
end

Base.copy(logf::RLogLikelihood) = RLogLikelihood(copy(logf.orglogf), copy(logf.R))

function (logf::RLogLikelihood{T})(x::V) where {T, V<:AbstractVector{T}}
    rx = logf.R*x
    return logf.orglogf(rx)
end

(logf::RLogLikelihood)(x, ::Val{:v}) = logf(x)

function (logf::RLogLikelihood{T})(x::V, ::Val{:g}) where {T, V<:AbstractVector{T}}
    rx = logf.R*x
    return R'*logf.orglogf(rx, Val(:g))
end

function (logf::RLogLikelihood{T})(x::V, ::Val{:vg}) where {T, V<:AbstractVector{T}}
    rx = logf.R*x
    v, g = logf.orglogf(rx, Val(:vg))
    return v, logf.R'*g
end


text:
function initialize!(integrator, cache::GenRosen4ConstantCache)
  integrator.kshortsize = 2
  integrator.k = typeof(integrator.k)(undef, integrator.kshortsize)
  integrator.fsalfirst = integrator.f(integrator.uprev, integrator.p, integrator.t)
  integrator.destats.nf += 1

  # Avoid undefined entries if k is an array of arrays
  integrator.fsallast = zero(integrator.fsalfirst)
  integrator.k[1] = integrator.fsalfirst
  integrator.k[2] = integrator.fsallast
end

@muladd function perform_step!(integrator, cache::GenRosen4ConstantCache, repeat_step=false)
  @unpack t,dt,uprev,u,f,p = integrator
  @unpack A,c,α,αEEst,stages = cache
  @unpack kk = cache

  # Calc First
  kk[1] = integrator.fsalfirst

  # Calc Middle
  for i = 2:stages-1
    utilde = zero(kk[1])
    for j = 1:i-1
      utilde = utilde + A[j,i]*kk[j]
    end
    kk[i] = f(t+c[i]*dt, @. uprev+dt*utilde)
    integrator.destats.nf += 1
  end

  # Calc Last
  utilde = zero(kk[1])
  for j = 1:stages-1
    utilde = utilde + A[j,end]*kk[j]
  end
  kk[end] = f(t+c[end]*dt, @. uprev+dt*utilde)
  integrator.destats.nf += 1
  integrator.fsallast = kk[end] # Uses fsallast as temp even if not fsal

  # Accumulate Result
  utilde = α[1]*kk[1]
  for i = 2:stages
    utilde = utilde + α[i]*kk[i]
  end
  u = uprev + dt*utilde

  if integrator.opts.adaptive
    utilde = (α[1]-αEEst[1])*kk[1]
    for i = 2:stages
      utilde = utilde + (α[i]-αEEst[i])*kk[i]
    end
    utilde = dt*utilde
    atmp = calculate_residuals(utilde, uprev, u, integrator.opts.abstol, integrator.opts.reltol,integrator.opts.internalnorm,t)
    integrator.EEst = integrator.opts.internalnorm(atmp,t)
  end

  if !isfsal(integrator.alg.tableau)
    integrator.fsallast = f(u, p, t+dt)
    integrator.destats.nf += 1
  end

  integrator.k[1] = integrator.fsalfirst
  integrator.k[2] = integrator.fsallast
  integrator.u = u
end


text:
export renderloop

function keycallback(window::Ptr{Cvoid}, key::mfb_key, mod::mfb_key_mod, isPressed::Bool)
    if isPressed
        if key == MiniFB.KB_KEY_Q
            global quit = true
        end
        println("key was pressed: ", key, ", modifier: ", mod)

    end
end

function renderloop(w::Window)
    mfb_set_keyboard_callback(w.wndptr, keycallback)
    global quit = false

    while mfb_wait_sync(w.wndptr)

        state = mfb_update(w.wndptr, w.buffer)
        if state != MiniFB.STATE_OK
            break
        end

        if quit
            mfb_update(w.wndptr, w.buffer)
            break
        end
    end
    close(w)
end

# w = Window("Hello World", 400, 500)
# draw(w, Rect(10, 10, 200, 120))
# renderloop(w)