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

"""
    CreateApplication()

Adds an application that is created from a resource group.

# Required Parameters
- `ResourceGroupName`: The name of the resource group.

# Optional Parameters
- `CWEMonitorEnabled`:  Indicates whether Application Insights can listen to CloudWatch events for the application resources, such as instance terminated, failed deployment, and others.
- `OpsCenterEnabled`:  When set to true, creates opsItems for any problems detected on an application.
- `OpsItemSNSTopicArn`:  The SNS topic provided to Application Insights that is associated to the created opsItem. Allows you to receive notifications for updates to the opsItem.
- `Tags`: List of tags to add to the application. tag key (Key) and an associated tag value (Value). The maximum length of a tag key is 128 characters. The maximum length of a tag value is 256 characters.
"""
create_application(ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("CreateApplication", Dict{String, Any}("ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
create_application(ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("CreateApplication", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    CreateComponent()

Creates a custom component by grouping similar standalone instances to monitor.

# Required Parameters
- `ComponentName`: The name of the component.
- `ResourceGroupName`: The name of the resource group.
- `ResourceList`: The list of resource ARNs that belong to the component.

"""
create_component(ComponentName, ResourceGroupName, ResourceList; aws_config::AWSConfig=global_aws_config()) = application_insights("CreateComponent", Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName, "ResourceList"=>ResourceList); aws_config=aws_config)
create_component(ComponentName, ResourceGroupName, ResourceList, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("CreateComponent", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName, "ResourceList"=>ResourceList), args)); aws_config=aws_config)

"""
    CreateLogPattern()

Adds an log pattern to a LogPatternSet.

# Required Parameters
- `Pattern`: The log pattern. The pattern must be DFA compatible. Patterns that utilize forward lookahead or backreference constructions are not supported.
- `PatternName`: The name of the log pattern.
- `PatternSetName`: The name of the log pattern set.
- `Rank`: Rank of the log pattern. Must be a value between 1 and 1,000,000. The patterns are sorted by rank, so we recommend that you set your highest priority patterns with the lowest rank. A pattern of rank 1 will be the first to get matched to a log line. A pattern of rank 1,000,000 will be last to get matched. When you configure custom log patterns from the console, a Low severity pattern translates to a 750,000 rank. A Medium severity pattern translates to a 500,000 rank. And a High severity pattern translates to a 250,000 rank. Rank values less than 1 or greater than 1,000,000 are reserved for AWS-provided patterns.
- `ResourceGroupName`: The name of the resource group.

"""
create_log_pattern(Pattern, PatternName, PatternSetName, Rank, ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("CreateLogPattern", Dict{String, Any}("Pattern"=>Pattern, "PatternName"=>PatternName, "PatternSetName"=>PatternSetName, "Rank"=>Rank, "ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
create_log_pattern(Pattern, PatternName, PatternSetName, Rank, ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("CreateLogPattern", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Pattern"=>Pattern, "PatternName"=>PatternName, "PatternSetName"=>PatternSetName, "Rank"=>Rank, "ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    DeleteApplication()

Removes the specified application from monitoring. Does not delete the application.

# Required Parameters
- `ResourceGroupName`: The name of the resource group.

"""
delete_application(ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("DeleteApplication", Dict{String, Any}("ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
delete_application(ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("DeleteApplication", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    DeleteComponent()

Ungroups a custom component. When you ungroup custom components, all applicable monitors that are set up for the component are removed and the instances revert to their standalone status.

# Required Parameters
- `ComponentName`: The name of the component.
- `ResourceGroupName`: The name of the resource group.

"""
delete_component(ComponentName, ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("DeleteComponent", Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
delete_component(ComponentName, ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("DeleteComponent", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    DeleteLogPattern()

Removes the specified log pattern from a LogPatternSet.

# Required Parameters
- `PatternName`: The name of the log pattern.
- `PatternSetName`: The name of the log pattern set.
- `ResourceGroupName`: The name of the resource group.

"""
delete_log_pattern(PatternName, PatternSetName, ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("DeleteLogPattern", Dict{String, Any}("PatternName"=>PatternName, "PatternSetName"=>PatternSetName, "ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
delete_log_pattern(PatternName, PatternSetName, ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("DeleteLogPattern", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("PatternName"=>PatternName, "PatternSetName"=>PatternSetName, "ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    DescribeApplication()

Describes the application.

# Required Parameters
- `ResourceGroupName`: The name of the resource group.

"""
describe_application(ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeApplication", Dict{String, Any}("ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
describe_application(ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeApplication", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    DescribeComponent()

Describes a component and lists the resources that are grouped together in a component.

# Required Parameters
- `ComponentName`: The name of the component.
- `ResourceGroupName`: The name of the resource group.

"""
describe_component(ComponentName, ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeComponent", Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
describe_component(ComponentName, ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeComponent", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    DescribeComponentConfiguration()

Describes the monitoring configuration of the component.

# Required Parameters
- `ComponentName`: The name of the component.
- `ResourceGroupName`: The name of the resource group.

"""
describe_component_configuration(ComponentName, ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeComponentConfiguration", Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
describe_component_configuration(ComponentName, ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeComponentConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    DescribeComponentConfigurationRecommendation()

Describes the recommended monitoring configuration of the component.

# Required Parameters
- `ComponentName`: The name of the component.
- `ResourceGroupName`: The name of the resource group.
- `Tier`: The tier of the application component. Supported tiers include DOT_NET_CORE, DOT_NET_WORKER, DOT_NET_WEB, SQL_SERVER, and DEFAULT.

"""
describe_component_configuration_recommendation(ComponentName, ResourceGroupName, Tier; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeComponentConfigurationRecommendation", Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName, "Tier"=>Tier); aws_config=aws_config)
describe_component_configuration_recommendation(ComponentName, ResourceGroupName, Tier, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeComponentConfigurationRecommendation", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName, "Tier"=>Tier), args)); aws_config=aws_config)

"""
    DescribeLogPattern()

Describe a specific log pattern from a LogPatternSet.

# Required Parameters
- `PatternName`: The name of the log pattern.
- `PatternSetName`: The name of the log pattern set.
- `ResourceGroupName`: The name of the resource group.

"""
describe_log_pattern(PatternName, PatternSetName, ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeLogPattern", Dict{String, Any}("PatternName"=>PatternName, "PatternSetName"=>PatternSetName, "ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
describe_log_pattern(PatternName, PatternSetName, ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeLogPattern", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("PatternName"=>PatternName, "PatternSetName"=>PatternSetName, "ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    DescribeObservation()

Describes an anomaly or error with the application.

# Required Parameters
- `ObservationId`: The ID of the observation.

"""
describe_observation(ObservationId; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeObservation", Dict{String, Any}("ObservationId"=>ObservationId); aws_config=aws_config)
describe_observation(ObservationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeObservation", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ObservationId"=>ObservationId), args)); aws_config=aws_config)

"""
    DescribeProblem()

Describes an application problem.

# Required Parameters
- `ProblemId`: The ID of the problem.

"""
describe_problem(ProblemId; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeProblem", Dict{String, Any}("ProblemId"=>ProblemId); aws_config=aws_config)
describe_problem(ProblemId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeProblem", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ProblemId"=>ProblemId), args)); aws_config=aws_config)

"""
    DescribeProblemObservations()

Describes the anomalies or errors associated with the problem.

# Required Parameters
- `ProblemId`: The ID of the problem.

"""
describe_problem_observations(ProblemId; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeProblemObservations", Dict{String, Any}("ProblemId"=>ProblemId); aws_config=aws_config)
describe_problem_observations(ProblemId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("DescribeProblemObservations", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ProblemId"=>ProblemId), args)); aws_config=aws_config)

"""
    ListApplications()

Lists the IDs of the applications that you are monitoring.

# Optional Parameters
- `MaxResults`: The maximum number of results to return in a single call. To retrieve the remaining results, make another call with the returned NextToken value.
- `NextToken`: The token to request the next page of results.
"""
list_applications(; aws_config::AWSConfig=global_aws_config()) = application_insights("ListApplications"; aws_config=aws_config)
list_applications(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("ListApplications", args; aws_config=aws_config)

"""
    ListComponents()

Lists the auto-grouped, standalone, and custom components of the application.

# Required Parameters
- `ResourceGroupName`: The name of the resource group.

# Optional Parameters
- `MaxResults`: The maximum number of results to return in a single call. To retrieve the remaining results, make another call with the returned NextToken value.
- `NextToken`: The token to request the next page of results.
"""
list_components(ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("ListComponents", Dict{String, Any}("ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
list_components(ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("ListComponents", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    ListConfigurationHistory()

 Lists the INFO, WARN, and ERROR events for periodic configuration updates performed by Application Insights. Examples of events represented are:    INFO: creating a new alarm or updating an alarm threshold.   WARN: alarm not created due to insufficient data points used to predict thresholds.   ERROR: alarm not created due to permission errors or exceeding quotas.

# Optional Parameters
- `EndTime`: The end time of the event.
- `EventStatus`: The status of the configuration update event. Possible values include INFO, WARN, and ERROR.
- `MaxResults`:  The maximum number of results returned by ListConfigurationHistory in paginated output. When this parameter is used, ListConfigurationHistory returns only MaxResults in a single page along with a NextToken response element. The remaining results of the initial request can be seen by sending another ListConfigurationHistory request with the returned NextToken value. If this parameter is not used, then ListConfigurationHistory returns all results.
- `NextToken`: The NextToken value returned from a previous paginated ListConfigurationHistory 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.
- `ResourceGroupName`: Resource group to which the application belongs.
- `StartTime`: The start time of the event.
"""
list_configuration_history(; aws_config::AWSConfig=global_aws_config()) = application_insights("ListConfigurationHistory"; aws_config=aws_config)
list_configuration_history(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("ListConfigurationHistory", args; aws_config=aws_config)

"""
    ListLogPatternSets()

Lists the log pattern sets in the specific application.

# Required Parameters
- `ResourceGroupName`: The name of the resource group.

# Optional Parameters
- `MaxResults`: The maximum number of results to return in a single call. To retrieve the remaining results, make another call with the returned NextToken value.
- `NextToken`: The token to request the next page of results.
"""
list_log_pattern_sets(ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("ListLogPatternSets", Dict{String, Any}("ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
list_log_pattern_sets(ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("ListLogPatternSets", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    ListLogPatterns()

Lists the log patterns in the specific log LogPatternSet.

# Required Parameters
- `ResourceGroupName`: The name of the resource group.

# Optional Parameters
- `MaxResults`: The maximum number of results to return in a single call. To retrieve the remaining results, make another call with the returned NextToken value.
- `NextToken`: The token to request the next page of results.
- `PatternSetName`: The name of the log pattern set.
"""
list_log_patterns(ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("ListLogPatterns", Dict{String, Any}("ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
list_log_patterns(ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("ListLogPatterns", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    ListProblems()

Lists the problems with your application.

# Optional Parameters
- `EndTime`: The time when the problem ended, in epoch seconds. If not specified, problems within the past seven days are returned.
- `MaxResults`: The maximum number of results to return in a single call. To retrieve the remaining results, make another call with the returned NextToken value.
- `NextToken`: The token to request the next page of results.
- `ResourceGroupName`: The name of the resource group.
- `StartTime`: The time when the problem was detected, in epoch seconds. If you don't specify a time frame for the request, problems within the past seven days are returned.
"""
list_problems(; aws_config::AWSConfig=global_aws_config()) = application_insights("ListProblems"; aws_config=aws_config)
list_problems(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("ListProblems", args; aws_config=aws_config)

"""
    ListTagsForResource()

Retrieve a list of the tags (keys and values) that are associated with a specified application. A tag is a label that you optionally define and associate with an application. Each tag consists of a required tag key and an optional associated tag value. A tag key is a general label that acts as a category for more specific tag values. A tag value acts as a descriptor within a tag key.

# Required Parameters
- `ResourceARN`: The Amazon Resource Name (ARN) of the application that you want to retrieve tag information for.

"""
list_tags_for_resource(ResourceARN; aws_config::AWSConfig=global_aws_config()) = application_insights("ListTagsForResource", Dict{String, Any}("ResourceARN"=>ResourceARN); aws_config=aws_config)
list_tags_for_resource(ResourceARN, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("ListTagsForResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceARN"=>ResourceARN), args)); aws_config=aws_config)

"""
    TagResource()

Add one or more tags (keys and values) to a specified application. A tag is a label that you optionally define and associate with an application. Tags can help you categorize and manage application in different ways, such as by purpose, owner, environment, or other criteria.  Each tag consists of a required tag key and an associated tag value, both of which you define. A tag key is a general label that acts as a category for more specific tag values. A tag value acts as a descriptor within a tag key.

# Required Parameters
- `ResourceARN`: The Amazon Resource Name (ARN) of the application that you want to add one or more tags to.
- `Tags`: A list of tags that to add to the application. A tag consists of a required tag key (Key) and an associated tag value (Value). The maximum length of a tag key is 128 characters. The maximum length of a tag value is 256 characters.

"""
tag_resource(ResourceARN, Tags; aws_config::AWSConfig=global_aws_config()) = application_insights("TagResource", Dict{String, Any}("ResourceARN"=>ResourceARN, "Tags"=>Tags); aws_config=aws_config)
tag_resource(ResourceARN, Tags, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("TagResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceARN"=>ResourceARN, "Tags"=>Tags), args)); aws_config=aws_config)

"""
    UntagResource()

Remove one or more tags (keys and values) from a specified application.

# Required Parameters
- `ResourceARN`: The Amazon Resource Name (ARN) of the application that you want to remove one or more tags from.
- `TagKeys`: The tags (tag keys) that you want to remove from the resource. When you specify a tag key, the action removes both that key and its associated tag value. To remove more than one tag from the application, append the TagKeys parameter and argument for each additional tag to remove, separated by an ampersand.

"""
untag_resource(ResourceARN, TagKeys; aws_config::AWSConfig=global_aws_config()) = application_insights("UntagResource", Dict{String, Any}("ResourceARN"=>ResourceARN, "TagKeys"=>TagKeys); aws_config=aws_config)
untag_resource(ResourceARN, TagKeys, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("UntagResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceARN"=>ResourceARN, "TagKeys"=>TagKeys), args)); aws_config=aws_config)

"""
    UpdateApplication()

Updates the application.

# Required Parameters
- `ResourceGroupName`: The name of the resource group.

# Optional Parameters
- `CWEMonitorEnabled`:  Indicates whether Application Insights can listen to CloudWatch events for the application resources, such as instance terminated, failed deployment, and others.
- `OpsCenterEnabled`:  When set to true, creates opsItems for any problems detected on an application.
- `OpsItemSNSTopicArn`:  The SNS topic provided to Application Insights that is associated to the created opsItem. Allows you to receive notifications for updates to the opsItem.
- `RemoveSNSTopic`:  Disassociates the SNS topic from the opsItem created for detected problems.
"""
update_application(ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("UpdateApplication", Dict{String, Any}("ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
update_application(ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("UpdateApplication", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    UpdateComponent()

Updates the custom component name and/or the list of resources that make up the component.

# Required Parameters
- `ComponentName`: The name of the component.
- `ResourceGroupName`: The name of the resource group.

# Optional Parameters
- `NewComponentName`: The new name of the component.
- `ResourceList`: The list of resource ARNs that belong to the component.
"""
update_component(ComponentName, ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("UpdateComponent", Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
update_component(ComponentName, ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("UpdateComponent", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    UpdateComponentConfiguration()

Updates the monitoring configurations for the component. The configuration input parameter is an escaped JSON of the configuration and should match the schema of what is returned by DescribeComponentConfigurationRecommendation.

# Required Parameters
- `ComponentName`: The name of the component.
- `ResourceGroupName`: The name of the resource group.

# Optional Parameters
- `ComponentConfiguration`: The configuration settings of the component. The value is the escaped JSON of the configuration. For more information about the JSON format, see Working with JSON. You can send a request to DescribeComponentConfigurationRecommendation to see the recommended configuration for a component. For the complete format of the component configuration file, see Component Configuration.
- `Monitor`: Indicates whether the application component is monitored.
- `Tier`: The tier of the application component. Supported tiers include DOT_NET_WORKER, DOT_NET_WEB, DOT_NET_CORE, SQL_SERVER, and DEFAULT.
"""
update_component_configuration(ComponentName, ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("UpdateComponentConfiguration", Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
update_component_configuration(ComponentName, ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("UpdateComponentConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ComponentName"=>ComponentName, "ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)

"""
    UpdateLogPattern()

Adds a log pattern to a LogPatternSet.

# Required Parameters
- `PatternName`: The name of the log pattern.
- `PatternSetName`: The name of the log pattern set.
- `ResourceGroupName`: The name of the resource group.

# Optional Parameters
- `Pattern`: The log pattern. The pattern must be DFA compatible. Patterns that utilize forward lookahead or backreference constructions are not supported.
- `Rank`: Rank of the log pattern. Must be a value between 1 and 1,000,000. The patterns are sorted by rank, so we recommend that you set your highest priority patterns with the lowest rank. A pattern of rank 1 will be the first to get matched to a log line. A pattern of rank 1,000,000 will be last to get matched. When you configure custom log patterns from the console, a Low severity pattern translates to a 750,000 rank. A Medium severity pattern translates to a 500,000 rank. And a High severity pattern translates to a 250,000 rank. Rank values less than 1 or greater than 1,000,000 are reserved for AWS-provided patterns.
"""
update_log_pattern(PatternName, PatternSetName, ResourceGroupName; aws_config::AWSConfig=global_aws_config()) = application_insights("UpdateLogPattern", Dict{String, Any}("PatternName"=>PatternName, "PatternSetName"=>PatternSetName, "ResourceGroupName"=>ResourceGroupName); aws_config=aws_config)
update_log_pattern(PatternName, PatternSetName, ResourceGroupName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = application_insights("UpdateLogPattern", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("PatternName"=>PatternName, "PatternSetName"=>PatternSetName, "ResourceGroupName"=>ResourceGroupName), args)); aws_config=aws_config)


text:
using LinearAlgebra
#include("types.jl")

function isplanar(simplex::Simplex, fp::PointND, d1::Dim, d2::Dim)
  checkdims = [x for x in 1:length(fp) if x!=d1 && x!=d2]
  # need to check if the remaining dims are equal to the focus point
  all([all(simplex[:,d] .== fp[d]) for d in checkdims])
end

# TODO: ensure simplex and fp are compatible
function simplexPointIntersection(simplex::Simplex, fp::PointND, d1::Dim, d2::Dim)
  n = Dim(length(fp) + 1) # number of lambdas to check, dimensionality of the space + 1

  # Set up matrix for barycentric computation
  # Append a set of ones to the simplex and incorporate the focus point
  # to create a square matrix
  T = ones(Float64,(n,n)) # TODO: use square matrix type if exists
  T[1:n-1,1:n-1] = simplex'
  T[1:n-1,n] = fp

  if det(T) == 0 # extra focus point may be in the plane of the
                 # simplex or might be numerical problems
    if isplanar(simplex, fp, d1, d2)
      # if the simplex lies in the plane then just return the simplex as
      # a 2D projection of line segments
      nrow = size(simplex, 1)
      # all pairs of vertices in the simplex
      verts = filter(x -> x[1] != x[2], collect(Iterators.product(1:(nrow-1), 2:nrow)))
      v2d = [
        Intersect2D(simplex[pts[1], d1], simplex[pts[1], d2],
                    simplex[pts[2], d1], simplex[pts[2], d2])
        for pts = verts
      ]
      return v2d
    else
      T[1:n-1,n] = fp .+ (rand(n-1)*1e-9) # offset slightly to make matrix non-singluar
    end
  end

  # compute lambda as best we can (there will be 3 parts)
  rr = vcat(fp, 1.)
  rr[d1] = rr[d2] = 0
  rry = zeros(length(rr))
  rrx = zeros(length(rr))
  rrx[d1] = rry[d2] = 1.
  # We are trying to compute T^(-1) . [x-xn, y-yn,...,z-zn]
  Tlu = factorize(T)
  lc = Tlu \ rr # This way is more stable than inverting once
  lx = Tlu \ rrx
  ly = Tlu \ rry

  # find the d1 and d2 ranges that make each lambda 0
  # most indices are based on solving ax + by + c = 0
  # but keeping the other lambdas between 0 and 1

  # put y=mx+b into each other lambda formula and try and get a good range
  ccr(lx, ly, lc, n) # only consider the last lambda
end

## The common-cross-range functions
function ccr(lx::LambdaND, ly::LambdaND, lz::LambdaND, i::Dim)
  if lx[i] == 0 && ly[i] == 0
    return []
  elseif lx[i] == 0
    ccrX0(lx, ly, lz, i)
  elseif ly[i] == 0
    ccrY0(lx, ly, lz, i)
  else
    ccrXY(lx, ly, lz, i)
  end
end

function ccrX0(lx::LambdaND, ly::LambdaND, lc::LambdaND, i::Dim)
  # solve ly * y + c = 0
  y = -lc[i] / ly[i]
  # replace y in all other formulas and solve lx * x + ly * y + lc >=0 for x
  xs = lx[1:end .!= i]
  cs = ly[1:end .!= i] * y + lc[1:end .!= i]
  res = -cs ./ xs

  if any(xs .== 0) && any(cs[xs .== 0] .< 0) # no intersection
    return []
  else
    xsp = xs[map(isfinite,res)] # for filtering res later
    res = res[map(isfinite,res)]
    xrng = (maximum(res[xsp .>= 0]), minimum(res[xsp .< 0]))
    # some final bounds checking
    if xrng[2] - xrng[1] < -EPS
      return []
    end
    return [Intersect2D(xrng[1], y, xrng[2], y)]
  end
end

function ccrY0(lx::LambdaND, ly::LambdaND, lc::LambdaND, i::Dim)
  # solve ly * y + c = 0
  x = -lc[i] / lx[i]
  # replace x in all other formulas and solve lx * x + ly * y + lc >=0 for y
  ys = ly[1:end .!= i]
  cs = lx[1:end .!= i] * x + lc[1:end .!= i]
  res = -cs ./ ys

  if any(ys .== 0) && any(cs[ys .== 0] .< 0) # no intersection
    return []
  else
    ysp = ys[map(isfinite,res)] # for filtering res later
    res = res[map(isfinite,res)]
    yrng = (maximum(res[ysp .>= 0]), minimum(res[ysp .< 0]))
    # some final bounds checking
    if yrng[2] - yrng[1] < -EPS
      return []
    end
    return [Intersect2D(x, yrng[1], x, yrng[2])]
  end
end

# assumes lx[i] and ly[i] are non-zero
function ccrXY(lx::LambdaND, ly::LambdaND, lc::LambdaND, i::Dim)
  # solve lx * x + ly * y + c = 0 and substitute
  xs = lx[1:end .!= i] - ly[1:end .!= i] .* lx[i] ./ ly[i]
  cs = lc[1:end .!= i] - ly[1:end .!= i] .* lc[i] ./ ly[i]
  res = -cs ./ xs # solving for xs + cs >= 0

  if any(xs .== 0) && any(cs[xs .== 0] .< 0) # no intersection
    return []
  else
    xsp = xs[map(isfinite,res)] # for filtering res later
    res = res[map(isfinite,res)]
    xrng = (maximum(res[xsp .>= 0]), minimum(res[xsp .< 0]))
    yrng = (-lc[i] .- lx[i] .* xrng) ./ ly[i]
    # some final bounds checking
    if xrng[2] - xrng[1] < -EPS
      return []
    end
    return [Intersect2D(xrng[1], yrng[1], xrng[2], yrng[2])]
  end
end

# TODO: force triangle to be a triangle in 3D space
function intersectTri(triangle, fp::PointND, d1::Dim, d2::Dim)
  # compute the normal to the slicing plane
  n = ones(3)
  n[d1] = n[d2] = 0.0

  # figure out the point projection
  i1 = dot(n, (fp - triangle[1,:])) / dot(n, (triangle[2,:] - triangle[1,:]))
  i2 = dot(n, (fp - triangle[1,:])) / dot(n, (triangle[3,:] - triangle[1,:]))
  i3 = dot(n, (fp - triangle[2,:])) / dot(n, (triangle[3,:] - triangle[2,:]))
  p1 = triangle[1,:] + i1 * (triangle[2,:] - triangle[1,:])
  p2 = triangle[1,:] + i2 * (triangle[3,:] - triangle[1,:])
  p3 = triangle[2,:] + i3 * (triangle[3,:] - triangle[2,:])

  pts = filter(x -> isfinite(x[1]), [p1, p2, p3])
  if length(pts) == 0
    return []
  else
    return [Intersect2D(pts[1][d1], pts[1][d2], pts[2][d1], pts[2][d2])]
  end
end

ext: jl


text:
#   Unit "gortzel" of the FourierAnalysis Package for julia language
#
#   MIT License
#   Copyright (c) 2019-2022,
#   Marco Congedo, CNRS, Grenobe, France:
#   https://sites.google.com/site/marcocongedo/home

# ? CONTENTS :
#   This unit implements Goertzel's algorithms for estimating
#   DFT complex coefficients at a specific frequency
#   in the time domain for FFT analysis.
#   NB: The result is practically identical to the output of an FFT,
#   but requieres only `t` operations, where `t` is the window length
#   and is not restricted to a discrete Fourier Frequency.
#   Since the complexity of FFT algirthms is t*log(t), Goertzels' algorithm
#   are advantageous when only one or a few coefficients are needed.
#   Smart block on-line implementations are also possible.
#
#   See: Goertzel G (1958) An algorithm for the evaluation of finite trigonometric series
#   The American Mathematical Monthly, 65(1), 34-35.
#   https://pdfs.semanticscholar.org/a5e4/d0faf65627374b1ac82c3c79006d010173c9.pdf
#   See also
#   https://www.st.com/content/ccc/resource/technical/document/design_tip/group0/20/06/95/0b/c3/8d/4a/7b/DM00446805/files/DM00446805.pdf/jcr:content/translations/en.DM00446805.pdf

#   ~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~  #
#                                                                             #
#   ~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~~¤~  #

"""
```julia
function goertzel( x   :: Vector{T},
                   f   :: IntOrReal,
                   sr  :: Int,
                   wl  :: Int,
               startAT :: Int = 1) where T<:Union{Real, Complex}
```

Given a time series as input vector `x` sampled at `sr` sampling rate,
return the DFT complex coefficient at the discrete Fourier frequency which is
the closest to `f`. The coefficient is computed for the time window starting
at `startAt` (one-based) and of lenght `wl`.

If `startAT`=1 (default) the first `wl` samples of the vector are considered.

`wl` does not need to be power of 2.

**See also**: [`goertzel_fast`](@ref), [`goertzel2`](@ref).

**Examples**:
```julia
using FourierAnalysis
sr, t, f, a = 128, 128, 5, 10
v=sinusoidal(a, f, sr, t, 0)
c=goertzel(v, f, sr, t) # should output 0+aim
```
"""
function goertzel( x   :: Vector{T},
                   f   :: IntOrReal,
                   sr  :: Int,
                   wl  :: Int,
               startAT :: Int = 1) where T<:Union{Real, Complex}
    p, a = 2π*round(UInt16, (f*wl)/sr)/wl, 2/wl
    s, c = sincos(p)
    d = 2*c
    return goertzel_fast(x, wl, a, c, s, d, startAT)
end

"""
```julia
function goertzel_fast( x  :: Vector{T},
                        wl :: Int,
                        a  :: Real,
                        c  :: Real,
                        s  :: Real,
                        d  :: Real,
                    startAT:: Int = 1) where T<:Union{Real, Complex}
```

Fast version of the [`goertzel`](@ref) function to be preferred if the function
is invoked repeatedly and speed is of concern. The user provides as arguments:

- a time series as input vector `x`,
- `wl`, the number of samples in `x` (or the window length),
- `a` = ``2/wl``,
- `c` = ``cos(p)`` where ``p``=`2*π*round(UInt16, (f*wl)/sr)/wl`, ``f`` is the desired frequency and ``sr`` the sampling rate,
- `s` = ``sin(p)``
- `d` = 2*`c`
- `startAt` as in the [`goertzel`](@ref) function.

**See also**: [`goertzel`](@ref), [`goertzel2`](@ref).
"""
function goertzel_fast( x  :: Vector{T},
                        wl :: Int,
                        a  :: Real,
                        c  :: Real,
                        s  :: Real,
                        d  :: Real,
                    startAT:: Int = 1) where T<:Union{Real, Complex}
    z1, z2 = T(0), T(0)
    @inbounds for i = startAT : startAT + wl-1
     z0 = muladd(d, z1, x[i]-z2)
     z2 = z1
     z1 = z0
    end
    return muladd(z1, c, -z2)*a + *(z1, s, a)im
end

"""
```julia
function goertzel2( x  :: Vector{T},
                    f  :: IntOrReal,
                    sr :: Int,
                    wl :: Int,
                startAT:: Int = 1) where T<:Union{Real, Complex}
```

Like the [`goertzel`](@ref) function, but allows estimating the DFT coefficient
in the whole positive real line up to the Nyquist frequency.
This is useful when the DFT coefficient is sought
for a frequency which is not a discrete Fourier Frequency.

Using an appropriate taper this function allows almost exact recovery of
both amplitude and phase at all frequencies in case of one sinusoid,
whereas the `goertzel` function can do so only at exact Fourier discrete
frequencies.

**See also**: [`goertzel_fast`](@ref), [`goertzel`](@ref).

**Examples**:
```julia
using FourierAnalysis
sr, t, f, a = 128, 128, 5, 10
ftrue=f+0.15
v=sinusoidal(a, ftrue, sr, t, 0 )
c=goertzel(v, f, sr, t) # should be 0+aim, but clearly fails
d=goertzel2(v, ftrue, sr, t) # this get closer
```
"""
function goertzel2( x  :: Vector{T},
                    f  :: IntOrReal,
                    sr :: Int,
                    wl :: Int,
                startAT:: Int = 1) where T<:Union{Real, Complex}
    q = (2π*f*wl)/sr
    p = q/wl
    a = 2/wl
    s, c = sincos(p)
    d = 2*c
    z = goertzel_fast(x, wl, a, c, s, d, startAT)
    s2, c2 = sincos(q)
    return muladd(real(z), c2, imag(z)*s2) + muladd(-real(z), s2, imag(z)*c2)im
end


text:
#
# Result
# can have either of the following:
# - recordset
# - number of rows affected
#
# pending results can be
# - checked for readiness
# - cancelled
#
# results must be closed

"""number of records to fetch with every fetchnext"""
const DEFAULT_FETCH_SIZE = 1024 * 1024

mutable struct PendingResult
    session::HiveSession
    handle::TOperationHandle
    status::Union{Nothing,TGetOperationStatusResp}
end

const RowCount = Float64

mutable struct ResultSet
    session::HiveSession
    handle::TOperationHandle
    schema::Union{Nothing,TTableSchema}
    rowset::Union{Nothing,TRowSet}
    position::Int
    fetchsize::Int
    eof::Bool

    function ResultSet(session::HiveSession, handle::TOperationHandle)
        new(session, handle, nothing, nothing, 0, DEFAULT_FETCH_SIZE, false)
    end
end

function show(io::IO, rs::ResultSet)
    print(io, "ResultSet(eof=$(rs.eof), position=$(rs.position), fetchsize=$(rs.fetchsize))")
end

const Result = Union{ResultSet, RowCount, PendingResult}

result(pending::PendingResult) = isready(pending) ? result(pending.session, true, pending.handle) : pending
result(rs::ResultSet) = rs
function result(session::HiveSession, ready::Bool, handle::TOperationHandle)
    ready || (return PendingResult(session, handle, nothing))

    # hasResultSet == true => a result set (possibly empty) can be fetched, modifiedRowCount is not set.
    # hasResultSet == false => modifiedRowCount is set
    handle.hasResultSet && (return ResultSet(session, handle))

    # modifiedRowCount >= 0 => number of rows affected is known
    # modifiedRowCount < 0 => operation is capable fo modifying rows, but the count is unknown. e.g. LOAD DATA
    return handle.modifiedRowCount
end

eof(r::ResultSet) = r.eof

close(pending::PendingResult) = close(pending.session, pending.handle)
close(resultset::ResultSet) = close(resultset.session, resultset.handle)
function close(session::HiveSession, handle::TOperationHandle)
    conn = session.conn
    request = thriftbuild(TCloseOperationReq, Dict(:operationHandle => handle))
    response = CloseOperation(conn.client, request)
    check_status(response.status)
end

cancel(pending::PendingResult) = cancel(pending.session, pending.handle)
cancel(resultset::ResultSet) = cancel(resultset.session, resultset.handle)
function cancel(session::HiveSession, handle::TOperationHandle)
    conn = session.conn
    request = thriftbuild(TCancelOperationReq, Dict(:operationHandle => handle))
    response = CancelOperation(conn.client, request)
    check_status(response.status)
end

function status(pending::PendingResult)
    if pending.status === nothing
        conn = pending.session.conn
        request = thriftbuild(TGetOperationStatusReq, Dict(:operationHandle => pending.handle))
        response = GetOperationStatus(conn.client, request)
        check_status(response.status)
        if response.operationState in READY_STATUS
            pending.status = response
        end
    end
    pending.status
end

const READY_STATUS = (TOperationState.FINISHED_STATE, TOperationState.CANCELED_STATE, TOperationState.CLOSED_STATE, TOperationState.ERROR_STATE)
const RESULT_STATUS = (TOperationState.FINISHED_STATE)
isready(::ResultSet) = true
isready(::RowCount) = true
isready(pending::PendingResult) = status(pending).operationState in READY_STATUS
hasresult(pending::PendingResult) = status(pending).operationState in RESULT_STATUS
function sqlerror(pending::PendingResult)
    isready(pending) || (return "")
    hasresult(pending) && (return "")
    response = pending.status
    sqlstate = isfilled(response, :sqlState) ? getfield(response, :sqlState) : ""
    errormessage = isfilled(response, :errorMessage) ? getfield(response, :errorMessage) : ""
    errorcode = isfilled(response, :errorCode) ? getfield(response, :errorCode) : Int32(0)
    "Error. $errormessage ($sqlstate, $errorcode)"
end

const SCHEMA_CACHE = Dict{Union{AbstractString,Symbol}, TTableSchema}()

function schema(rs::ResultSet; cached::Union{AbstractString,Symbol,Nothing}=nothing)
    if rs.schema === nothing
        if (cached !== nothing) && haskey(SCHEMA_CACHE, cached)
            sch = SCHEMA_CACHE[cached]
        else
            conn = rs.session.conn
            request = thriftbuild(TGetResultSetMetadataReq, Dict(:operationHandle => rs.handle))
            response = GetResultSetMetadata(conn.client, request)
            check_status(response.status)
            sch = response.schema
            (cached !== nothing) && (SCHEMA_CACHE[cached] = sch)
        end
        rs.schema = sch
    end
    rs.schema
end

# Fetch rows from the server corresponding to a particular OperationHandle.
fetchsize(rs::ResultSet) = rs.fetchsize
fetchsize!(rs::ResultSet, sz::Integer) = (rs.fetchsize = sz)

function fetchfirst(rs::ResultSet, nrows::Integer=rs.fetchsize)
    rs.position = 0
    fetchnext(rs, nrows)
end

function fetchnext(rs::ResultSet, nrows::Integer=rs.fetchsize)
    rs.eof && return nothing
    conn = rs.session.conn
    orientation = rs.position > 0 ? TFetchOrientation.FETCH_NEXT : TFetchOrientation.FETCH_FIRST
    request = thriftbuild(TFetchResultsReq, Dict(
        :operationHandle => rs.handle,
        :orientation => orientation,
        :maxRows => nrows))
    response = FetchResults(conn.client, request)
    check_status(response.status)

    rowset = response.results
    rs.rowset = rowset
    nfetched = 0
    if isfilled(rowset, :columns)
        onecol = rowset.columns[1]
        for fld in fieldnames(TColumn)
            if isfilled(onecol, fld)
                val = getfield(onecol, fld)
                nfetched = length(val.values)
            end
        end
    else
        nfetched = length(rowset.rows)
    end

    if nfetched > 0
        rs.position += nfetched
    else
        rs.eof = !response.hasMoreRows
    end

    rs
end

##
# Iterators
# - records, record iterator: fetches one record at a time as a tuple
# - tabulars, tabular iterator: fetches one batch of records at a time, returns a Tabular
# - tabular(tabular iterator): fetches and returns all data as one Tabular
# - columnchunks, columnchunks iterator: fetched one batch of records at a time, returns a vector of pairs of column names and data
# - columnchunk(columnchunks iterator): fetched and returns all data as one column chunk

struct ColumnChunksIterator
    rs::ResultSet

    function ColumnChunksIterator(rs::ResultSet, fetchsz::Integer=DEFAULT_FETCH_SIZE)
        fetchsize!(rs, fetchsz)
        new(rs)
    end
end

columnchunks(rs::ResultSet, fetchsz::Integer=DEFAULT_FETCH_SIZE) = ColumnChunksIterator(rs, fetchsz)
columnchunk(rs::ResultSet, fetchsz::Integer=DEFAULT_FETCH_SIZE) = columnchunk(ColumnChunksIterator(rs, fetchsz))
function columnchunk(iter::ColumnChunksIterator)
    iter_result = iterate(iter)
    if iter_result === nothing
        v0 = iter_result
    else
        v0, state = iter_result
        iter_result = iterate(iter, state)
        while iter_result !== nothing
            v1, state = iter_result
            v0 = [v0[idx][1]=>vcat(v0[idx][2], v1[idx][2]) for idx in 1:length(v0)]
            iter_result = iterate(iter, state)
        end
    end
    v0
end

iteratorsize(::Type{ColumnChunksIterator}) = Base.SizeUnknown()
function iterate(iter::ColumnChunksIterator, state_eof=iter.rs.eof)
    state_eof && (return nothing)

    rs = iter.rs
    fetchnext(rs)

    rowset = rs.rowset
    sch = schema(rs)
    ncols = length(sch.columns)
    cconvs = colconvfns(sch)

    if isfilled(rowset, :columns)
        @logmsg("reading columns")
        # ref: https://issues.apache.org/jira/browse/HIVE-3746
        colvecs = [julia_type(col, colconv) for (col,colconv) in zip(rowset.columns,cconvs)]
    else
        ctypes = coltypes(sch)
        colvecs = [data_with_missings(T[]) for T in ctypes]
        @logmsg("reading rows for coltypes: $(coltypes(sch))")
        for row in rowset.rows
            colidx = 1
            for col in row.colVals
                push!(colvecs[colidx], julia_type(col, cconvs[colidx]))
                colidx += 1
            end
        end
    end

    cc = [Symbol(sch.columns[colidx].columnName)=>colvecs[colidx] for colidx in 1:ncols]
    cc, rs.eof
end

struct TabularIterator
    cc::ColumnChunksIterator
    dispargs::Any

    function TabularIterator(rs::ResultSet, fetchsz::Integer=DEFAULT_FETCH_SIZE; kwargs...)
        new(ColumnChunksIterator(rs, fetchsz), kwargs)
    end
end

tabulars(rs::ResultSet, fetchsz::Integer=DEFAULT_FETCH_SIZE; kwargs...) = TabularIterator(rs, fetchsz; kwargs...)
tabular(rs::ResultSet, fetchsz::Integer=DEFAULT_FETCH_SIZE; kwargs...) = tabular(tabulars(rs, fetchsz; kwargs...))
function tabular(iter::TabularIterator)
    t = reduce(vcat, iter)
    close(iter.cc.rs)
    t
end

iteratorsize(::Type{TabularIterator}) = Base.SizeUnknown()
function iterate(iter::TabularIterator, state_eof=iter.cc.rs.eof)
    state_eof && (return nothing)
    cols,eof = iterate(iter.cc, state_eof)
    Tabular(cols; iter.dispargs...), eof
end

mutable struct RecordIterator
    cciter::ColumnChunksIterator
    ccpos::Int
    cc::Union{Nothing,Vector{Pair{Symbol,Vector}}}

    RecordIterator(rs::ResultSet) = new(ColumnChunksIterator(rs), 1, nothing)
end

records(rs::ResultSet) = RecordIterator(rs)

iteratorsize(::Type{RecordIterator}) = Base.SizeUnknown()
function iterate(iter::RecordIterator, state_eof=iter.cciter.rs.eof)
    state_eof && (return nothing)
    (nothing !== iter.cc) && (iter.ccpos > length(iter.cc[1][2])) && (return nothing)

    if (nothing === iter.cc) || (iter.ccpos > length(iter.cc[1][2]))
        cc, state_eof = iterate(iter.cciter, state_eof)
        iter.cc = cc
        iter.ccpos = 1
    else
        cc = iter.cc
    end
    recs = (iter.ccpos > length(cc[1][2])) ? nothing : tuple([col[2][iter.ccpos] for col in cc]...)
    iter.ccpos += 1
    recs, state_eof
end


text:
"""copy a FEFunction on a FE Space"""
clone_fe_function(space,f)=FEFunction(space,copy(get_free_dof_values(f)))

"""
 Given an arbitrary number of FEFunction arguments,
 returns a tuple with their corresponding free DoF Values
"""
function Gridap.get_free_dof_values(functions...)
  map(get_free_dof_values,functions)
end

function setup_mixed_spaces(model, order)
  reffe_rt  = ReferenceFE(raviart_thomas, Float64, order)
  V = FESpace(model, reffe_rt ; conformity=:HDiv)
  U = TrialFESpace(V)
  reffe_lgn = ReferenceFE(lagrangian, Float64, order)
  Q = FESpace(model, reffe_lgn; conformity=:L2)
  P = TrialFESpace(Q)
  reffe_lgn = ReferenceFE(lagrangian, Float64, order+1)
  S = FESpace(model, reffe_lgn; conformity=:H1)
  R = TrialFESpace(S)

  R, S, U, V, P, Q
end

function setup_and_factorize_mass_matrices(dΩ,
                                           R, S, U, V, P, Q;
                                           mass_matrix_solver=BackslashSolver())
  amm(a,b) = ∫(a⋅b)dΩ
  H1MM   = assemble_matrix(amm, R, S)
  RTMM   = assemble_matrix(amm, U, V)
  L2MM   = assemble_matrix(amm, P, Q)

  ssH1MM = symbolic_setup(mass_matrix_solver,H1MM)
  nsH1MM = numerical_setup(ssH1MM,H1MM)

  ssRTMM = symbolic_setup(mass_matrix_solver,RTMM)
  nsRTMM = numerical_setup(ssRTMM,RTMM)

  ssL2MM = symbolic_setup(mass_matrix_solver,L2MM)
  nsL2MM = numerical_setup(ssL2MM,L2MM)

  H1MM, RTMM, L2MM, nsH1MM, nsRTMM, nsL2MM
end

function new_vtk_step(Ω,file,_cellfields)
  n = size(_cellfields)[1]
  createvtk(Ω,
            file,
            cellfields=_cellfields,
            nsubcells=n)
end

max_stars_repo_name: santiagobadia/GridapGeosciences

max_issues_repo_name: santiagobadia/GridapGeosciences

max_forks_repo_name: santiagobadia/GridapGeosciences


text:
using Oracle.Timestamps

OraTimestamp(date::Date) = OraTimestamp(Dates.year(date), Dates.month(date), Dates.day(date), 0, 0, 0, 0, 0, 0)
OraTimestamp(datetime::DateTime) = OraTimestamp(Dates.year(datetime), Dates.month(datetime), Dates.day(datetime), Dates.hour(datetime), Dates.minute(datetime), Dates.second(datetime), Int64(Dates.millisecond(datetime)*1E6), 0, 0)

function OraTimestamp(ts::Timestamp)
    yy = Int16(Dates.year(ts))
    mm = UInt8(Dates.month(ts))
    dd = Dates.day(ts)
    hh = Dates.hour(ts)
    mi = Dates.minute(ts)
    ss = Dates.second(ts)
    fsecond = Dates.millisecond(ts) * 1_000_000 + Dates.microsecond(ts) * 1_000 + Dates.nanosecond(ts)
    return OraTimestamp(yy, mm, dd, hh, mi, ss, fsecond, 0, 0)
end

function OraTimestamp(ts::TimestampTZ)
    yy = Int16(Dates.year(ts))
    mm = UInt8(Dates.month(ts))
    dd = Dates.day(ts)
    hh = Dates.hour(ts)
    mi = Dates.minute(ts)
    ss = Dates.second(ts)
    fsecond = Dates.millisecond(ts) * 1_000_000 + Dates.microsecond(ts) * 1_000 + Dates.nanosecond(ts)
    return OraTimestamp(yy, mm, dd, hh, mi, ss, fsecond, ts.tz_offset.hour, ts.tz_offset.minute)
end

function parse_timestamp(oracle_type::OraOracleTypeNum, oracle_timestamp::OraTimestamp) :: Union{Dates.DateTime, Timestamp, TimestampTZ}
    if oracle_type == ORA_ORACLE_TYPE_DATE
        return parse_datetime(oracle_timestamp)
    elseif oracle_type == ORA_ORACLE_TYPE_TIMESTAMP
        return parse_timestamp(oracle_timestamp)
    elseif oracle_type == ORA_ORACLE_TYPE_TIMESTAMP_TZ
        return parse_timestamp_tz(oracle_timestamp)
    elseif oracle_type == ORA_ORACLE_TYPE_TIMESTAMP_LTZ
        return parse_timestamp_ltz(oracle_timestamp)
    else
        error("Unexpected oracle type for timestamp: $oracle_type.")
    end
end

function parse_datetime(ts::OraTimestamp) :: Dates.DateTime
    @assert ts.fsecond == 0
    @assert ts.tzHourOffset == 0
    @assert ts.tzMinuteOffset == 0
    return DateTime(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second)
end

function parse_timestamp(ts::OraTimestamp) :: Timestamp
    @assert ts.tzHourOffset == 0
    @assert ts.tzMinuteOffset == 0
    return Timestamp(ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.fsecond)
end

function parse_timestamp_tz(ts::OraTimestamp) :: TimestampTZ
    return TimestampTZ(false, ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.fsecond, ts.tzHourOffset, ts.tzMinuteOffset)
end

function parse_timestamp_ltz(ts::OraTimestamp) :: TimestampTZ
    return TimestampTZ(true, ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.second, ts.fsecond, ts.tzHourOffset, ts.tzMinuteOffset)
end


text:
log_temperature(t) = 1 / log(t)

constant_temperature(t) = 1.0

function default_neighbor!(x::AbstractArray{T}, x_proposal::AbstractArray) where T
    @assert size(x) == size(x_proposal)
    for i in 1:length(x)
        @inbounds x_proposal[i] = x[i] + T(randn()) # workaround because all types might not have randn
    end
    return
end

struct SimulatedAnnealing{Tn, Ttemp} <: ZerothOrderOptimizer
    neighbor!::Tn
    temperature::Ttemp
    keep_best::Bool # not used!?
end

"""
# SimulatedAnnealing
## Constructor
```julia
SimulatedAnnealing(; neighbor = default_neighbor!,
                     temperature = log_temperature,
                     keep_best::Bool = true)
```

The constructor takes 3 keywords:
* `neighbor = a!(x_proposed, x_current)`, a mutating function of the current `x`,
and the proposed `x`
* `T = b(iteration)`, a function of the current iteration that returns a temperature
* `p = c(f_proposal, f_current, T)`, a function of the current temperature, current
function value and proposed function value that returns an acceptance probability

## Description
Simulated Annealing is a derivative free method for optimization. It is based on the
Metropolis-Hastings algorithm that was originally used to generate samples from a
thermodynamics system, and is often used to generate draws from a posterior when doing
Bayesian inference. As such, it is a probabilistic method for finding the minimum of a
function, often over a quite large domains. For the historical reasons given above, the
algorithm uses terms such as cooling, temperature, and acceptance probabilities.
"""
SimulatedAnnealing(;neighbor = default_neighbor!,
                    temperature = log_temperature,
                    keep_best::Bool = true) =
  SimulatedAnnealing(neighbor, temperature, keep_best)

Base.summary(::SimulatedAnnealing) = "Simulated Annealing"

mutable struct SimulatedAnnealingState{Tx,T} <: ZerothOrderState
    x::Tx
    iteration::Int
    x_current::Tx
    x_proposal::Tx
    f_x_current::T
    f_proposal::T
end
# We don't have an f_x_previous in SimulatedAnnealing, so we need to special case these
pick_best_x(f_increased, state::SimulatedAnnealingState) = state.x
pick_best_f(f_increased, state::SimulatedAnnealingState, d) = value(d)

function initial_state(method::SimulatedAnnealing, options, d, initial_x::AbstractArray{T}) where T

    value!!(d, initial_x)

    # Store the best state ever visited
    best_x = copy(initial_x)
    SimulatedAnnealingState(copy(best_x), 1, best_x, copy(initial_x), value(d), value(d))
end

function update_state!(nd, state::SimulatedAnnealingState{Tx, T}, method::SimulatedAnnealing) where {Tx, T}

    # Determine the temperature for current iteration
    t = method.temperature(state.iteration)

    # Randomly generate a neighbor of our current state
    method.neighbor!(state.x_current, state.x_proposal)

    # Evaluate the cost function at the proposed state
    state.f_proposal = value(nd, state.x_proposal)

    if state.f_proposal <= state.f_x_current
        # If proposal is superior, we always move to it
        copyto!(state.x_current, state.x_proposal)
        state.f_x_current = state.f_proposal

        # If the new state is the best state yet, keep a record of it
        if state.f_proposal < value(nd)
            nd.F = state.f_proposal
            copyto!(state.x, state.x_proposal)
        end
    else
        # If proposal is inferior, we move to it with probability p
        p = exp(-(state.f_proposal - state.f_x_current) / t)
        if rand() <= p
            copyto!(state.x_current, state.x_proposal)
            state.f_x_current = state.f_proposal
        end
    end

    state.iteration += 1
    false
end


text:
# Autogenerated wrapper script for nlminb_jll for x86_64-unknown-freebsd-libgfortran3
export libnlminb

using CompilerSupportLibraries_jll
using OpenBLAS32_jll
JLLWrappers.@generate_wrapper_header("nlminb")
JLLWrappers.@declare_library_product(libnlminb, "libnlminb.so")
function __init__()
    JLLWrappers.@generate_init_header(CompilerSupportLibraries_jll, OpenBLAS32_jll)
    JLLWrappers.@init_library_product(
        libnlminb,
        "lib/libnlminb.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@generate_init_footer()
end  # __init__()


text:
using Test
using IncrementalInference

##

@testset "test generic functions on distributions" begin
##

@test getDimension(Uniform(0,1)) == 1
@test getDimension(Normal()) == 1
@test getDimension(MvNormal([1;1;0.1])) == 3

p = manikde!(ContinuousScalar, [randn(1) for i in 1:100])
@test getDimension(p) == 1

##
end


text:
code_dic = Dict()
code = []
open("day09/day09.in") do io
    line_num = 1
    global instructions
    for line in readlines(io)
        num = parse(Int64, line)
        code_dic[num] = line_num
        line_num += 1
        push!(code, num)
    end
end

check = 25
for num_pos in (check+1):length(code)
    num = code[num_pos]
    num_check = false
    for pos_back in 1:check
        pair_num = num - code[num_pos-pos_back]
        if get(code_dic, pair_num, 0) != 0 && (num_pos-pos_back <= code_dic[pair_num] <= num_pos-1)
            num_check = true
        end
    end
    if !num_check
        println(num)
    end
end

max_stars_repo_name: detrin/advent-of-code

max_issues_repo_name: detrin/advent-of-code

max_forks_repo_name: detrin/advent-of-code


text:
# [1] Pratt, William K., Digital Image Processing, New York, John Wiley & Sons, Inc., 1991, p. 634.
function measure_feature(property::Boundary, t::IndexedTable, labels::AbstractArray, N::Int = 0)
    fill_properties(property, t, labels)
end

function fill_properties(property::Boundary, t::IndexedTable, labels::AbstractArray)
    t = property.inner ? compute_inner_contour(t, labels) : t
    t = property.outer ? compute_outer_contour(t, labels) : t
end

function compute_inner_contour(t::IndexedTable, labels::AbstractArray)
    boundaries = trace_boundary(MooreInner(), labels)
    t = pushcol(t, :inner_boundary => boundaries)
end

function compute_outer_contour(t::IndexedTable, labels::AbstractArray)
    boundaries = trace_boundary(CostaOuter(), labels)
    t = pushcol(t, :outer_boundary => boundaries)
end


text:
CD = ComparisonDataset

# Test patch pasting
z = zeros(Int, 10, 10)
o = ones(Int, 2, 2)
CD.paste!(z, o, 4, 4)
@test z ==
[0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0
 0  0  0  1  1  0  0  0  0  0
 0  0  0  1  1  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0  0]
@test o == ones(2,2)
@test_throws BoundsError CD.paste!(z,o, -1, -1)
@test_throws BoundsError CD.paste!(z,o, 10, 10)
@test_throws BoundsError CD.paste!(o,z,1, 1)

# Test grow
a = [1 2 3
     4 5 6
     7 8 9]
@test CD.grow(a,2) ==
  [1 1 2 2 3 3
   1 1 2 2 3 3
   4 4 5 5 6 6
   4 4 5 5 6 6
   7 7 8 8 9 9
   7 7 8 8 9 9]

b = [1 2
     3 4]
@test CD.grow(b,3) ==
  [1 1 1 2 2 2
   1 1 1 2 2 2
   1 1 1 2 2 2
   3 3 3 4 4 4
   3 3 3 4 4 4
   3 3 3 4 4 4]

@test CD.grow(a, 1) == a
@test CD.grow(b, 1) == b
@test_throws AssertionError CD.grow(a, 0)

@testset "Patch" begin
  # Test patch generation
  p = CD.Patch(CD.Size(30,50),[0,1], 12, 13)
  @test CD.top(p) == 12
  @test CD.left(p) == 13
  @test CD.width(p) == 50
  @test CD.height(p) == 30
  @test CD.set(p) == Set([0,1])
  con = copy(CD.content(p))
  @test size(con) == (30,50)

  # Test random filling of patch
  rand!(p)
  @test CD.content(p) != con
  @test 1 ∈ CD.content(p)
  @test 0 ∈ CD.content(p)
  @test count(x->x==0, CD.content(p)) + count(x->x==1,CD.content(p)) == 30*50

  # Test random generation of patch
  rndp = rand(Patch, CD.Size(20,10), Set([0,1]), 2, 4)
  @test 0 ∈ CD.content(rndp)
  @test 1 ∈ CD.content(rndp)
  @test size(CD.content(rndp)) == (20, 10)
  rndp = rand(Patch, CD.Size(20,10), [0,1], 2, 4)
  @test 0 ∈ CD.content(rndp)
  @test 1 ∈ CD.content(rndp)
  @test size(CD.content(rndp)) == (20, 10)

  # Test flipping of elements of content
  con = copy(CD.content(p))
  CD.flip!(p,2)
  @test sum(con .!= CD.content(p)) == 2

  newpatch = CD.flip(p, 5)
  @test sum(CD.content(newpatch) .!= CD.content(p)) == 5
  @test CD.content(newpatch) !== CD.content(p)

  # Test equality
  mat = zeros(Int, 8,8)
  @test p != newpatch
  p1 = CD.Patch(mat,Set([0,1]), 12, 13)
  p2 = CD.Patch(mat,Set([0,1]), 12, 13)
  @test p1 == p2
  p2 = CD.Patch(mat,Set([0,1]), 12, 14)
  @test p1 != p2
  p2 = CD.Patch(mat,Set([0,1]), 11, 13)
  @test p1 != p2
  p2 = CD.Patch(mat,Set([1,1]), 12, 13)
  @test p1 != p2
  p2 = CD.Patch(mat,Set([0,0]), 12, 13)
  @test p1 != p2
  p2 = CD.Patch(zeros(Int, 8, 9),Set([0,1]), 12, 13)
  @test p1 != p2
  p2 = CD.Patch(zeros(Int, 9, 8),Set([0,1]), 12, 13)
  @test p1 != p2
  p2 = CD.Patch(ones(Int, 8, 8),Set([0,1]), 12, 13)
  @test p1 != p2
end


text:
Dict{Int32, String}(
    004 => "AF",
    248 => "AX",
    008 => "AL",
    012 => "DZ",
    016 => "AS",
    020 => "AD",
    024 => "AO",
    660 => "AI",
    010 => "AQ",
    028 => "AG",
    032 => "AR",
    051 => "AM",
    533 => "AW",
    036 => "AU",
    040 => "AT",
    031 => "AZ",
    044 => "BS",
    048 => "BH",
    050 => "BD",
    052 => "BB",
    112 => "BY",
    056 => "BE",
    084 => "BZ",
    204 => "BJ",
    060 => "BM",
    064 => "BT",
    068 => "BO",
    535 => "BQ",
    070 => "BA",
    072 => "BW",
    074 => "BV",
    076 => "BR",
    086 => "IO",
    096 => "BN",
    100 => "BG",
    854 => "BF",
    108 => "BI",
    132 => "CV",
    116 => "KH",
    120 => "CM",
    124 => "CA",
    136 => "KY",
    140 => "CF",
    148 => "TD",
    152 => "CL",
    156 => "CN",
    162 => "CX",
    166 => "CC",
    170 => "CO",
    174 => "KM",
    178 => "CG",
    180 => "CD",
    184 => "CK",
    188 => "CR",
    384 => "CI",
    191 => "HR",
    192 => "CU",
    531 => "CW",
    196 => "CY",
    203 => "CZ",
    208 => "DK",
    262 => "DJ",
    212 => "DM",
    214 => "DO",
    218 => "EC",
    818 => "EG",
    222 => "SV",
    226 => "GQ",
    232 => "ER",
    233 => "EE",
    748 => "SZ",
    231 => "ET",
    238 => "FK",
    234 => "FO",
    242 => "FJ",
    246 => "FI",
    250 => "FR",
    254 => "GF",
    258 => "PF",
    260 => "TF",
    266 => "GA",
    270 => "GM",
    268 => "GE",
    276 => "DE",
    288 => "GH",
    292 => "GI",
    300 => "GR",
    304 => "GL",
    308 => "GD",
    312 => "GP",
    316 => "GU",
    320 => "GT",
    831 => "GG",
    324 => "GN",
    624 => "GW",
    328 => "GY",
    332 => "HT",
    334 => "HM",
    336 => "VA",
    340 => "HN",
    344 => "HK",
    348 => "HU",
    352 => "IS",
    356 => "IN",
    360 => "ID",
    364 => "IR",
    368 => "IQ",
    372 => "IE",
    833 => "IM",
    376 => "IL",
    380 => "IT",
    388 => "JM",
    392 => "JP",
    832 => "JE",
    400 => "JO",
    398 => "KZ",
    404 => "KE",
    296 => "KI",
    408 => "KP",
    410 => "KR",
    414 => "KW",
    417 => "KG",
    418 => "LA",
    428 => "LV",
    422 => "LB",
    426 => "LS",
    430 => "LR",
    434 => "LY",
    438 => "LI",
    440 => "LT",
    442 => "LU",
    446 => "MO",
    807 => "MK",
    450 => "MG",
    454 => "MW",
    458 => "MY",
    462 => "MV",
    466 => "ML",
    470 => "MT",
    584 => "MH",
    474 => "MQ",
    478 => "MR",
    480 => "MU",
    175 => "YT",
    484 => "MX",
    583 => "FM",
    498 => "MD",
    492 => "MC",
    496 => "MN",
    499 => "ME",
    500 => "MS",
    504 => "MA",
    508 => "MZ",
    104 => "MM",
    516 => "NA",
    520 => "NR",
    524 => "NP",
    528 => "NL",
    540 => "NC",
    554 => "NZ",
    558 => "NI",
    562 => "NE",
    566 => "NG",
    570 => "NU",
    574 => "NF",
    580 => "MP",
    578 => "NO",
    512 => "OM",
    586 => "PK",
    585 => "PW",
    275 => "PS",
    591 => "PA",
    598 => "PG",
    600 => "PY",
    604 => "PE",
    608 => "PH",
    612 => "PN",
    616 => "PL",
    620 => "PT",
    630 => "PR",
    634 => "QA",
    638 => "RE",
    642 => "RO",
    643 => "RU",
    646 => "RW",
    652 => "BL",
    654 => "SH",
    659 => "KN",
    662 => "LC",
    663 => "MF",
    666 => "PM",
    670 => "VC",
    882 => "WS",
    674 => "SM",
    678 => "ST",
    682 => "SA",
    686 => "SN",
    688 => "RS",
    690 => "SC",
    694 => "SL",
    702 => "SG",
    534 => "SX",
    703 => "SK",
    705 => "SI",
    090 => "SB",
    706 => "SO",
    710 => "ZA",
    239 => "GS",
    728 => "SS",
    724 => "ES",
    144 => "LK",
    729 => "SD",
    740 => "SR",
    744 => "SJ",
    752 => "SE",
    756 => "CH",
    760 => "SY",
    158 => "TW",
    762 => "TJ",
    834 => "TZ",
    764 => "TH",
    626 => "TL",
    768 => "TG",
    772 => "TK",
    776 => "TO",
    780 => "TT",
    788 => "TN",
    792 => "TR",
    795 => "TM",
    796 => "TC",
    798 => "TV",
    800 => "UG",
    804 => "UA",
    784 => "AE",
    826 => "GB",
    840 => "US",
    581 => "UM",
    858 => "UY",
    860 => "UZ",
    548 => "VU",
    862 => "VE",
    704 => "VN",
    092 => "VG",
    850 => "VI",
    876 => "WF",
    732 => "EH",
    887 => "YE",
    894 => "ZM",
    716 => "ZW",
    typemax(Int32) => "MISSING"
)


text:
export WeightedMeasure, AbstractWeightedMeasure

"""
    struct WeightedMeasure{R,M} <: AbstractMeasure
        logweight :: R
        base :: M
    end
"""

abstract type AbstractWeightedMeasure <: AbstractMeasure end

logweight(μ::AbstractWeightedMeasure) = μ.logweight
basemeasure(μ::AbstractWeightedMeasure) = μ.base

@inline function logdensity(sm::AbstractWeightedMeasure, x)
    logdensity(sm.base, x) + sm.logweight
end

###############################################################################

struct WeightedMeasure{R,M} <: AbstractWeightedMeasure
    logweight::R
    base::M
end

basemeasure_type(::WeightedMeasure{R,M}) where {R,M} = M

function Base.show(io::IO, μ::WeightedMeasure)
    io = IOContext(io, :compact => true)
    print(io, exp(μ.logweight), " ⊙ ", μ.base)
end

function Base.show_unquoted(io::IO, μ::WeightedMeasure, indent::Int, prec::Int)
    io = IOContext(io, :compact => true)
    if Base.operator_precedence(:*) ≤ prec
        print(io, "(")
        show(io, μ)
        print(io, ")")
    else
        show(io, μ)
    end
    return nothing
end

function ⊙(k::T, m::AbstractMeasure) where {T<:Number}
    logk = log(k)
    return weightedmeasure(logk, m)
end

⊙(m::AbstractMeasure, k::Real) = k ⊙ m

weightedmeasure(ℓ, μ) = WeightedMeasure(ℓ, μ)


text:
using DSGE

# construct a model object
m = Model990()

# estimate as of 2015-Q3 using the default data vintage from 2015 Nov 27
m <= Setting(:data_vintage, "151127")
m <= Setting(:date_mainsample_end, quartertodate("2015-Q3"))

# reoptimize parameter vector, compute Hessian at mode, and full posterior
# parameter sampling
estimate(m)

# produce LaTeX tables of parameter moments
compute_moments(m)


text:
using RemPiO2
using Base.Test
import Base: TwicePrecision, convert

# Welcome to the Reduction Lab

# First
x = 0.32423423
out1 = RemPiO2.rem_pio2_kernel(x)
out2 = Base.Math.ieee754_rem_pio2(x)

@test out1[1] == out2[1]
@test out1[2].hi == out2[2][1]
@test out1[2].lo == out2[2][2]

using BenchmarkTools
nx = 10000
intervals = []
# Testing some important intervals and values around bad cases that need higher precision
for i = 1:9
    push!(intervals, linspace(-pi*i/4, -pi*(i-1)/4, nx))
    push!(intervals, linspace(pi*(i-1)/4, pi*i/4, nx))
end

#push!(intervals, linspace(-2.0^20, -pi*7/4, nx))
#push!(intervals, linspace(pi*7/4, 2.0^20, nx))
#push!(intervals, linspace(2.0^20, 2.0^60, nx))
#intervals = [intervals[end]]
time_my_rem = []
time_rem = []
function printheader()
    println("--"^29)
    println("Testing speed and accuracy of rempio2 in [-pi*9/4, pi*9/4]")
    println("Numbers below are elapsed time returned from @belapsed")
    println()
    println("Every number is checked between the two implementations")
    println("using a @test such that any difference results in termi-")
    println("nation of the program.")
    println()
    println("(1) -> New rempio2")
    println("(2) -> Old rempio2")
    println("(3) -> (1)/(2)")
    println()
    println("interval    (1)        (2)        (3)      ")
    println("-"^41)
end

for (i, inter) in enumerate(intervals)
    x = collect(inter)
    push!(time_my_rem, @belapsed RemPiO2.rem_pio2_kernel.($x))
    push!(time_rem, @belapsed Base.Math.ieee754_rem_pio2.($x))
    for _x in x
        out1 = RemPiO2.rem_pio2_kernel(_x)
        out2 = Base.Math.ieee754_rem_pio2(_x)
        @test out1[1] == out2[1]
        @test out1[2].hi == out2[2][1]
        @test out1[2].lo == out2[2][2]
    end
    i == 1 && println("Testing values in [-pi*9/4, pi*9/4]")
    i == 1 && printheader()
    @printf "%3.0d         %.5f    %.5f    %.5f\n" i time_my_rem[i] time_rem[i] time_my_rem[i]/time_rem[i]
end

intervals = []
push!(intervals, linspace(-2.0^5, -pi*9/4, nx))
push!(intervals, linspace(pi*9/4, 2.0^5, nx))
push!(intervals, linspace(2.0^5, 2.0^10, nx))
push!(intervals, linspace(-2.0^10, -2.0^5, nx))
push!(intervals, linspace(2.0^10, 2.0^15, nx))
push!(intervals, linspace(-2.0^15, -2.0^10, nx))
push!(intervals, linspace(2.0^20, 2.0^15, nx))
push!(intervals, linspace(-2.0^15, -2.0^20, nx))

println("Testing values in [-22.0^20, -pi*9/4] and [pi*9/4, 2.0^20]")
for (i, inter) in enumerate(intervals)
    x = collect(inter)
    push!(time_my_rem, @belapsed RemPiO2.rem_pio2_kernel.($x))
    push!(time_rem, @belapsed Base.Math.ieee754_rem_pio2.($x))
    for _x in x
        out1 = RemPiO2.rem_pio2_kernel(_x)
        out2 = Base.Math.ieee754_rem_pio2(_x)
        @test out1[1] == out2[1]
        @test out1[2].hi == out2[2][1]
        @test out1[2].lo == out2[2][2]
    end
    @printf "%3.0d         %.5f    %.5f    %.5f\n" i time_my_rem[i] time_rem[i] time_my_rem[i]/time_rem[i]
end

intervals = []
for i = 1:10
    push!(intervals, linspace(2.0^(20+(i-1)*5), 2.0^(20+i*5), nx))
    push!(intervals, linspace(-2.0^(20+(i-1)*5), -2.0^(20+i*5), nx))
end

println("Testing values in [-2.0^70, -pi*9/4] and [pi*9/4, 2.0^70]")
for (i, inter) in enumerate(intervals)
    x = collect(inter)
    push!(time_my_rem, @belapsed RemPiO2.rem_pio2_kernel.($x))
    push!(time_rem, @belapsed Base.Math.ieee754_rem_pio2.($x))
    for _x in x
        out1 = RemPiO2.rem_pio2_kernel(_x)
        out2 = Base.Math.ieee754_rem_pio2(_x)
#        @test out1[1] == out2[1]
#        @test out1[2].hi == out2[2][1]
#        @test out1[2].lo == out2[2][2]
        @test out1[2].hi+out1[2].lo == sum(out2[2])
    end
    @printf "%3.0d         %.5f    %.5f    %.5f\n" i time_my_rem[i] time_rem[i] time_my_rem[i]/time_rem[i]
end

intervals = []
for i = 1:2
    push!(intervals, linspace(2.0^(1023-(i-1)*5), 2.0^(1023-i*5), nx))
    push!(intervals, linspace(-2.0^(1023-(i-1)*5), -2.0^(1023-i*5), nx))
end

println("Testing values in [-2.0^1023, -2.0^(1023-10)] and [2.0^(1023-10), 2.0^1023]")
for (i, inter) in enumerate(intervals)
    x = collect(inter)
    push!(time_my_rem, @belapsed RemPiO2.rem_pio2_kernel.($x))
    push!(time_rem, @belapsed Base.Math.ieee754_rem_pio2.($x))
    for _x in x
        out1 = RemPiO2.rem_pio2_kernel(_x)
        out2 = Base.Math.ieee754_rem_pio2(_x)
#        @test out1[1] == out2[1]
#        @test out1[2].hi == out2[2][1]
#        @test out1[2].lo == out2[2][2]
        @test out1[2].hi+out1[2].lo == sum(out2[2])
    end
    @printf "%3.0d         %.5f    %.5f    %.5f\n" i time_my_rem[i] time_rem[i] time_my_rem[i]/time_rem[i]
end

x = intervals[1][1]
xʰ = RemPiO2.highword(x)
# positive part of highword
xʰ⁺ = xʰ&0x7fffffff
RemPiO2.rem_pio2_kernel(x, xʰ, xʰ⁺)

# Additional notes:
# - worst case (Muller et al, 2005, p 183) is x = 6381956970095103.0 * 2.0^797
#   for which abs(rem(x,π/2, RoundNearest)) ≥ 2^-60.9
# - error of w is ~ 2^-128
# - error of f is ~ 2^-126
# - error of z is ~ |z|*2^-(53+26) + 2^-126
# - error of y is ~ 3*|y|*2^-(53+26) + 1.6*2^-126
# (TODO: check these)
# Total error ~ 2^-12 ulps

function rem_pio2(x::BigFloat)
    setprecision(BigFloat, 4096)
    rem(big(x), big(pi)/big(2), RoundNearest)
end
function big_to_hilo(x::BigFloat)
    hi = convert(Float64, x)
    lo = convert(Float64, x - hi)
    Base.TwicePrecision(hi, lo)
end

function convert(::Type{TwicePrecision{Float64}}, x::BigFloat)
    hi = convert(Float64, x)
    lo = convert(Float64, x - hi)
    Base.TwicePrecision(hi, lo)
end

x = 3.334234234
bigy = rem_pio2(big(x))
bigytp = convert(TwicePrecision{Float64}, bigy)
newy = RemPiO2.rem_pio2(x)
oldy = Base.Math.ieee754_rem_pio2(x)
oldytp = (oldy[1], TwicePrecision(oldy[2]...))

using Openlibm
Openlibm.sin(big_to_hilo(big(x)))


text:
include("lib/PolelikeCoordinate.jl")
include("lib/BasicMatrixOperators.jl")
include("lib/AdvancedMatrixOperators.jl")
include("lib/Pop2Coord.jl")
include("lib/MapTransform.jl")

using ArgParse, JSON
using NCDatasets
using Formatting
using .PolelikeCoordinate
using SparseArrays: spdiagm

missing2nan  = (x,) -> nomissing(x, NaN)
missing2zero = (x,) -> nomissing(x, 0.0)

function parse_commandline()

    s = ArgParseSettings()
    @add_arg_table s begin

        "--input-dir"
            help = "Input directory"

        "--input-files"
            help = "Input files delimited by comma."
            arg_type = String
            required = true

        "--output-dir"
            help = "Output directory."
            arg_type = String
            required = true

        "--domain-file"
            help = "Domain file."
            arg_type = String
            required = true

        "--Ekman-layers"
            help = "Number of layers that is Ekman velocity."
            arg_type = Int64
            required = true

        "--total-layers"
            help = "Number of layers summing Ekman layers and return flow layers."
            arg_type = Int64
            required = true

        "--ref-file"
            help = "File containing coordinate."
            arg_type = String
            default = ""

    end

    return parse_args(ARGS, s)
end

if ! isdefined(Main, :parsed)
    parsed = parse_commandline()
end

print(json(parsed, 4))

input_files = split(parsed["input-files"], ",")
sub_zrng = 1:40

if parsed["ref-file"] == ""
    ref_file = joinpath(parsed["input-dir"], input_files[1])
else
    ref_file = parsed["ref-file"]
end

Dataset(ref_file, "r") do ds

    TEMP   = rearrangePOP2Grid(ds["TEMP"][:, :, sub_zrng, :]  |> missing2nan,  :T; has_time=true)
    H_T    = rearrangePOP2Grid(ds["HT"][:] |> missing2zero, :T; has_time=false) / 100.0

    z_w_top = - ds["z_w_top"][sub_zrng] / 100.0 |> missing2nan
    z_w_bot = - ds["z_w_bot"][sub_zrng] / 100.0 |> missing2nan

    global Nz, Nx, Ny, _ = size(TEMP)
    global z_w = zeros(Float64, Nz+1)
    z_w[1:end-1] = z_w_top
    z_w[end] = z_w_bot[end]

    global mask_T    = zeros(Float64, Nz, Nx, Ny)
    mask_T[isfinite.(view(TEMP, :, :, :, 1))] .= 1.0

    global mask_T_inactive_idx = (mask_T .== 0.0)

    invH_T = H_T.^(-1.0)
    invH_T[isinf.(invH_T) .| isnan.(invH_T)] .= 0.0
    global T_invH_T = spdiagm( 0 => invH_T[:] )

    # Integration in different ocean
    REGION_MASK = rearrangePOP2Grid((ds["REGION_MASK"][:]*1.0) |> missing2nan, :T; has_time=false)

    global mask_ATL_sT = REGION_MASK * 0.0
    global mask_ATL_sT[REGION_MASK .>= 6] .= 1

    global mask_INDPAC_sT = REGION_MASK * 0.0
    global mask_INDPAC_sT[(REGION_MASK .<= 4) .& (REGION_MASK .>= 2)] .= 1

end

println("Loading MapInfo")
grid_file = PolelikeCoordinate.CurvilinearSphericalGridFile(
    parsed["domain-file"];
    R  = 6371229.0,
    Ω  = 2π / (86400 / (1 + 365/365)),
)

println("Making slab grid")
gd_slab = PolelikeCoordinate.genGrid(
    grid_file,
    [0, -1.0];  # fake z_w grid
)

println("Making 3D sub_zrng grid")
gd = PolelikeCoordinate.genGrid(
    grid_file,
    z_w, #, -2.0];  # fake z_w grid
)

println("Test if slab AMO is there")
if ! isdefined(Main, :amo_slab)
    println("Construct slab AMO")
    @time amo_slab = AdvancedMatrixOperators(;
        gd = gd_slab,
        mask_T = mask_T[1:1, :, :],
    )
end
println("Slab AMO and BMO constructed")

println("Test if 3D AMO sub_zrng is there")
if ! isdefined(Main, :amo)
    println("Construct AMO")
    @time amo = AdvancedMatrixOperators(;
        gd = gd,
        mask_T = mask_T,
    )
end
println("3D AMO and BMO constructed")

println("Setup Ekman transport configuration")
# Ekman transport setup
ϵ_uv = ones(Float64, Nx, Ny+1) * 1e-5
f_uv = 2 * gd.Ω * sin.(gd.ϕ_UV[1, :, :])
β_uv = 2 * gd.Ω * cos.(gd.ϕ_UV[1, :, :]) / gd.R

ρ0 = 1026.0
cp = 3996.0
ρ0s2 = ρ0 * (ϵ_uv.^2.0 + f_uv.^2.0)

#Nlayers_Ek = 5
Nlayers_Ek = parsed["Ekman-layers"]
Nlayers_Rt = parsed["total-layers"] - Nlayers_Ek  # 1000m

H_Ek = z_w[1] - z_w[Nlayers_Ek+1]
H_Rt = z_w[Nlayers_Ek+1] - z_w[Nlayers_Ek+Nlayers_Rt+1]
H = H_Ek + H_Rt
println(format("H_Ek = {:.1f} m", H_Ek))
println(format("H_Rt = {:.1f} m", H_Rt))
println(format("H = H_Ek + H_Rt =  {:.1f} m", H))

# Setup masks of U and V to forbid flow if the ocean is not deep enough
noflowmask_T = sum(mask_T, dims=1)
noflowmask_T[noflowmask_T .< (Nlayers_Rt+Nlayers_Ek)] .= 0.0
noflowmask_T[noflowmask_T .!= 0.0] .= 1.0
noflowmask_T = repeat(noflowmask_T, outer=(Nz, 1, 1))
noflowmask_T = noflowmask_T .* mask_T

V_noflowmask_V = spdiagm( 0 => (amo.bmo.V_N_T * noflowmask_T[:]) .* (amo.bmo.V_S_T * noflowmask_T[:]) )
U_noflowmask_U = spdiagm( 0 => (amo.bmo.U_E_T * noflowmask_T[:]) .* (amo.bmo.U_W_T * noflowmask_T[:]) )

rshp_T = (arr,) -> reshape(arr , Nz, Nx, Ny)
rshpt_T = (arr,) -> reshape(arr , Nz, Nx, Ny, 1)

println("Setup additional operator for streamfunction")

m = mask_T[1, :, :][:]
ψmo = (
    UV_clean_UV = spdiagm( 0 =>
           (amo_slab.bmo.UV_SW_T * m)
        .* (amo_slab.bmo.UV_SE_T * m)
        .* (amo_slab.bmo.UV_NW_T * m)
        .* (amo_slab.bmo.UV_NE_T * m)
    ),
    U_δy_UV = amo_slab.U_mask_U * (amo_slab.bmo.U_S_UV  - amo_slab.bmo.U_N_UV),
    V_δx_UV = amo_slab.V_mask_V * (amo_slab.bmo.V_W_UV  - amo_slab.bmo.V_E_UV),
    T_δx_U = amo_slab.T_mask_T * (amo_slab.bmo.T_W_U  - amo_slab.bmo.T_E_U  ) ,
    T_δy_V = amo_slab.T_mask_T * (amo_slab.bmo.T_S_V  - amo_slab.bmo.T_N_V  ) ,
)

# Setup tools to compute heat transport
lat_v = range(-90.0, 90.0, length=181) |> collect
lat_t = (lat_v[1:end-1] + lat_v[2:end]) / 2.0
σ_sT  = gd.Δx_T[1, :, :] .* gd.Δy_T[1, :, :]
r = MapTransform.Relation(;
    lat     = rad2deg.(gd.ϕ_T[1, :, :]),
    area    = σ_sT,
    mask    = grid_file.mask,
    lat_bnd = lat_v,
)

r_ATL = MapTransform.Relation(;
    lat     = rad2deg.(gd.ϕ_T[1, :, :]),
    area    = σ_sT,
    mask    = mask_ATL_sT,
    lat_bnd = lat_v,
)

r_INDPAC = MapTransform.Relation(;
    lat     = rad2deg.(gd.ϕ_T[1, :, :]),
    area    = σ_sT,
    mask    = mask_INDPAC_sT,
    lat_bnd = lat_v,
)

function main(
    input_file :: String,
    output_file :: String,
)

    local SHF, ADVT, TEMP, Kh, τx_uv, τy_uv, HOR_DIFF, VVEL, UVEL, BSF
    global sub_zrng

    # Load Domain, T, S, wind stress
    Dataset(input_file, "r") do ds
        TEMP   = rearrangePOP2Grid(ds["TEMP"][:, :, sub_zrng, :]  |> missing2zero,  :T;  has_time=true)
        BSF    = rearrangePOP2Grid(ds["BSF"][:]  |> missing2zero,  :UV; has_time=true) * 1e6
        SHF    = rearrangePOP2Grid(ds["SHF"][:]   |> missing2zero,  :T;  has_time=true) * 1.0
        ADVT   = rearrangePOP2Grid(ds["ADVT"][:]  |> missing2zero,  :T;  has_time=true) * 0.01
        τx_uv  = rearrangePOP2Grid(ds["TAUX"][:]  |> missing2zero,  :UV; has_time=true) * (-1.0 / 10.0)
        τy_uv  = rearrangePOP2Grid(ds["TAUY"][:]  |> missing2zero,  :UV; has_time=true) * (-1.0 / 10.0)
        view(TEMP, :, :, :, 1)[mask_T_inactive_idx] .= 0.0

        τx_uv = τx_uv[:, :, 1]
        τy_uv = τy_uv[:, :, 1]

        HOR_DIFF   = rearrangePOP2Grid(ds["HOR_DIFF"][:, :, sub_zrng, :] |> missing2zero,  :T; has_time=true) / 1e4
    end

    TEMP_T = view(TEMP, :)

    # Compute Ekman flow
    # ∇×τ

    curlτ_uv = reshape(amo_slab.UV_interp_V * amo_slab.V_∂x_UV * view(τy_uv,:) - amo_slab.UV_interp_U * amo_slab.U_∂y_UV * view(τx_uv,:), Nx, Ny+1)

    τeast_uv, τnorth_uv = PolelikeCoordinate.project(gd, τx_uv, τy_uv; direction=:Backward, grid=:UV)
    volflx_east_uv  = τeast_uv * 0.0
    volflx_north_uv = (- f_uv .* τeast_uv + (ϵ_uv.^2) .* curlτ_uv ./ β_uv) ./ ρ0s2

    volflx_x, volflx_y = PolelikeCoordinate.project(gd, volflx_east_uv, volflx_north_uv; direction=:Forward, grid=:UV)

    τeast_t  = reshape(amo_slab.T_interp_UV * τeast_uv[:], Nx, Ny)
    τnorth_t = reshape(amo_slab.T_interp_UV * τnorth_uv[:], Nx, Ny)

    # Codron
    #volflx_x = (ϵ_uv .* τx_uv + f_uv .* τy_uv) ./ ρ0s2
    #volflx_y = (ϵ_uv .* τy_uv - f_uv .* τx_uv) ./ ρ0s2

    u_UV = zeros(Float64, Nz, Nx, Ny+1)
    v_UV = zeros(Float64, Nz, Nx, Ny+1)

    for k=1:Nlayers_Ek
        u_UV[k, :, :] = volflx_x / H_Ek
        v_UV[k, :, :] = volflx_y / H_Ek
    end

    for k=(Nlayers_Ek+1):(Nlayers_Ek+Nlayers_Rt)
        u_UV[k, :, :] = - volflx_x / H_Rt
        v_UV[k, :, :] = - volflx_x / H_Rt
    end

    u_U = U_noflowmask_U * amo.U_interp_UV * u_UV[:]
    v_V = V_noflowmask_V * amo.V_interp_UV * v_UV[:]

    TEMP_U = amo.U_interp_T * TEMP_T
    TEMP_V = amo.V_interp_T * TEMP_T

    uT_U = u_U .* TEMP_U
    vT_V = v_V .* TEMP_V

    # Compute Ekman heat convergence
    TEMPconvx_T = amo.T_DIVx_U * uT_U
    TEMPconvy_T = amo.T_DIVy_V * vT_V
    TEMPconvh_T = TEMPconvx_T + TEMPconvy_T

    # Check if we have convergence in masked
    if any(rshp_T(TEMPconvx_T)[noflowmask_T .== 0] .!= 0)
        throw(ErrorException("Please check mask TEMPconvx_T"))
    end

    if any(rshp_T(TEMPconvy_T)[noflowmask_T .== 0] .!= 0)
        throw(ErrorException("Please check mask TEMPconvy_T"))
    end

    ∫_TEMPconvh_dz_sT = sum(rshpt_T( amo.T_Δz_T * TEMPconvh_T ), dims=1)[1, :, :, :]

    # Compute Ekman divergence for testing
    Conv_Vol_t = permutedims(rshpt_T(amo.T_DIVx_U * u_U + amo.T_DIVy_V * v_V), [2,3,1,4])

    Conv_Ek_t    = reshape(  MapTransform.transform(r, view(∫_TEMPconvh_dz_sT, :, :, 1)) * ρ0 * cp, :, 1)
    OHT_Ek_v     = reshape(- MapTransform.∫∂a(r, view(∫_TEMPconvh_dz_sT, :, :, 1)) * ρ0 * cp,       :, 1)
    OHT_ADVT_v  = reshape(- MapTransform.∫∂a(r, view(ADVT, :, :, 1)) * ρ0 * cp,                    :, 1)
    SHF_t  = reshape(  MapTransform.transform(r, view(SHF, :, :, 1)),                         :, 1)
    OHT_SHF_v   = reshape(- MapTransform.∫∂a(r, view(SHF, :, :, 1)),                               :, 1)

    # External Mode (Barotropic gyre)
    # first, compute vertical mean temperature
    TEMPm_sT = T_invH_T * sum(reshape( amo.T_Δz_T * TEMP_T, Nz, Nx, Ny), dims=1)[:]
    TEMPm_sU = amo_slab.U_interp_T * TEMPm_sT
    TEMPm_sV = amo_slab.V_interp_T * TEMPm_sT

    # in m^3/s
    BSF = ψmo.UV_clean_UV * BSF[:]
    uBTFlux_sU = - ψmo.U_δy_UV * BSF
    vBTFlux_sV =   ψmo.V_δx_UV * BSF

    # special, due to the definition of BSF, we use δ instead of DIV
    BTConv_sT = - ( amo_slab.T_invΔx_T * amo_slab.T_invΔy_T *
                      ( ψmo.T_δy_V * (vBTFlux_sV .* TEMPm_sV)
                      + ψmo.T_δx_U * (uBTFlux_sU .* TEMPm_sU) )) * ρ0 * cp

    BTConv_sT = reshape(BTConv_sT, Nx, Ny)

    Conv_BT_t = reshape(   MapTransform.transform(r, BTConv_sT), :, 1)
    OHT_BT_v  = reshape( - MapTransform.∫∂a(r, BTConv_sT), :, 1)

    # Horizontal diffusion
    U_Kh_U = spdiagm(0 => amo.U_mask_U * amo.U_interp_T * view(HOR_DIFF, :))
    V_Kh_V = spdiagm(0 => amo.V_mask_V * amo.V_interp_T * view(HOR_DIFF, :))

    TEMP_HDIFF_conv_T =  ( amo.T_DIVx_U * U_Kh_U * amo.U_∂x_T
                         + amo.T_DIVy_V * V_Kh_V * amo.V_∂y_T ) * TEMP_T

    ∫_TEMP_HDIFF_conv_dz_sT = sum(rshpt_T( amo.T_Δz_T * TEMP_HDIFF_conv_T ), dims=1)[1, :, :, :]
    Conv_DIFF_t = reshape(   MapTransform.transform(r, view(∫_TEMP_HDIFF_conv_dz_sT, :, :, 1)) * ρ0 * cp, :, 1)
    OHT_DIFF_v  = reshape( - MapTransform.∫∂a(r, view(∫_TEMP_HDIFF_conv_dz_sT, :, :, 1)) * ρ0 * cp,       :, 1)

    # convert wind field
    τeast_latT  = reshape( MapTransform.transform(r, τeast_t), :, 1)
    τnorth_latT = reshape( MapTransform.transform(r, τnorth_t), :, 1)

    # Regional integration

    ATL_OHT_Ek_v       = reshape(- MapTransform.∫∂a(r_ATL, view(∫_TEMPconvh_dz_sT, :, :, 1); zero_point=:end) * ρ0 * cp,       :, 1)
    ATL_OHT_ADVT_v     = reshape(- MapTransform.∫∂a(r_ATL, view(ADVT, :, :, 1); zero_point=:end) * ρ0 * cp,                    :, 1)
    ATL_OHT_BT_v       = reshape(- MapTransform.∫∂a(r_ATL, BTConv_sT; zero_point=:end), :, 1)

    INDPAC_OHT_Ek_v    = reshape(- MapTransform.∫∂a(r_INDPAC, view(∫_TEMPconvh_dz_sT, :, :, 1); zero_point=:end) * ρ0 * cp,       :, 1)
    INDPAC_OHT_ADVT_v  = reshape(- MapTransform.∫∂a(r_INDPAC, view(ADVT, :, :, 1); zero_point=:end) * ρ0 * cp,                    :, 1)
    INDPAC_OHT_BT_v    = reshape(- MapTransform.∫∂a(r_INDPAC, BTConv_sT; zero_point=:end), :, 1)

    Dataset(output_file, "c") do ds

        defDim(ds, "nlon", Nx)
        defDim(ds, "nlat", Ny)
        defDim(ds, "nlatp1", Ny+1)
        defDim(ds, "z_t", Nz)
        defDim(ds, "lat_t", length(lat_t))
        defDim(ds, "lat_v", length(lat_v))
        defDim(ds, "time", Inf)

        for (varname, vardata, vardim, attrib) in [
            ("lat_v", lat_v,  ("lat_v", ), Dict()),
            ("lat_t", lat_t,  ("lat_t", ), Dict()),
            ("int_TEMPconvh_dz_sT", ∫_TEMPconvh_dz_sT, ("nlon", "nlat", "time"), Dict()),
            ("int_TEMP_HDIFF_conv_dz_sT", ∫_TEMP_HDIFF_conv_dz_sT, ("nlon", "nlat", "time"), Dict()),
            ("Conv_Vol_t",    Conv_Vol_t,  ("nlon", "nlat", "z_t", "time"), Dict()),
            ("Conv_Ek_t",     Conv_Ek_t,   ("lat_t", "time",), Dict()),
            ("Conv_DIFF_t",   Conv_DIFF_t, ("lat_t", "time",), Dict()),
            ("Conv_BT_t",     Conv_BT_t,   ("lat_t", "time",), Dict()),
            ("SHF_t",         SHF_t,       ("lat_t", "time",), Dict()),
            ("OHT_Ek_v",      OHT_Ek_v,    ("lat_v", "time",), Dict()),
            ("OHT_DIFF_v",    OHT_DIFF_v,  ("lat_v", "time",), Dict()),
            ("OHT_BT_v",      OHT_BT_v,    ("lat_v", "time",), Dict()),
            ("OHT_ADVT_v",    OHT_ADVT_v,  ("lat_v", "time",), Dict()),
            ("OHT_SHF_v",     OHT_SHF_v,   ("lat_v", "time",), Dict()),

            ("ATL_OHT_Ek_v",      ATL_OHT_Ek_v,    ("lat_v", "time",), Dict()),
            ("ATL_OHT_BT_v",      ATL_OHT_BT_v,    ("lat_v", "time",), Dict()),
            ("ATL_OHT_ADVT_v",    ATL_OHT_ADVT_v,  ("lat_v", "time",), Dict()),

            ("INDPAC_OHT_Ek_v",   INDPAC_OHT_Ek_v,    ("lat_v", "time",), Dict()),
            ("INDPAC_OHT_BT_v",   INDPAC_OHT_BT_v,    ("lat_v", "time",), Dict()),
            ("INDPAC_OHT_ADVT_v", INDPAC_OHT_ADVT_v,  ("lat_v", "time",), Dict()),

            ("taueast_t",  τeast_latT,  ("lat_t", "time",), Dict()),
            ("taunorth_t", τnorth_latT, ("lat_t", "time",), Dict()),
        ]
            println("Doing varname:", varname)
            var = defVar(ds, varname, Float64, vardim)
            var.attrib["_FillValue"] = 1e20

            for (k, v) in attrib
                var.attrib[k] = v
            end

            rng = []
            for i in 1:length(vardim)
                push!(rng, UnitRange(1, size(vardata)[i]))
            end

            var[rng...] = vardata[rng...]

        end

    end
end

for (i, input_file) in enumerate(input_files)

    local output_file

    println("Doing file: ", input_file)
    output_file = format("processed_{:s}", input_file)
    main(
        joinpath(parsed["input-dir"], input_file),
        joinpath(parsed["output-dir"], output_file),
    )

    println("Generate: ", joinpath(parsed["output-dir"], output_file))

end

max_stars_repo_name: meteorologytoday/IOM

max_issues_repo_name: meteorologytoday/IOM

max_forks_repo_name: meteorologytoday/IOM


text:
# ] activate "I:\My Documents\00 AFIT\Research\Julia Projects\StrategyGames"
# Sequence-form Kuhn Poker
# G = (N, Σ, g, C)

# Useful extensive-form websites:
# https://cw.fel.cvut.cz/old/_media/courses/be4m36mas/6.pdf

using Pkg; Pkg.activate(pwd())
using JuMP, Clp
using LinearAlgebra

# using Convex, SCS
# const cvx = Convex
# vals = [5.0, 3.0, 1.0]
# q = [0.1, 0.2, 0.7]
# del = 0.2

# take = cvx.Variable(3)
# p = cvx.Variable(3)
# obj = sum(vals[i] * take[i] * p[i] for i = 1:3)
# c1 = sum(p) == 1
# c2 = p >= 0
# c3 = take >= 0
# c4 = take <= 1
# c5 = -sum(q[i] * log(p[i] / q[i]) for i in 1:length(q)) <= del
# constraints = [c1, c2, c3, c4, c5]
# problem = maximize(obj, constraints)
# solve!(problem)
# problem.status
# problem.optval
#
# m = Model(solver = SCSSolver())
#
# @variable(m, 0 <= take[1:3] <= 1)
# @variable(m, p[1:3] >= 0)
# @objective(m, Max, sum(vals[i] * take[i] * p[i] for i = 1:3))
# @constraint(m, sum(p) == 1)
# @constraint(m, -sum(q[i] * log(p[i] / q[i]) for i in 1:length(q)) <= del)
# solve(m)
# println(getvalue(take))

#################################
# Game Definition

# N : player indices
# Two-player, nature not included
N = [1, 2]

# I : information sets
I1 = ["JX", "QX", "KX",
      "JX-check1-bet2", "QX-check1-bet2", "KX-check1-bet2"]
I11 = view(I1, 1:3)
I12 = view(I1, 4:6)
I2 = ["XJ-check1", "XJ-bet1", "XQ-check1", "XQ-bet1", "XK-check1", "XK-bet1"]
I = (I1, I2)

# Σ : sequences
Σ1 = ["∅",
      "JX-check1", "JX-bet1", "QX-check1", "QX-bet1", "KX-check1", "KX-bet1",
      "JX-check1-fold1", "JX-check1-call1", "QX-check1-fold1", "QX-check1-call1", "KX-check1-fold1", "KX-check1-call1"]
Σ2 = ["∅",
      "XJ-check2", "XJ-bet2", "XJ-fold2", "XJ-call2",
      "XQ-check2", "XQ-bet2", "XQ-fold2", "XQ-call2",
      "XK-check2", "XK-bet2", "XK-fold2", "XK-call2",]
Σ = (Σ1, Σ2)

# g : payoff function
g = [0 0 0 0 0 0 0 0 0 0 0 0 0;
     0 0 0 0 0 -1 0 0 0 -1 0 0 0;
     0 0 0 0 0 0 0 1 -2 0 0 1 -2;
     0 1 0 0 0 0 0 0 0 -1 0 0 0;
     0 0 0 1 2 0 0 0 0 0 0 1 -2;
     0 1 0 0 0 1 0 0 0 0 0 0 0;
     0 0 0 1 2 0 0 1 2 0 0 0 0;
     0 0 0 0 0 0 -1 0 0 0 -1 0 0;
     0 0 0 0 0 0 -2 0 0 0 -2 0 0;
     0 0 -1 0 0 0 0 0 0 0 -1 0 0;
     0 0 2 0 0 0 0 0 0 0 -2 0 0;
     0 0 -1 0 0 0 -1 0 0 0 0 0 0;
     0 0 2 0 0 0 2 0 0 0 0 0 0]

 # probability of each branch
 p = 1/6

 #################################
 # Best Response

## r2 : player 2 model
r2 = [1.0,
      2/3, 1/3, 1, 0,
      1, 0, 2/3, 1/3,
      0, 1, 0, 1]

## best response model
ns1 = length(Σ1)
m = Model(Clp.Optimizer)
@variable(m, r[1:ns1] >= 0)
@objective(m, Max, sum(sum(g[s1, s2] * p * r2[s2] for s2 = 1:13) * r[s1] for s1 = 1:13))
@constraint(m, r[1] == 1.0)
@constraint(m, r[2] + r[3] == r[1])
@constraint(m, r[4] + r[5] == r[1])
@constraint(m, r[6] + r[7] == r[1])
@constraint(m, r[8] + r[9] == r[2])
@constraint(m, r[10] + r[11] == r[4])
@constraint(m, r[12] + r[13] == r[6])
# print(m)
optimize!(m)
println("Objective value: ", objective_value(m))
println("r = ", JuMP.value.(r))

# above answer: α = 1.0
# correct ansewr: α ∈ [0, 1/3]

strategy1 = hcat(Σ1, value.(r))
strategy2 = hcat(Σ2, r2)

val = dot(fill(p, 6), [0, -2, 1/3, -1, 1, 4/3])

function gval(strat::Vector{Float64})
    sum(sum(g[s1, s2] * (1/6) * r2[s2] for s2 = 1:13) * strat[s1] for s1 = 1:13)
end
α = 1/3
rNE = [1.0, 1 - α, α, 1, 0, 1 - 3α, 3α, 2/3, 0, 2/3 - α, 1/3 + α, 0, 0]
strategyNE = hcat(Σ1, rNE)
gval(rNE)
gval(JuMP.value.(r))

tab = hcat(1:13,strategyNE,1:13,strategy1,1:13,strategy2)

# strategy 1 is a best response but not a NE (i.e. multiple player 1 strategies
# have the same value, but only some of those are NE)
# 13×3 Array{Any,2}:
#   1  "∅"                 1.0
#   2  "JX-check1"        -0.0
#   3  "JX-bet1"           1.0
#   4  "QX-check1"         1.0
#   5  "QX-bet1"           0.0
#   6  "KX-check1"        -0.0
#   7  "KX-bet1"           1.0
#   8  "JX-check1-fold1"   0.0
#   9  "JX-check1-call1"   0.0
#  10  "QX-check1-fold1"   1.0
#  11  "QX-check1-call1"   0.0
#  12  "KX-check1-fold1"   0.0
#  13  "KX-check1-call1"   0.0

#################################
# Nash  Equilibrium

## Nash Equilibrium Solver
ns2 = length(Σ2)
ni1 = length(I1)
mne = Model(Clp.Optimizer)
@variable(mne, r2[1:ns2] >= 0)
@variable(mne, v1[1:ni1])
@variable(mne, v0)
@objective(mne, Min, v0)
@constraint(mne, val1, v0 - (v1[1] + v1[2] + v1[3]) >= sum(g[1, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, val2, v1[1] - v1[4] >= sum(g[2, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, val3, v1[1] >= sum(g[3, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, val4, v1[2] - v1[5] >= sum(g[4, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, val5, v1[2] >= sum(g[5, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, val6, v1[3] - v1[6] >= sum(g[6, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, val7, v1[3] >= sum(g[7, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, val8, v1[4] >= sum(g[8, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, val9, v1[4] >= sum(g[9, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, val10, v1[5] >= sum(g[10, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, val11, v1[5] >= sum(g[11, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, val12, v1[6] >= sum(g[12, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, val13, v1[6] >= sum(g[13, s2] * r2[s2] for s2 = 1:ns2))
@constraint(mne, r2[1] == 1.0)
@constraint(mne, r2[2] + r2[3] == r2[1])
@constraint(mne, r2[4] + r2[5] == r2[1])
@constraint(mne, r2[6] + r2[7] == r2[1])
@constraint(mne, r2[8] + r2[9] == r2[1])
@constraint(mne, r2[10] + r2[11] == r2[1])
@constraint(mne, r2[12] + r2[13] == r2[1])

## Solve
optimize!(mne)
val_constraints = [val1,
                    val2,
                    val3,
                    val4,
                    val5,
                    val6,
                    val7,
                    val8,
                    val9,
                    val10,
                    val11,
                    val12,
                    val13]

## Values and Duals
# r1 = dual_row_solution(getrawsolver(mne))[1:13] # player 1 strategy is the dual of player 1 values for each sequence constraint
r1 = dual.(val_constraints)

println("Objective value: ", objective_value(mne))
println("r2 = ", value.(r2))
println("v0 = ", value(v0))
println("v1 = ", value.(v1))

strategy1 = hcat(Σ1, r1)
strategy2 = hcat(Σ2, value.(r2))
α = 1/3
r1NE = [1.0, 1 - α, α, 1, 0, 1 - 3α, 3α, 2/3, 0, 2/3 - α, 1/3 + α, 0, 0]
strategy1NE = hcat(Σ1, r1NE)
gval(r1)

tab = hcat(1:13,strategy1NE,1:13,strategy1,1:13,strategy2)

# strategies for player 1 and player 2 match NE

max_stars_repo_name: ajkeith/Cyber-Air-Defense

max_issues_repo_name: ajkeith/Cyber-Air-Defense


text:
function drag_acceleration(obj::DragSensitive, arg0::AbsoluteDate, arg1::Frame, arg2::Vector3D, arg3::Rotation, arg4::jdouble, arg5::jdouble, arg6::Vector3D, arg7::Vector{jdouble})
    return jcall(obj, "dragAcceleration", Vector3D, (AbsoluteDate, Frame, Vector3D, Rotation, jdouble, jdouble, Vector3D, Vector{jdouble}), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
end

function drag_acceleration(obj::DragSensitive, arg0::FieldAbsoluteDate, arg1::Frame, arg2::FieldVector3D, arg3::FieldRotation, arg4::RealFieldElement, arg5::RealFieldElement, arg6::FieldVector3D, arg7::Vector{RealFieldElement})
    return jcall(obj, "dragAcceleration", FieldVector3D, (FieldAbsoluteDate, Frame, FieldVector3D, FieldRotation, RealFieldElement, RealFieldElement, FieldVector3D, Vector{RealFieldElement}), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
end

function get_drag_parameters_drivers(obj::DragSensitive)
    return jcall(obj, "getDragParametersDrivers", Vector{ParameterDriver}, ())
end