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

"""
    associate_configuration_items_to_application(application_configuration_id, configuration_ids)
    associate_configuration_items_to_application(application_configuration_id, configuration_ids, params::Dict{String,<:Any})

Associates one or more configuration items with an application.

# Arguments
- `application_configuration_id`: The configuration ID of an application with which items
  are to be associated.
- `configuration_ids`: The ID of each configuration item to be associated with an
  application.

"""
function associate_configuration_items_to_application(
    applicationConfigurationId,
    configurationIds;
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "AssociateConfigurationItemsToApplication",
        Dict{String,Any}(
            "applicationConfigurationId" => applicationConfigurationId,
            "configurationIds" => configurationIds,
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function associate_configuration_items_to_application(
    applicationConfigurationId,
    configurationIds,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "AssociateConfigurationItemsToApplication",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "applicationConfigurationId" => applicationConfigurationId,
                    "configurationIds" => configurationIds,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deletes one or more import tasks, each identified by their import ID. Each import task has
a number of records that can identify servers or applications.  AWS Application Discovery
Service has built-in matching logic that will identify when discovered servers match
existing entries that you've previously discovered, the information for the
already-existing discovered server is updated. When you delete an import task that contains
records that were used to match, the information in those matched records that comes from
the deleted records will also be deleted.

# Arguments
- `import_task_ids`: The IDs for the import tasks that you want to delete.

"""
function batch_delete_import_data(
    importTaskIds; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "BatchDeleteImportData",
        Dict{String,Any}("importTaskIds" => importTaskIds);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function batch_delete_import_data(
    importTaskIds,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "BatchDeleteImportData",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("importTaskIds" => importTaskIds), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Creates an application with the given name and description.

# Arguments
- `name`: Name of the application to be created.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"description"`: Description of the application to be created.
"""
function create_application(name; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "CreateApplication",
        Dict{String,Any}("name" => name);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_application(
    name, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "CreateApplication",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("name" => name), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_tags(configuration_ids, tags)
    create_tags(configuration_ids, tags, params::Dict{String,<:Any})

Creates one or more tags for configuration items. Tags are metadata that help you
categorize IT assets. This API accepts a list of multiple configuration items.

# Arguments
- `configuration_ids`: A list of configuration items that you want to tag.
- `tags`: Tags that you want to associate with one or more configuration items. Specify the
  tags that you want to create in a key-value format. For example:  {\"key\": \"serverType\",
  \"value\": \"webServer\"}

"""
function create_tags(
    configurationIds, tags; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "CreateTags",
        Dict{String,Any}("configurationIds" => configurationIds, "tags" => tags);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_tags(
    configurationIds,
    tags,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "CreateTags",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("configurationIds" => configurationIds, "tags" => tags),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deletes a list of applications and their associations with configuration items.

# Arguments
- `configuration_ids`: Configuration ID of an application to be deleted.

"""
function delete_applications(
    configurationIds; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "DeleteApplications",
        Dict{String,Any}("configurationIds" => configurationIds);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_applications(
    configurationIds,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "DeleteApplications",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("configurationIds" => configurationIds), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deletes the association between configuration items and one or more tags. This API accepts
a list of multiple configuration items.

# Arguments
- `configuration_ids`: A list of configuration items with tags that you want to delete.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"tags"`: Tags that you want to delete from one or more configuration items. Specify the
  tags that you want to delete in a key-value format. For example:  {\"key\": \"serverType\",
  \"value\": \"webServer\"}
"""
function delete_tags(configurationIds; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "DeleteTags",
        Dict{String,Any}("configurationIds" => configurationIds);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_tags(
    configurationIds,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "DeleteTags",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("configurationIds" => configurationIds), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Lists agents or connectors as specified by ID or other filters. All agents/connectors
associated with your user account can be listed if you call DescribeAgents as is without
passing any parameters.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"agentIds"`: The agent or the Connector IDs for which you want information. If you
  specify no IDs, the system returns information about all agents/Connectors associated with
  your AWS user account.
- `"filters"`: You can filter the request using various logical operators and a key-value
  format. For example:   {\"key\": \"collectionStatus\", \"value\": \"STARTED\"}
- `"maxResults"`: The total number of agents/Connectors to return in a single page of
  output. The maximum value is 100.
- `"nextToken"`: Token to retrieve the next set of results. For example, if you previously
  specified 100 IDs for DescribeAgentsRequestagentIds but set DescribeAgentsRequestmaxResults
  to 10, you received a set of 10 results along with a token. Use that token in this query to
  get the next set of 10.
"""
function describe_agents(; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "DescribeAgents"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_agents(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "DescribeAgents", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

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

Retrieves attributes for a list of configuration item IDs.  All of the supplied IDs must be
for the same asset type from one of the following:   server   application   process
connection   Output fields are specific to the asset type specified. For example, the
output for a server configuration item includes a list of attributes about the server, such
as host name, operating system, number of network cards, etc. For a complete list of
outputs for each asset type, see Using the DescribeConfigurations Action in the AWS
Application Discovery Service User Guide.

# Arguments
- `configuration_ids`: One or more configuration IDs.

"""
function describe_configurations(
    configurationIds; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "DescribeConfigurations",
        Dict{String,Any}("configurationIds" => configurationIds);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function describe_configurations(
    configurationIds,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "DescribeConfigurations",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("configurationIds" => configurationIds), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Lists exports as specified by ID. All continuous exports associated with your user account
can be listed if you call DescribeContinuousExports as is without passing any parameters.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"exportIds"`: The unique IDs assigned to the exports.
- `"maxResults"`: A number between 1 and 100 specifying the maximum number of continuous
  export descriptions returned.
- `"nextToken"`: The token from the previous call to DescribeExportTasks.
"""
function describe_continuous_exports(; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "DescribeContinuousExports"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_continuous_exports(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "DescribeContinuousExports",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 DescribeExportConfigurations is deprecated. Use DescribeImportTasks, instead.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"exportIds"`: A list of continuous export IDs to search for.
- `"maxResults"`: A number between 1 and 100 specifying the maximum number of continuous
  export descriptions returned.
- `"nextToken"`: The token from the previous call to describe-export-tasks.
"""
function describe_export_configurations(; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "DescribeExportConfigurations";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function describe_export_configurations(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "DescribeExportConfigurations",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieve status of one or more export tasks. You can retrieve the status of up to 100
export tasks.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"exportIds"`: One or more unique identifiers used to query the status of an export
  request.
- `"filters"`: One or more filters.    AgentId - ID of the agent whose collected data will
  be exported
- `"maxResults"`: The maximum number of volume results returned by DescribeExportTasks in
  paginated output. When this parameter is used, DescribeExportTasks only returns maxResults
  results in a single page along with a nextToken response element.
- `"nextToken"`: The nextToken value returned from a previous paginated DescribeExportTasks
  request where maxResults was used and the results exceeded the value of that parameter.
  Pagination continues from the end of the previous results that returned the nextToken
  value. This value is null when there are no more results to return.
"""
function describe_export_tasks(; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "DescribeExportTasks"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_export_tasks(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "DescribeExportTasks",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Returns an array of import tasks for your account, including status information, times,
IDs, the Amazon S3 Object URL for the import file, and more.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filters"`: An array of name-value pairs that you provide to filter the results for the
  DescribeImportTask request to a specific subset of results. Currently, wildcard values
  aren't supported for filters.
- `"maxResults"`: The maximum number of results that you want this request to return, up to
  100.
- `"nextToken"`: The token to request a specific page of results.
"""
function describe_import_tasks(; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "DescribeImportTasks"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_import_tasks(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "DescribeImportTasks",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves a list of configuration items that have tags as specified by the key-value pairs,
name and value, passed to the optional parameter filters. There are three valid tag filter
names:   tagKey   tagValue   configurationId   Also, all configuration items associated
with your user account that have tags can be listed if you call DescribeTags as is without
passing any parameters.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filters"`: You can filter the list using a key-value format. You can separate these
  items by using logical operators. Allowed filters include tagKey, tagValue, and
  configurationId.
- `"maxResults"`: The total number of items to return in a single page of output. The
  maximum value is 100.
- `"nextToken"`: A token to start the list. Use this token to get the next set of results.
"""
function describe_tags(; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "DescribeTags"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function describe_tags(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "DescribeTags", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

"""
    disassociate_configuration_items_from_application(application_configuration_id, configuration_ids)
    disassociate_configuration_items_from_application(application_configuration_id, configuration_ids, params::Dict{String,<:Any})

Disassociates one or more configuration items from an application.

# Arguments
- `application_configuration_id`: Configuration ID of an application from which each item
  is disassociated.
- `configuration_ids`: Configuration ID of each item to be disassociated from an
  application.

"""
function disassociate_configuration_items_from_application(
    applicationConfigurationId,
    configurationIds;
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "DisassociateConfigurationItemsFromApplication",
        Dict{String,Any}(
            "applicationConfigurationId" => applicationConfigurationId,
            "configurationIds" => configurationIds,
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function disassociate_configuration_items_from_application(
    applicationConfigurationId,
    configurationIds,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "DisassociateConfigurationItemsFromApplication",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "applicationConfigurationId" => applicationConfigurationId,
                    "configurationIds" => configurationIds,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Deprecated. Use StartExportTask instead. Exports all discovered configuration data to an
Amazon S3 bucket or an application that enables you to view and evaluate the data. Data
includes tags and tag associations, processes, connections, servers, and system
performance. This API returns an export ID that you can query using the
DescribeExportConfigurations API. The system imposes a limit of two configuration exports
in six hours.

"""
function export_configurations(; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "ExportConfigurations"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function export_configurations(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "ExportConfigurations",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves a short summary of discovered assets. This API operation takes no request
parameters and is called as is at the command prompt as shown in the example.

"""
function get_discovery_summary(; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "GetDiscoverySummary"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function get_discovery_summary(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "GetDiscoverySummary",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves a list of configuration items as specified by the value passed to the required
parameter configurationType. Optional filtering may be applied to refine search results.

# Arguments
- `configuration_type`: A valid configuration identified by Application Discovery Service.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"filters"`: You can filter the request using various logical operators and a key-value
  format. For example:   {\"key\": \"serverType\", \"value\": \"webServer\"}  For a complete
  list of filter options and guidance about using them with this action, see Using the
  ListConfigurations Action in the AWS Application Discovery Service User Guide.
- `"maxResults"`: The total number of items to return. The maximum value is 100.
- `"nextToken"`: Token to retrieve the next set of results. For example, if a previous call
  to ListConfigurations returned 100 items, but you set ListConfigurationsRequestmaxResults
  to 10, you received a set of 10 results along with a token. Use that token in this query to
  get the next set of 10.
- `"orderBy"`: Certain filter criteria return output that can be sorted in ascending or
  descending order. For a list of output characteristics for each filter, see Using the
  ListConfigurations Action in the AWS Application Discovery Service User Guide.
"""
function list_configurations(
    configurationType; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "ListConfigurations",
        Dict{String,Any}("configurationType" => configurationType);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_configurations(
    configurationType,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "ListConfigurations",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("configurationType" => configurationType), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Retrieves a list of servers that are one network hop away from a specified server.

# Arguments
- `configuration_id`: Configuration ID of the server for which neighbors are being listed.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: Maximum number of results to return in a single page of output.
- `"neighborConfigurationIds"`: List of configuration IDs to test for one-hop-away.
- `"nextToken"`: Token to retrieve the next set of results. For example, if you previously
  specified 100 IDs for ListServerNeighborsRequestneighborConfigurationIds but set
  ListServerNeighborsRequestmaxResults to 10, you received a set of 10 results along with a
  token. Use that token in this query to get the next set of 10.
- `"portInformationNeeded"`: Flag to indicate if port and protocol information is needed as
  part of the response.
"""
function list_server_neighbors(
    configurationId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "ListServerNeighbors",
        Dict{String,Any}("configurationId" => configurationId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_server_neighbors(
    configurationId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "ListServerNeighbors",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("configurationId" => configurationId), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Start the continuous flow of agent's discovered data into Amazon Athena.

"""
function start_continuous_export(; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "StartContinuousExport"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function start_continuous_export(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "StartContinuousExport",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Instructs the specified agents or connectors to start collecting data.

# Arguments
- `agent_ids`: The IDs of the agents or connectors from which to start collecting data. If
  you send a request to an agent/connector ID that you do not have permission to contact,
  according to your AWS account, the service does not throw an exception. Instead, it returns
  the error in the Description field. If you send a request to multiple agents/connectors and
  you do not have permission to contact some of those agents/connectors, the system does not
  throw an exception. Instead, the system shows Failed in the Description field.

"""
function start_data_collection_by_agent_ids(
    agentIds; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "StartDataCollectionByAgentIds",
        Dict{String,Any}("agentIds" => agentIds);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function start_data_collection_by_agent_ids(
    agentIds,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "StartDataCollectionByAgentIds",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("agentIds" => agentIds), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

 Begins the export of discovered data to an S3 bucket.  If you specify agentIds in a
filter, the task exports up to 72 hours of detailed data collected by the identified
Application Discovery Agent, including network, process, and performance details. A time
range for exported agent data may be set by using startTime and endTime. Export of detailed
agent data is limited to five concurrently running exports.   If you do not include an
agentIds filter, summary data is exported that includes both AWS Agentless Discovery
Connector data and summary data from AWS Discovery Agents. Export of summary data is
limited to two exports per day.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"endTime"`: The end timestamp for exported data from the single Application Discovery
  Agent selected in the filters. If no value is specified, exported data includes the most
  recent data collected by the agent.
- `"exportDataFormat"`: The file format for the returned export data. Default value is CSV.
  Note: The GRAPHML option has been deprecated.
- `"filters"`: If a filter is present, it selects the single agentId of the Application
  Discovery Agent for which data is exported. The agentId can be found in the results of the
  DescribeAgents API or CLI. If no filter is present, startTime and endTime are ignored and
  exported data includes both Agentless Discovery Connector data and summary data from
  Application Discovery agents.
- `"startTime"`: The start timestamp for exported data from the single Application
  Discovery Agent selected in the filters. If no value is specified, data is exported
  starting from the first data collected by the agent.
"""
function start_export_task(; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "StartExportTask"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function start_export_task(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "StartExportTask", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

"""
    start_import_task(import_url, name)
    start_import_task(import_url, name, params::Dict{String,<:Any})

Starts an import task, which allows you to import details of your on-premises environment
directly into AWS Migration Hub without having to use the Application Discovery Service
(ADS) tools such as the Discovery Connector or Discovery Agent. This gives you the option
to perform migration assessment and planning directly from your imported data, including
the ability to group your devices as applications and track their migration status. To
start an import request, do this:   Download the specially formatted comma separated value
(CSV) import template, which you can find here:
https://s3-us-west-2.amazonaws.com/templates-7cffcf56-bd96-4b1c-b45b-a5b42f282e46/import_tem
plate.csv.   Fill out the template with your server and application data.   Upload your
import file to an Amazon S3 bucket, and make a note of it's Object URL. Your import file
must be in the CSV format.   Use the console or the StartImportTask command with the AWS
CLI or one of the AWS SDKs to import the records from your file.   For more information,
including step-by-step procedures, see Migration Hub Import in the AWS Application
Discovery Service User Guide.  There are limits to the number of import tasks you can
create (and delete) in an AWS account. For more information, see AWS Application Discovery
Service Limits in the AWS Application Discovery Service User Guide.

# Arguments
- `import_url`: The URL for your import file that you've uploaded to Amazon S3.  If you're
  using the AWS CLI, this URL is structured as follows: s3://BucketName/ImportFileName.CSV
- `name`: A descriptive name for this request. You can use this name to filter future
  requests related to this import task, such as identifying applications and servers that
  were included in this import task. We recommend that you use a meaningful name for each
  import task.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"clientRequestToken"`: Optional. A unique token that you can provide to prevent the same
  import request from occurring more than once. If you don't provide a token, a token is
  automatically generated. Sending more than one StartImportTask request with the same client
  request token will return information about the original import task with that client
  request token.
"""
function start_import_task(
    importUrl, name; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "StartImportTask",
        Dict{String,Any}(
            "importUrl" => importUrl,
            "name" => name,
            "clientRequestToken" => string(uuid4()),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function start_import_task(
    importUrl,
    name,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "StartImportTask",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "importUrl" => importUrl,
                    "name" => name,
                    "clientRequestToken" => string(uuid4()),
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Stop the continuous flow of agent's discovered data into Amazon Athena.

# Arguments
- `export_id`: The unique ID assigned to this export.

"""
function stop_continuous_export(exportId; aws_config::AbstractAWSConfig=global_aws_config())
    return application_discovery_service(
        "StopContinuousExport",
        Dict{String,Any}("exportId" => exportId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function stop_continuous_export(
    exportId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "StopContinuousExport",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("exportId" => exportId), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Instructs the specified agents or connectors to stop collecting data.

# Arguments
- `agent_ids`: The IDs of the agents or connectors from which to stop collecting data.

"""
function stop_data_collection_by_agent_ids(
    agentIds; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "StopDataCollectionByAgentIds",
        Dict{String,Any}("agentIds" => agentIds);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function stop_data_collection_by_agent_ids(
    agentIds,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "StopDataCollectionByAgentIds",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("agentIds" => agentIds), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

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

Updates metadata about an application.

# Arguments
- `configuration_id`: Configuration ID of the application to be updated.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"description"`: New description of the application to be updated.
- `"name"`: New name of the application to be updated.
"""
function update_application(
    configurationId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return application_discovery_service(
        "UpdateApplication",
        Dict{String,Any}("configurationId" => configurationId);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_application(
    configurationId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return application_discovery_service(
        "UpdateApplication",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("configurationId" => configurationId), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end


text:
module MANOVABNPTest

# Imports
using DataFrames: DataFrame, filter!
using Distributions: Beta, Gamma, InverseWishart, MvNormal, pdf
using LinearAlgebra: cholesky, Cholesky, I, lowrankupdate!, lowrankdowndate!, logdet, Symmetric
using OffsetArrays: OffsetArray
using Parameters: @with_kw, @unpack
using StaticArrays: MMatrix, MVector, SVector, @MVector, @MMatrix
using StatsFuns: logmvgamma
using StatsBase: mean, cov, standardize, ZScoreTransform
using Random: randperm, randperm!, MersenneTwister

# Write your package code here.
include("01-utils.jl")
include("02-chain.jl")
include("03-model.jl")
include("04-suffstats.jl")
include("05-logl.jl")
include("06-gibbs.jl")

# Exports
export Model, SuffStats, suffstats0!, suffstats!, ChainState, log_pl, log_ml, ph0, fit, train, train_γ
export update_z!, update_γ!, update_α!
export γcode, γvector, γstr, γvec
export test_sample

end

ext: jl


text:
#########
#File: c:\Users\digan\Dropbox\Dynamic_Networks\repos\ScoreDrivenExponentialRandomGraphs\_research\analysis_for_paper_revision\new_application_\wiki_load_change_stats_and_estimate.jl
#Project: c:\Users\digan\Dropbox\Dynamic_Networks\repos\ScoreDrivenExponentialRandomGraphs\_research\analysis_for_paper_revision\new_application_
#Created Date: Friday April 23rd 2021
#Author: Domenico Di Gangi,  <digangidomenico@gmail.com>
#-----
#Last Modified: Thursday June 3rd 2021 5:18:23 pm
#Modified By:  Domenico Di Gangi
#-----
#Description:
#-----
########

#%%
using DrWatson
@quickactivate "ScoreDrivenExponentialRandomGraphs"
DrWatson.greet()

using Distributed

begin
using TableView
using Blink
viewtab(df) = body!(Window(), showtable(df))
using Logging
using ScoreDrivenERGM
import ScoreDrivenERGM:StaticNets,DynNets, Utilities, ErgmRcall
using LinearAlgebra
using CSV
using DataFrames
using Dates
using PyPlot
pygui(true)

end

#%%
#load data
begin
data_path = "./data/collegeMsg/raw_data/"

df = CSV.read(data_path * "collegeMsg_daily_edges.csv", DataFrame)

df.date = Dates.Date.(df.date)

dates = unique(df.date)

# get sequence of edge lists at a given frequency
edge_list_T = [Matrix(gdf[[:source, :target]]) for gdf in groupby(df,[:date])]
edge_list_pres_T = [Utilities.edge_list_pres(l) for l in edge_list_T]

N = length(unique(reshape(Matrix(df[[:source,:target]]), :)))
n_links_T = [size(e)[1] for e in edge_list_T]
n_nodes_T = [ length(unique(reshape(e, :))) for e in edge_list_T]

end

@elapsed dfEst = collect_results( datadir("collegeMsg", "ch_stats_all"))
# viewtab(dfEst[Not(:ch_stats)])
begin
row = dfEst[1,:]
model = row.model
T = row.Tf
t0_train = 10
tend_train = T

obsT = row.ch_stats[t0_train:tend_train]

ENV["JULIA_DEBUG"] = ScoreDrivenERGM

res_est = DynNets.estimate_and_filter(model, N, obsT; show_trace = true)
fig, ax = DynNets.plot_filtered(model, N, res_est[3])

# res_conf = DynNets.conf_bands_given_SD_estimates(model, N, obsT, DynNets.unrestrict_all_par(model, res_est.vEstSdResParAll), res_est.ftot_0, [[0.975, 0.025]]; , offset=0, plotFlag=true, parUncMethod = "WHITE-MLE", xval = dates[t0_train:tend_train], winsorProp = 0.25)
# res_conf.ax[1].set_title("college msgs $(model.staticModel.ergmTermsString)")

estSS_T = DynNets.estimate_single_snap_sequence(model, obsT)
fig, ax = DynNets.plot_filtered(model, N, estSS_T, ax=ax, lineType = ".", lineColor="r")
end

using Statistics
var(res_est.fVecT_filt[:, 100:end], dims = 2)

DynNets.plot_filtered(model, N, estParSS_T; lineType = ".", lineColor = "k", fig = res_conf.fig, ax=res_conf.ax, gridFlag=false)

dates[100]

max_stars_repo_name: domenicodigangi/SDERGM

max_issues_repo_name: domenicodigangi/SDERGM

max_forks_repo_name: domenicodigangi/SDERGM


text:
#using aeroCoeff
#include("aerodynamic_coeff.jl")
#export trajectoryMPMM!, QEfinderMPMM!, iniCond

function mpmm(du,u,p,t)
    proj,w_bar, R, g₀,ω_bar,target,dist,tp,aero = p

    Iₓ=proj.Ix
    d =proj.calibre
    m=proj.mass

    vx= u[4]
    vy=u[5]
    vz=u[6]
    X₁ = u[1]
    X₂ = u[2]
    X₃ = u[3]
    pₛ = u[7]
   u_bar =[u[4], u[5], u[6]]
   v_bar= u_bar - w_bar
    v = norm(v_bar)
    du_bar = [du[4], du[5],du[6]]
    #println(X₂)
    ρ =  density(X₂)
    #println("ρ", " ", ρ)
    #α = atan(vz/vx)
    #β = asin(vy/v)
    α = atan(vy/vx)
    β = asin(vz/v)

    #mach = Utils.machNumber(v,X₂)
    if tp==nothing
        tp = temperature(X₂)
    end

    mach = machNumber(v,tp)
    CMα₀ = inter(aero.mach, aero.cma)#cma
    #CMα₂ = CM_α2_inter(mach)
    CMα = CMα₀(mach) #+ CMα₂*(sin(αₜ))^2
    #println(du_bar)

   αₑ_bar = yawOfRepose(v_bar, du_bar,pₛ, t, Iₓ, ρ,d,CMα,v)
   #println("αₑ", " ", αₑ_bar)
    αₑ = norm(αₑ_bar)
    #αₜ = asin(αₑ)
    αₜ = αₑ
    #println("1", " ", αₜ)
    #αₜ = asin(sqrt((sin(α)*cos(β))^2+(sin(β)^2)))
    #println("2", " ", αₜ)
    #println("αₜ", " ", αₜ )
    #println("αₜ2", " ", sin(αₑ))

    CX0 = inter(aero.mach,aero.cx)
    CX2 = inter(aero.mach,aero.cx2)
    CDα⁴ = 0.0
    CNa = inter(aero.mach,aero.cna)
    CLα³ = 0.0
    CLα⁵ = 0.0
    cnpα_matrix = matrix(aero.cnpα_1,aero.cnpα_2, aero.cnpα_5,aero.cnpα_10)
    cnpα = inter_matrix(aero.mach, cnpα_matrix, [1.0,2.0,5.0,10.0])

    #Cmag = CN_pα_inter(mach,(rad2deg(αₜ))^2)#cnpa
    Cmag = cnpα(mach,rad2deg(αₜ))
    clp = inter(aero.mach,aero.clp)
    Cₛₚᵢₙ = clp(mach)#clp

    CD = drag(CX0,CX2,αₜ,mach,CNa)
    #CD = drag(CX0,CX2,αₜ,α,β,mach,CNa)
    #println("α", " ",αₜ)
    #println("mach", " ", mach)
    #println("CD", " ", CD)
    CL = lift(CX0,CX2,αₜ,mach,CNa)
    #println("CL", " ", CL)
    FDx = - pi*ρ*d^2/(8)*(CD)*v*v_bar[1] #drag
    FDy = - pi*ρ*d^2/(8)*(CD)*v*v_bar[2] #drag
    FDz = - pi*ρ*d^2/(8)*(CD)*v*v_bar[3] #drag
    FLx = pi*ρ*d^2/(8)*(CL)*v^2*αₑ_bar[1] #lift
    FLy = pi*ρ*d^2/(8)*(CL)*v^2*αₑ_bar[2] #lift
    FLz = pi*ρ*d^2/(8)*(CL)*v^2*αₑ_bar[3] #lift
    FMx = -pi*ρ*d^3*pₛ*Cmag/8*cross(αₑ_bar,v_bar)[1]
    FMy = -pi*ρ*d^3*pₛ*Cmag/8*cross(αₑ_bar,v_bar)[2]
    FMz = -pi*ρ*d^3*pₛ*Cmag/8*cross(αₑ_bar,v_bar)[3]
    #println("cmag", " ", Cmag)
    FGx = - g₀*X₁/R*m
    FGy = -g₀*(1-2*X₂/R)*m
    FGz = - g₀*X₃/R*m
    #FGz = 0.0
    FCx = -2*cross(ω_bar,u_bar)[1]*m
    FCy = -2*cross(ω_bar,u_bar)[2]*m
    FCz = -2*cross(ω_bar,u_bar)[3]*m
    #println("FDx", " ", FDx)
    #println("FLx", " ", FLx)
    #println("FMx", " ", FMx)
    #println("FGx", " ", FGx)
    #println("FCx", " ", FCx)
    Fx =  FDx + FLx +FGx +FMx+FCx
    Fy =  FDy + FLy +FGy +FMy+FCy
    Fz =  FDz + FLz +FGz +FMz+FCz
    #println("Fx", " ", Fx)
    #println("FDx", " ", FDx)
    #println("FLx", " ", FLx)
    #println("FMx", " ", FMx)
    #println("FMy", " ", FMy)
    #println("FMz", " ", FMz)
    #println("FGx", " ", FGx)
    #println("FCx", " ", FCx)
    du[1] = u[4] #x
    du[2] = u[5] #y
    du[3] = u[6] #z
    du[4] =Fx/m #ax
    du[5] = Fy/m#ay
    du[6] = Fz/m#az
    du[7] = pi*ρ*d^4*pₛ*v*Cₛₚᵢₙ/(8*Iₓ)#pdot
    global yaw = αₑ_bar

end

function yawOfRepose(v_bar::Array{Float64,1}, du_bar::Array{Float64,1},pₛ::Float64, t::Float64, Iₓ::Float64, ρ::Float64,d::Float64,CMα::Float64,v::Float64)
    if t==0
        return [0.0,0.0,0.0]
    else
       αₑ_bar = -8*Iₓ*pₛ*cross(v_bar,du_bar)/(pi*ρ*d^3*(CMα)*v^4)

        return αₑ_bar
    end
end

#u₀ = norm()

#canon = gun(0.0,0.0,0.0)

#sol = solve(prob, Tsit5(), reltol=1e-6, abstol=1e-6)
#sol = solve(prob, AutoTsit5(Rosenbrock23()))
#sol = solve(prob)

function condition(u,t,integrator) # Event when event_f(u,t) == 0

  norm(integrator.p[6])-norm([u[1],u[2],u[3]])
  #integrator.p[8][1]-u[1]
  #integrator.p[8][1]>u[1]
end

"""
    conditionHeight(u, t, integrator)

    ContinousCallback function is used to stop algorithm when the Height reach 0.00
"""
function conditionHeight(u,t,integrator)

  if u[1] > 0.1 && u[2] < 0.00
    return norm(integrator.p[10])
  else
    return 1
  end

end

function timeFuze(u,t,integrator)
    #euclidean([u[1],u[2],u[3]],integrator.p[8])-integrator.p[9]

    #close=(euclidean([u[1],u[2],u[3]],integrator.p[8])-integrator.p[9])<0.0
    close=(euclidean([u[1],u[2],u[3]],integrator.p[8])-integrator.p[9])-1e-6
    #println((euclidean([u[1],u[2],u[3]],integrator.p[8])-integrator.p[9]))
    #println(close)
    return close
end

affect!(integrator) = terminate!(integrator)
affect_tf!(integrator) = terminate!(integrator)

"""
    trajectoryMPMM(proj, target, gun, aero; args ... )

Returns the impact point (vector), the velocity at impact (vector) and the time of flight of the projectile (proj).
The stop condition for the trajectory computation is the range of the target. Launcher conditions are specified by the gun
    parameters. The projectile aerodynamic coefficient are specified in the aero variable.
Optional arguments are:

* tspan = the computational time interval. Default is (0.0,1000.0)
* R = the earth radius. Default is 6.356766*1e6
* Ω = the earth spin rate. Default is 7.292115*1e-5
* w_bar = the wind velocity. Default is [0.0,0.0,0.0]
* atm =the atmosphere characteristics. Default is nothing

The projectile trajectory is computed using MPMM

"""
function trajectoryMPMM(proj::AbstractPenetrator, target::AbstractTarget, gun::Gun, aero::DataFrame; tspan = (0.0,1000.0), R = 6.356766*1e6, Ω = 7.292115*1e-5, w_bar=[0.0,0.0,0.0],atm=nothing )
    #global dist = target.position[1]
    #append!(p,dist)
    ω_bar = [Ω*cosd(gun.lat)*cosd(gun.AZ), Ω*sind(gun.lat), -Ω*cosd(gun.lat)*sind(gun.AZ)]
    g₀=grav0(gun.lat)
    if atm==nothing
        tp =nothing

    else
        tp = temperature(atm.t, atm.rh, atm.p)
    end
    p = [proj,w_bar, R, g₀, ω_bar,target.position,5.0,tp,aero]

    p₀ = 2*pi*gun.u₀/(gun.tc*proj.calibre)
    u0=[proj.position[1],proj.position[2],proj.position[3],proj.velocity[1],proj.velocity[2],proj.velocity[3],p₀]
    prob = ODEProblem(mpmm,u0,tspan, p)
    #cb = DiscreteCallback(condition,affect!)
#println(target.x)
    cb = ContinuousCallback(condition,affect!)
    #cb_tf = ContinuousCallback(timeFuze,affect!)
    #cb_tf=DiscreteCallback(timeFuze,affect_tf!)
    #cbs = CallbackSet(cb,cb_tf)
    sol = solve(prob,Tsit5(),callback=cb, reltol=1e-8, abstol=1e-8)
#sol = solve(prob,Tsit5(),callback=cb)
#sol = solve(prob,BS5(),callback=cb)
#sol = solve(prob,AutoTsit5(Rosenbrock23()),callback=cb)
 #proj.position[1] = sol.u[end][1]
 #proj.position[2] = sol.u[end][2]
 #proj.position[3] = sol.u[end][3]
 #proj.velocity[1] = sol.u[end][4]
 #proj.velocity[2] = sol.u[end][5]
 #proj.velocity[3] = sol.u[end][6]
 #proj.tof = sol.t[end]
 #proj.spin = sol.u[end][7]
 return [sol.u[end][1], sol.u[end][2], sol.u[end][3]], [sol.u[end][4], sol.u[end][5], sol.u[end][6]],sol.t[end]
end

function iniCond(gun::Gun, calibre::Float64)
    p₀ = 2*pi*gun.u₀/(gun.tc*calibre)
    u₀_bar = [gun.u₀*cosd(gun.QE)*cosd(gun.AZ), gun.u₀*sind(gun.QE), gun.u₀*cosd(gun.QE)*sind(gun.AZ)]
    X₀_bar = [gun.lw*cosd(gun.QE)*cosd(gun.AZ), gun.X2w + gun.lw *sind(gun.QE), gun.lw*cosd(gun.QE)*sind(gun.AZ)]
    u0 = [X₀_bar[1], X₀_bar[2], X₀_bar[3], u₀_bar[1], u₀_bar[2], u₀_bar[3],p₀]
    return u0
end

"""
    QEfinderMPMM!(drone, proj, gun,aero;args ...)

Returns the elevation and azimuth departure angles of the projectile (proj) with target (drone).
Launcher conditions are specified by the gun parameters, projectile aerodynamic coefficient are specified in the aero variable.
Optional arguments are:

* tspan = the computational time interval. Default is (0.0,1000.0)
* w_bar = the wind velocity. Default is [0.0,0.0,0.0]
* atm =the atmosphere characteristics. Default is nothing

The trajectory is computed using MPMM

"""
function QEfinderMPMM!(drone::AbstractTarget, proj::AbstractPenetrator, gun::Gun,aero::DataFrame;w_bar=[0.0,0.0,0.0],atmosphere=nothing, maxiters=1e6)

    epsilonAz = 1e6
    epsilonQE = 1e6
    precisie = 0.001
    g₀=grav0(gun.lat)
    ddoel = euclidean(proj.position, drone.position)
    tdoel = sqrt(drone.position[1]^2+drone.position[3]^2)/gun.u₀
    #gun.QE = (drone.position[2] - proj.position[2] + g₀ /2 *tdoel^2)*tdoel/gun.u₀
    #gun.AZ = 0.0
    gun.QE=deg2rad(gun.QE)
    gun.AZ=deg2rad(gun.AZ)
    tspan = (0.0,1000.0)
    #R = 6.356766*1e6 #m
    #Ω = 7.292115*1e-5 #rad/s
    #ω_bar = [Ω*cosd(gun.lat)*cosd(gun.AZ), Ω*sind(gun.lat), -Ω*cosd(gun.lat)*sind(gun.AZ)]
    #p = [proj.inertia[1],w_bar, proj.calibre, R, g₀, ω_bar, proj.mass,drone]
    #αₑ_bar = [0.0,0.0,0.0]
    #p = [proj.inertia[1],w_bar, proj.calibre, R, g₀, ω_bar, proj.mass,drone.position,0.0]
    global n=0

    while abs(epsilonAz)>precisie || abs(epsilonQE)>precisie

        #proj.velocity = [gun.u₀*cos(gun.QE)*cos(gun.AZ), gun.u₀*sin(gun.QE), gun.u₀*cos(gun.QE)*sin(gun.AZ)]
        #proj.position = [gun.lw*cos(gun.QE)*cos(gun.AZ), gun.X2w + gun.lw *sin(gun.QE), gun.lw*cos(gun.QE)*sin(gun.AZ)]

        #proj = createProjectile(projectile.mass,projectile.calibre, velocity=muzzle_velocity,  position=muzzle_position, Ix=projectile.Ix )
        #target = ExternalBallistics.createTarget(drone_position)
        #gun = createGun(weapon.u₀,latitude,weapon.θₜ+tourelle.θ,weapon.ξₜ+tourelle.ξ,weapon.tc)

        #u0 = iniCond(gun, proj.calibre)
        #global proj = projectile(u0[1],u0[2],u0[3],u0[4],u0[5],u0[6],0.0)
        #proj = projectile(u0[1],u0[2],u0[3],u0[4],u0[5],u0[6],0.0)
        #proj.position = [u0[1],u0[2],u0[3]]
        #proj.velocity = [u0[4],u0[5],u0[6]]
        #proj.tof = 0.0
        impactP =trajectoryMPMM(proj, drone, gun,aero,atm=atmosphere)[1]
        #trajectoryMPMM!(u0, tspan, p, proj, drone)

        #global epsilonQE = proj.y - drone.y
        epsilonQE = impactP[2] - drone.position[2]
        #println("epsilonQE", " ", epsilonQE)
        #QE = QE0 + (accuracy)/(range_/QE0)
        #global epsilonAz = (sqrt((proj.z-drone.z)^2+(proj.x-drone.x)^2)*sign(atan(proj.z)/proj.x)-atan(drone.z/drone.x))
        epsilonAz = (sqrt((impactP[3]-drone.position[3])^2+(impactP[1]-drone.position[1])^2)*sign(atan(impactP[3])/impactP[1])-atan(drone.position[3]/drone.position[1]))
        #println("epsilonAz", " ", epsilonAz)
        #global AZ = AZ - epsilonAz/ddoel
        gun.AZ = gun.AZ - epsilonAz/ddoel
        #global QE = QE - epsilonQE/ddoel
        gun.QE = gun.QE - epsilonQE/ddoel

        proj.velocity = [gun.u₀*cos(gun.QE)*cos(gun.AZ), gun.u₀*sin(gun.QE), gun.u₀*cos(gun.QE)*sin(gun.AZ)]
        proj.position = [gun.lw*cos(gun.QE)*cos(gun.AZ), gun.X2w + gun.lw *sin(gun.QE), gun.lw*cos(gun.QE)*sin(gun.AZ)]
        if n>=maxiters
            break
        end
        global n+=1

        #trajectory!(u0, tspan, p, proj, drone)
        #calcRange = euclidean([0.0,0.0,0.0], [proj.x,proj.y, proj.z])
        #global accuracy = range_  - calcRange
        #println("AZ", " ", gun.AZ)
        #println("QE", " ", gun.QE)

    end

return gun.QE,gun.AZ
end

function DirectFireTableMPMM(proj::AbstractPenetrator, target::AbstractTarget, gun::Gun, aero::DataFrame, stop_condition::String; tspan = (0.0,1000.0), R = 6.356766*1e6, Ω = 7.292115*1e-5, w_bar=[0.0,0.0,0.0],atm=nothing )

    ω_bar = [Ω*cosd(gun.lat)*cosd(gun.AZ), Ω*sind(gun.lat), -Ω*cosd(gun.lat)*sind(gun.AZ)]
    g₀=grav0(gun.lat)
    if atm==nothing
        tp = nothing
    else
        tp = temperature(atm.t, atm.rh, atm.p)
    end

    p = [proj,w_bar, R, g₀, ω_bar,target.position,5.0,tp,aero, 0.00]
    p₀ = 2*pi*gun.u₀/(gun.tc*proj.calibre)

    u0=[proj.position[1],proj.position[2],proj.position[3],proj.velocity[1],proj.velocity[2],proj.velocity[3],p₀]

    prob = ODEProblem(mpmm,u0,tspan, p)

    if stop_condition == "Range"
        cb  = ContinuousCallback(condition,affect!)
    elseif stop_condition == "Height"
        cb  = ContinuousCallback(conditionHeight, affect!)
    end

    sol = solve(prob, Tsit5(), callback=cb, reltol=1e-8, abstol=1e-8)
    return prob, cb, sol

end

"""
```julia
DirecFireTableQEfinderMPMM!(drone, proj, gun,aero, stop_condition;
                            w_bar=[0.0,0.0,0.0],
                            atmosphere=nothing,
                            maxiters=1e6)
```
Returns the elevation and azimuth departure angles of the projectile (proj) with target (drone).
Launcher conditions are specified by the gun parameters, projectile aerodynamic coefficient are specified in the aero variable.

# Arguments
- ´drone´         : AbstractTarget
- `proj`          : AbstractPenetrator
- `gun`           : Gun
- `aero`          : DataFrame
- `stop_condition`: String
# Optional Arguments
- `w_bar`     : the wind velocity. Default is [0.0,0.0,0.0]
- `atmosphere`: the atmosphere characteristics. Defalut is nothing
- `maxiters`  :
"""

function DirecFireTableQEfinderMPMM!(drone::AbstractTarget, proj::AbstractPenetrator, gun::Gun, aero::DataFrame, stop_condition::String; w_bar=[0.0,0.0,0.0],atmosphere=nothing, maxiters=1e6)
    # error precision
    epsilonAZ = 1e6
    epsilonQE = 1e6
    precision = 0.001

    # out condition initialization
    global n = 0

    # Calibration and Conversion
    g₀     = grav0(gun.lat)     # Gravitational Calibration
    gun.QE = deg2rad(gun.QE)    # Convert Gun    Elevation from Degree to radian
    gun.AZ = deg2rad(gun.AZ)    # Convert Turret Azimuth from Degree to radian

    RealTgtRange = euclidean(proj.position, drone.position) # Equivalente to a Direct Line Of Sight
    tspan = (0.00, 1000.00)

    # data array to export value
    arrProb = []
    arrCb   = []
    arrSol  = []

    while abs(epsilonAZ)>precision || abs(epsilonQE)>precision

        # calculate the MPMM Trajectory
        prob, cb, sol = DirectFireTableMPMM(proj, drone, gun, aero, stop_condition, atm=atmosphere)

        # Calculate the QE / AZ evaluated by the MPMM
        epsilonQE = sol.u[end][2] - drone.position[2]
        epsilonAZ = sqrt((sol.u[end][3] - drone.position[3])^2 + (sol.u[end][1] - drone.position[1])^2) * sign(atan(sol.u[end][3] / sol.u[end][1]) - atan(drone.position[3] / drone.position[1]))

        # Calculate QE / AZ
        gun.AZ = gun.AZ - epsilonAZ / RealTgtRange
        gun.QE = gun.QE - epsilonQE / RealTgtRange

        # Set initial velocity and position in the 3D-Space
        proj.velocity = [gun.u₀ * cos(gun.QE) * cos(gun.AZ), gun.u₀ * sin(gun.QE), gun.u₀ * cos(gun.QE) * sin(gun.AZ)]
        proj.position = [gun.lw * cos(gun.QE) * cos(gun.AZ), gun.X2w + gun.lw * sin(gun.QE), gun.lw * cos(gun.QE) * sin(gun.AZ)]

        # out condition in case of infinity loop
        if n>=maxiters
            break
        end # end if maxiters

        # Store data
        push!(arrProb, prob)
        push!(arrCb, cb)
        push!(arrSol, sol)

        # increment maxiters
        global n+=1
    end # end while precision

    return gun.QE,gun.AZ, arrProb, arrCb, arrSol
end # end DirecFireTableQEfinderMPMM!


text:
using NumericalMethodsforEngineers
using Test

a = Float64[16 4 8;4 5 -4;8 -4 22]
b = Float64[4, 2, 5]
n = size(a, 1)

(lower, upper) = lufac(a)
subfor!(lower, b)
subbac!(upper, b)
s = copy(b)

a = Float64[16 4 8;4 5 -4;8 -4 22]
b = Float64[4, 2, 5]
n = size(a, 1)
d = zeros(n)

ldlt!(a, d)
lower = zeros(3, 3)
for i in 1:n
  for j in 1:i
    lower[i, j] = a[i, j] / d[j]
  end
end

ldlfor!(a, b)
for i in 1:n
  a[i, :] = a[i, :] / d[i]
end

subbac!(a, b)

@test b == s


text:
using YTDL
using Test

@testset "YTDL.jl" begin
    # YTDL is under construction.
end


text:
# GPU impelmentation

# a port of the GPU kernels from Baidu's C++ warp-ctc package
# GitHub: https://github.com/baidu-research/warp-ctc/
# paper: https://arxiv.org/pdf/1512.02595.pdf

using Flux
using Statistics
using CUDA

const MAX_THREADS = 256

function log_plus_f(p1, p2)

  isinf(p1) && return p2
  isinf(p2) && return p1

  if p1 < p2
    p1, p2 = p2, p1
  end

  return p1 + CUDA.log(1+CUDA.exp(p2 - p1))
end

function countRepeats(A)
  repeats = 0
  for (i,elem) in enumerate(A)
    if i > 1 && A[i] == A[i-1]
      repeats += 1
    end
  end
  return repeats
end

function computeAlphaKernel(probs, labelSize, uttLength, repeats, labelsWithoutBlanks, labelsWithBlanks, alpha, blankLabel)

  tid = threadIdx().x
  L = labelSize
  T = uttLength
  S = length(labelsWithBlanks)

  if L + repeats > T
    return nothing
  end

  labels = labelsWithBlanks

  # Corner-case checking
  start = (L + repeats <= T) ? 0 : 1
  last = S > 1 ? 2 : 1

  # Fill in first column (time step)
  i = tid
  while i <= last - start
    alpha[start+i, 1] = probs[labels[start+i], 1]
    i += blockDim().x
  end

  sync_threads()

  # Fill in coefficients for each time step
  for t=2:T

    # Corner-case checking
    if tid == 1 && !(1 < S - 2*(T-t) - 1)
      if start == 0
        alpha[1, t] = probs[blankLabel, t] + alpha[1, t-1]
      elseif start == 1
        alpha[1, t] = alpha[1, t-1]
      end
    end

    sync_threads()

    # Fill in coefficients for each label class in the target output sequence;
    # each thread will process the calculations for one class
    idx = tid+1
    while idx <= S

      prevSum = log_plus_f(alpha[idx, t-1], alpha[idx-1, t-1])

      if labels[idx] != blankLabel && idx != 2 && labels[idx] != labels[idx-2]
        prevSum = log_plus_f(prevSum, alpha[idx-2, t-1])
      end

      if idx < S - 2*(T-t) - 1
        alpha[idx, t] = -Inf32
      else
        alpha[idx, t] = prevSum + probs[labels[idx], t]
      end

      idx += blockDim().x
    end

    sync_threads()
  end
  return nothing
end

function computeBetasAndGradKernel(probs, labelSize, uttLength,
                  repeatsInLabel, labelsWithBlanks,
                  alphas, beta, output, accum,
                  grad, blankLabel)

  tid = threadIdx().x
  L = labelSize
  T = uttLength
  S = 2*L + 1
  repeats = repeatsInLabel

  labels = labelsWithBlanks

  if (L+repeats) > T
    return nothing
  end

  # Corner-case checking
  start = S > 1 ? S-2 : 0
  last = L + repeats < T ? S : S-1

  sync_threads()

  i = tid

  # Calculate coefficients for last column (time step)
  # then determine alpha and beta product
  while i <= last - start + 1
    beta[i+start, T] = 0
    output[i+start, T] = beta[i+start, T] + alphas[i+start, T]
    i += blockDim().x
  end

  sync_threads()

  # Fill in `accum` for last column (time step)
  if tid == 1
    for i=1:S
      labelIdx = labels[i]
      accum[labelIdx, T] = log_plus_f(accum[labelIdx, T], output[i, T])
    end
  end

  sync_threads()

  # Fill in `grad` for last column (time step)
  idx = tid
  while idx <= size(grad, 1)

    s = -Inf32

    for i=1:S
      s = log_plus_f(s, output[i, T])
    end

    # ∂L/∂a (where a is activation before logsoftmax)
    grad[idx, T] = CUDA.exp(probs[idx, T]) - CUDA.exp(accum[idx, T] - s)
    idx += blockDim().x
  end

  sync_threads()

  # Fill in the rest of the coefficients
  t = T-1
  while t >= 1
    if t < T

      idx = tid
      # while idx <= S-1
      while idx <= S

        nextSum = beta[idx, t+1] + probs[labels[idx], t+1]

        if idx < S

          nextSum = log_plus_f(nextSum,
            beta[idx+1, t+1] + probs[labels[idx+1], t+1])
        end

        if labels[idx] != blankLabel && idx != S-1 && labels[idx] != labels[idx+2]
          nextSum = log_plus_f(nextSum,
            beta[idx + 2, t+1] + probs[labels[idx+2], t+1])
        end

        if idx > 2*t
          beta[idx, t] = -Inf32
        else
          beta[idx, t] = nextSum

        end

        idx += blockDim().x
      end

      sync_threads()

      if tid == 1 && last == S
        beta[S, t] = beta[S, t] + probs[blankLabel, t+1]
      end

      sync_threads()

      idx = tid
      while idx <= S
        output[idx, t] = alphas[idx, t] + beta[idx, t]
        idx += blockDim().x
      end

      sync_threads()
    end

    sync_threads()

    # Calculate accumulated alpha-beta products for each label class for
    # each time step; used in calculating gradients
    if tid == 1
      for i=1:S
        labelIdx = labels[i]
        accum[labelIdx, t] = log_plus_f(accum[labelIdx, t], output[i, t])
      end
    end

    sync_threads()

    idx = tid

    # Calculate gradients
    while idx <= size(grad, 1)

      s = -Inf32

      for i=1:S
        s = log_plus_f(s, output[i, t])
      end

      # ∂L/∂a (where a is activation before logsoftmax)
      grad[idx, t] = CUDA.exp(probs[idx, t]) - CUDA.exp(accum[idx, t] - s)
      idx += blockDim().x
    end

    sync_threads()

    t -= 1
    sync_threads()
  end

  return nothing
end

# methods for `ctc_` helper function
ctc(ŷ::CuArray, y::Array) = ctc_(ŷ, y)[1] |> mean
ctc(ŷ::Array, y::CuArray) = ctc_(CuArray(ŷ), collect(y))[1] |> mean
ctc(ŷ::CuArray, y::CuArray) = ctc_(ŷ, collect(y))[1] |> mean
ctc_(ŷ::Array, y::CuArray) =  ctc_(CuArray(ŷ), collect(y))

function ctc_(ŷ::CuArray, y)

  ŷ = logsoftmax(ŷ)

  blank = size(ŷ, 1)
  labels = [Base.argmax(y[:,i]) for i in 1:size(y, 2)]
  z = F(labels, blank)
  z′ = [blank]
  for label in z
    push!(z′, label)
    push!(z′, blank)
  end

  T = size(ŷ, 2)
  U′ = 2*length(z) + 1

  alphas = CUDA.fill(log(zero(ŷ[1])), U′, T)
  betas = CUDA.fill(log(zero(ŷ[1])), U′, T)
  output = CUDA.fill(log(zero(ŷ[1])), U′, T)

  nRepeats = countRepeats(labels)
  nThreads = min(U′, MAX_THREADS)

  @cuda blocks=1 threads=nThreads computeAlphaKernel(ŷ, length(z), size(ŷ,2), nRepeats, CuArray(z), CuArray(z′), alphas, blank)

  grads = CUDA.fill(log(zero(ŷ[1])), size(ŷ))
  accum = CUDA.fill(log(zero(ŷ[1])), size(ŷ))

  @cuda blocks=1 threads=nThreads computeBetasAndGradKernel(ŷ, length(z), size(ŷ,2), nRepeats, CuArray(z′), alphas, betas, output, accum, grads, blank)

  ls = collect(output)
  ls = vec(-1 .* [logsum(ls[:,i]) for i in 1:size(ls, 2)])

  ŷ = alphas = betas = output = accum = nothing
  return ls, grads
end

max_stars_repo_name: maetshju/flux-ctc-grad

max_issues_repo_name: maetshju/flux-ctc-grad

max_forks_repo_name: maetshju/flux-ctc-grad


text:
"""
	Implements all needed parts for constructing SkipGANomaly model
		(https://arxiv.org/pdf/1901.08954.pdf) for detecting anomalies.
	Code is inspired by original Pytorch implementation https://github.com/samet-akcay/skip-ganomaly.

"""

struct UnetSkipBlock
	model
	cat_pass # BOOL if concatenate input and output "cat(x, model(x))"" or not
end

Flux.@functor UnetSkipBlock

function (Unet::UnetSkipBlock)(x; dims=3)
	if Unet.cat_pass
		return cat(x, Unet.model(x), dims=dims)
	else
		return Unet.model(x)
	end
end

"""
	function ConvUnetSkipBlock(in_ch::Int, inner_ch::Int; sub_level=x->x, layer_type="middle")

Create individual Unet layers which can be stacked.
	in_ch      - number of input channels
	inner_ch   - number of covnolutional masks/filters within this block/layer
	sub_level  - lower Unet block or some function like indentity (x->x)
	layer_type - type of Unet block ["bottom", "middle", "top"]
"""
function ConvUnetSkipBlock(in_ch::Int, inner_ch::Int; sub_level=x->x, layer_type="middle")
	if layer_type == "top"
		pass = false
		fm = 2 # filter multiplier

		down = Chain(Conv((4, 4), in_ch=>inner_ch; stride=2, pad=1), BatchNorm(inner_ch))
		up = Chain(x->relu.(x), ConvTranspose((4, 4), fm*inner_ch=>in_ch; stride=2, pad=1))

		return UnetSkipBlock(Chain(down, sub_level, up), pass)

	elseif layer_type == "bottom"
		pass = true
		fm = 1
	elseif layer_type == "middle"
		pass = true
		fm = 2
	else
		error("unkown layer type")
	end
	down = Chain(x->leakyrelu.(x, 0.2f0),
			Conv((4, 4), in_ch=>inner_ch; stride=2, pad=1),
			BatchNorm(inner_ch))
	up = Chain(x->relu.(x),
			ConvTranspose((4, 4), fm*inner_ch=>in_ch; stride=2, pad=1),
			BatchNorm(in_ch))

	return UnetSkipBlock(Chain(down, sub_level, up), pass)
end

"""
	UnetSkipGenerator
"""

struct UnetSkipGenerator
	model
end

Flux.@functor UnetSkipGenerator

function (Unet::UnetSkipGenerator)(x)
	return Unet.model(x)
end

"""
	function UnetSkipGenerator(isize::Int, in_ch::Int, nf::Int)

Create the convolutional generator (Encoder-Decoder) with skip connections with Unet shape
	isize      - size of output image (must be divisible by 32 i.e isize%32==0)
	in_ch      - number of input channels
	nf         - number of covnolutional masks/filters

Example: isize=32, in_ch=3, nf=64

	3=>64                        ->                     64+64=>3
		|                                                  ^
		v                                                  |
		64=>128                  ->               128+128=>64
			 |                                         ^
			 v                                         |
			 128=>256            ->          256+256=>128
				   |                              ^
				   v                              |
				  256=>512       ->     512+512=>256
						|                 ^
						v                 |
						512=>512 -> 512=>512
"""
function UnetSkipGenerator(isize::Int, in_ch::Int, nf::Int)
	@assert isize%32==0 && isize >= 32
	layers = 0
	while isize >= 2
		layers += 1
		isize = isize/2
	end
	unet = ConvUnetSkipBlock(nf*8, nf*8, layer_type="bottom")
	for i = 1:(layers - 5)
		unet = ConvUnetSkipBlock(nf*8, nf*8, sub_level=unet, layer_type="middle")
	end
	unet = ConvUnetSkipBlock(nf*4, nf*8, sub_level=unet, layer_type="middle")
	unet = ConvUnetSkipBlock(nf*2, nf*4, sub_level=unet, layer_type="middle")
	unet = ConvUnetSkipBlock(nf, nf*2, sub_level=unet, layer_type="middle")
	unet = ConvUnetSkipBlock(in_ch, nf, sub_level=unet, layer_type="top")
	return Chain(UnetSkipGenerator(unet), x->tanh.(x))
end

"""
	SkipGANomaly
"""
struct SkipGANomaly
	generator
	discriminator
end

Flux.@functor SkipGANomaly

function SkipGANomaly(isize::Int, in_ch::Int, out_ch::Int, nf::Int, extra_layers::Int)
	gen = UnetSkipGenerator(isize, in_ch, nf)
	disc = ConvDiscriminator(isize, in_ch, out_ch, nf, extra_layers)
	return SkipGANomaly(gen, disc)
end

"""
	Implementation of loss functions for both generator and discriminator
"""

"""
	function generator_loss(SkipGAN::SkipGANomaly, real_input, weights=[1,50,1])

will perform forward pass of generator and returns NTuple{4, Float32} of losses.
	Generator loss:     L_gen = w_1 * L_adv + w_2 * L_con + w_3 * L_lat
	Adversarial loss:   L_adv = E[log(D(x_real))] + E[log(1-D(x_fake))]
	Contextual loss:    L_con = || x - D(G(x)) ||_1
	Latent loss:        L_lat = || f(x_real) - f(x_fake) ||_2

"""
function generator_loss(SkipGAN::SkipGANomaly, real_input; weights=[1,50,1])
	fake = SkipGAN.generator(real_input) #+ randn(typeof(real_input[1]),size(real_input))

	pred_real, feat_real = SkipGAN.discriminator(real_input)
	pred_fake, feat_fake = SkipGAN.discriminator(fake)

	# adv_loss from original code => self.opt.w_adv * self.l_adv(self.pred_fake, self.real_label)
	adv_loss = Flux.crossentropy(pred_fake, 1f0) # adversarial loss
	con_loss  = Flux.mae(fake, real_input) # contextual loss
	lat_loss = Flux.mse(feat_fake, feat_real) # loss of latent representation

	return adv_loss * weights[1] + con_loss * weights[2] + lat_loss * weights[3],
		adv_loss, con_loss, lat_loss
end

"""
	function discriminator_loss(SkipGAN::SkipGANomaly, real_input)

will perform forward pass of discriminator and returns its loss.
	Discriminator loss:    L_gen = L_adv + L_lat
	Adversarial loss:      L_adv = E[log(D(x_real))] + E[log(1-D(x_fake))]
	Latent loss:           L_lat = || f(x_real) - f(x_fake) ||_2
"""
function discriminator_loss(SkipGAN::SkipGANomaly, real_input)
	fake = SkipGAN.generator(real_input) # + randn(typeof(real_input[1]), size(real_input))

	pred_real, feat_real = SkipGAN.discriminator(real_input)
	pred_fake, feat_fake = SkipGAN.discriminator(fake)

	lat_loss = Flux.mse(feat_fake, feat_real) # loss of latent representation
	loss_for_real = Flux.crossentropy(pred_real, 1f0) # ones(typeof(pred_real), size(pred_real)) has same speed
	loss_for_fake = Flux.crossentropy(1f0.-pred_fake, 1f0)
	return loss_for_real + loss_for_fake + lat_loss
end

"""
	function validation_loss(SkipGAN::SkipGANomaly, real_input, weights=[1,50,1])
computes generator and discriminator loss without additional pass through model
"""
function validation_loss(SkipGAN::SkipGANomaly, real_input; weights=[1,50,1], to_testmode::Bool=true)
	(to_testmode == true) ? Flux.testmode!(SkipGAN) : nothing
	fake = SkipGAN.generator(real_input)

	pred_real, feat_real = SkipGAN.discriminator(real_input)
	pred_fake, feat_fake = SkipGAN.discriminator(fake)

	adv_loss = Flux.crossentropy(pred_fake, 1f0)
	con_loss  = Flux.mae(fake, real_input)
	lat_loss = Flux.mse(feat_fake, feat_real)

	loss_for_real = Flux.crossentropy(pred_real, 1f0)
	loss_for_fake = Flux.crossentropy(1f0.-pred_fake, 1f0)

	(to_testmode == true) ? Flux.testmode!(SkipGAN, false) : nothing
	return adv_loss * weights[1] + con_loss * weights[2] + lat_loss * weights[3],
		loss_for_real + loss_for_fake + lat_loss, con_loss, lat_loss
end

"""
	function anomaly_score(SkipGAN::SkipGANomaly, real_input; lambda = 0.5)
computes unscaled anomaly score of real input, losses are weighted by factor lambda
"""
function anomaly_score(SkipGAN::SkipGANomaly, real_input; lambda = 0.9, dims=[1,2,3], to_testmode::Bool=true)
	(to_testmode == true) ? Flux.testmode!(SkipGAN) : nothing
	fake = SkipGAN.generator(real_input) # + randn(typeof(real_input[1]), size(real_input))

	pred_real, feat_real = SkipGAN.discriminator(real_input)
	pred_fake, feat_fake = SkipGAN.discriminator(fake)

	rec_loss  = Flux.mae(fake, real_input, agg=x->Flux.mean(x, dims=dims)) # reconstruction loss -> similar to contextual loss
	lat_loss = Flux.mse(feat_fake, feat_real, agg=x->Flux.mean(x, dims=dims)) # loss of latent representation
	(to_testmode == true) ? Flux.testmode!(SkipGAN, false) : nothing
	return lambda .* rec_loss .+ (1 - lambda) .* lat_loss |>cpu
end

function generalized_anomaly_score(SkipGAN::SkipGANomaly, real_input; R="mae", L="mae", lambda=0.9, dims=[1,2,3], to_testmode::Bool=true)
	(to_testmode == true) ? Flux.testmode!(SkipGAN) : nothing
	fake = SkipGAN.generator(real_input) # + randn(typeof(real_input[1]), size(real_input))

	pred_real, feat_real = SkipGAN.discriminator(real_input)
	pred_fake, feat_fake = SkipGAN.discriminator(fake)

	R = getfield(Flux, Symbol(R))
	L = getfield(Flux, Symbol(L))
	rec_loss  = R(fake, real_input, agg=x->Flux.mean(x, dims=dims)) # reconstruction loss -> similar to contextual loss
	lat_loss = L(feat_fake, feat_real, agg=x->Flux.mean(x, dims=dims)) # loss of latent representation
	(to_testmode == true) ? Flux.testmode!(SkipGAN, false) : nothing
	return lambda .* rec_loss .+ (1 - lambda) .* lat_loss |>cpu
end

function generalized_anomaly_score_gpu(SkipGAN::SkipGANomaly, real_input; R="mae", L="mae", lambda=0.9, dims=[1,2,3], batch_size=64, to_testmode::Bool=true)
	real_input = Flux.Data.DataLoader(real_input, batchsize=batch_size)
	(to_testmode == true) ? Flux.testmode!(SkipGAN) : nothing
	SkipGAN = SkipGAN |> gpu
	R = getfield(Flux, Symbol(R))
	L = getfield(Flux, Symbol(L))
	Rs = Array{Float32}([])
	Ls = Array{Float32}([])
	for X in real_input
		fake = SkipGAN.generator(X|>gpu)
		pred_real, feat_real = SkipGAN.discriminator(X|>gpu)
		pred_fake, feat_fake = SkipGAN.discriminator(fake)

		Rs = cat(Rs, vec(R(fake, X|>gpu, agg=x->Flux.mean(x, dims=dims))|>cpu), dims=1)
		Ls = cat(Ls, vec(L(feat_fake, feat_real, agg=x->Flux.mean(x, dims=dims))|>cpu), dims=1)
		#output = cat(output,vec(Flux.mae(latent_i, latent_o, agg=x->mean(x, dims=dims))) |> cpu, dims=1)
	end
	(to_testmode == true) ? Flux.testmode!(SkipGAN, false) : nothing
	return lambda .* Rs .+ (1 - lambda) .* Ls
end

"""
	Model's training and inference
"""

"""
	fit!(SkipGAN::SkipGANomaly, data, params)
"""
function StatsBase.fit!(SkipGAN::SkipGANomaly, data, params)
	# prepare batches & loaders
	train_loader, val_loader = prepare_dataloaders(data, params)
	# training info logger
	history = GANomalyHistory()
	history["anomality"] =  Array{Float32}([])
	# prepare for early stopping
	best_model = deepcopy(SkipGAN)
	patience = params.patience
	best_val_loss = 1e10
	val_batches = length(val_loader)
	# define optimiser
	# ADAMW(η = 0.001, β = (0.9, 0.999), decay = 0) = Optimiser(ADAM(η, β), WeightDecay(decay))
	opt_g = haskey(params, :decay) ? ADAMW(params.lr, (0.9, 0.999), params.decay) : ADAM(params.lr)
	opt_d = haskey(params, :decay) ? ADAMW(params.lr, (0.9, 0.999), params.decay) : ADAM(params.lr)

	ps_g = Flux.params(SkipGAN.generator)
	ps_d = Flux.params(SkipGAN.discriminator)

	progress = Progress(length(train_loader))
	for (iter, X) in enumerate(train_loader)
		#generator update
		loss1, back = Flux.pullback(ps_g) do
			generator_loss(SkipGAN, getobs(X)|>gpu, weights=params.weights)
		end
		grad = back((1f0, 0f0, 0f0, 0f0))
		Flux.Optimise.update!(opt_g, ps_g, grad)

		# discriminator update
		loss2, back = Flux.pullback(ps_d) do
			discriminator_loss(SkipGAN, getobs(X)|>gpu)
		end
		grad = back(1f0)
		Flux.Optimise.update!(opt_d, ps_d, grad)

		history = update_history(history, loss1, loss2)
		next!(progress; showvalues=[
			(:iters, "$(iter)/$(params.iters)"),
			(:generator_loss, loss1[1]),
			(:discriminator_loss, loss2)
			])
		#TODO optionaly add discriminator restrart if its loss drops under 1e-5
		if mod(iter, params.check_every) == 0
			tot_val_loss_g, tot_val_loss_d, tot_val_loss_rl, tot_val_loss_ll = 0, 0, 0, 0
			for X_val in val_loader
				vgl, vdl,  rl, ll = validation_loss(SkipGAN, X_val |> gpu, weights=params.weights)
				tot_val_loss_g += vgl
				tot_val_loss_d += vdl
				tot_val_loss_rl += rl
				tot_val_loss_ll += ll
			end
			history = update_val_history(history, tot_val_loss_g/val_batches, tot_val_loss_d/val_batches)
			anomality = (params.lambda*tot_val_loss_rl + (1-params.lambda)*tot_val_loss_ll)
			push!(history["anomality"], anomality)
			if anomality < best_val_loss
				best_val_loss = anomality
				patience = params.patience
				best_model = deepcopy(SkipGAN)
			else
				patience -= 1
				if patience == 0
					@info "Stopped training after $(iter) iters"
					global iters = iter - params.check_every*params.patience
					break
				end
			end
		end
		if iter == params.iters
			global iters = params.iters
		end
	end
	return history, best_model, sum(map(p->length(p), ps_g)) + sum(map(p->length(p), ps_d)), iters
end

"""
	conv SkipGANomaly constructor for parameters
"""
function SkipGANomaly_constructor(kwargs)
	params = (isize=kwargs.isize,
			  in_ch = kwargs.in_ch,
			  out_ch = kwargs.out_ch,
			  nf = kwargs.num_filters,
			  extra_layers = kwargs.extra_layers)

	# little control to random initialization
  	(kwargs.init_seed != nothing) ? Random.seed!(kwargs.init_seed) : nothing
	SkipGAN = SkipGANomaly(params...)
	(kwargs.init_seed != nothing) ? Random.seed!() : nothing
	return SkipGAN, params
end


text:
abstract type Variable <: FEMContainer end

# mutable struct NodalVariable <: FEMContainer
#     name::String
#     values::Vector{Float64}
# end

# mutable struct ElementVariable <: FEMContainer
#     name::String
#     values::Vector{Float64}
# end

# NodalVariables = Vector{NodalVariable}
# ElementVariables = Vector{ElementVariable}

function read_number_of_nodal_variables(exo_id::ExoID)
    num_vars = Ref{Int64}(0)
    error = ccall((:ex_get_variable_param, libexodus), Int64,
                  (Int64, Int64, Ref{Int64}),
                  exo_id, EX_NODAL, num_vars)
    exodus_error_check(error, "read_number_of_nodal_variables")
    return num_vars[]
end

function read_nodal_variable_names!(exo_id::ExoID, num_vars::Int64, var_name::Vector{UInt8}, var_names::Vector{String})
    for n = 1:num_vars
        error = ccall((:ex_get_variable_name, libexodus), Int64,
                      (Int64, Int64, Int64, Ptr{UInt8}),
                      exo_id, EX_NODAL, n, var_name)
        exodus_error_check(error, "read_nodal_variable_names")
        var_names[n] = unsafe_string(pointer(var_name))
    end
end

function read_nodal_variable_names(exo_id::ExoID)
    num_vars = read_number_of_nodal_variables(exo_id)
    var_names = Vector{String}(undef, num_vars)
    var_name = Vector{UInt8}(undef, MAX_STR_LENGTH)
    read_nodal_variable_names!(exo_id, num_vars, var_name, var_names)
    return var_names
end

function read_nodal_variable_values(exo_id::ExoID, time_step::Int64, variable_index::Int64, num_nodes::Int64)
    values = Vector{Float64}(undef, num_nodes)
    error = ccall((:ex_get_var, libexodus), ExodusError,
                  (ExoID, Int64, ExodusConstant, Int64, ExodusConstant, Int64, Ref{Float64}),
                  exo_id, time_step, EX_NODAL, variable_index, 1, num_nodes, values)
    exodus_error_check(error, "read_nodal_variable")
    return values
end

function write_number_of_nodal_variables(exo_id::ExoID, num_vars::Int64)
    error = ccall((:ex_put_variable_param, libexodus), ExodusError,
                  (ExoID, ExodusConstant, Int64),
                  exo_id, EX_NODAL, num_vars)
    exodus_error_check(error, "write_number_of_nodal_variables")
end

function write_nodal_variable_names(exo_id::ExoID, var_indices::Vector{Int64}, var_names::Vector{String})
    if size(var_indices, 1) != size(var_names, 1)
        AssertionError("Indices and Names need to be the same length")
    end
    for n = 1:size(var_indices, 1)
        temp = Vector{UInt8}(var_names[n])
        error = ccall((:ex_put_variable_name, libexodus), ExodusError,
                      (ExoID, ExodusConstant, Int64, Ptr{UInt8}),
                      exo_id, EX_NODAL, var_indices[n], temp)
        exodus_error_check(error, "write_nodal_variable_names")
    end
end

function write_nodal_variable_values(exo_id::ExoID, time_step::Int64,
                                     var_index::Int64, var_values::Vector{Float64})
    #
    #
    num_nodes = size(var_values, 1)
    error = ccall((:ex_put_var, libexodus), ExodusError,
                  (ExoID, Int64, ExodusConstant, Int64, Int64, Int64, Ref{Float64}),
                  exo_id, time_step, EX_NODAL, var_index, 1, num_nodes, var_values)
    exodus_error_check(error, "write_nodal_variable_values")
end


text:
export
    daylight_timezone_name,
    daylight_timezone_offset,
    latitude,
    longitude,
    currentobliquity,
    month_names,
    season_names,
    standard_timezone_name,
    standard_timezone_offset

# Abbreviation for standard timezone (e.g., "CST" for North American
# Central Standard Time)

global standard_timezone_name = "CET "

# Time in fractional days to be subtracted from UT to calculate the standard
# time zone offset. Locations east of Greenwich should use negative values.

global standard_timezone_offset = -1

# Abbreviation for daylight savings timezone (e.g., "CDT" for North American
# Central Daylight Time)

# This is optional. If set to None, no daylight savings conversions
# will be performed.

global daylight_timezone_name = "CEST"

# Time in fractional days to be subtracted from UT to calculate the daylight savings
# time zone offset. Locations east of Greenwich should use negative values.

# This value is not used unless "daylight_timezone_name" has an value other
# than None.

global daylight_timezone_offset = -2

# Observer's longitude in radians, measured positive west of Greenwich,
# negative to the east. Should be between -pi...pi.
# To set longitude, use set_longitude(deg2rad(longdegrees))

global longitude = deg2rad(-7.27)

# Observer's latitude in radians, measured positive north of the equator,
# negative to the south. Should be between -pi/2...pi/2.
# To set longitude, use set_latitude(deg2rad(latdegrees))

global latitude =  deg2rad(43.7)

# Month names. There must be twelve. The default is three-character
# abbreviations so that listings line up.

global month_names = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]

# Season names. There must be four. These are used to characterize the
# equinoxes and solstices.

global season_names = ["spring", "summer", "autumn", "winter"]

global currentobliquity


text:
function getIncomeGrid()

# A function that returns:
# 1. an income grid
# 2. A Markovian transition matrix (Q) over income realisations
# 3. A vector of minimum incomes in each year
# 4. A vector of maximum incomes in each year

# ------------------------------------------------------------------------
#  Declare the global variables that will be necessary in this function
#global T Tretire sigma mu rho isUncertainty        % Structural economic paramters
#global hcIncome hcIncPDF                        % Income process (hardcoded)
#global normBnd numPointsY uncertaintyMethod     % Numerical methods

# ------------------------------------------------------------------------

#----------------------------------------%
# Scenario where there is no uncertainty
#----------------------------------------%
if isUncertainty == 0
    y = exp(mu);                # income is set equal to the exp of the log mean
    minInc = y;
    maxInc = y;
    Q = [1];                    # The transition matrix Q is simply a constant 1
                                # with prob 1 each perio\d income is 1

#----------------------------------------%
# Scenario where there is uncertainty - we have hardcoded the discrete
# number of income draws and their pdf
#----------------------------------------%
elseif isUncertainty == 1

    if uncertaintyMethod == 0
        y = hcIncome;           # The hard-coded incomes

        # hcIncPDF contains a single PDF. But we need a Markov transition
        # matrix that gives probability of each income next period
        # conditional on income this period
        Q = repmat(hcIncPDF', numPointsY,1);

        minInc = minimum(y);
        maxInc = maximum(y);

#----------------------------------------%
# Scenario where there is uncertainty - income draws are log normally distributed
#----------------------------------------%
    elseif uncertaintyMethod == 1
        #First get the standard deviation of income (from sigma and rho)
        sig_inc = sigma/((1-rho^2)^0.5);

        (lNormDev, ly ) = getEquiprobNormalDeviates(mu, sig_inc, numPointsY ); # thanks to Alex

        #---------------------%
        #Get transition matrix Q(i, j). The prob of income j in t+1
        #conditional on income i in t
        #---------------------%
         Q = Array(Float64,numPointsY, numPointsY);             #initialise the transition matrix

        for i = 1:1:numPointsY
            for j = 1:1:numPointsY
                hiDraw = lNormDev[j+1] - (1-rho)*mu - rho * ly[i]; #highest innovation that will give us income j tomorrow
                loDraw = lNormDev[j]   - (1-rho)*mu - rho * ly[i]; #lowest  innovation that will give us income j tomorrow

                P_part1=cdf(Normal(), hiDraw/sigma );
                P_part2=cdf(Normal(), loDraw/sigma );

                Q[i,j] = P_part1 - P_part2;
            end #j

            #Each of the rows of Q should add up to 1. But
            #due to the truncation of the normal distribution they will
            #not. So we divide through by the sum of elements in the row
            Q[i, :] = Q[i, :] ./ sum(Q[i, :]);
        end #i

        y = exp(ly);                # Get y from log y
        minInc = exp(-normBnd * sig_inc); # Get the minimum income in each year
        maxInc = exp(normBnd * sig_inc);  # Get the maximum income in each year

        if (y[1] < 1e-4) || (y[numPointsY] > 1e5)
            println("Combination of sigma and rho give a very high income variance. Numerical instability possible")
        end

     end  # if uncertaintyMethod == 0
 end  # if isUncertainty == 0

#----------------------------------------%
# Now get a matrix, T * numPointsY that holds the grid for each income in
# each year. Do likewise with minimum and maximum income
#----------------------------------------%
Ygrid = repmat(y', T, 1);
minInc = repmat([minInc]', T, 1);
maxInc = repmat([maxInc]', T, 1);

#----------------------------------------%
# Replace these arays with zeros for all years after retirement
#----------------------------------------%
if Tretire == 0         # no work (retired at birth)
    Ygrid[:, :] = 0;
    minInc[:, :] = 0;
    maxInc[:, :] = 0;
elseif (Tretire > 0) && (Tretire <=T)  #retire at some age
     Ygrid[Tretire:T, :] = 0;
     minInc[Tretire:T, :] = 0;
     maxInc[Tretire:T, :] = 0;
end

println("Income Grid Done")

return Ygrid, Q, minInc, maxInc

end

max_stars_repo_name: floswald/ucl-econ-julia

max_issues_repo_name: floswald/ucl-econ-julia

max_forks_repo_name: floswald/ucl-econ-julia


text:
# Copyright (c) 2021 Idiap Research Institute, http://www.idiap.ch/
#  Niccolò Antonello <nantonel@idiap.ch>

"""
`inv(fst::WFST)`

Inverts `fst` such that input labels are swaped with output labels.

```julia
julia> A = linearfst(["a","b","c"],[1,2,3],ones(3))
WFST #states: 4, #arcs: 3, #isym: 3, #osym: 3
|1/1.0|
a:1/1.0 → (2)
(2)
b:2/1.0 → (3)
(3)
c:3/1.0 → (4)
((4/1.0))

julia> inv(A)
WFST #states: 4, #arcs: 3, #isym: 3, #osym: 3
|1/1.0|
1:a/1.0 → (2)
(2)
2:b/1.0 → (3)
(3)
3:c/1.0 → (4)
((4/1.0))
```
"""
function Base.inv(fst::WFST)
  ifst = arcmap(inv, fst)
  ifst = WFST(ifst.states,ifst.initials,ifst.finals,ifst.osym,ifst.isym)
  return ifst
end


text:
using Formatting, FFTW, Jets, JetPackWaveFD, LinearAlgebra, SpecialFunctions, Statistics, Test, WaveFD

modeltypes = (WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_V, WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_B, WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_VB)

function make_op(interpmethod, modeltype, fs; comptype = Float32, st = 0.0, wavelet = WaveletCausalRicker(f=5.0))
    nsponge = 10
    pad = 20
    nx = 50+2*pad
    ny = 40+2*pad
    nz = 30+2*pad
    nt = 101
    dx,dy,dz,dt = 25.0,25.0,25.0,0.002
    xmin,ymin,zmin,tmin = -pad*dx,-pad*dy,-pad*dz,0.0
    xmax,ymax,zmax,tmax = xmin+dx*(nx-pad-1),ymin+dy*(ny-pad-1),zmin+dz*(nz-pad-1),tmin+dt*(nt-1)
    sx = dx*div(nx,2)
    sy = dy*div(ny,2)
    sz = dz
    rz = [dz for iy = 1+pad:ny-pad, ix = 1+pad:nx-pad][:]
    ry = [(iy-1)*dy for iy = 1+pad:ny-pad, ix=1+pad:nx-pad][:]
    rx = [(ix-1)*dx for iy = 1+pad:ny-pad, ix=1+pad:nx-pad][:]

    b = ones(Float32,nz,ny,nx)
    v = 1500 .* ones(Float32,nz,ny,nx)

    local m
    if modeltype == WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_V
        kwargs = (b = b, )
        m = reshape(v, nz, ny, nx, 1)
    elseif modeltype == WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_VB
        kwargs = (nz = nz, ny = ny, nx = nx)
        m = zeros(Float32, nz, ny, nx, 2)
        m[:,:,:,1] .= v
        m[:,:,:,2] .= b
    elseif modeltype == WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_B
        kwargs = (v = v, )
        m = reshape(b, nz, ny, nx, 1)
    end

    F = JopNlProp3DAcoIsoDenQ_DEO2_FDTD(; kwargs...,
        z0 = zmin, y0 = ymin, x0 = xmin, dz = dz, dy = dy, dx = dx,
        sz = sz, sy = sy, sx = sx, st = st, rz = rz, ry = ry, rx = rx,
        dtrec = dt, dtmod = dt, ntrec = nt, nsponge = nsponge, comptype = comptype, compscale = 1e-4,
        freqQ = 5.0, qMin = 0.1, qInterior = 100.0, wavelet = wavelet, freesurface = fs,
        reportinterval = 0, interpmethod = interpmethod, isinterior = false)

    m,F
end

@testset "JopProp3DAcoIsoDenQ_DEO2_FDTD -- close, modeltype=$modeltype" for modeltype in modeltypes
    m₀, F = make_op(:hicks, modeltype, false)
    d = F * m₀
    @test isfile(state(F).srcfieldfile*"-pold")
    @test isfile(state(F).srcfieldfile*"-pspace")
    close(F)
    @test !(isfile(state(F).srcfieldfile*"-pold"))
    @test !(isfile(state(F).srcfieldfile*"-pspace"))
    d = F * m₀
    @test isfile(state(F).srcfieldfile*"-pold")
    @test isfile(state(F).srcfieldfile*"-pspace")
    close(F)
    @test !(isfile(state(F).srcfieldfile*"-pold"))
    @test !(isfile(state(F).srcfieldfile*"-p"))

    close(F)
end

@testset "JopProp3DAcoIsoDenQ_DEO2_FDTD -- perfstat, modeltype=$modeltype" for modeltype in modeltypes
    m₀, F = make_op(:hicks, modeltype, false)

    s = Jets.perfstat(F)
    @test isa(s["MCells/s"], Float64)
    @test isa(s["%io"], Float64)
    @test isa(s["%inject/extract"], Float64)
    @test s["%imaging"] ≈ 0.0

    J = jacobian!(F, m₀)
    d = J * m₀
    s = Jets.perfstat(J)
    @test isa(s["MCells/s"], Float64)
    @test isa(s["%io"], Float64)
    @test isa(s["%inject/extract"], Float64)
    @test isa(s["%imaging"], Float64)

    m = J' * d
    s = Jets.perfstat(J)
    @test isa(s["MCells/s"], Float64)
    @test isa(s["%io"], Float64)
    @test isa(s["%inject/extract"], Float64)
    @test isa(s["%imaging"], Float64)

    close(F)
end

@testset "JopProp3DAcoIsoDenQ_DEO2_FDTD -- non-causal source injection" begin
    wavelet = WaveletRicker(;f=5.0)
    mₒ, F₁ = make_op(:hicks, WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_V, false; wavelet, st=-1.0)
    mₒ, F₂ = make_op(:hicks, WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_V, false; wavelet, st=-2.0)

    d₁ = F₁ * mₒ
    d₂ = F₂ * mₒ
    @test d₁ ≈ d₂
end

@testset "JopProp3DAcoIsoDenQ_DEO2_FDTD -- linearization, interpmethod=$interpmethod, fs=$fs, modeltype=$modeltype" for interpmethod in (:linear,:hicks), fs in (true,false), modeltype in modeltypes
    mₒ, F = make_op(interpmethod, modeltype, fs)

    δm = -1 .+ 2 .* rand(domain(F))
    if modeltype == WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_V
        δm[:,:,:,1] .*= 50
    elseif modeltype == WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_VB
        δm[:,:,:,1] .*= 50
        δm[:,:,:,2] .*= 0.1
    elseif modeltype == WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_B
        δm[:,:,:,1] .*= 0.1
    end

    μobs, μexp = linearization_test(F, mₒ, δm = δm,
        μ = sqrt.([1.0,1.0/2.0,1.0/4.0,1.0/8.0,1.0/16.0,1.0/32.0,1.0/64.0,1.0/128.0,1.0/256.0,1.0/512.0]))

    @show μobs, μexp
    @show minimum(abs, μobs - μexp)
    @test minimum(abs, μobs - μexp) < 0.01

    close(F)
end

@testset "JopProp3DAcoIsoDenQ_DEO2_FDTD -- dot product, interpmethod=$interpmethod, fs=$fs, modeltype=$modeltype" for interpmethod in (:linear,:hicks), fs in (true,false), modeltype in modeltypes
    m₀, F = make_op(interpmethod, modeltype, fs)

    m = -1 .+ 2 .* rand(domain(F))
    if modeltype == WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_V
        m[:,:,:,1] .*= 50
    elseif modeltype == WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_VB
        m[:,:,:,1] .*= 50
        m[:,:,:,2] .*= 0.1
    elseif modeltype == WaveFD.Prop3DAcoIsoDenQ_DEO2_FDTD_Model_B
        m[:,:,:,1] .*= 0.1
    end

    J = jacobian!(F, m₀)
    m = -1 .+ 2*rand(domain(J))
    d = -1 .+ 2*rand(range(J))

    lhs, rhs = dot_product_test(J, m, d)
    err = abs(lhs - rhs) / abs(lhs + rhs)
    @show lhs,rhs,(lhs-rhs)/(lhs+rhs)
    @test lhs ≈ rhs rtol=1e-4
    @test err < 1e-4

    close(F)
end

@testset "JopProp3DAcoIsoDenQ_DEO2_FDTD -- linearity, interpmethod=$interpmethod, fs=$fs, modeltype=$modeltype" for interpmethod in (:linear,:hicks), fs in (true,false), modeltype in modeltypes
    m₀, F = make_op(interpmethod, modeltype, fs)
    J = jacobian!(F, m₀)
    lhs,rhs = linearity_test(J)
    @test lhs ≈ rhs

    close(F)
end

# note the compression is exercised on the second pass of F * m₀
@testset "JopProp3DAcoVTIDenQ_DEO2_FDTD -- serialization, modeltype=$modeltype, C=$C" for C in (Float32, UInt32), modeltype in modeltypes
    m₀, F = make_op(:linear, modeltype, false, comptype = C)
    d₁ = F * m₀
    d₂ = F * m₀
    @test d₁ ≈ d₂

    close(F)
end

@testset "JopProp3DAcoVTIDenQ_DEO2_FDTD -- srcillum, C=$C, modeltype=$modeltype" for C in (Float32, UInt32), modeltype in modeltypes
    m₀, F = make_op(:hicks, modeltype, false, comptype = C)
    d₁ = F * m₀;
    J = jacobian(F, m₀);
    s1 = srcillum(F, m₀);
    s2 = srcillum(J);
    close(F)
    @test s1 ≈ s2
    @test maximum(s1) > 0
end

#=
@testset "JopProp3DAcoIsoDenQ_DEO2_FDTD -- analytic, direct, interpmethod=$interpmethod" for interpmethod in (:hicks,:linear)
    z,y,x,dz,dy,dx,dtrec,dtmod,tmax,sz,sy,sx,c = 2000.0,500.0,2500.0,40.0,40.0,40.0,0.016,0.004,2.0,1000.0,250.0,20.0,1500.0
    nz,ny,nx,nt = round(Int,z/dz)+1,round(Int,y/dy)+1,round(Int,x/dx)+1,round(Int,tmax/dtrec)+1

    fmax = c/6/max(dx,dy,dz)
    fdef = WaveletCausalRicker(f=fmax/2)

    function analytic_result()
        # non-negative frequency axis
        nt_pad = nextprod([2,3,5,7],4*nt)
        nw = div(nt_pad,2)+1
        w = range(0, stop=pi/dtrec, length=nw)

        # wavelet
        f = WaveFD.get(fdef, dtrec*collect(0:nt_pad-1))
        F = rfft(f)

        # Morse and Feshbach, 1953, p. 891
        u_ana = zeros(Float32,nt,nz,ny,nx)
        U = zeros(Complex{Float64},nw)
        for ix = 1:nx, iy = 1:ny, iz = 1:nz
            z = (iz-1)*dz
            y = (iy-1)*dy
            x = (ix-1)*dx
            r = sqrt((z-sz)^2+(y-sy)^2+(x-sx)^2)
            for iw = 2:nw
                if r*w[iw] > eps(Float32)
                    U[iw] = exp(-im*w[iw]/c*r)*F[iw]
                end
            end
            u_ana[:,iz,iy,ix] = irfft(U,nt_pad)[1:nt]
            printfmt("{:.2f}\r", ((ix-1)*ny*nz+(iy-1)*nz+iz-1)/(nz*ny*nx)*100)
        end
        u_ana
    end
    @info "computing analytic result (be patient, can take several minutes)..."
    u_ana = analytic_result()
    @info "...done."

    rx = (dx*[0:nx-1;] * ones(ny)')[:]
    ry = (ones(nx) * (dy*[0:ny-1;])')[:]
    rz = 2*dz*ones(length(rx))

    # Finite difference
    M = JopNlProp3DAcoIsoDenQ_DEO2_FDTD(
        b = (1.0f0/2.0f0)*ones(Float32,nz,ny,nx),
        comptype = UInt32,
        sz = sz,
        sy = sy,
        sx = sx,
        rz = rz,
        ry = ry,
        rx = rx,
        interpmethod = interpmethod,
        dz = dz,
        dy = dy,
        dx = dx,
        dtrec = dtrec,
        dtmod = dtmod,
        ntrec = nt,
        wavelet = fdef,
        nsponge = 200,
        freqQ = 5.0,
        qMin = 0.1,
        qInterior = 100.0,
        freesurface = false,
        reportinterval = 250)

    vp = c*ones(nz,ny,nx)
    @info "computing numerical result (be patient)"
    d_tmp = M*vp
    @info "...done."

    # Read FD field back from disk
    u_fd = zeros(Float32,state(M).ntrec,nz,ny,nx)
    u_snap = zeros(Float32,nz,ny,nx)
    u_snap_ginsu = zeros(Float32,size(state(M).ginsu, interior=false)...)
    io = open("$(state(M).srcfieldfile)-P")

    open(state(M).compressor["P"])
    for i = 1:state(M).ntrec
        WaveFD.compressedread!(io, state(M).compressor["P"], i, u_snap_ginsu)
        super!(u_snap,state(M).ginsu,u_snap_ginsu,interior=false)
        u_fd[i,:,:,:] = u_snap[:,:,:]
    end
    close(state(M).compressor["P"])

    # compute Pearson correlation (https://en.wikipedia.org/wiki/Pearson_product-moment_correlation_coefficient)
    xx = ones(nz,ny,nx)
    for ix = 1:nx, iy = 1:ny, iz = 1:nz
        xx[iz,iy,ix] = cor(u_fd[:,iz,iy,ix],u_ana[:,iz,iy,ix])
    end
    xx_mean = mean(xx)
    @test xx_mean > .9

    @info "be patient, the garbage collection is probably deleting large scratch-files"

    close(M)
end
=#

max_stars_repo_name: ChevronETC/JetPackWaveFD

max_issues_repo_name: ChevronETC/JetPackWaveFD

max_forks_repo_name: ChevronETC/JetPackWaveFD


text:
using Twilert

function error_program()
    # We're doing some stuff and BAM we hit an error...
    try
        x = 1
        if x == 1
            error("Onhoes!")
        end
    catch
        Twilert.alert("Ohnoes! There was an error in ur codez!")
    end
end

function success_program()
    # Program is all done, so we let ourselves know!
    x = 0
    for i = 1:100
        x += i
    end
    Twilert.alert("Yay! All done, good job!")
end

error_program()
success_program()


text:
@testset "deprecation" begin
    @testset "restrict" begin
        A = rand(N0f8, 4, 5, 3)
        @test restrict(A, [1, 2]) == restrict(A, (1, 2))
    end

    @testset "statistics" begin
        A = rand(Float32, 4, 4) .- 0.5
        @test minfinite(A, dims=1) == minimum_finite(A, dims=1)
        @test minfinite(A) == minimum_finite(A)
        @test maxfinite(A, dims=1) == maximum_finite(A, dims=1)
        @test maxfinite(A) == maximum_finite(A)

        @test maxabsfinite(A) == maximum_finite(abs, A)
        @test maxabsfinite(A, dims=1) == maximum_finite(abs, A, dims=1)
    end

    @testset "fdiff entrypoints" begin
        A = rand(Float32, 5)
        @test ImageBase.fdiff(A, rev=true) == ImageBase.FiniteDiff.fdiff(A, rev=true)
        out = similar(A)
        @test ImageBase.fdiff!(out, A, rev=false) == ImageBase.FiniteDiff.fdiff!(out, A, rev=false)
    end
end


text:
"""
  Interface that all mesh types must satisfy
"""
module MeshInterface

end

max_stars_repo_name: OptimalDesignLab/CSEInterfaces

max_issues_repo_name: OptimalDesignLab/CSEInterfaces

max_forks_repo_name: OptimalDesignLab/CSEInterfaces


text:
export
ruleSPPoissonOutNP,
ruleSPPoissonLPN,
ruleVBPoissonOut,
ruleVBPoissonL

ruleSPPoissonOutNP(msg_out::Nothing, msg_l::Message{PointMass, Univariate}) =
    Message(Univariate, Poisson, l=msg_l.dist.params[:m])

ruleSPPoissonLPN(msg_out::Message{PointMass, Univariate}, msg_l::Nothing) =
    Message(Univariate, Gamma, a=msg_out.dist.params[:m] + 1.0, b=1.0)

ruleVBPoissonOut(marg_out::Any, marg_l::ProbabilityDistribution{Univariate, Gamma}) =
    Message(Univariate, Poisson, l=(marg_l.params[:a] - 0.5) / marg_l.params[:b])

ruleVBPoissonL(marg_out::ProbabilityDistribution{Univariate}, marg_l::Any) =
    Message(Univariate, Gamma, a=unsafeMean(marg_out) + 1.0, b=1.0)


text:
l = @latexify dummyfunc(x; y=1, z=3) = x^2/y + z
@test l == raw"$\mathrm{dummyfunc}\left( x; y = 1, z = 3 \right) = \frac{x^{2}}{y} + z$"

@test_throws UndefVarError dummyfunc(1.)

l2 = @latexrun dummyfunc2(x; y=1, z=3) = x^2/y + z
@test l2 == raw"$\mathrm{dummyfunc2}\left( x; y = 1, z = 3 \right) = \frac{x^{2}}{y} + z$"

@test dummyfunc2(1.) == 4

l3 = @latexify dummyfunc2(x::Number; y=1, z=3) = x^2/y + z
@test l3 == raw"$\mathrm{dummyfunc2}\left( x::Number; y = 1, z = 3 \right) = \frac{x^{2}}{y} + z$"

l4 = @latexify dummyfunc2(::Number; y=1, z=3) = x^2/y + z
@test l4 == raw"$\mathrm{dummyfunc2}\left( ::Number; y = 1, z = 3 \right) = \frac{x^{2}}{y} + z$"

l5 = @latexify x = abs2(-3)
@test l5 == raw"$x = \left|-3\right|^{2}$"

l6 = @latexify x = $(abs2(-3))
@test l6 == raw"$x = 9$"

l7 = @latexrun x = abs2(-3)
@test l7 == raw"$x = \left|-3\right|^{2}$"
@test x == 9

l8 = @latexrun x = $(abs2(-3))
@test l8 == raw"$x = 9$"
@test x == 9

l9 = @latexdefine x = abs2(-2)
@test l9 == raw"$x = \left|-2\right|^{2} = 4$"
@test x == 4

l10 = @latexdefine x = $(abs2(-2))
@test l10 == raw"$x = 4 = 4$"
@test x == 4

l11 = @latexify x = 1 env=:raw
@test l11 == raw"x = 1"

l12 = @latexrun x = 1 env=:raw
@test l12 == raw"x = 1"

l13 = @latexdefine y = x env=:raw
@test l13 == raw"y = x = 1"

#= # Loading a file with this in it doesn't work on VERSION < v"1.5.0"
env = :raw
l14 = @latexdefine y env
@test l14 == raw"y = 1"
=#

@test latexify(:(@hi(x / y))) == replace(
raw"$\mathrm{@hi}\left( \frac{x}{y} \right)$", "\r\n"=>"\n")