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

"""
    AssociateResolverEndpointIpAddress()

Adds IP addresses to an inbound or an outbound Resolver endpoint. If you want to add more than one IP address, submit one AssociateResolverEndpointIpAddress request for each IP address. To remove an IP address from an endpoint, see DisassociateResolverEndpointIpAddress.

# Required Parameters
- `IpAddress`: Either the IPv4 address that you want to add to a Resolver endpoint or a subnet ID. If you specify a subnet ID, Resolver chooses an IP address for you from the available IPs in the specified subnet.
- `ResolverEndpointId`: The ID of the Resolver endpoint that you want to associate IP addresses with.

"""
associate_resolver_endpoint_ip_address(IpAddress, ResolverEndpointId; aws_config::AWSConfig=global_aws_config()) = route53resolver("AssociateResolverEndpointIpAddress", Dict{String, Any}("IpAddress"=>IpAddress, "ResolverEndpointId"=>ResolverEndpointId); aws_config=aws_config)
associate_resolver_endpoint_ip_address(IpAddress, ResolverEndpointId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("AssociateResolverEndpointIpAddress", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IpAddress"=>IpAddress, "ResolverEndpointId"=>ResolverEndpointId), args)); aws_config=aws_config)

"""
    AssociateResolverQueryLogConfig()

Associates an Amazon VPC with a specified query logging configuration. Route 53 Resolver logs DNS queries that originate in all of the Amazon VPCs that are associated with a specified query logging configuration. To associate more than one VPC with a configuration, submit one AssociateResolverQueryLogConfig request for each VPC.  The VPCs that you associate with a query logging configuration must be in the same Region as the configuration.  To remove a VPC from a query logging configuration, see DisassociateResolverQueryLogConfig.

# Required Parameters
- `ResolverQueryLogConfigId`: The ID of the query logging configuration that you want to associate a VPC with.
- `ResourceId`: The ID of an Amazon VPC that you want this query logging configuration to log queries for.  The VPCs and the query logging configuration must be in the same Region.

"""
associate_resolver_query_log_config(ResolverQueryLogConfigId, ResourceId; aws_config::AWSConfig=global_aws_config()) = route53resolver("AssociateResolverQueryLogConfig", Dict{String, Any}("ResolverQueryLogConfigId"=>ResolverQueryLogConfigId, "ResourceId"=>ResourceId); aws_config=aws_config)
associate_resolver_query_log_config(ResolverQueryLogConfigId, ResourceId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("AssociateResolverQueryLogConfig", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverQueryLogConfigId"=>ResolverQueryLogConfigId, "ResourceId"=>ResourceId), args)); aws_config=aws_config)

"""
    AssociateResolverRule()

Associates a Resolver rule with a VPC. When you associate a rule with a VPC, Resolver forwards all DNS queries for the domain name that is specified in the rule and that originate in the VPC. The queries are forwarded to the IP addresses for the DNS resolvers that are specified in the rule. For more information about rules, see CreateResolverRule.

# Required Parameters
- `ResolverRuleId`: The ID of the Resolver rule that you want to associate with the VPC. To list the existing Resolver rules, use ListResolverRules.
- `VPCId`: The ID of the VPC that you want to associate the Resolver rule with.

# Optional Parameters
- `Name`: A name for the association that you're creating between a Resolver rule and a VPC.
"""
associate_resolver_rule(ResolverRuleId, VPCId; aws_config::AWSConfig=global_aws_config()) = route53resolver("AssociateResolverRule", Dict{String, Any}("ResolverRuleId"=>ResolverRuleId, "VPCId"=>VPCId); aws_config=aws_config)
associate_resolver_rule(ResolverRuleId, VPCId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("AssociateResolverRule", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverRuleId"=>ResolverRuleId, "VPCId"=>VPCId), args)); aws_config=aws_config)

"""
    CreateResolverEndpoint()

Creates a Resolver endpoint. There are two types of Resolver endpoints, inbound and outbound:   An inbound Resolver endpoint forwards DNS queries to the DNS service for a VPC from your network.   An outbound Resolver endpoint forwards DNS queries from the DNS service for a VPC to your network.

# Required Parameters
- `CreatorRequestId`: A unique string that identifies the request and that allows failed requests to be retried without the risk of executing the operation twice. CreatorRequestId can be any unique string, for example, a date/time stamp.
- `Direction`: Specify the applicable value:    INBOUND: Resolver forwards DNS queries to the DNS service for a VPC from your network    OUTBOUND: Resolver forwards DNS queries from the DNS service for a VPC to your network
- `IpAddresses`: The subnets and IP addresses in your VPC that DNS queries originate from (for outbound endpoints) or that you forward DNS queries to (for inbound endpoints). The subnet ID uniquely identifies a VPC.
- `SecurityGroupIds`: The ID of one or more security groups that you want to use to control access to this VPC. The security group that you specify must include one or more inbound rules (for inbound Resolver endpoints) or outbound rules (for outbound Resolver endpoints). Inbound and outbound rules must allow TCP and UDP access. For inbound access, open port 53. For outbound access, open the port that you're using for DNS queries on your network.

# Optional Parameters
- `Name`: A friendly name that lets you easily find a configuration in the Resolver dashboard in the Route 53 console.
- `Tags`: A list of the tag keys and values that you want to associate with the endpoint.
"""
create_resolver_endpoint(CreatorRequestId, Direction, IpAddresses, SecurityGroupIds; aws_config::AWSConfig=global_aws_config()) = route53resolver("CreateResolverEndpoint", Dict{String, Any}("CreatorRequestId"=>CreatorRequestId, "Direction"=>Direction, "IpAddresses"=>IpAddresses, "SecurityGroupIds"=>SecurityGroupIds); aws_config=aws_config)
create_resolver_endpoint(CreatorRequestId, Direction, IpAddresses, SecurityGroupIds, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("CreateResolverEndpoint", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("CreatorRequestId"=>CreatorRequestId, "Direction"=>Direction, "IpAddresses"=>IpAddresses, "SecurityGroupIds"=>SecurityGroupIds), args)); aws_config=aws_config)

"""
    CreateResolverQueryLogConfig()

Creates a Resolver query logging configuration, which defines where you want Resolver to save DNS query logs that originate in your VPCs. Resolver can log queries only for VPCs that are in the same Region as the query logging configuration. To specify which VPCs you want to log queries for, you use AssociateResolverQueryLogConfig. For more information, see AssociateResolverQueryLogConfig.  You can optionally use AWS Resource Access Manager (AWS RAM) to share a query logging configuration with other AWS accounts. The other accounts can then associate VPCs with the configuration. The query logs that Resolver creates for a configuration include all DNS queries that originate in all VPCs that are associated with the configuration.

# Required Parameters
- `CreatorRequestId`: A unique string that identifies the request and that allows failed requests to be retried without the risk of executing the operation twice. CreatorRequestId can be any unique string, for example, a date/time stamp.
- `DestinationArn`: The ARN of the resource that you want Resolver to send query logs. You can send query logs to an S3 bucket, a CloudWatch Logs log group, or a Kinesis Data Firehose delivery stream. Examples of valid values include the following:    S3 bucket:   arn:aws:s3:::examplebucket  You can optionally append a file prefix to the end of the ARN.  arn:aws:s3:::examplebucket/development/     CloudWatch Logs log group:   arn:aws:logs:us-west-1:123456789012:log-group:/mystack-testgroup-12ABC1AB12A1:*     Kinesis Data Firehose delivery stream:  arn:aws:kinesis:us-east-2:0123456789:stream/my_stream_name
- `Name`: The name that you want to give the query logging configuration

# Optional Parameters
- `Tags`: A list of the tag keys and values that you want to associate with the query logging configuration.
"""
create_resolver_query_log_config(CreatorRequestId, DestinationArn, Name; aws_config::AWSConfig=global_aws_config()) = route53resolver("CreateResolverQueryLogConfig", Dict{String, Any}("CreatorRequestId"=>CreatorRequestId, "DestinationArn"=>DestinationArn, "Name"=>Name); aws_config=aws_config)
create_resolver_query_log_config(CreatorRequestId, DestinationArn, Name, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("CreateResolverQueryLogConfig", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("CreatorRequestId"=>CreatorRequestId, "DestinationArn"=>DestinationArn, "Name"=>Name), args)); aws_config=aws_config)

"""
    CreateResolverRule()

For DNS queries that originate in your VPCs, specifies which Resolver endpoint the queries pass through, one domain name that you want to forward to your network, and the IP addresses of the DNS resolvers in your network.

# Required Parameters
- `CreatorRequestId`: A unique string that identifies the request and that allows failed requests to be retried without the risk of executing the operation twice. CreatorRequestId can be any unique string, for example, a date/time stamp.
- `DomainName`: DNS queries for this domain name are forwarded to the IP addresses that you specify in TargetIps. If a query matches multiple Resolver rules (example.com and www.example.com), outbound DNS queries are routed using the Resolver rule that contains the most specific domain name (www.example.com).
- `RuleType`: When you want to forward DNS queries for specified domain name to resolvers on your network, specify FORWARD. When you have a forwarding rule to forward DNS queries for a domain to your network and you want Resolver to process queries for a subdomain of that domain, specify SYSTEM. For example, to forward DNS queries for example.com to resolvers on your network, you create a rule and specify FORWARD for RuleType. To then have Resolver process queries for apex.example.com, you create a rule and specify SYSTEM for RuleType. Currently, only Resolver can create rules that have a value of RECURSIVE for RuleType.

# Optional Parameters
- `Name`: A friendly name that lets you easily find a rule in the Resolver dashboard in the Route 53 console.
- `ResolverEndpointId`: The ID of the outbound Resolver endpoint that you want to use to route DNS queries to the IP addresses that you specify in TargetIps.
- `Tags`: A list of the tag keys and values that you want to associate with the endpoint.
- `TargetIps`: The IPs that you want Resolver to forward DNS queries to. You can specify only IPv4 addresses. Separate IP addresses with a comma.  TargetIps is available only when the value of Rule type is FORWARD.
"""
create_resolver_rule(CreatorRequestId, DomainName, RuleType; aws_config::AWSConfig=global_aws_config()) = route53resolver("CreateResolverRule", Dict{String, Any}("CreatorRequestId"=>CreatorRequestId, "DomainName"=>DomainName, "RuleType"=>RuleType); aws_config=aws_config)
create_resolver_rule(CreatorRequestId, DomainName, RuleType, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("CreateResolverRule", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("CreatorRequestId"=>CreatorRequestId, "DomainName"=>DomainName, "RuleType"=>RuleType), args)); aws_config=aws_config)

"""
    DeleteResolverEndpoint()

Deletes a Resolver endpoint. The effect of deleting a Resolver endpoint depends on whether it's an inbound or an outbound Resolver endpoint:    Inbound: DNS queries from your network are no longer routed to the DNS service for the specified VPC.    Outbound: DNS queries from a VPC are no longer routed to your network.

# Required Parameters
- `ResolverEndpointId`: The ID of the Resolver endpoint that you want to delete.

"""
delete_resolver_endpoint(ResolverEndpointId; aws_config::AWSConfig=global_aws_config()) = route53resolver("DeleteResolverEndpoint", Dict{String, Any}("ResolverEndpointId"=>ResolverEndpointId); aws_config=aws_config)
delete_resolver_endpoint(ResolverEndpointId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("DeleteResolverEndpoint", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverEndpointId"=>ResolverEndpointId), args)); aws_config=aws_config)

"""
    DeleteResolverQueryLogConfig()

Deletes a query logging configuration. When you delete a configuration, Resolver stops logging DNS queries for all of the Amazon VPCs that are associated with the configuration. This also applies if the query logging configuration is shared with other AWS accounts, and the other accounts have associated VPCs with the shared configuration. Before you can delete a query logging configuration, you must first disassociate all VPCs from the configuration. See DisassociateResolverQueryLogConfig. If you used Resource Access Manager (RAM) to share a query logging configuration with other accounts, you must stop sharing the configuration before you can delete a configuration. The accounts that you shared the configuration with can first disassociate VPCs that they associated with the configuration, but that's not necessary. If you stop sharing the configuration, those VPCs are automatically disassociated from the configuration.

# Required Parameters
- `ResolverQueryLogConfigId`: The ID of the query logging configuration that you want to delete.

"""
delete_resolver_query_log_config(ResolverQueryLogConfigId; aws_config::AWSConfig=global_aws_config()) = route53resolver("DeleteResolverQueryLogConfig", Dict{String, Any}("ResolverQueryLogConfigId"=>ResolverQueryLogConfigId); aws_config=aws_config)
delete_resolver_query_log_config(ResolverQueryLogConfigId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("DeleteResolverQueryLogConfig", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverQueryLogConfigId"=>ResolverQueryLogConfigId), args)); aws_config=aws_config)

"""
    DeleteResolverRule()

Deletes a Resolver rule. Before you can delete a Resolver rule, you must disassociate it from all the VPCs that you associated the Resolver rule with. For more information, see DisassociateResolverRule.

# Required Parameters
- `ResolverRuleId`: The ID of the Resolver rule that you want to delete.

"""
delete_resolver_rule(ResolverRuleId; aws_config::AWSConfig=global_aws_config()) = route53resolver("DeleteResolverRule", Dict{String, Any}("ResolverRuleId"=>ResolverRuleId); aws_config=aws_config)
delete_resolver_rule(ResolverRuleId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("DeleteResolverRule", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverRuleId"=>ResolverRuleId), args)); aws_config=aws_config)

"""
    DisassociateResolverEndpointIpAddress()

Removes IP addresses from an inbound or an outbound Resolver endpoint. If you want to remove more than one IP address, submit one DisassociateResolverEndpointIpAddress request for each IP address. To add an IP address to an endpoint, see AssociateResolverEndpointIpAddress.

# Required Parameters
- `IpAddress`: The IPv4 address that you want to remove from a Resolver endpoint.
- `ResolverEndpointId`: The ID of the Resolver endpoint that you want to disassociate an IP address from.

"""
disassociate_resolver_endpoint_ip_address(IpAddress, ResolverEndpointId; aws_config::AWSConfig=global_aws_config()) = route53resolver("DisassociateResolverEndpointIpAddress", Dict{String, Any}("IpAddress"=>IpAddress, "ResolverEndpointId"=>ResolverEndpointId); aws_config=aws_config)
disassociate_resolver_endpoint_ip_address(IpAddress, ResolverEndpointId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("DisassociateResolverEndpointIpAddress", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("IpAddress"=>IpAddress, "ResolverEndpointId"=>ResolverEndpointId), args)); aws_config=aws_config)

"""
    DisassociateResolverQueryLogConfig()

Disassociates a VPC from a query logging configuration.  Before you can delete a query logging configuration, you must first disassociate all VPCs from the configuration. If you used Resource Access Manager (RAM) to share a query logging configuration with other accounts, VPCs can be disassociated from the configuration in the following ways:   The accounts that you shared the configuration with can disassociate VPCs from the configuration.   You can stop sharing the configuration.

# Required Parameters
- `ResolverQueryLogConfigId`: The ID of the query logging configuration that you want to disassociate a specified VPC from.
- `ResourceId`: The ID of the Amazon VPC that you want to disassociate from a specified query logging configuration.

"""
disassociate_resolver_query_log_config(ResolverQueryLogConfigId, ResourceId; aws_config::AWSConfig=global_aws_config()) = route53resolver("DisassociateResolverQueryLogConfig", Dict{String, Any}("ResolverQueryLogConfigId"=>ResolverQueryLogConfigId, "ResourceId"=>ResourceId); aws_config=aws_config)
disassociate_resolver_query_log_config(ResolverQueryLogConfigId, ResourceId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("DisassociateResolverQueryLogConfig", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverQueryLogConfigId"=>ResolverQueryLogConfigId, "ResourceId"=>ResourceId), args)); aws_config=aws_config)

"""
    DisassociateResolverRule()

Removes the association between a specified Resolver rule and a specified VPC.  If you disassociate a Resolver rule from a VPC, Resolver stops forwarding DNS queries for the domain name that you specified in the Resolver rule.

# Required Parameters
- `ResolverRuleId`: The ID of the Resolver rule that you want to disassociate from the specified VPC.
- `VPCId`: The ID of the VPC that you want to disassociate the Resolver rule from.

"""
disassociate_resolver_rule(ResolverRuleId, VPCId; aws_config::AWSConfig=global_aws_config()) = route53resolver("DisassociateResolverRule", Dict{String, Any}("ResolverRuleId"=>ResolverRuleId, "VPCId"=>VPCId); aws_config=aws_config)
disassociate_resolver_rule(ResolverRuleId, VPCId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("DisassociateResolverRule", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverRuleId"=>ResolverRuleId, "VPCId"=>VPCId), args)); aws_config=aws_config)

"""
    GetResolverEndpoint()

Gets information about a specified Resolver endpoint, such as whether it's an inbound or an outbound Resolver endpoint, and the current status of the endpoint.

# Required Parameters
- `ResolverEndpointId`: The ID of the Resolver endpoint that you want to get information about.

"""
get_resolver_endpoint(ResolverEndpointId; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverEndpoint", Dict{String, Any}("ResolverEndpointId"=>ResolverEndpointId); aws_config=aws_config)
get_resolver_endpoint(ResolverEndpointId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverEndpoint", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverEndpointId"=>ResolverEndpointId), args)); aws_config=aws_config)

"""
    GetResolverQueryLogConfig()

Gets information about a specified Resolver query logging configuration, such as the number of VPCs that the configuration is logging queries for and the location that logs are sent to.

# Required Parameters
- `ResolverQueryLogConfigId`: The ID of the Resolver query logging configuration that you want to get information about.

"""
get_resolver_query_log_config(ResolverQueryLogConfigId; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverQueryLogConfig", Dict{String, Any}("ResolverQueryLogConfigId"=>ResolverQueryLogConfigId); aws_config=aws_config)
get_resolver_query_log_config(ResolverQueryLogConfigId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverQueryLogConfig", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverQueryLogConfigId"=>ResolverQueryLogConfigId), args)); aws_config=aws_config)

"""
    GetResolverQueryLogConfigAssociation()

Gets information about a specified association between a Resolver query logging configuration and an Amazon VPC. When you associate a VPC with a query logging configuration, Resolver logs DNS queries that originate in that VPC.

# Required Parameters
- `ResolverQueryLogConfigAssociationId`: The ID of the Resolver query logging configuration association that you want to get information about.

"""
get_resolver_query_log_config_association(ResolverQueryLogConfigAssociationId; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverQueryLogConfigAssociation", Dict{String, Any}("ResolverQueryLogConfigAssociationId"=>ResolverQueryLogConfigAssociationId); aws_config=aws_config)
get_resolver_query_log_config_association(ResolverQueryLogConfigAssociationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverQueryLogConfigAssociation", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverQueryLogConfigAssociationId"=>ResolverQueryLogConfigAssociationId), args)); aws_config=aws_config)

"""
    GetResolverQueryLogConfigPolicy()

Gets information about a query logging policy. A query logging policy specifies the Resolver query logging operations and resources that you want to allow another AWS account to be able to use.

# Required Parameters
- `Arn`: The ARN of the query logging configuration that you want to get the query logging policy for.

"""
get_resolver_query_log_config_policy(Arn; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverQueryLogConfigPolicy", Dict{String, Any}("Arn"=>Arn); aws_config=aws_config)
get_resolver_query_log_config_policy(Arn, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverQueryLogConfigPolicy", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Arn"=>Arn), args)); aws_config=aws_config)

"""
    GetResolverRule()

Gets information about a specified Resolver rule, such as the domain name that the rule forwards DNS queries for and the ID of the outbound Resolver endpoint that the rule is associated with.

# Required Parameters
- `ResolverRuleId`: The ID of the Resolver rule that you want to get information about.

"""
get_resolver_rule(ResolverRuleId; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverRule", Dict{String, Any}("ResolverRuleId"=>ResolverRuleId); aws_config=aws_config)
get_resolver_rule(ResolverRuleId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverRule", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverRuleId"=>ResolverRuleId), args)); aws_config=aws_config)

"""
    GetResolverRuleAssociation()

Gets information about an association between a specified Resolver rule and a VPC. You associate a Resolver rule and a VPC using AssociateResolverRule.

# Required Parameters
- `ResolverRuleAssociationId`: The ID of the Resolver rule association that you want to get information about.

"""
get_resolver_rule_association(ResolverRuleAssociationId; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverRuleAssociation", Dict{String, Any}("ResolverRuleAssociationId"=>ResolverRuleAssociationId); aws_config=aws_config)
get_resolver_rule_association(ResolverRuleAssociationId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverRuleAssociation", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverRuleAssociationId"=>ResolverRuleAssociationId), args)); aws_config=aws_config)

"""
    GetResolverRulePolicy()

Gets information about a Resolver rule policy. A Resolver rule policy specifies the Resolver operations and resources that you want to allow another AWS account to be able to use.

# Required Parameters
- `Arn`: The ID of the Resolver rule policy that you want to get information about.

"""
get_resolver_rule_policy(Arn; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverRulePolicy", Dict{String, Any}("Arn"=>Arn); aws_config=aws_config)
get_resolver_rule_policy(Arn, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("GetResolverRulePolicy", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Arn"=>Arn), args)); aws_config=aws_config)

"""
    ListResolverEndpointIpAddresses()

Gets the IP addresses for a specified Resolver endpoint.

# Required Parameters
- `ResolverEndpointId`: The ID of the Resolver endpoint that you want to get IP addresses for.

# Optional Parameters
- `MaxResults`: The maximum number of IP addresses that you want to return in the response to a ListResolverEndpointIpAddresses request. If you don't specify a value for MaxResults, Resolver returns up to 100 IP addresses.
- `NextToken`: For the first ListResolverEndpointIpAddresses request, omit this value. If the specified Resolver endpoint has more than MaxResults IP addresses, you can submit another ListResolverEndpointIpAddresses request to get the next group of IP addresses. In the next request, specify the value of NextToken from the previous response.
"""
list_resolver_endpoint_ip_addresses(ResolverEndpointId; aws_config::AWSConfig=global_aws_config()) = route53resolver("ListResolverEndpointIpAddresses", Dict{String, Any}("ResolverEndpointId"=>ResolverEndpointId); aws_config=aws_config)
list_resolver_endpoint_ip_addresses(ResolverEndpointId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("ListResolverEndpointIpAddresses", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverEndpointId"=>ResolverEndpointId), args)); aws_config=aws_config)

"""
    ListResolverEndpoints()

Lists all the Resolver endpoints that were created using the current AWS account.

# Optional Parameters
- `Filters`: An optional specification to return a subset of Resolver endpoints, such as all inbound Resolver endpoints.  If you submit a second or subsequent ListResolverEndpoints request and specify the NextToken parameter, you must use the same values for Filters, if any, as in the previous request.
- `MaxResults`: The maximum number of Resolver endpoints that you want to return in the response to a ListResolverEndpoints request. If you don't specify a value for MaxResults, Resolver returns up to 100 Resolver endpoints.
- `NextToken`: For the first ListResolverEndpoints request, omit this value. If you have more than MaxResults Resolver endpoints, you can submit another ListResolverEndpoints request to get the next group of Resolver endpoints. In the next request, specify the value of NextToken from the previous response.
"""
list_resolver_endpoints(; aws_config::AWSConfig=global_aws_config()) = route53resolver("ListResolverEndpoints"; aws_config=aws_config)
list_resolver_endpoints(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("ListResolverEndpoints", args; aws_config=aws_config)

"""
    ListResolverQueryLogConfigAssociations()

Lists information about associations between Amazon VPCs and query logging configurations.

# Optional Parameters
- `Filters`: An optional specification to return a subset of query logging associations.  If you submit a second or subsequent ListResolverQueryLogConfigAssociations request and specify the NextToken parameter, you must use the same values for Filters, if any, as in the previous request.
- `MaxResults`: The maximum number of query logging associations that you want to return in the response to a ListResolverQueryLogConfigAssociations request. If you don't specify a value for MaxResults, Resolver returns up to 100 query logging associations.
- `NextToken`: For the first ListResolverQueryLogConfigAssociations request, omit this value. If there are more than MaxResults query logging associations that match the values that you specify for Filters, you can submit another ListResolverQueryLogConfigAssociations request to get the next group of associations. In the next request, specify the value of NextToken from the previous response.
- `SortBy`: The element that you want Resolver to sort query logging associations by.   If you submit a second or subsequent ListResolverQueryLogConfigAssociations request and specify the NextToken parameter, you must use the same value for SortBy, if any, as in the previous request.  Valid values include the following elements:    CreationTime: The ID of the query logging association.    Error: If the value of Status is FAILED, the value of Error indicates the cause:     DESTINATION_NOT_FOUND: The specified destination (for example, an Amazon S3 bucket) was deleted.    ACCESS_DENIED: Permissions don't allow sending logs to the destination.   If Status is a value other than FAILED, ERROR is null.    Id: The ID of the query logging association    ResolverQueryLogConfigId: The ID of the query logging configuration    ResourceId: The ID of the VPC that is associated with the query logging configuration    Status: The current status of the configuration. Valid values include the following:    CREATING: Resolver is creating an association between an Amazon VPC and a query logging configuration.    CREATED: The association between an Amazon VPC and a query logging configuration was successfully created. Resolver is logging queries that originate in the specified VPC.    DELETING: Resolver is deleting this query logging association.    FAILED: Resolver either couldn't create or couldn't delete the query logging association. Here are two common causes:   The specified destination (for example, an Amazon S3 bucket) was deleted.   Permissions don't allow sending logs to the destination.
- `SortOrder`: If you specified a value for SortBy, the order that you want query logging associations to be listed in, ASCENDING or DESCENDING.  If you submit a second or subsequent ListResolverQueryLogConfigAssociations request and specify the NextToken parameter, you must use the same value for SortOrder, if any, as in the previous request.
"""
list_resolver_query_log_config_associations(; aws_config::AWSConfig=global_aws_config()) = route53resolver("ListResolverQueryLogConfigAssociations"; aws_config=aws_config)
list_resolver_query_log_config_associations(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("ListResolverQueryLogConfigAssociations", args; aws_config=aws_config)

"""
    ListResolverQueryLogConfigs()

Lists information about the specified query logging configurations. Each configuration defines where you want Resolver to save DNS query logs and specifies the VPCs that you want to log queries for.

# Optional Parameters
- `Filters`: An optional specification to return a subset of query logging configurations.  If you submit a second or subsequent ListResolverQueryLogConfigs request and specify the NextToken parameter, you must use the same values for Filters, if any, as in the previous request.
- `MaxResults`: The maximum number of query logging configurations that you want to return in the response to a ListResolverQueryLogConfigs request. If you don't specify a value for MaxResults, Resolver returns up to 100 query logging configurations.
- `NextToken`: For the first ListResolverQueryLogConfigs request, omit this value. If there are more than MaxResults query logging configurations that match the values that you specify for Filters, you can submit another ListResolverQueryLogConfigs request to get the next group of configurations. In the next request, specify the value of NextToken from the previous response.
- `SortBy`: The element that you want Resolver to sort query logging configurations by.   If you submit a second or subsequent ListResolverQueryLogConfigs request and specify the NextToken parameter, you must use the same value for SortBy, if any, as in the previous request.  Valid values include the following elements:    Arn: The ARN of the query logging configuration    AssociationCount: The number of VPCs that are associated with the specified configuration     CreationTime: The date and time that Resolver returned when the configuration was created    CreatorRequestId: The value that was specified for CreatorRequestId when the configuration was created    DestinationArn: The location that logs are sent to    Id: The ID of the configuration    Name: The name of the configuration    OwnerId: The AWS account number of the account that created the configuration    ShareStatus: Whether the configuration is shared with other AWS accounts or shared with the current account by another AWS account. Sharing is configured through AWS Resource Access Manager (AWS RAM).    Status: The current status of the configuration. Valid values include the following:    CREATING: Resolver is creating the query logging configuration.    CREATED: The query logging configuration was successfully created. Resolver is logging queries that originate in the specified VPC.    DELETING: Resolver is deleting this query logging configuration.    FAILED: Resolver either couldn't create or couldn't delete the query logging configuration. Here are two common causes:   The specified destination (for example, an Amazon S3 bucket) was deleted.   Permissions don't allow sending logs to the destination.
- `SortOrder`: If you specified a value for SortBy, the order that you want query logging configurations to be listed in, ASCENDING or DESCENDING.  If you submit a second or subsequent ListResolverQueryLogConfigs request and specify the NextToken parameter, you must use the same value for SortOrder, if any, as in the previous request.
"""
list_resolver_query_log_configs(; aws_config::AWSConfig=global_aws_config()) = route53resolver("ListResolverQueryLogConfigs"; aws_config=aws_config)
list_resolver_query_log_configs(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("ListResolverQueryLogConfigs", args; aws_config=aws_config)

"""
    ListResolverRuleAssociations()

Lists the associations that were created between Resolver rules and VPCs using the current AWS account.

# Optional Parameters
- `Filters`: An optional specification to return a subset of Resolver rules, such as Resolver rules that are associated with the same VPC ID.  If you submit a second or subsequent ListResolverRuleAssociations request and specify the NextToken parameter, you must use the same values for Filters, if any, as in the previous request.
- `MaxResults`: The maximum number of rule associations that you want to return in the response to a ListResolverRuleAssociations request. If you don't specify a value for MaxResults, Resolver returns up to 100 rule associations.
- `NextToken`: For the first ListResolverRuleAssociation request, omit this value. If you have more than MaxResults rule associations, you can submit another ListResolverRuleAssociation request to get the next group of rule associations. In the next request, specify the value of NextToken from the previous response.
"""
list_resolver_rule_associations(; aws_config::AWSConfig=global_aws_config()) = route53resolver("ListResolverRuleAssociations"; aws_config=aws_config)
list_resolver_rule_associations(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("ListResolverRuleAssociations", args; aws_config=aws_config)

"""
    ListResolverRules()

Lists the Resolver rules that were created using the current AWS account.

# Optional Parameters
- `Filters`: An optional specification to return a subset of Resolver rules, such as all Resolver rules that are associated with the same Resolver endpoint.  If you submit a second or subsequent ListResolverRules request and specify the NextToken parameter, you must use the same values for Filters, if any, as in the previous request.
- `MaxResults`: The maximum number of Resolver rules that you want to return in the response to a ListResolverRules request. If you don't specify a value for MaxResults, Resolver returns up to 100 Resolver rules.
- `NextToken`: For the first ListResolverRules request, omit this value. If you have more than MaxResults Resolver rules, you can submit another ListResolverRules request to get the next group of Resolver rules. In the next request, specify the value of NextToken from the previous response.
"""
list_resolver_rules(; aws_config::AWSConfig=global_aws_config()) = route53resolver("ListResolverRules"; aws_config=aws_config)
list_resolver_rules(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("ListResolverRules", args; aws_config=aws_config)

"""
    ListTagsForResource()

Lists the tags that you associated with the specified resource.

# Required Parameters
- `ResourceArn`: The Amazon Resource Name (ARN) for the resource that you want to list tags for.

# Optional Parameters
- `MaxResults`: The maximum number of tags that you want to return in the response to a ListTagsForResource request. If you don't specify a value for MaxResults, Resolver returns up to 100 tags.
- `NextToken`: For the first ListTagsForResource request, omit this value. If you have more than MaxResults tags, you can submit another ListTagsForResource request to get the next group of tags for the resource. In the next request, specify the value of NextToken from the previous response.
"""
list_tags_for_resource(ResourceArn; aws_config::AWSConfig=global_aws_config()) = route53resolver("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()) = route53resolver("ListTagsForResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceArn"=>ResourceArn), args)); aws_config=aws_config)

"""
    PutResolverQueryLogConfigPolicy()

Specifies an AWS account that you want to share a query logging configuration with, the query logging configuration that you want to share, and the operations that you want the account to be able to perform on the configuration.

# Required Parameters
- `Arn`: The Amazon Resource Name (ARN) of the account that you want to share rules with.
- `ResolverQueryLogConfigPolicy`: An AWS Identity and Access Management policy statement that lists the query logging configurations that you want to share with another AWS account and the operations that you want the account to be able to perform. You can specify the following operations in the Actions section of the statement:    route53resolver:AssociateResolverQueryLogConfig     route53resolver:DisassociateResolverQueryLogConfig     route53resolver:ListResolverQueryLogConfigAssociations     route53resolver:ListResolverQueryLogConfigs    In the Resource section of the statement, you specify the ARNs for the query logging configurations that you want to share with the account that you specified in Arn.

"""
put_resolver_query_log_config_policy(Arn, ResolverQueryLogConfigPolicy; aws_config::AWSConfig=global_aws_config()) = route53resolver("PutResolverQueryLogConfigPolicy", Dict{String, Any}("Arn"=>Arn, "ResolverQueryLogConfigPolicy"=>ResolverQueryLogConfigPolicy); aws_config=aws_config)
put_resolver_query_log_config_policy(Arn, ResolverQueryLogConfigPolicy, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("PutResolverQueryLogConfigPolicy", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Arn"=>Arn, "ResolverQueryLogConfigPolicy"=>ResolverQueryLogConfigPolicy), args)); aws_config=aws_config)

"""
    PutResolverRulePolicy()

Specifies an AWS account that you want to share rules with, the Resolver rules that you want to share, and the operations that you want the account to be able to perform on those rules.

# Required Parameters
- `Arn`: The Amazon Resource Name (ARN) of the account that you want to share rules with.
- `ResolverRulePolicy`: An AWS Identity and Access Management policy statement that lists the rules that you want to share with another AWS account and the operations that you want the account to be able to perform. You can specify the following operations in the Actions section of the statement:    route53resolver:GetResolverRule     route53resolver:AssociateResolverRule     route53resolver:DisassociateResolverRule     route53resolver:ListResolverRules     route53resolver:ListResolverRuleAssociations    In the Resource section of the statement, you specify the ARNs for the rules that you want to share with the account that you specified in Arn.

"""
put_resolver_rule_policy(Arn, ResolverRulePolicy; aws_config::AWSConfig=global_aws_config()) = route53resolver("PutResolverRulePolicy", Dict{String, Any}("Arn"=>Arn, "ResolverRulePolicy"=>ResolverRulePolicy); aws_config=aws_config)
put_resolver_rule_policy(Arn, ResolverRulePolicy, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("PutResolverRulePolicy", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Arn"=>Arn, "ResolverRulePolicy"=>ResolverRulePolicy), args)); aws_config=aws_config)

"""
    TagResource()

Adds one or more tags to a specified resource.

# Required Parameters
- `ResourceArn`: The Amazon Resource Name (ARN) for the resource that you want to add tags to. To get the ARN for a resource, use the applicable Get or List command:     GetResolverEndpoint     GetResolverRule     GetResolverRuleAssociation     ListResolverEndpoints     ListResolverRuleAssociations     ListResolverRules
- `Tags`: The tags that you want to add to the specified resource.

"""
tag_resource(ResourceArn, Tags; aws_config::AWSConfig=global_aws_config()) = route53resolver("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()) = route53resolver("TagResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceArn"=>ResourceArn, "Tags"=>Tags), args)); aws_config=aws_config)

"""
    UntagResource()

Removes one or more tags from a specified resource.

# Required Parameters
- `ResourceArn`: The Amazon Resource Name (ARN) for the resource that you want to remove tags from. To get the ARN for a resource, use the applicable Get or List command:     GetResolverEndpoint     GetResolverRule     GetResolverRuleAssociation     ListResolverEndpoints     ListResolverRuleAssociations     ListResolverRules
- `TagKeys`: The tags that you want to remove to the specified resource.

"""
untag_resource(ResourceArn, TagKeys; aws_config::AWSConfig=global_aws_config()) = route53resolver("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()) = route53resolver("UntagResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceArn"=>ResourceArn, "TagKeys"=>TagKeys), args)); aws_config=aws_config)

"""
    UpdateResolverEndpoint()

Updates the name of an inbound or an outbound Resolver endpoint.

# Required Parameters
- `ResolverEndpointId`: The ID of the Resolver endpoint that you want to update.

# Optional Parameters
- `Name`: The name of the Resolver endpoint that you want to update.
"""
update_resolver_endpoint(ResolverEndpointId; aws_config::AWSConfig=global_aws_config()) = route53resolver("UpdateResolverEndpoint", Dict{String, Any}("ResolverEndpointId"=>ResolverEndpointId); aws_config=aws_config)
update_resolver_endpoint(ResolverEndpointId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("UpdateResolverEndpoint", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResolverEndpointId"=>ResolverEndpointId), args)); aws_config=aws_config)

"""
    UpdateResolverRule()

Updates settings for a specified Resolver rule. ResolverRuleId is required, and all other parameters are optional. If you don't specify a parameter, it retains its current value.

# Required Parameters
- `Config`: The new settings for the Resolver rule.
- `ResolverRuleId`: The ID of the Resolver rule that you want to update.

"""
update_resolver_rule(Config, ResolverRuleId; aws_config::AWSConfig=global_aws_config()) = route53resolver("UpdateResolverRule", Dict{String, Any}("Config"=>Config, "ResolverRuleId"=>ResolverRuleId); aws_config=aws_config)
update_resolver_rule(Config, ResolverRuleId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = route53resolver("UpdateResolverRule", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Config"=>Config, "ResolverRuleId"=>ResolverRuleId), args)); aws_config=aws_config)


text:
# These objects are used to control the recalculation of the jacobian
# and preconditioner

"""
  This is the supertype of all types that tell a method when to recalculate
  the Jacobian.  Each subtype defines a different policy for when to
  recalculate.
"""
abstract type RecalculationPolicy end

"""
  This function returns the enum specifying whether the PC and/or LO should
  be recalculated.

  Every implementation of [`RecalculationPolicy`](@ref) should extend this
  function with a new method.

  **Inputs**

   * policy: a [`RecalculationPolicy`](@ref)
   * itr: the current iteration

  **Outputs**

   * the num: see [`RECALC_BOTH`](@ref)
"""
function decideRecalculation(policy::RecalculationPolicy, itr::Integer)

  error("abstract decideRecalculation() reached.  Did you forget to extend this function for your RecalculationPolicy type?")
end

"""
  This function uses [`decideRecalculation`](@ref) and the [`LinearSolver`](@ref)
  interface to recalculate the PC and/or LO as specified by the policy.

  This is the main interface the different methods should use for
  recalculating the PC and/or LO.  The only case when
  [`decideRecalculation`](@ref) is better is when the method is not using
  the LinearSolvers module to define the PC and LO.

  **Inputs**

   * policy: a [`RecalculationPolicy`](@ref)
   * itr: current iteration number

  The following arguments exactly match the signature of [`calcPCandLO`](@ref)

   * ls
   * mesh
   * sbp
   * eqn
   * opts
   * ctx_residual
   * t

  When this function exits, the PC and/or LO will have been updated, if
  specified by the RecalculationPolicy.
"""
function doRecalculation(policy::RecalculationPolicy, itr::Integer,
                         ls::LinearSolver,
                         mesh::AbstractMesh, sbp::AbstractOperator,
                         eqn::AbstractSolutionData, opts,
                         ctx_residual, t)

  recalc_type = decideRecalculation(policy, itr)
  if recalc_type == RECALC_BOTH
    calcPCandLO(ls, mesh, sbp, eqn, opts, ctx_residual, t)
  elseif recalc_type == RECALC_PC
    calcPC(ls, mesh, sbp, eqn, opts, ctx_residual, t)
  elseif recalc_type == RECALC_LO
    calcLinearOperator(ls, mesh, sbp, eqn, opts, ctx_residual, t)
  end

  return nothing
end

"""
  This function should reset the RecalculationPolicy to its initial state.
  This function is called at the beginning of Newton's method (making it
  safe to reuse the RecalculationPolicy for repeated calls to Newton)

  Every [`RecalculationPolicy`](@ref) should extend function with a new
  method.

  **Inputs**

   * policy: a [`RecalculationPolicy`](@ref)

  **Outputs**

   * none
"""
function resetRecalculationPolicy(policy::RecalculationPolicy)

  error("abstract resetRecalculationPolicy() reached.  Did you forget to extend this function for your RecalculationPolicy type?")

end
"""
  Helper function to [`decideRecalculation`](@ref)

  **Inputs**

   * recalc_pc: bool specifying whether the PC should be recalculated
   * recalc_lo: bool specifying whether the LO should be recalculated

  **Outputs**

   * recalculation enum (see [`RECALC_BOTH`](@ref)

"""
function getRecalculationEnum(recalc_pc::Bool, recalc_lo::Bool)

  # TODO: move this to own function for convenience
  if recalc_pc && recalc_lo
    return RECALC_BOTH
  elseif recalc_pc
    return RECALC_PC
  elseif recalc_lo
    return RECALC_LO
  else
    return RECALC_NONE
  end

  return nothing
end

"""
  Enums returned by [`decideRecalculation`](@ref) telling the caller what to
  recalculate.

  **Enum Names**

   * RECALC_BOTH: recalculate PC and LO
   * RECALC_PC: recalculate PC only
   * RECALC_LO: recalculate LO only
   * RECALC_NONE: don't recalculate anything
"""
global const RECALC_BOTH = 1
global const RECALC_PC = 2
global const RECALC_LO = 3
global const RECALC_NONE = 4

#------------------------------------------------------------------------------
# RecalculateFixedIntervals

"""
  This [`RecalculationPolicy`](@ref) recalculates the LO and PC every `x`
  number if iterations.

  **Options Keys**

   * "\$prefix_prec_recalc_freq": frequency of PC recalculation
   * "\$prefix_jac_recalc_freq": frequency of LO recalculation
   * "\$prefix_recalc_first": if true, recalculate the PC and LO on the first
                              iteration, even if other criteria not met.

  where "\$prefix" is the prefix passed into [`getRecalculationPolicy`](@ref)
"""
mutable struct RecalculateFixedIntervals <: RecalculationPolicy
  prec_freq::Int  # recalculate this preconditioner every this many iterations
  jac_freq::Int   # recalculate the jacobian every this many iterations
  last_prec::Int  # last iteration the prec was recalculated
  last_jac::Int    # last iteration the jac was recalculated
  recalc_first::Bool  # true if everything should be recalculated on the
                      # first iteration, even if other criteria not met
end

function RecalculateFixedIntervals(opts, prefix="")

  prec_freq = opts[string(prefix, "_prec_recalc_freq")]
  jac_freq = opts[string(prefix, "_jac_recalc_freq")]
  recalc_first = opts[string(prefix, "_recalc_first")]

  @assert prec_freq > 0
  @assert prec_freq > 0

  last_prec = 0
  last_jac = 0

  return RecalculateFixedIntervals(prec_freq, jac_freq, last_prec, last_jac, recalc_first)
end

function decideRecalculation(policy::RecalculateFixedIntervals, itr::Integer)

  recalc_pc = false
  recalc_lo = false

  if policy.recalc_first && itr == 1
    recalc_pc = true
    recalc_lo = true
  else
    recalc_pc = ( itr - policy.last_prec == policy.prec_freq )
    recalc_lo = ( itr - policy.last_jac == policy.jac_freq )
  end

  if recalc_pc
    policy.last_prec = itr
  end
  if recalc_lo
    policy.last_jac = itr
  end

  return getRecalculationEnum(recalc_pc, recalc_lo)
end

function resetRecalculationPolicy(policy::RecalculateFixedIntervals)

  policy.last_prec = 0
  policy.last_jac = 0

  return nothing
end

#------------------------------------------------------------------------------
# Recalculate Never

"""
 This [`RecalculationPolicy`](@ref) never recalculates the PC or LO.
 This is useful when Newton's method is used inside other methods to solve
 easy problems.
"""
mutable struct RecalculateNever <: RecalculationPolicy
end

function RecalculateNever(opts, prefix="")

  return RecalculateNever()
end

function decideRecalculation(policy::RecalculateNever, itr::Integer)

  recalc_pc = false
  recalc_lo = false

  return getRecalculationEnum(recalc_pc, recalc_lo)
end

function resetRecalculationPolicy(policy::RecalculateNever)

  # nothing to do here

  return nothing
end

#------------------------------------------------------------------------------
# Constructors

"""
  Maps names to [`RecalculationPolicy`](@ref) constructors.  All new
  recalculation policies must be added to this list.

  The constructors must have the signature:

    MyPolicyName(opts::Dict, prefix::String)

  where `opts` is the options dictionary and `prefix` is the prefix passed into
  [`getRecalculationPolicy`](@ref).
"""
global const RecalculationPolicyDict = Dict{String, Any}(
"RecalculateFixedIntervals" => RecalculateFixedIntervals,
"RecalculateNever"          => RecalculateNever,
)
# Note: the second type parameter can't be Any, because Julia seems to confuse
#       types and their outer constructors

"""
  This function constructs and returns the recalculation policy specified by
  the options dictionary.

  Methods that want to use a RecalculationPolicy should this this function
  to get it (do not call the constructors directly).

  **Inputs**

   * opts: options dictionary
   * prefix: prefix of options to use.  This is usually the name of the method
             the returned object will be used in, eg. "newton"

  **Outputs**

   * policy: a RecalculationPolicy of some kind

  **Options Keys**

   * "\$prefix_recalculation_policy": name of recalculation policy to get

  **Current Policies**

  $(keys(RecalculationPolicyDict))

"""
function getRecalculationPolicy(opts, prefix="")

  # right now there is only one, but there may be more in the future

  keyname = string(prefix, "_recalculation_policy")
  name = opts[keyname]
  return RecalculationPolicyDict[name](opts, prefix)
end

ext: jl


text:
using JSON
using PyPlot
using StatsBase
using DataFrames, CSV
using Random
include("consistent_agent_utils.jl")
include("spread_sample.jl")

json_fldr = "test_data/"

# load the files that will be used, this will vary based on the experiment that you ran in `make_nets_and_data.jl`
# the following is the data that was used in the actual SC_experiment, and is included here as an example, new files should be loaded to make data for a new experiment
data1 = JSON.parsefile("$(json_fldr)experiment_data_mturk_1_Ntprob_solver.json")
data2 = JSON.parsefile("$(json_fldr)experiment_data_mturk_2_Ntprob_solver.json")
data3 = JSON.parsefile("$(json_fldr)experiment_data_mturk_3_Ntprob_solver.json")
data4 = JSON.parsefile("$(json_fldr)experiment_data_mturk_4_Ntprob_solver.json")
data5 = JSON.parsefile("$(json_fldr)experiment_data_mturk_5_Ntprob_solver.json")

data = merge_dicts([data1,data2,data3,data4,data5]) # don't include data1 for training because it is 'trusted' sovler
exp_data = data4 # `candidate` data that will be used in the experiment

pygui(false)

xQ, xP, outcome, Xp, Xn, Xp_m, Xp_c, Xn_m, Xn_c, N_c, tp_c = get_data(data)

xQe, xPe, outcomee, Xpe, Xne, Xp_me, Xp_ce, Xn_me, Xn_ce, N_e, tp_e, tn_e = get_data(exp_data)

####################
### plot full data set
####################
fig_individual, ax_individual = PyPlot.subplots(1,1)
fig_individual[:set_size_inches](5,5)
ax_individual[:scatter](xQ[outcome],xP[outcome],label="success",alpha=0.5)
ax_individual[:scatter](xQ[.!outcome],xP[.!outcome],label="failure",alpha=0.5)
ax_individual[:legend]()
ax_individual[:set_title](L"$x_Q/x_O$ Plane---All Data",size=15)
ax_individual[:set_xlabel](L"x_Q",size=15)
ax_individual[:set_ylabel](L"x_O",size=15)
ax_individual[:set_xlim]((0.0,2.0))
ax_individual[:set_ylim]((-1.0,1.0))
ax_individual[:axvline](1.0,c=:gray)
ax_individual[:axhline](0.0,c=:gray)
fig_individual[:tight_layout]()
fig_individual[:savefig]("plots/xQxO_Plane.pdf",dpi=300,tranparent=true)
#####################

#####################
### Here is where the experiment task subset is selected, may need to change nubmers for other experiments
### this code depends on having `enough` data to be able to select successes and failures from each quadrant
### see the above plot `xQxO_Plane.pdf` to visualize your data before proceeding and expecting it to work
### there will be errors if there isn't enough data to do this. As set up now using the `experiment_data_mturk_fast_NN_Ntprob_solver.json` files there is not enough data
#####################
exp_trial_set = choose_equal_portion_set_lhc(xQe,xPe,outcomee,[12,8,15,8],max_num=16,min_num=8)

#  exp_trial_set = collect(1:length(xQe)) # use this for testing *all* of the examples
#####################
### end experiment task subset selection
#####################

####################
### plot experiment data set
####################
exp_success = sum(outcomee[exp_trial_set])
exp_failure = sum(.!outcomee[exp_trial_set])
fig_individual, ax_individual = PyPlot.subplots(1,1)
fig_individual[:set_size_inches](5,5)
ax_individual[:scatter](xQe[exp_trial_set][outcomee[exp_trial_set]],xPe[exp_trial_set][outcomee[exp_trial_set]],label="successes: $exp_success",alpha=0.5)
ax_individual[:scatter](xQe[exp_trial_set][.!outcomee[exp_trial_set]],xPe[exp_trial_set][.!outcomee[exp_trial_set]],label="failures: $exp_failure",alpha=0.5)
ax_individual[:set_title](L"$x_Q/x_O$ Plane---Experiment Task Set",size=15)
ax_individual[:set_xlabel](L"x_Q",size=15)
ax_individual[:set_ylabel](L"x_O",size=15)
ax_individual[:axvline](1.0,c=:gray)
ax_individual[:axhline](0.0,c=:gray)
ax_individual[:set_xlim]((0.0,2.0))
ax_individual[:set_ylim]((-1.0,1.0))
ax_individual[:legend]()
fig_individual[:tight_layout]()
fig_individual[:savefig]("plots/xQxO_plane_experiment_set.pdf")
#####################

# need to export file for the list of networks to be used in experiment, the indices
# are different because in this file we have only cared about the array, but we need
# to associate the array indices with the network numbers before exporting
psiturk_trial_set = tn_e[exp_trial_set]
open("experiment_trial_set.json","w") do f
    dat = JSON.json(psiturk_trial_set,4)
    write(f,dat)
end

copy_file_to_experiment = false
if copy_file_to_experiment
    # this is useful if you're updating the files, and don't want to forget to get the most updated version in the experiment folder
    expt_fldr = "../SC_experiment/"
    run(`cp experiment_trial_set.json $(expt_fldr)templates/json/`)
    run(`cp json/experiment_data_mturk_4_Ntprob_solver.json $(expt_fldr)templates/json/v2_support.json`)
end

max_stars_repo_name: COHRINT/FaMSeC

max_issues_repo_name: COHRINT/FaMSeC

max_forks_repo_name: COHRINT/FaMSeC


text:
abstract type AbstractServer end
abstract type AbstractFile end

mutable struct File
    path::String
    source::String
    cst::EXPR
    root::Union{Nothing,File}
    server
end

mutable struct FileServer <: AbstractServer
    files::Dict{String,File}
    roots::Set{File}
    symbolserver::SymbolServer.EnvStore
    symbol_extends::Dict{SymbolServer.VarRef,Vector{SymbolServer.VarRef}}
end
FileServer() = FileServer(Dict{String,File}(), Set{File}(), deepcopy(SymbolServer.stdlibs), SymbolServer.collect_extended_methods(SymbolServer.stdlibs))

# Interface spec.
# AbstractServer :-> (has/canload/load/set/get)file, getsymbolserver, getsymbolextends
# AbstractFile :-> (get/set)path, (get/set)root, (get/set)cst, scopepass, (get/set)server

hasfile(server::FileServer, path::String) = haskey(server.files, path)
canloadfile(server, path) = isfile(path)
function setfile(server::FileServer, path::String, file::File)
    server.files[path] = file
end
getfile(server::FileServer, path::String) = server.files[path]
function loadfile(server::FileServer, path::String)
    source = read(path, String)
    cst = CSTParser.parse(source, true)
    f = File(path, source, cst, nothing, server)
    setroot(f, f)
    setfile(server, path, f)
    return getfile(server, path)
end
getsymbolserver(server::FileServer) = server.symbolserver
getsymbolextendeds(server::FileServer) = server.symbol_extends

function scopepass(file, target=nothing)
    server = file.server
    setscope!(getcst(file), Scope(nothing, getcst(file), Dict(), Dict{Symbol,Any}(:Base => getsymbolserver(server)[:Base], :Core => getsymbolserver(server)[:Core]), nothing))
    state = Toplevel(file, target, [getpath(file)], scopeof(getcst(file)), EXPR[], server)
    state(getcst(file))
    for x in state.delayed
        if hasscope(x)
            traverse(x, Delayed(scopeof(x), server))
        else
            ds = retrieve_delayed_scope(x)
            traverse(x, Delayed(ds, server))
        end
    end
end

getpath(file::File) = file.path

getroot(file::File) = file.root
function setroot(file::File, root::File)
    file.root = root
    return file
end

getcst(file::File) = file.cst
function setcst(file::File, cst::EXPR)
    file.cst = cst
    return file
end

getserver(file::File) = file.server
function setserver(file::File, server::FileServer)
    file.server = server
    return file
end

function Base.display(f::File)
    println(f.path)
end

function Base.display(s::FileServer)
    n = length(s.files)
    println(n, "-file Server")
    cnt = 0
    for (p, f) in s.files
        cnt += 1
        println(" ", p)
        cnt > 10 && break
    end
end

"""
    get_path(x::EXPR)

Usually called on the argument to `include` calls, and attempts to determine
the path of the file to be included. Has limited support for `joinpath` calls.
"""
function get_path(x::EXPR, state)
    if is_call(x) && length(x) == 4
        parg = x[3]
        if CSTParser.is_lit_string(parg)
            path = CSTParser.str_value(parg)
            path = normpath(path)
            Base.containsnul(path) && throw(SLInvalidPath("Couldn't convert '$x' into a valid path. Got '$path'"))
            return path
        elseif typof(parg) === x_Str && length(parg) == 2 && isidentifier(parg[1]) && valof(parg[1]) == "raw" && typof(parg[2]) === CSTParser.LITERAL && (kindof(parg[2]) == CSTParser.Tokens.STRING || kindof(parg[2]) == CSTParser.Tokens.TRIPLE_STRING)
            path = normpath(CSTParser.str_value(parg[2]))
            Base.containsnul(path) && throw(SLInvalidPath("Couldn't convert '$x' into a valid path. Got '$path'"))
            return path
        elseif is_call(parg) && isidentifier(parg[1]) && CSTParser.str_value(parg[1]) == "joinpath"
            path_elements = String[]

            for i = 2:length(parg)
                arg = parg[i]
                if ispunctuation(arg)
                elseif _is_macrocall_to_BaseDIR(arg) # Assumes @__DIR__ points to Base macro.
                    push!(path_elements, dirname(getpath(state.file)))
                elseif CSTParser.is_lit_string(arg)
                    push!(path_elements, string(CSTParser.str_value(arg)))
                else
                    return ""
                end
            end
            isempty(path_elements) && return ""

            path = normpath(joinpath(path_elements...))
            Base.containsnul(path) && throw(SLInvalidPath("Couldn't convert '$x' into a valid path. Got '$path'"))
            return path
        end
    end
    return ""
end

_is_macrocall_to_BaseDIR(arg) = is_macro_call(arg) && length(arg) == 1 &&
    is_macroname(arg[1]) &&
    valof(arg[1][2]) == "__DIR__"


text:
mutable struct MustacheTokens
    tokens
end

mutable struct AnIndex
    ind
    value
end
Base.string(ind::AnIndex) = string(ind.value)

## after parsing off to squash, nest and render the tokens

## Make the intial set of tokens before squashing and nesting
function make_tokens(template, tags)

    tags = ["{{", "}}"]         # we hard code tags!
    tagRes = [r"{{", r"}}"]

    scanner = Scanner(template)

    sections = Array{Any}(undef,0)
    tokens = Array{Any}(undef, 0)
    spaces = Array{Integer}(undef, 0)
    hasTag = false
    nonSpace = false

    function stripSpace(hasTag, nonSpace)
        if hasTag && !nonSpace
            while length(spaces) > 0
                delete!(tokens, pop!(spaces))
            end
        else
            spaces = Array{Integer}(undef,0)
        end

        hasTag = false
        nonSpace = false
    end

    while !eos(scanner)
        start = scanner.pos

        value = scanUntil!(scanner, tagRes[1])

        if !falsy(value)
#            for i in 1:length(value)
#                chr = string(value[i])
            for val in value
                chr = string(val)
                if isWhitespace(chr)
                    push!(spaces, length(tokens))
                else
                    nonSpace = true
                end

                push!(tokens, Any["text", chr, start, start + lastindex(chr)])
                start += lastindex(chr)

                if chr == "\n"
                    #stripSpace(hasTag, nonSpace)
                end

            end
        end

        if scan(scanner, tagRes[1]) == ""
            break
        end

        hasTag = true

        ## find type #,/,^,{, ...
        _type = scan(scanner, tagRe)

        if _type == ""
            _type = "name"
        end

        if _type == "="
            value = scanUntil!(scanner, eqRe)
            scan(scanner, eqRe)
            scanUntil!(scanner, tagRes[2])
        elseif _type == ""
            ## XXX hard code tags
            value = scanUntil!(scanner, r"\\s*\}\}\}")
            scan(scanner, curlyRe)
            scanUntil!(scanner, tagRes[2])
            _type = "&"
        elseif _type == "{"
            value = scanUntil!(scanner, tagRes[2])
            scan(scanner, r"}")
        else
            value = scanUntil!(scanner, tagRes[2])
        end

        if scan(scanner, tagRes[2]) == ""
            error("Unclosed tag at " * string(scanner.pos))
        end

        token = Any[_type, value, start, scanner.pos]

        push!(tokens, token)

        if _type == "#" || _type == "^"
            push!(sections, token)
        elseif _type == "/"
            ## section nestinng
            if length(sections) == 0
                error("Unopened section $value at $start")
            end

            openSection = pop!(sections)
            if openSection[2] != value
                error("Unclosed section" * openSection[2] * " at $start")
            end

        elseif _type == "name" || _type == "{" || _type == "&"
            nonSpace = true
        elseif _type == "="
            tags = split(value, spaceRe)
            if length(tags) != 2
                error("Invalid tags at $start:" * join(tags, ", "))
            end

        end
    end

    if length(sections) > 0
        openSection = pop!(sections)
        error("Unclosed section " * string(openSection[2]) * "at " * string(scanner.pos))
    end

    return(tokens)
end

## take single character tokens and collaps into chunks
function squashTokens(tokens)
    squashedTokens = Array{Any}(undef, 0)
    lastToken = nothing

    for i in 1:length(tokens)
        token = tokens[i]
        if !falsy(lastToken) && token[1] == "text"  && lastToken[1] == "text"
            lastToken[2] *= token[2]
            lastToken[4] = token[4]
        else
            lastToken = token
            push!(squashedTokens, token)
        end
    end

    return(squashedTokens)
end

## Forms the given array of `tokens` into a nested tree structure where
## tokens that represent a section have two additional items: 1) an array of
## all tokens that appear in that section and 2) the index in the original
## template that represents the end of that section.
function nestTokens(tokens)
    tree = Array{Any}(undef, 0)
    collector = tree
    sections = Array{Any}(undef, 0)

    for i in 1:length(tokens)
        token = tokens[i]
        ## a {{#name}}...{{/name}} will iterate over name
        ## a {{^name}}...{{/name}} does ... if we have no name
        ## start nesting
        if token[1] == "^" || token[1] == "#"
            push!(sections, token)
            push!(collector, token)
            push!(token, Array{Any}(undef, 0))
            collector = token[5]
        elseif token[1] == "/"
            section = pop!(sections)
            collector = length(sections) > 0 ? sections[end][5] : tree
        else
            push!(collector, token)
        end
    end

    function print_tree(x, k)
        for i in x
            if length(i) > 4
                println(" " ^ (k-1), (k, i[1:4]))
                print_tree(i[5], k+1)
            else
                println(" " ^ (k-1), (k, i))
            end
        end
    end

    return(tree)
end

function renderTokensByValue(value, io, token, writer, context, template)
    if is_dataframe(value)
        for i in 1:size(value)[1]
            renderTokens(io, token[5], writer, ctx_push(context, value[i,:]), template)
        end
    else
        _renderTokensByValue(value, io, token, writer, context, template)
    end
end

## Helper function for dispatch based on value in renderTokens
function _renderTokensByValue(value::Dict, io, token, writer, context, template)
    renderTokens(io, token[5], writer, ctx_push(context, value), template)
end

function _renderTokensByValue(value::Array, io, token, writer, context, template)
    if falsy(value)
        renderTokens(io, token[5], writer, ctx_push(context, ""), template)
    else
        for v in value
            renderTokens(io, token[5], writer, ctx_push(context, v), template)
        end
    end
end

## ## DataFrames
## function renderTokensByValue(value::DataFrames.DataFrame, io, token, writer, context, template)
##     ## iterate along row, Call one for each row
##     for i in 1:size(value)[1]
##         renderTokens(io, token[5], writer, ctx_push(context, value[i,:]), template)
##     end
## end

## what to do with an index value `.[ind]`?
## We have `.[ind]` being of a leaf type (values are not pushed onto a Context) so of simple usage
function _renderTokensByValue(value::AnIndex, io, token, writer, context, template)
    if token[1] == "#"
        # print if match
        if value.value == context.view
            renderTokens(io, token[5], writer, context, template)
        end
    elseif token[1] == "^"
        # print if *not* a match
        if value.value != context.view
            renderTokens(io, token[5], writer, context, template)
        end
    else
        renderTokens(io, token[5], writer, ctx_push(context, value.value), template)
    end
end

function _renderTokensByValue(value::Function, io, token, writer, context, template)
    ## function get's passed
    # When the value is a callable
    # object, such as a function or lambda, the object will
    # be invoked and passed the block of text. The text
    # passed is the literal block, unrendered. {{tags}} will
    # not have been expanded - the lambda should do that on
    # its own. In this way you can implement filters or
    # caching.

    render = (tokens) -> begin
        sprint(io -> renderTokens(io, tokens, writer, context, template))
    end

    out = (value())(token[5], render)
    write(io, out)
end

function _renderTokensByValue(value::Any, io, token, writer, context, template)
    if !falsy(value)
        renderTokens(io, token[5], writer, context, template)
    end
end

## Low-level function that renders the given `tokens` using the given `writer`
## and `context`. The `template` string is only needed for templates that use
## higher-order sections to extract the portion of the original template that
## was contained in that section.
function renderTokens(io, tokens, writer, context, template)
    for i in 1:length(tokens)
        token = tokens[i]
        tokenValue = token[2]

        if token[1] == "#"
            ## iterate over value if Dict, Array or DataFrame,
            ## or display conditionally
            value = lookup(context, tokenValue)
            if !isa(value, AnIndex)
                context = Context(value, context)
            end
            renderTokensByValue(value, io, token, writer, context, template)
            ## ##  many things based on value of value
            ## if isa(value, Dict)
            ##     renderTokens(io, token[5], writer, ctx_push(context, value), template)
            ## elseif isa(value, Array)
            ##     for v in value
            ##         renderTokens(io, token[5], writer, ctx_push(context, v), template)
            ##     end
            ## elseif Main.isdefined(:DataFrame) && isa(value, Main.DataFrame)
            ##     ## iterate along row, Call one for each row
            ##     for i in 1:size(value)[1]
            ##         renderTokens(io, token[5], writer, ctx_push(context, value[i,:]), template)
            ##     end
            ## elseif isa(value, Function)
            ##     ## function get's passed
            ##     # When the value is a callable
            ##     # object, such as a function or lambda, the object will
            ##     # be invoked and passed the block of text. The text
            ##     # passed is the literal block, unrendered. {{tags}} will
            ##     # not have been expanded - the lambda should do that on
            ##     # its own. In this way you can implement filters or
            ##     # caching.

            ##     function render(tokens)
            ##         sprint(io -> renderTokens(io, tokens, writer, context, template))
            ##     end

            ##     out = (value())(token[5], render)
            ##     write(io, out)

            ## elseif !falsy(value)
            ##     renderTokens(io, token[5], writer, context, template)
            ## end

        elseif token[1] == "^"
            ## display if falsy, unlike #
            value = lookup(context, tokenValue)
            if !isa(value, AnIndex)
                context = Context(value, context)

                if falsy(value)
                    renderTokensByValue(value, io, token, writer, context, template)
                end
            else
                # for indices falsy test is performed in
                # _renderTokensByValue(value::AnIndex,...)
                renderTokensByValue(value, io, token, writer, context, template)
            end

        elseif token[1] == ">"
            ## partials
            fname = stripWhitepace(tokenValue)
            if isfile(fname)
                renderTokens(io, template_from_file(fname).tokens, writer, context, template)
            end

        elseif token[1] == "<"
            ## partials without parse
            fname = stripWhitepace(tokenValue)
            if isfile(fname)
                print(io, open(readstring, fname))
            else
                warn("File $fname not found")
            end

        elseif token[1] == "&"
            value = lookup(context, tokenValue)
            if value != nothing
                print(io, value)
            end

        elseif token[1] == "{"
            value = lookup(context, tokenValue)
            if value != nothing
                print(io, value)
            end

        elseif token[1] == "name"
            value = lookup(context, tokenValue)
            # we had Nullable field support here, but this is dropped
            # in v"0.7.0" in favor of Union{T, Nothing} so we check for nothing
            # we could add a check for Missing too
            value != nothing && print(io, escape_html(value))

        elseif token[1] == "text"
            print(io, string(tokenValue))
        end

    end

    #    return(buffer)
end


text:
function Base.eltype(::BipartiteProbabilisticNetwork{IT,ST}) where {IT,ST}
    return NamedTuple{(:from, :to, :probability),Tuple{ST,ST,IT}}
end

function Base.eltype(::BipartiteQuantitativeNetwork{IT,ST}) where {IT,ST}
    return NamedTuple{(:from, :to, :strength),Tuple{ST,ST,IT}}
end

function Base.eltype(::BipartiteNetwork{IT,ST}) where {IT,ST}
    return NamedTuple{(:from, :to),Tuple{ST,ST}}
end

function Base.eltype(::UnipartiteProbabilisticNetwork{IT,ST}) where {IT,ST}
    return NamedTuple{(:from, :to, :probability),Tuple{ST,ST,IT}}
end

function Base.eltype(::UnipartiteQuantitativeNetwork{IT,ST}) where {IT,ST}
    return NamedTuple{(:from, :to, :strength),Tuple{ST,ST,IT}}
end

function Base.eltype(::UnipartiteNetwork{IT,ST}) where {IT,ST}
    return NamedTuple{(:from, :to),Tuple{ST,ST}}
end

function Base.IteratorSize(::Type{T}) where {T <: AbstractEcologicalNetwork}
    return Base.HasLength()
end

function Base.IteratorEltype(::Type{T}) where {T <: AbstractEcologicalNetwork}
    return Base.HasEltype()
end

function Base.isempty(N::T) where {T <: AbstractEcologicalNetwork}
    return iszero(length(N))
end

function _network_state(N::T, i::Int64) where {T <: BinaryNetwork}
    f,t = findall(!iszero, N.edges)[i].I
    return (from=species(N;dims=1)[f],to=species(N;dims=2)[t])
end

function _network_state(N::T, i::Int64) where {T <: QuantitativeNetwork}
    f,t = findall(!iszero, N.edges)[i].I
    return (from=species(N;dims=1)[f],to=species(N;dims=2)[t],strength=N[f,t])
end

function _network_state(N::T, i::Int64) where {T <: ProbabilisticNetwork}
    f,t = findall(!iszero, N.edges)[i].I
    return (from=species(N;dims=1)[f],to=species(N;dims=2)[t],probability=N[f,t])
end

"""
    Base.iterate(N::T) where {T <: AbstractEcologicalNetwork}

Returns the interactions in a network (this uses less memory than `interactions`
but is a bit slower).
"""
function Base.iterate(N::T) where {T <: AbstractEcologicalNetwork}
    isempty(N) && return nothing
    return (_network_state(N, 1), 1)
end

"""
    Base.iterate(N::T) where {T <: AbstractEcologicalNetwork}

Returns the interactions in a network (this uses less memory than `interactions`
but is a bit slower).
"""
function Base.iterate(N::T, state::Int64) where {T <: AbstractEcologicalNetwork}
    next = state == length(N) ? nothing : state+1
    isnothing(next) && return nothing
    return (_network_state(N, next), next)
end


text:
using ..Continuations: AbstractContinuationProblem, AbstractContinuationSolver,
    AbstractContinuationCache,
    as, SweepSetup, ContinuationSweep, ContinuationSolution,
    ContinuationCache, ContinuationOptions, ContinuationSolver,
    residual_jacobian!

using ..BifurcationsBase: timekind, Continuous, Discrete
import ..BifurcationsBase: TimeKind

using ..BifurcationsBase
using ..BifurcationsBase: SpecialPoint, SpecialPointInterval,
    BifurcationSweep, BifurcationSolution, BifurcationSolver,
    BifurcationProblem, BifurcationCache,
    eigvals_prototype, allocate_sweep!, check_sweep_length, record!
import ..BifurcationsBase: analyze!, re_analyze!

import ..Codim1: testfn

module PointTypes
@enum(
    PointType,
    none,
    saddle_node,
)
end  # module
using .PointTypes: PointType

const Codim1LCSweep{tkind <: TimeKind, ptType <: PointType} =
    BifurcationSweep{tkind, ptType}
const Codim1LCSolution{S <: ContinuationSolution, W <: Codim1LCSweep} =
    BifurcationSolution{S, W}
# The constraints `<: TimeKind` and `<: ContinuationSolution` are
# important.
# See: [[../codim1/solver.jl::Codim1Sweep]]

BifurcationsBase.point_type_type(::Codim1LCProblem) = PointType

BifurcationsBase.regular_point(::Type{PointType}) = PointTypes.none

function BifurcationsBase.eigvals_prototype(prob::Codim1LCProblem,
                                            cache::ContinuationCache)
    n = length(prob.de_prob.u0)
    return similar(cache.u[1:1] .+ 1im, n)
end

mutable struct Codim1LCCache{P, C <: ContinuationCache{P},
                             JType, eType,
                             } <: BifurcationCache{P}
    super::C
    prev_det::Float64
    J::JType
    eigvals::eType
    point_type::PointType
end

function Codim1LCCache(super::C,
                       J::JType,
                       eigvals::eType,
                       point_type = PointTypes.none,
                       ) where {P, C <: ContinuationCache{P},
                                JType, eType}
    return Codim1LCCache{P, C, JType, eType}(
        super,
        NaN, J, eigvals,
        point_type)
end
# TODO: Remove this constructor after removing the type parameter `P`.

Codim1LCCache(prob::Codim1LCProblem, super::ContinuationCache) =
    Codim1LCCache(
        super,
        let v = eigvals_prototype(prob, super)
            v * v'
        end,
        # ds_jacobian(super),
        copy(eigvals_prototype(prob, super)),
    )

BifurcationsBase.BifurcationCache(prob::Codim1LCProblem,
                                  super::ContinuationCache) =
    Codim1LCCache(prob, super)

const Codim1LCSolver{
        R <: ContinuationSolver,
        P <: Codim1LCProblem,
        C <: Codim1LCCache,
        S <: Codim1LCSolution,
        } =
    BifurcationSolver{R, P, C, S}

# TODO: trait
BifurcationsBase.contkind(::Codim1LCProblem) = LimitCycleCont()

function re_analyze!(solver::Codim1LCSolver, u::AbstractVector)
    residual_jacobian!(as(solver.cache, ContinuationCache), u)
    analyze!(solver.cache, solver.opts)

    # Suppress special point recording:
    # It's a bit ugly hack... (communicate by sharing!)
    solver.cache.point_type = PointTypes.none  # TODO: FIX!

    record!(solver.sol, solver.cache)
end

function analyze!(cache::Codim1LCCache, opts)
    cache.point_type = PointTypes.none

    curr_det = det(@view as(cache, ContinuationCache).J[:, 1:end-1])
    if curr_det * cache.prev_det < 0
        cache.point_type = PointTypes.saddle_node
    end
    cache.prev_det = curr_det

    #=
    cache.J = J = ds_jacobian(cache)
    eigvals = ds_eigvals(timekind(cache), J)
    cache.point_type = guess_point_type(timekind(cache), cache, eigvals, opts)
    cache.eigvals = eigvals
    =#
    set_reference!(cache)
end

testfn(::Val{PointTypes.saddle_node}, ::Continuous, ::LimitCycleCont,
       prob_cache, u, J, L, Q) =
    det(@view J[:, 1:end-1])

function set_reference!(wrapper)
    cache = as(wrapper, ContinuationCache)
    prob_cache = as(cache.prob_cache, LimitCycleCache)
    set_reference!(prob_cache, cache.u)
end


text:
# Interesting cross-type indexing operations (Dic[Arr] -> Arr, etc)
@testset "indexing" begin
    v1 = Vec([4,3,2])
    d1 = Dic(4=>11, 3=>12, 2=>13)

    @test d1[v1] isa Vec{Int}
    @test d1[v1] == Vec([11,12,13])

    d2 = Dic(4=>3, 5=>2, 6=>1)
    v2 = Vec([11,12,13])

    @test v2[d2] isa Dic{Int, Int}
    @test v2[d2] == Dic(4=>13, 5=>12, 6=>11)
end


text:
using Images
using Statistics
using TestImages
using ImageBinarization

"""
    edges = sujoy(img; four_connectivity=true)

Compute edges of an image using the Sujoy algorithm.

# Parameters

* `img` (Required): any gray image
* `four_connectivity=true`: if true, kernel is based on 4-neighborhood, else, kernel is based on
   8-neighborhood,

# Returns

* `edges` : gray image
"""
function sujoy(img; four_connectivity=true)
    img_channel = Gray.(img)

    min_val = minimum(img_channel)
    img_channel = img_channel .- min_val
    max_val = maximum(img_channel)

    if max_val == 0
        return img
    end

    img_channel = img_channel./max_val

    if four_connectivity
        krnl_h = centered(Gray{Float32}[0 -1 -1 -1 0; 0 -1 -1 -1 0; 0 0 0 0 0; 0 1 1 1 0; 0 1 1 1 0]./12)
        krnl_v = centered(Gray{Float32}[0 0 0 0 0; -1 -1 0 1 1;-1 -1 0 1 1;-1 -1 0 1 1;0 0 0 0 0 ]./12)
    else
        krnl_h = centered(Gray{Float32}[0 0 -1 0 0; 0 -1 -1 -1 0; 0 0 0 0 0; 0 1 1 1 0; 0 0 1 0 0]./8)
        krnl_v = centered(Gray{Float32}[0 0 0 0 0;  0 -1 0 1 0; -1 -1 0 1 1;0 -1 0 1 0; 0 0 0 0 0 ]./8)
    end

    grad_h = imfilter(img_channel, krnl_h')
    grad_v = imfilter(img_channel, krnl_v')

    grad = (grad_h.^2) .+ (grad_v.^2)

    return grad
end

# This file was generated using Literate.jl, https://github.com/fredrikekre/Literate.jl

max_stars_repo_name: jjgomezcadenas/laserlab

max_issues_repo_name: jjgomezcadenas/laserlab

max_forks_repo_name: jjgomezcadenas/laserlab


text:
#
include("Yfind.jl")
include("is_it_exit2.jl")
include("is_it.jl")

@everywhere function BASIN_PSS_function_parallel(K)

    Q_start=-1.5
    Q_end=1.5
    P_start=-2.5
    P_end=2.5
    n_iter_P=2000
    n_iter_Q=2001

    delta_P=(P_end-P_start)/n_iter_P
    delta_Q=(Q_end-Q_start)/n_iter_Q

    ArrP=P_start: delta_P:P_end
    ArrQ=Q_start: delta_Q: Q_end

    Q=ArrQ[Int(ceil(K/n_iter_Q))]
    P=ArrP[mod(K,n_iter_P)+1]

    max_hit=5
    Energy=.25
    t_end=1000
    tol_dist=1e-5
    H=(2*Energy)^2

    Q_0=0
    P_0=0

    Q_1=0
    P_1=0

    Q_2=0
    P_2=0

    Q_3=0
    P_3=0

    Y=Yfind(Q,P,H)
    if ~isempty(Y)
        u0=zeros(5)
        u0[1]=0 #X
        u0[2]=P #P
        u0[3]=Q #Q
        u0[4]=Y[1] #Y
        u0[5]=0 #Y
        # counter variable
        #are the initial conditions right?
        # prob_test= ODEProblem(Eq_of_M,u0,(0., 10.))
        # sol_test=solve(prob_test, RK4(),maxiters=1e10 )
        # S=sign(sol_test.u[2][1])
        if true
            prob = ODEProblem(Eq_of_M,u0,(0., t_end))
            # sol=solve(prob,RK4(),maxiters=1e20, reltol=1e-6,abstol=1e-8,callback=cb)
            sol=solve(prob, Vern9(),maxiters=1e10, reltol=1e-8,abstol=1e-10,callback=cb)
            uf=zeros(5)
            uf[1]=sol[1,end] #X
            uf[2]=sol[2,end] #P
            uf[3]=sol[3,end] #Q
            uf[4]=sol[4,end] #Y
            uf[5]=0
            dH=abs(H_test(uf)-H)
            #
            if dH<1e-5
                B=hcat(sol.u[end-10],sol.u[end])'

                if is_it_exit2(B,H,tol_dist) && is_it_exit(sol.u[end],H,tol_dist)
                    return sol.u[end][5]/2.0
                else
                    return -1
                end
            end
        end
    end
    return -2
end


text:
using PriorityChannels
using Test

# This file is a part of Julia. License is MIT: https://julialang.org/license

using Random

@testset "various constructors" begin
    c = PriorityChannel(1)
    @test eltype(c) == Any
    @test put!(c, 1) == 1
    @test isready(c) == true
    @test take!(c) == 1
    @test isready(c) == false
    @test eltype(PriorityChannel(1.0)) == Any

    c = PriorityChannel{Int,Int}(1)
    @test eltype(c) == Int
    @test_throws MethodError put!(c, "Hello")

    c = PriorityChannel{Int,Int}(Inf)
    @test eltype(c) == Int
    pvals = map(i->put!(c,i,i), 1:10^6)
    tvals = Int[take!(c) for i in 1:10^6]
    @test pvals == tvals

    @test_throws MethodError PriorityChannel()
    @test_throws ArgumentError PriorityChannel(-1)
    @test_throws InexactError PriorityChannel(1.5)
end

@testset "priorities" begin
    c = PriorityChannel(10)
    for i = 1:10
        e = rand(1:100)
        put!(c,e,e)
    end
    elems = [take!(c) for i = 1:10]
    @test issorted(elems)
end

@testset "multiple concurrent put!/take! on a channel for different sizes" begin
    function testcpt(sz)
        c = PriorityChannel{Int,Int}(sz)
        size = 0
        inc() = size += 1
        dec() = size -= 1
        @sync for i = 1:10^4
            @async (sleep(rand()); put!(c, i); inc())
            @async (sleep(rand()); take!(c); dec())
        end
        @test size == 0
    end
    testcpt(1)
    testcpt(32)
    testcpt(Inf)
end

@testset "type conversion in put!" begin
    c = PriorityChannel{Int64,Int}(1)
    @async put!(c, Int32(1))
    wait(c)
    @test isa(take!(c), Int64)
    @test_throws MethodError put!(c, "")
end

@testset "multiple for loops waiting on the same channel" begin
    # Test multiple "for" loops waiting on the same channel which
    # is closed after adding a few elements.
    c = PriorityChannel(32)
    results = []
    @sync begin
        for i in 1:20
            @async for ii in c
                push!(results, ii)
            end
        end
        sleep(1.0)
        for i in 1:5
            put!(c,i)
        end
        close(c)
    end
    @test sum(results) == 15
end

# Tests for channels bound to tasks.
using Distributed
@testset "channels bound to tasks" begin
    N = 10
    # Normal exit of task
    c=PriorityChannel(N)
    bind(c, @async (yield();nothing))
    @test_throws InvalidStateException take!(c)
    @test !isopen(c)

    # Error exception in task
    c=PriorityChannel(N)
    bind(c, @async (yield();error("foo")))
    @test_throws ErrorException take!(c)
    @test !isopen(c)

    # Multiple channels closed by the same bound task
    cs = [PriorityChannel(N) for i in 1:5]
    tf2 = () -> begin

    foreach(c->(@assert take!(c)==2), cs)

    yield()
    error("foo")
end
task = Task(tf2)
foreach(c->bind(c, task), cs)
schedule(task)

for i in 1:5
    @test put!(cs[i], 2) == 2
end

for i in 1:5
    while (isopen(cs[i])); yield(); end
    @test_throws ErrorException wait(cs[i])
    @test_throws ErrorException take!(cs[i])
    @test_throws ErrorException put!(cs[i], 1)
    @test_throws ErrorException fetch(cs[i])
end

# Multiple tasks, first one to terminate closes the channel
nth = rand(1:5)
ref = Ref(0)
cond = Condition()
tf3(i) = begin
    if i == nth
        ref[] = i
    else
        sleep(2.0)
    end
end

tasks = [Task(()->tf3(i)) for i in 1:5]
c = PriorityChannel(N)
foreach(t->bind(c,t), tasks)
foreach(schedule, tasks)
@test_throws InvalidStateException wait(c)
@test !isopen(c)
@test ref[] == nth

# channeled_tasks
for T in [Any, Int]
    chnls, tasks = Base.channeled_tasks(2, (c1,c2)->(@assert take!(c1)==1; put!(c2,2)); ctypes=[T,T], csizes=[N,N])
    put!(chnls[1], 1)
    @test take!(chnls[2]) == 2
    @test_throws InvalidStateException wait(chnls[1])
    @test_throws InvalidStateException wait(chnls[2])
    @test istaskdone(tasks[1])
    @test !isopen(chnls[1])
    @test !isopen(chnls[2])

    f=Future()
    tf4 = (c1,c2) -> begin
    @assert take!(c1)==1
    wait(f)
end

tf5 = (c1,c2) -> begin
put!(c2,2)
wait(f)
end

chnls, tasks = Base.channeled_tasks(2, tf4, tf5; ctypes=[T,T], csizes=[N,N])
put!(chnls[1], 1)
@test take!(chnls[2]) == 2
yield()
put!(f, 1)

@test_throws InvalidStateException wait(chnls[1])
@test_throws InvalidStateException wait(chnls[2])
@test istaskdone(tasks[1])
@test istaskdone(tasks[2])
@test !isopen(chnls[1])
@test !isopen(chnls[2])
end

# channel
tf6 = c -> begin
@assert take!(c)==2
error("foo")
end

for T in [Any, Int]
    taskref = Ref{Task}()
    chnl = PriorityChannel(tf6, ctype=T, csize=N, taskref=taskref)
    put!(chnl, 2)
    yield()
    @test_throws ErrorException wait(chnl)
    @test istaskdone(taskref[])
    @test !isopen(chnl)
    @test_throws ErrorException take!(chnl)
end
end

using Dates
@testset "timedwait on multiple channels" begin
    @sync begin
        rr1 = PriorityChannel(1)
        rr2 = PriorityChannel(1)
        rr3 = PriorityChannel(1)

        callback() = all(map(isready, [rr1, rr2, rr3]))
        # precompile functions which will be tested for execution time
        @test !callback()
        @test timedwait(callback, 0.0) === :timed_out

        @async begin sleep(0.5); put!(rr1, :ok) end
        @async begin sleep(1.0); put!(rr2, :ok) end
        @async begin sleep(2.0); put!(rr3, :ok) end

        et = @elapsed timedwait(callback, Dates.Second(1))

        # assuming that 0.5 seconds is a good enough buffer on a typical modern CPU
        try
            @assert (et >= 1.0) && (et <= 1.5)
            @assert !isready(rr3)
        catch
            @warn "`timedwait` tests delayed. et=$et, isready(rr3)=$(isready(rr3))"
        end
        @test isready(rr1)
    end
end

@testset "check_channel_state" begin
    c = PriorityChannel(1)
    close(c)
    @test !isopen(c)
    c.excp == nothing # to trigger the branch
    @test_throws InvalidStateException Base.check_channel_state(c)
end


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

using Markdown
using InteractiveUtils

# ╔═╡ 5a3f9995-3d45-40b9-af98-7de36713a942
begin
    import Pkg
    # activate a clean environment
    Pkg.activate(mktempdir())

    Pkg.add("Gumbo,Cascadia,HTTP,Plots,DataFrames" |> x->split(x, ',') .|>
		name -> Pkg.PackageSpec(name=name)
    )
	using Gumbo,Cascadia, HTTP, Plots, DataFrames
end

# ╔═╡ 224bf02a-bc07-4791-a1a8-be06747359fe
@eval(PlutoRunner, table_row_display_limit = 270)

# ╔═╡ 83753096-85ba-403b-aa9f-c0fc75d2823b
years_with_statistics = [
	2021:-1:2006...,
	2004,
	2003,
	1997,
	1995,
	1991,
	1989
]

# ╔═╡ f0a2d124-1cc4-4da7-9e58-847bf3e8f566
get_competition_url(year) = "https://stats.ioinformatics.org/results/$year"

# ╔═╡ 309dad61-df77-4347-b397-048774915f24
read_url(url) = url |> HTTP.get |> x -> x.body |> String |> parsehtml

# ╔═╡ 57308935-f6a9-4ecc-ae6c-0d5aca5ab967
get_competition_page(year) = get_competition_url(year) |> read_url

# ╔═╡ 687c7f1e-e383-42fb-8faa-101ed2a8a681
function get_tasks_statistics(year)
	h = get_competition_page(year)

	task_names = String[]
	task_scores = Vector{Float64}[]
	n_tasks = 0
	function handle(x::HTMLElement{:a})
		n_tasks += 1
		push!(task_names, x.attributes["href"])
		push!(task_scores, Float64[])
	end

	idx = -1
	function handle(x::HTMLText)
		idx += 1
		x.text == "–" && return
		push!(task_scores[(idx % n_tasks) + 1], min(100.0, parse(Float64, x.text)))
	end

	for elm ∈ eachmatch(Selector(".taskscore"), h.root)
		handle(elm[1])
	end
	res = Dict()
	for i ∈ 1:n_tasks
		res[task_names[i]] = task_scores[i] |> sort!
	end
	res |> collect
end

# ╔═╡ 53c99b97-7e13-4bfc-bbb5-c208dcb3b083
get_all_tasks() = vcat(
	asyncmap(get_tasks_statistics, years_with_statistics)...)

# ╔═╡ 30cda10a-9545-444c-88ac-e6664ef912c1
tasks = get_all_tasks()

# ╔═╡ 632d7079-83e7-4fbb-b10b-b51fc871d43d
function dist_to_gradient(dist)
	"Take a distribution and changes it to a cumulative gradient you can draw"
	stats = zeros(Float64, 101)
	for i ∈ dist
		stats[round(Int, i) + 1] += 1
	end
	stats = cumsum(stats)
	stats = stats ./ stats[end]
	stats
end

# ╔═╡ 46e5ab26-7ddc-4377-80c7-42afac6795a2
function plot_dist(scores)
	dist = dist_to_gradient(scores)
	# plot(dist, xtick=false, ytick=false, cbar=false,
	# 		size=(1000, 150), legend=false,
	# 		fillrange=0)
	# heatmap(reshape(dist, 1, :),
	# 		xtick=false, ytick=false, cbar=false, size=(1000, 150))
	ax = plot(dist, xtick=false, ytick=false, cbar=false,
		size=(1000, 150), legend=false,
		fill_between=0
	)
	histogram(
		ax,
		scores,
		normalize=:probability,
		xtick=false, ytick=false, cbar=false,
		size=(1000, 150), legend=false,
		bins=0.0:101/15:101.0
	)
end

# ╔═╡ 01c93793-9ceb-426b-aa16-2f6af64d569f
plots = [name => plot_dist(scores) for (name, scores) ∈ tasks]

# ╔═╡ 8ad30675-6c5d-41bc-b8d9-203ec3eca49a
function to_dataframe(plots)
	names = [i for (i,j) ∈ plots]
	plots = [j for (i,j) ∈ plots]
	DataFrame(name=names, cumulative_plot=plots)
end

# ╔═╡ d1848f8b-3dbe-4a9f-bb3c-3b7a0815180c
to_dataframe(plots) # for pretty prints

# ╔═╡ Cell order:
# ╠═224bf02a-bc07-4791-a1a8-be06747359fe
# ╠═d1848f8b-3dbe-4a9f-bb3c-3b7a0815180c
# ╠═5a3f9995-3d45-40b9-af98-7de36713a942
# ╠═83753096-85ba-403b-aa9f-c0fc75d2823b
# ╠═f0a2d124-1cc4-4da7-9e58-847bf3e8f566
# ╠═309dad61-df77-4347-b397-048774915f24
# ╠═57308935-f6a9-4ecc-ae6c-0d5aca5ab967
# ╠═687c7f1e-e383-42fb-8faa-101ed2a8a681
# ╠═53c99b97-7e13-4bfc-bbb5-c208dcb3b083
# ╠═30cda10a-9545-444c-88ac-e6664ef912c1
# ╠═632d7079-83e7-4fbb-b10b-b51fc871d43d
# ╠═46e5ab26-7ddc-4377-80c7-42afac6795a2
# ╠═01c93793-9ceb-426b-aa16-2f6af64d569f
# ╠═8ad30675-6c5d-41bc-b8d9-203ec3eca49a

max_stars_repo_name: kessido/IOITaskStatistics

max_issues_repo_name: kessido/IOITaskStatistics

max_forks_repo_name: kessido/IOITaskStatistics


text:
module Trials

using DocStringExtensions

const ValsDict = Dict{Symbol, Real}

"""
$(TYPEDEF)

Contains the suggested hyperparameters and the resulting loss for a particular trial.

$(TYPEDFIELDS)

# Arguments

- `hyperparams` : suggested hyperparameters for the trial stored in a form that can be
    submitted to the user's function
- `vals` : suggested hyperparameters for the trial stored in a form that can be learnt from.
    e.g. choices are indexs rather than choice values
- `loss` : the float returned by evaluating the user's function
"""
mutable struct Trial
    hyperparams::Any
    vals::ValsDict
    loss::Float64
end

end # module Trials


text:
# ## ARITHMETIC

const ERR_DIFFERENT_SAMPLE_SPACES = ArgumentError(
    "Adding two `UnivariateFinite` objects whose "*
    "sample spaces have different labellings is not allowed. ")

import Base: +, *, /, -

pdf_matrix(d::UnivariateFinite, L) = pdf.(d, L)
pdf_matrix(d::AbstractArray{<:UnivariateFinite}, L) = pdf(d, L)

function +(d1::U, d2::U) where U <: SingletonOrArray
    L = classes(d1)
    L == classes(d2) || throw(ERR_DIFFERENT_SAMPLE_SPACES)
    return UnivariateFinite(L, pdf_matrix(d1, L) + pdf_matrix(d2, L))
end

function _minus(d, T)
    S = d.scitype
    decoder = d.decoder
    prob_given_ref = copy(d.prob_given_ref)
    for ref in keys(prob_given_ref)
        prob_given_ref[ref] = -prob_given_ref[ref]
    end
    return T(S, decoder, prob_given_ref)
end
-(d::UnivariateFinite) = _minus(d, UnivariateFinite)
-(d::UnivariateFiniteArray) = _minus(d, UnivariateFiniteArray)

function -(d1::U, d2::U) where U <: SingletonOrArray
    L = classes(d1)
    L == classes(d2) || throw(ERR_DIFFERENT_SAMPLE_SPACES)
    return UnivariateFinite(L, pdf_matrix(d1, L) - pdf_matrix(d2, L))
end

# It seems that the restriction `x::Number` below (applying only to the
# array case) is unavoidable because of a method ambiguity with
# `Base.*(::AbstractArray, ::Number)`.

function _times(d, x, T)
    S = d.scitype
    decoder = d.decoder
    prob_given_ref = copy(d.prob_given_ref)
    for ref in keys(prob_given_ref)
        prob_given_ref[ref] *= x
    end
    return T(d.scitype, decoder, prob_given_ref)
end
*(d::UnivariateFinite, x) = _times(d, x, UnivariateFinite)
*(d::UnivariateFiniteArray, x::Number) = _times(d, x, UnivariateFiniteArray)

*(x, d::UnivariateFinite) = d*x
*(x::Number, d::UnivariateFiniteArray) = d*x
/(d::UnivariateFinite, x) = d*inv(x)
/(d::UnivariateFiniteArray, x::Number) = d*inv(x)


text:
using JuLIP, QMMM2, SHIPs, PrettyTables, LinearAlgebra, Plots
using JuLIP.MLIPs
include(@__DIR__() * "/swqmmm.jl")

##
sw = StillingerWeber()
r0 = rnn(:Si)
# domain radius of reference domain ("exact" solution)
Rmax = 16.0 * r0
# domain radius on approximation domains
RDOM = [2.0, 3.0, 5.0, 7.0, 9.0] * r0
RBUF = 2*cutoff(sw) * ones(length(RDOM))

atmax = SWqmmm.int_config(Rmax, sw)
AT, Iinmax, Iinnext = QMMM2.Solve.cluster_sequence(atmax, RDOM, RBUF)
UU, EE, Umax, Emax  =  QMMM2.Solve.solve_sequence(atmax, AT, Iinmax, Iinnext)
err2, errinf = QMMM2.Solve.errors(atmax, AT, Iinmax, UU, Umax)
Eerr = abs.(EE .- Emax)

##

plot(; xaxis = (:log, "domain radius [Å]"),
       yaxis = (:log, "errors"),
       title = "Domain Test, Si, SW, Interstitial",
       legend = :bottomleft )
plot!( RDOM, err2,   c=1, lw=3, m=:o, ms=8, label =  "energy-norm" )
plot!( RDOM, errinf, c=2, lw=3, m=:o, ms=8, label =  "max-norm (strains)" )
plot!( RDOM, Eerr,   c=3, lw=3, m=:o, ms=8, label =  "energy-diff. [eV]" )
t = RDOM[3:5]
t1 = RDOM[2:5]
plot!(t, 4.5*t.^(-1.5),  c=:black, lw=2, ls=:dot, label = "R^-1.5, R^-3")
plot!(t1, 6*t1.^(-3),  c=:black, lw=2, ls=:dot, label = "")
plot!(t, 30*t.^(-3), c=:black, lw=2, ls=:dot, label = "")