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

"""
    AddTags()

Adds one or more tags to a trail, up to a limit of 50. Overwrites an existing tag's value when a new value is specified for an existing tag key. Tag key names must be unique for a trail; you cannot have two keys with the same name but different values. If you specify a key without a value, the tag will be created with the specified key and a value of null. You can tag a trail that applies to all AWS Regions only from the Region in which the trail was created (also known as its home region).

# Required Parameters
- `ResourceId`: Specifies the ARN of the trail to which one or more tags will be added. The format of a trail ARN is:  arn:aws:cloudtrail:us-east-2:123456789012:trail/MyTrail

# Optional Parameters
- `TagsList`: Contains a list of CloudTrail tags, up to a limit of 50
"""
add_tags(ResourceId; aws_config::AWSConfig=global_aws_config()) = cloudtrail("AddTags", Dict{String, Any}("ResourceId"=>ResourceId); aws_config=aws_config)
add_tags(ResourceId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("AddTags", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceId"=>ResourceId), args)); aws_config=aws_config)

"""
    CreateTrail()

Creates a trail that specifies the settings for delivery of log data to an Amazon S3 bucket.

# Required Parameters
- `Name`: Specifies the name of the trail. The name must meet the following requirements:   Contain only ASCII letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), or dashes (-)   Start with a letter or number, and end with a letter or number   Be between 3 and 128 characters   Have no adjacent periods, underscores or dashes. Names like my-_namespace and my--namespace are invalid.   Not be in IP address format (for example, 192.168.5.4)
- `S3BucketName`: Specifies the name of the Amazon S3 bucket designated for publishing log files. See Amazon S3 Bucket Naming Requirements.

# Optional Parameters
- `CloudWatchLogsLogGroupArn`: Specifies a log group name using an Amazon Resource Name (ARN), a unique identifier that represents the log group to which CloudTrail logs will be delivered. Not required unless you specify CloudWatchLogsRoleArn.
- `CloudWatchLogsRoleArn`: Specifies the role for the CloudWatch Logs endpoint to assume to write to a user's log group.
- `EnableLogFileValidation`: Specifies whether log file integrity validation is enabled. The default is false.  When you disable log file integrity validation, the chain of digest files is broken after one hour. CloudTrail will not create digest files for log files that were delivered during a period in which log file integrity validation was disabled. For example, if you enable log file integrity validation at noon on January 1, disable it at noon on January 2, and re-enable it at noon on January 10, digest files will not be created for the log files delivered from noon on January 2 to noon on January 10. The same applies whenever you stop CloudTrail logging or delete a trail.
- `IncludeGlobalServiceEvents`: Specifies whether the trail is publishing events from global services such as IAM to the log files.
- `IsMultiRegionTrail`: Specifies whether the trail is created in the current region or in all regions. The default is false, which creates a trail only in the region where you are signed in. As a best practice, consider creating trails that log events in all regions.
- `IsOrganizationTrail`: Specifies whether the trail is created for all accounts in an organization in AWS Organizations, or only for the current AWS account. The default is false, and cannot be true unless the call is made on behalf of an AWS account that is the master account for an organization in AWS Organizations.
- `KmsKeyId`: Specifies the KMS key ID to use to encrypt the logs delivered by CloudTrail. The value can be an alias name prefixed by \"alias/\", a fully specified ARN to an alias, a fully specified ARN to a key, or a globally unique identifier. Examples:   alias/MyAliasName   arn:aws:kms:us-east-2:123456789012:alias/MyAliasName   arn:aws:kms:us-east-2:123456789012:key/12345678-1234-1234-1234-123456789012   12345678-1234-1234-1234-123456789012
- `S3KeyPrefix`: Specifies the Amazon S3 key prefix that comes after the name of the bucket you have designated for log file delivery. For more information, see Finding Your CloudTrail Log Files. The maximum length is 200 characters.
- `SnsTopicName`: Specifies the name of the Amazon SNS topic defined for notification of log file delivery. The maximum length is 256 characters.
- `TagsList`:
"""
create_trail(Name, S3BucketName; aws_config::AWSConfig=global_aws_config()) = cloudtrail("CreateTrail", Dict{String, Any}("Name"=>Name, "S3BucketName"=>S3BucketName); aws_config=aws_config)
create_trail(Name, S3BucketName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("CreateTrail", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Name"=>Name, "S3BucketName"=>S3BucketName), args)); aws_config=aws_config)

"""
    DeleteTrail()

Deletes a trail. This operation must be called from the region in which the trail was created. DeleteTrail cannot be called on the shadow trails (replicated trails in other regions) of a trail that is enabled in all regions.

# Required Parameters
- `Name`: Specifies the name or the CloudTrail ARN of the trail to be deleted. The format of a trail ARN is: arn:aws:cloudtrail:us-east-2:123456789012:trail/MyTrail

"""
delete_trail(Name; aws_config::AWSConfig=global_aws_config()) = cloudtrail("DeleteTrail", Dict{String, Any}("Name"=>Name); aws_config=aws_config)
delete_trail(Name, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("DeleteTrail", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Name"=>Name), args)); aws_config=aws_config)

"""
    DescribeTrails()

Retrieves settings for one or more trails associated with the current region for your account.

# Optional Parameters
- `includeShadowTrails`: Specifies whether to include shadow trails in the response. A shadow trail is the replication in a region of a trail that was created in a different region, or in the case of an organization trail, the replication of an organization trail in member accounts. If you do not include shadow trails, organization trails in a member account and region replication trails will not be returned. The default is true.
- `trailNameList`: Specifies a list of trail names, trail ARNs, or both, of the trails to describe. The format of a trail ARN is:  arn:aws:cloudtrail:us-east-2:123456789012:trail/MyTrail  If an empty list is specified, information for the trail in the current region is returned.   If an empty list is specified and IncludeShadowTrails is false, then information for all trails in the current region is returned.   If an empty list is specified and IncludeShadowTrails is null or true, then information for all trails in the current region and any associated shadow trails in other regions is returned.    If one or more trail names are specified, information is returned only if the names match the names of trails belonging only to the current region. To return information about a trail in another region, you must specify its trail ARN.
"""
describe_trails(; aws_config::AWSConfig=global_aws_config()) = cloudtrail("DescribeTrails"; aws_config=aws_config)
describe_trails(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("DescribeTrails", args; aws_config=aws_config)

"""
    GetEventSelectors()

Describes the settings for the event selectors that you configured for your trail. The information returned for your event selectors includes the following:   If your event selector includes read-only events, write-only events, or all events. This applies to both management events and data events.   If your event selector includes management events.   If your event selector includes data events, the Amazon S3 objects or AWS Lambda functions that you are logging for data events.   For more information, see Logging Data and Management Events for Trails  in the AWS CloudTrail User Guide.

# Required Parameters
- `TrailName`: Specifies the name of the trail or trail ARN. If you specify a trail name, the string must meet the following requirements:   Contain only ASCII letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), or dashes (-)   Start with a letter or number, and end with a letter or number   Be between 3 and 128 characters   Have no adjacent periods, underscores or dashes. Names like my-_namespace and my--namespace are not valid.   Not be in IP address format (for example, 192.168.5.4)   If you specify a trail ARN, it must be in the format:  arn:aws:cloudtrail:us-east-2:123456789012:trail/MyTrail

"""
get_event_selectors(TrailName; aws_config::AWSConfig=global_aws_config()) = cloudtrail("GetEventSelectors", Dict{String, Any}("TrailName"=>TrailName); aws_config=aws_config)
get_event_selectors(TrailName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("GetEventSelectors", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("TrailName"=>TrailName), args)); aws_config=aws_config)

"""
    GetInsightSelectors()

Describes the settings for the Insights event selectors that you configured for your trail. GetInsightSelectors shows if CloudTrail Insights event logging is enabled on the trail, and if it is, which insight types are enabled. If you run GetInsightSelectors on a trail that does not have Insights events enabled, the operation throws the exception InsightNotEnabledException  For more information, see Logging CloudTrail Insights Events for Trails  in the AWS CloudTrail User Guide.

# Required Parameters
- `TrailName`: Specifies the name of the trail or trail ARN. If you specify a trail name, the string must meet the following requirements:   Contain only ASCII letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), or dashes (-)   Start with a letter or number, and end with a letter or number   Be between 3 and 128 characters   Have no adjacent periods, underscores or dashes. Names like my-_namespace and my--namespace are not valid.   Not be in IP address format (for example, 192.168.5.4)   If you specify a trail ARN, it must be in the format:  arn:aws:cloudtrail:us-east-2:123456789012:trail/MyTrail

"""
get_insight_selectors(TrailName; aws_config::AWSConfig=global_aws_config()) = cloudtrail("GetInsightSelectors", Dict{String, Any}("TrailName"=>TrailName); aws_config=aws_config)
get_insight_selectors(TrailName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("GetInsightSelectors", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("TrailName"=>TrailName), args)); aws_config=aws_config)

"""
    GetTrail()

Returns settings information for a specified trail.

# Required Parameters
- `Name`: The name or the Amazon Resource Name (ARN) of the trail for which you want to retrieve settings information.

"""
get_trail(Name; aws_config::AWSConfig=global_aws_config()) = cloudtrail("GetTrail", Dict{String, Any}("Name"=>Name); aws_config=aws_config)
get_trail(Name, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("GetTrail", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Name"=>Name), args)); aws_config=aws_config)

"""
    GetTrailStatus()

Returns a JSON-formatted list of information about the specified trail. Fields include information on delivery errors, Amazon SNS and Amazon S3 errors, and start and stop logging times for each trail. This operation returns trail status from a single region. To return trail status from all regions, you must call the operation on each region.

# Required Parameters
- `Name`: Specifies the name or the CloudTrail ARN of the trail for which you are requesting status. To get the status of a shadow trail (a replication of the trail in another region), you must specify its ARN. The format of a trail ARN is:  arn:aws:cloudtrail:us-east-2:123456789012:trail/MyTrail

"""
get_trail_status(Name; aws_config::AWSConfig=global_aws_config()) = cloudtrail("GetTrailStatus", Dict{String, Any}("Name"=>Name); aws_config=aws_config)
get_trail_status(Name, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("GetTrailStatus", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Name"=>Name), args)); aws_config=aws_config)

"""
    ListPublicKeys()

Returns all public keys whose private keys were used to sign the digest files within the specified time range. The public key is needed to validate digest files that were signed with its corresponding private key.  CloudTrail uses different private/public key pairs per region. Each digest file is signed with a private key unique to its region. Therefore, when you validate a digest file from a particular region, you must look in the same region for its corresponding public key.

# Optional Parameters
- `EndTime`: Optionally specifies, in UTC, the end of the time range to look up public keys for CloudTrail digest files. If not specified, the current time is used.
- `NextToken`: Reserved for future use.
- `StartTime`: Optionally specifies, in UTC, the start of the time range to look up public keys for CloudTrail digest files. If not specified, the current time is used, and the current public key is returned.
"""
list_public_keys(; aws_config::AWSConfig=global_aws_config()) = cloudtrail("ListPublicKeys"; aws_config=aws_config)
list_public_keys(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("ListPublicKeys", args; aws_config=aws_config)

"""
    ListTags()

Lists the tags for the trail in the current region.

# Required Parameters
- `ResourceIdList`: Specifies a list of trail ARNs whose tags will be listed. The list has a limit of 20 ARNs. The format of a trail ARN is:  arn:aws:cloudtrail:us-east-2:123456789012:trail/MyTrail

# Optional Parameters
- `NextToken`: Reserved for future use.
"""
list_tags(ResourceIdList; aws_config::AWSConfig=global_aws_config()) = cloudtrail("ListTags", Dict{String, Any}("ResourceIdList"=>ResourceIdList); aws_config=aws_config)
list_tags(ResourceIdList, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("ListTags", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceIdList"=>ResourceIdList), args)); aws_config=aws_config)

"""
    ListTrails()

Lists trails that are in the current account.

# Optional Parameters
- `NextToken`: The token to use to get the next page of results after a previous API call. This token must be passed in with the same parameters that were specified in the the original call. For example, if the original call specified an AttributeKey of 'Username' with a value of 'root', the call with NextToken should include those same parameters.
"""
list_trails(; aws_config::AWSConfig=global_aws_config()) = cloudtrail("ListTrails"; aws_config=aws_config)
list_trails(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("ListTrails", args; aws_config=aws_config)

"""
    LookupEvents()

Looks up management events or CloudTrail Insights events that are captured by CloudTrail. You can look up events that occurred in a region within the last 90 days. Lookup supports the following attributes for management events:   AWS access key   Event ID   Event name   Event source   Read only   Resource name   Resource type   User name   Lookup supports the following attributes for Insights events:   Event ID   Event name   Event source   All attributes are optional. The default number of results returned is 50, with a maximum of 50 possible. The response includes a token that you can use to get the next page of results.  The rate of lookup requests is limited to two per second, per account, per region. If this limit is exceeded, a throttling error occurs.

# Optional Parameters
- `EndTime`: Specifies that only events that occur before or at the specified time are returned. If the specified end time is before the specified start time, an error is returned.
- `EventCategory`: Specifies the event category. If you do not specify an event category, events of the category are not returned in the response. For example, if you do not specify insight as the value of EventCategory, no Insights events are returned.
- `LookupAttributes`: Contains a list of lookup attributes. Currently the list can contain only one item.
- `MaxResults`: The number of events to return. Possible values are 1 through 50. The default is 50.
- `NextToken`: The token to use to get the next page of results after a previous API call. This token must be passed in with the same parameters that were specified in the the original call. For example, if the original call specified an AttributeKey of 'Username' with a value of 'root', the call with NextToken should include those same parameters.
- `StartTime`: Specifies that only events that occur after or at the specified time are returned. If the specified start time is after the specified end time, an error is returned.
"""
lookup_events(; aws_config::AWSConfig=global_aws_config()) = cloudtrail("LookupEvents"; aws_config=aws_config)
lookup_events(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("LookupEvents", args; aws_config=aws_config)

"""
    PutEventSelectors()

Configures an event selector for your trail. Use event selectors to further specify the management and data event settings for your trail. By default, trails created without specific event selectors will be configured to log all read and write management events, and no data events.  When an event occurs in your account, CloudTrail evaluates the event selectors in all trails. For each trail, if the event matches any event selector, the trail processes and logs the event. If the event doesn't match any event selector, the trail doesn't log the event.  Example   You create an event selector for a trail and specify that you want write-only events.   The EC2 GetConsoleOutput and RunInstances API operations occur in your account.   CloudTrail evaluates whether the events match your event selectors.   The RunInstances is a write-only event and it matches your event selector. The trail logs the event.   The GetConsoleOutput is a read-only event but it doesn't match your event selector. The trail doesn't log the event.    The PutEventSelectors operation must be called from the region in which the trail was created; otherwise, an InvalidHomeRegionException is thrown. You can configure up to five event selectors for each trail. For more information, see Logging Data and Management Events for Trails  and Limits in AWS CloudTrail in the AWS CloudTrail User Guide.

# Required Parameters
- `TrailName`: Specifies the name of the trail or trail ARN. If you specify a trail name, the string must meet the following requirements:   Contain only ASCII letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), or dashes (-)   Start with a letter or number, and end with a letter or number   Be between 3 and 128 characters   Have no adjacent periods, underscores or dashes. Names like my-_namespace and my--namespace are invalid.   Not be in IP address format (for example, 192.168.5.4)   If you specify a trail ARN, it must be in the format:  arn:aws:cloudtrail:us-east-2:123456789012:trail/MyTrail

# Optional Parameters
- `AdvancedEventSelectors`:
- `EventSelectors`: Specifies the settings for your event selectors. You can configure up to five event selectors for a trail.
"""
put_event_selectors(TrailName; aws_config::AWSConfig=global_aws_config()) = cloudtrail("PutEventSelectors", Dict{String, Any}("TrailName"=>TrailName); aws_config=aws_config)
put_event_selectors(TrailName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("PutEventSelectors", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("TrailName"=>TrailName), args)); aws_config=aws_config)

"""
    PutInsightSelectors()

Lets you enable Insights event logging by specifying the Insights selectors that you want to enable on an existing trail. You also use PutInsightSelectors to turn off Insights event logging, by passing an empty list of insight types. In this release, only ApiCallRateInsight is supported as an Insights selector.

# Required Parameters
- `InsightSelectors`: A JSON string that contains the insight types you want to log on a trail. In this release, only ApiCallRateInsight is supported as an insight type.
- `TrailName`: The name of the CloudTrail trail for which you want to change or add Insights selectors.

"""
put_insight_selectors(InsightSelectors, TrailName; aws_config::AWSConfig=global_aws_config()) = cloudtrail("PutInsightSelectors", Dict{String, Any}("InsightSelectors"=>InsightSelectors, "TrailName"=>TrailName); aws_config=aws_config)
put_insight_selectors(InsightSelectors, TrailName, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("PutInsightSelectors", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("InsightSelectors"=>InsightSelectors, "TrailName"=>TrailName), args)); aws_config=aws_config)

"""
    RemoveTags()

Removes the specified tags from a trail.

# Required Parameters
- `ResourceId`: Specifies the ARN of the trail from which tags should be removed. The format of a trail ARN is:  arn:aws:cloudtrail:us-east-2:123456789012:trail/MyTrail

# Optional Parameters
- `TagsList`: Specifies a list of tags to be removed.
"""
remove_tags(ResourceId; aws_config::AWSConfig=global_aws_config()) = cloudtrail("RemoveTags", Dict{String, Any}("ResourceId"=>ResourceId); aws_config=aws_config)
remove_tags(ResourceId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("RemoveTags", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceId"=>ResourceId), args)); aws_config=aws_config)

"""
    StartLogging()

Starts the recording of AWS API calls and log file delivery for a trail. For a trail that is enabled in all regions, this operation must be called from the region in which the trail was created. This operation cannot be called on the shadow trails (replicated trails in other regions) of a trail that is enabled in all regions.

# Required Parameters
- `Name`: Specifies the name or the CloudTrail ARN of the trail for which CloudTrail logs AWS API calls. The format of a trail ARN is:  arn:aws:cloudtrail:us-east-2:123456789012:trail/MyTrail

"""
start_logging(Name; aws_config::AWSConfig=global_aws_config()) = cloudtrail("StartLogging", Dict{String, Any}("Name"=>Name); aws_config=aws_config)
start_logging(Name, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("StartLogging", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Name"=>Name), args)); aws_config=aws_config)

"""
    StopLogging()

Suspends the recording of AWS API calls and log file delivery for the specified trail. Under most circumstances, there is no need to use this action. You can update a trail without stopping it first. This action is the only way to stop recording. For a trail enabled in all regions, this operation must be called from the region in which the trail was created, or an InvalidHomeRegionException will occur. This operation cannot be called on the shadow trails (replicated trails in other regions) of a trail enabled in all regions.

# Required Parameters
- `Name`: Specifies the name or the CloudTrail ARN of the trail for which CloudTrail will stop logging AWS API calls. The format of a trail ARN is:  arn:aws:cloudtrail:us-east-2:123456789012:trail/MyTrail

"""
stop_logging(Name; aws_config::AWSConfig=global_aws_config()) = cloudtrail("StopLogging", Dict{String, Any}("Name"=>Name); aws_config=aws_config)
stop_logging(Name, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("StopLogging", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Name"=>Name), args)); aws_config=aws_config)

"""
    UpdateTrail()

Updates the settings that specify delivery of log files. Changes to a trail do not require stopping the CloudTrail service. Use this action to designate an existing bucket for log delivery. If the existing bucket has previously been a target for CloudTrail log files, an IAM policy exists for the bucket. UpdateTrail must be called from the region in which the trail was created; otherwise, an InvalidHomeRegionException is thrown.

# Required Parameters
- `Name`: Specifies the name of the trail or trail ARN. If Name is a trail name, the string must meet the following requirements:   Contain only ASCII letters (a-z, A-Z), numbers (0-9), periods (.), underscores (_), or dashes (-)   Start with a letter or number, and end with a letter or number   Be between 3 and 128 characters   Have no adjacent periods, underscores or dashes. Names like my-_namespace and my--namespace are invalid.   Not be in IP address format (for example, 192.168.5.4)   If Name is a trail ARN, it must be in the format:  arn:aws:cloudtrail:us-east-2:123456789012:trail/MyTrail

# Optional Parameters
- `CloudWatchLogsLogGroupArn`: Specifies a log group name using an Amazon Resource Name (ARN), a unique identifier that represents the log group to which CloudTrail logs will be delivered. Not required unless you specify CloudWatchLogsRoleArn.
- `CloudWatchLogsRoleArn`: Specifies the role for the CloudWatch Logs endpoint to assume to write to a user's log group.
- `EnableLogFileValidation`: Specifies whether log file validation is enabled. The default is false.  When you disable log file integrity validation, the chain of digest files is broken after one hour. CloudTrail will not create digest files for log files that were delivered during a period in which log file integrity validation was disabled. For example, if you enable log file integrity validation at noon on January 1, disable it at noon on January 2, and re-enable it at noon on January 10, digest files will not be created for the log files delivered from noon on January 2 to noon on January 10. The same applies whenever you stop CloudTrail logging or delete a trail.
- `IncludeGlobalServiceEvents`: Specifies whether the trail is publishing events from global services such as IAM to the log files.
- `IsMultiRegionTrail`: Specifies whether the trail applies only to the current region or to all regions. The default is false. If the trail exists only in the current region and this value is set to true, shadow trails (replications of the trail) will be created in the other regions. If the trail exists in all regions and this value is set to false, the trail will remain in the region where it was created, and its shadow trails in other regions will be deleted. As a best practice, consider using trails that log events in all regions.
- `IsOrganizationTrail`: Specifies whether the trail is applied to all accounts in an organization in AWS Organizations, or only for the current AWS account. The default is false, and cannot be true unless the call is made on behalf of an AWS account that is the master account for an organization in AWS Organizations. If the trail is not an organization trail and this is set to true, the trail will be created in all AWS accounts that belong to the organization. If the trail is an organization trail and this is set to false, the trail will remain in the current AWS account but be deleted from all member accounts in the organization.
- `KmsKeyId`: Specifies the KMS key ID to use to encrypt the logs delivered by CloudTrail. The value can be an alias name prefixed by \"alias/\", a fully specified ARN to an alias, a fully specified ARN to a key, or a globally unique identifier. Examples:   alias/MyAliasName   arn:aws:kms:us-east-2:123456789012:alias/MyAliasName   arn:aws:kms:us-east-2:123456789012:key/12345678-1234-1234-1234-123456789012   12345678-1234-1234-1234-123456789012
- `S3BucketName`: Specifies the name of the Amazon S3 bucket designated for publishing log files. See Amazon S3 Bucket Naming Requirements.
- `S3KeyPrefix`: Specifies the Amazon S3 key prefix that comes after the name of the bucket you have designated for log file delivery. For more information, see Finding Your CloudTrail Log Files. The maximum length is 200 characters.
- `SnsTopicName`: Specifies the name of the Amazon SNS topic defined for notification of log file delivery. The maximum length is 256 characters.
"""
update_trail(Name; aws_config::AWSConfig=global_aws_config()) = cloudtrail("UpdateTrail", Dict{String, Any}("Name"=>Name); aws_config=aws_config)
update_trail(Name, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = cloudtrail("UpdateTrail", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Name"=>Name), args)); aws_config=aws_config)


text:
using DataStructures
using Test

@testset "enforce_unique_attributes" begin
    @test CfGRIB.enforce_unique_attributes(
        OrderedDict("key" => [1]), ["key"]) |> length == 1

    for missing_value in [missing, "undef", "unknown"]
        @test CfGRIB.enforce_unique_attributes(
            OrderedDict("key" => [missing_value]), ["key"]) |> length == 0
    end

    @test_throws(
        CfGRIB.DatasetBuildError,
        CfGRIB.enforce_unique_attributes(OrderedDict("key" => [1, 2]), ["key"])
    )
end

@testset "OnDiskArray" begin
    oda = CfGRIB.OnDiskArray(
        "some_path",
        (4, 3, 2, 1),
        OrderedDict(),
        [1,2,3],
        missing,
        10,
        Float32
    )

    @test size(oda) == oda.size

    test_file = joinpath(dir_testfiles, "era5-levels-members.grib")
    res = CfGRIB.DataSet(test_file).variables["t"]

    @test res.data isa CfGRIB.OnDiskArray

    @test size(res.data[:, :, 2, 120, 61]) == size(res.data)[1:2]
end

@testset "Variable" begin
    res = CfGRIB.Variable(
        ("lat", ),
        [1, 2, 3],
        Dict("Test" => 10)
    )

    @test res == res
end

@testset "build_data_var_components" begin
    @testset "build_data_var_components_no_encode" begin
        test_file = joinpath(dir_testfiles, "era5-levels-members.grib")
        @test isfile(test_file)

        index = CfGRIB.FileIndex(
            test_file,
            CfGRIB.ALL_KEYS
        )

        @test index["paramId"] == [129, 130]

        CfGRIB.filter!(index, paramId=130)

        @test index["paramId"] == [130]
        #  TODO: Add logging
        dims, data_var, coord_vars = CfGRIB.build_variable_components(
            index
        )

        @test dims == OrderedDict(
            "number" => 10,
            "dataDate" => 2,
            "dataTime" => 2,
            "level" => 2,
            "values" => 7320
        )

        @test size(data_var.data) == (10, 2, 2, 2, 7320)

        data = convert(Array, data_var.data)

        @test sum(data) > 0
    end

    @testset "build_data_var_components_encode_cf_geography" begin
        test_file = joinpath(dir_testfiles, "era5-levels-members.grib")

        index = CfGRIB.FileIndex(
            test_file,
            CfGRIB.ALL_KEYS
        )

        CfGRIB.filter!(index, paramId=130)

        @test index["paramId"] == [130]
        #  TODO: Add logging
        dims, data_var, coord_vars = CfGRIB.build_variable_components(
            index; encode_cf=("geography", )
        )

        @test dims == OrderedDict(
            "number"    => 10,
            "dataDate"  => 2,
            "dataTime"  => 2,
            "level"     => 2,
            "longitude" => 120,
            "latitude"  => 61
        )

        @test size(data_var.data) == (10, 2, 2, 2, 120, 61)

        data = convert(Array, data_var.data)

        @test sum(data) > 0
    end
end

@testset "build_dataset_components_time_dims" begin
    test_file = joinpath(dir_testfiles, "forecast_monthly_ukmo.grib")
    index = CfGRIB.FileIndex(
        test_file,
        CfGRIB.ALL_KEYS
    )

    dims, _, _ = CfGRIB.build_dataset_components(
        index
    )
    @test dims == OrderedDict(
        "latitude"  => 6,
        "longitude" => 11,
        "number"    => 28,
        "step"      => 20,
        "time"      => 8
    )

    dims, _, _ = CfGRIB.build_dataset_components(
        index,
        time_dims=("indexing_time", "verifying_time")
    )
    @test dims == OrderedDict(
        "number" => 28,
        "indexing_time" => 2,
        "verifying_time" => 4,
        "latitude" => 6,
        "longitude" => 11,
    )

    dims, _, _ = CfGRIB.build_dataset_components(
        index,
        time_dims=("indexing_time", "step")
    )
    @test dims == OrderedDict(
        "number" => 28,
        "indexing_time" => 2,
        "step" => 20,
        "latitude" => 6,
        "longitude" => 11
    )
end

@testset "DataSet" begin
    @testset "DataSet_default_encode" begin
        test_file = joinpath(dir_testfiles, "era5-levels-members.grib")
        res = CfGRIB.DataSet(test_file)

        @test "Conventions" in keys(res.attributes)
        @test "institution" in keys(res.attributes)
        @test "history" in keys(res.attributes)

        @test res.attributes["GRIB_edition"] == 1

        @test res.dimensions == OrderedDict(
            "number"        => 10,
            "time"          => 4,
            "isobaricInhPa" => 2,
            "longitude"     => 120,
            "latitude"      => 61
        )

        @test length(res.variables) == 9
    end

    @testset "DataSet_no_encode" begin
        test_file = joinpath(dir_testfiles, "era5-levels-members.grib")
        res = CfGRIB.DataSet(test_file; encode_cf=())

        @test "Conventions" in keys(res.attributes)
        @test "institution" in keys(res.attributes)
        @test "history" in keys(res.attributes)

        @test res.attributes["GRIB_edition"] == 1

        @test res.dimensions == OrderedDict(
            "number"   => 10,
            "dataDate" => 2,
            "dataTime" => 2,
            "level"    => 2,
            "values"   => 7320
        )

        @test length(res.variables) == 9
    end

    @testset "DataSet_cf_time" begin
        test_file = joinpath(dir_testfiles, "era5-levels-members.grib")
        res = CfGRIB.DataSet(test_file; encode_cf=("time", ))

        @test "Conventions" in keys(res.attributes)
        @test "institution" in keys(res.attributes)
        @test "history" in keys(res.attributes)

        @test res.attributes["GRIB_edition"] == 1

        @test res.dimensions == OrderedDict(
            "number" => 10,
            "time"   => 4,
            "level"  => 2,
            "values" => 7320
        )

        @test length(res.variables) == 9
    end

    @testset "DataSet_cf_geography" begin
        test_file = joinpath(dir_testfiles, "era5-levels-members.grib")
        res = CfGRIB.DataSet(test_file; encode_cf=("geography", ))

        @test "Conventions" in keys(res.attributes)
        @test "institution" in keys(res.attributes)
        @test "history" in keys(res.attributes)

        @test res.attributes["GRIB_edition"] == 1

        @test res.dimensions == OrderedDict(
            "number"    => 10,
            "dataDate"  => 2,
            "dataTime"  => 2,
            "level"     => 2,
            "longitude" => 120,
            "latitude"  => 61
        )

        @test length(res.variables) == 9
    end

    @testset "DataSet_cf_vertical" begin
        test_file = joinpath(dir_testfiles, "era5-levels-members.grib")
        res = CfGRIB.DataSet(test_file; encode_cf=("vertical", ))

        @test "Conventions" in keys(res.attributes)
        @test "institution" in keys(res.attributes)
        @test "history" in keys(res.attributes)

        @test res.attributes["GRIB_edition"] == 1

        @test res.dimensions == OrderedDict(
            "number"        => 10,
            "dataDate"      => 2,
            "dataTime"      => 2,
            "isobaricInhPa" => 2,
            "values"        => 7320
        )

        @test length(res.variables) == 9
    end

    @testset "DataSet_gg_surface" begin
        test_file = joinpath(dir_testfiles, "regular_gg_sfc.grib")
        res = CfGRIB.DataSet(test_file)

        @test "Conventions" in keys(res.attributes)
        @test "institution" in keys(res.attributes)
        @test "history" in keys(res.attributes)

        @test res.attributes["GRIB_edition"] == 1

        @test res.dimensions == OrderedDict(
            "longitude" => 192,
            "latitude"  => 96
        )

        @test length(res.variables) == 8

        @test res.variables["latitude"].data[1:2] ≈ [88.57216851, 86.72253095]
    end
end

ext: jl


text:
# TEST PAIR OF VORTEX RINGS

include("vm2d.jl")

# create circle geometry
center = [0.0,0.0,0.0]
radius = 0.1
refinement = 150
gamma = -0.002
velocity=[0.0,0.0,0.0]
spacing = 0.05

ring1 = vortexring(radius,center,refinement,gamma;velocity=velocity)
ring2 = vortexring(radius,center.+[0.0,0.0,spacing],refinement,gamma;velocity=velocity)
particles = vcat(ring1,ring2)
# println("==== INITIAL PARTICLES =====")
# println(particles)
# println("")
# println("")

# save plots for debugging

# ## show circulation vectors
# plot_xy(particles; circulation=true, save=true, name="circulation_2rings")

# ## show velocity field
# plot_yz(particles; velocity=true, zs=range(-0.2,stop=0.2,length=8), ys=range(-0.2,stop=0.2,length=9), xs=[0.0], save=true, name="velocityfield_2rings")

                                                                                # set simulation variables
name = "vortexrings"
global currenttime
currenttime = 0.0
timestep = 0.01
numtimesteps = 2 # try 150
xoffset = 0.0
margin = 0.05

# animate!

# set up plot
plt.plot()
plt.hot()
plt.axis("equal")
for particle in particles
    plt.scatter(particle.x[1],particle.x[2],c=particle.gamma[3])
end
plt.title("time: "*string(round(currenttime; digits=3)))
if ~isdir("sim")
    mkdir("sim")
end
# animate
for i in range(1,length=numtimesteps)
    ## advance timestep
    advance(particles,timestep,Uinf)
    currenttime += timestep
    ## evaluate velocity field
    ### get center
    xcoordinates = Float64[]
    ycoordinates = Float64[]
    zcoordinates = Float64[]
    for particle in particles
        push!(xcoordinates, particle.x[1])
        push!(ycoordinates, particle.x[2])
        push!(zcoordinates, particle.x[3])
    end
    xs = [sum(xcoordinates)/length(xcoordinates) + xoffset]
    # xhi = maximum(xcoordinates)
    # xlo = minimum(xcoordinates)
    # xs = range(xlo-margin, stop = xhi + margin, length = 20)
    # ycenter = sum(ycoordinates)/length(ycoordinates)
    yhi = maximum(ycoordinates)
    ylo = minimum(ycoordinates)
    # ys = range(ycenter - 0.2, stop = ycenter + 0.2,length = 20)
    ys = range(ylo-margin, stop = yhi + margin, length = 20)
    zs = range(particles[1].x[3] - 0.07,
            stop = particles[1].x[3] + 0.1,
            length = 10)
    # zs = [sum(zcoordinates)/length(zcoordinates)]
    ## update plot
    name = "rings2d_150particles_yz"*"_"*string(i)
    println(name)
    plot_2d(particles, "yz"; velocity=true, xs=xs, ys=ys, zs=zs, title="time: "*string(round(currenttime; digits=3)), save=true, name=name)#*string(round(xoffset; digits=2)))
    # println("P1: ",particles[1])
    # println("P2: ",particles[2])
    # println("P3: ",particles[3])
    # println("P4: ",particles[4])
end


text:
# TESTSET FOR ALL CONCRETE TYPES
@testset "Concrete Type Definitions" begin

# end the testset
end


text:
export ZeDriver, api_version, properties, ipc_properties, extension_properties

struct ZeDriver
    handle::ze_driver_handle_t
end

Base.unsafe_convert(::Type{ze_driver_handle_t}, drv::ZeDriver) = drv.handle

function api_version(drv::ZeDriver)
    version_ref = Ref{ze_api_version_t}()
    zeDriverGetApiVersion(drv, version_ref)
    unmake_version(version_ref[])
end

function Base.show(io::IO, ::MIME"text/plain", drv::ZeDriver)
    props = properties(drv)
    print(io, "ZeDriver($(props.uuid), version $(props.driverVersion))")
end

## driver iteration

export drivers

struct ZeDrivers
    handles::Vector{ze_driver_handle_t}

    function ZeDrivers()
        count_ref = Ref{UInt32}(0)
        zeDriverGet(count_ref, C_NULL)

        handles = Vector{ze_driver_handle_t}(undef, count_ref[])
        zeDriverGet(count_ref, handles)

        new(handles)
    end
end

drivers() = ZeDrivers()

Base.eltype(::ZeDrivers) = ZeDriver

function Base.iterate(iter::ZeDrivers, i=1)
    i >= length(iter) + 1 ? nothing : (ZeDriver(iter.handles[i]), i+1)
end

Base.length(iter::ZeDrivers) = length(iter.handles)

Base.IteratorSize(::ZeDrivers) = Base.HasLength()

## properties

function properties(drv::ZeDriver)
    props_ref = Ref(ze_driver_properties_t())
    zeDriverGetProperties(drv, props_ref)

    props = props_ref[]
    return (
        uuid=Base.UUID(reinterpret(UInt128, [props.uuid.id...])[1]),
        driverVersion=VersionNumber((props.driverVersion & 0xFF000000) >> 24,
                                    (props.driverVersion & 0x00FF0000) >> 16,
                                    props.driverVersion & 0x0000FFFF),
    )
end

function ipc_properties(drv::ZeDriver)
    props_ref = Ref(ze_driver_ipc_properties_t())
    zeDriverGetIpcProperties(drv, props_ref)

    props = props_ref[]
    return (
        flags=props.flags,
    )
end

# FIXME: throws ZE_RESULT_ERROR_UNSUPPORTED_FEATURE
function extension_properties(drv::ZeDriver)
    count_ref = Ref{UInt32}(0)
    zeDriverGetExtensionProperties(drv, count_ref, C_NULL)

    all_props = Vector{ze_driver_extension_properties_t}(undef, count_ref[])
    zeDriverGetExtensionProperties(drv, count_ref, all_props)

    return [(name=String([props.name[1:findfirst(isequal(0), props.name)-1]...]),
             version=Int(props.version),
            ) for props in all_props[1:count_ref[]]]
end


text:
module GenericFieldTest

using Test

using TowerFields.BigIntField: addmod, submod, mulmod, sqmod, invmod, powmod, frobmod, FQ2, FQ3

const Q = 7

mulroot(x) = -x

@testset "addmod: FQ" begin
    @test addmod(Q, 0, 1) == 1  # additive identity
    @test addmod(Q, 2, 6) == 1  # basic arithmetic with modulus
    @test addmod(Q, 1, -2) == Q - 1  # signed arithmetic
end

@testset "addmod: FQ2" begin
    @test addmod(Q, (0, 0), (1, 1)) == (1, 1)  # additive identity
    @test addmod(Q, (1, 2), (2, 6)) == (3, 1)  # basic arithmetic with modulus
end

@testset "addmod: FQ3" begin
    @test addmod(Q, (0, 0, 0), (1, 1, 1)) == (1, 1, 1)  # additive identity
    @test addmod(Q, (1, 2, 3), (2, 3, 4)) == (3, 5, 0)  # basic arithmetic and modulus
end

@testset "submod: FQ" begin
    @test submod(Q, 1, 0) == 1  # additive identity
    @test submod(Q, 1, 2) == Q - 1  # basic arithmetic with modulus
    @test submod(Q, 1, -2) == 3  # signed arithmetic
end

@testset "submod: FQ2" begin
    @test submod(Q, (1, 1), (0, 0)) == (1, 1)  # additive identity
    @test submod(Q, (2, 3), (3, 2)) == (Q - 1, 1)  # basic arithmetic with modulus
end

@testset "submod: FQ3" begin
    @test submod(Q, (1, 1, 1), (0, 0, 0)) == (1, 1, 1) # additive identity
    @test submod(Q, (2, 3, 4), (4, 3, 2)) == (Q - 2, 0, 2)  # basic arithmetic and modulus
end

@testset "submod: FQ3" begin
    @test submod(Q, (1, 1, 1), (0, 0, 0)) == (1, 1, 1)  # additive identity
    @test submod(Q, (2, 3, 4), (4, 3, 2)) == (Q - 2, 0, 2)  # basic arithmetic and modulus
end

@testset "submod: FQ3" begin
    @test submod(Q, (1, 1, 1), (0, 0, 0)) == (1, 1, 1) # additive identity
    @test submod(Q, (2, 3, 4), (4, 3, 2)) == (Q - 2, 0, 2)  # basic arithmetic and modulus
end

@testset "mulmod: FQ1" begin
    @test mulmod(Q, mulroot, 2, 0) == 0 # additive identity
    @test mulmod(Q, mulroot, 2, 1) == 2 # multiplicative identity
    @test mulmod(Q, mulroot, 2, 4) == 1  # basic arithmetic and modulus
    @test mulmod(Q, mulroot, 1, -1) == Q - 1  # signed arithmetic
end

@testset "mulmod: FQ2" begin
    x = (2, 3)
    @test mulmod(Q, mulroot, x, (0, 0)) == (0, 0) # additive identity
    @test mulmod(Q, mulroot, x, (1, 0)) == x # multiplicative identity
    @test mulmod(Q, mulroot, x, (3, 4)) == (1, 3)  # basic arithmetic and modulus
    @test mulmod(Q, mulroot, x, (-3, -4)) == (6, 4)  # signed arithmetic
    @test mulmod(Q, mulroot, x, 2) == addmod(Q, x, x)  # scalar arithmetic
    @test mulmod(Q, mulroot, 2, x) == addmod(Q, x, x)  # scalar arithmetic
end

@testset "mulmod: FQ3" begin
    x = (2, 3, 4)
    @test mulmod(Q, mulroot, x, (0, 0, 0)) == (0, 0, 0) # additive identity
    @test mulmod(Q, mulroot, x, (1, 0, 0)) == x # multiplicative identity
    @test mulmod(Q, mulroot, x, (3, 4, 5)) == (3, 4, 6)  # basic arithmetic and modulus
    @test mulmod(Q, mulroot, x, (-3, -4, -5)) == (4, 3, 1)  # signed arithmetic
    @test mulmod(Q, mulroot, x, 2) ==  addmod(Q, x, x)  # scalar arithmetic
    @test mulmod(Q, mulroot, 2, x) ==  addmod(Q, x, x)  # scalar arithmetic
end

@testset "sqmod: FQ1" begin
    x = 4
    @test sqmod(Q, mulroot, 0) == 0 # additive identity
    @test sqmod(Q, mulroot, 1) == 1 # multiplicative identity
    @test sqmod(Q, mulroot, x) == mulmod(Q, mulroot, x, x) # basic arithmetic and modulus
    @test sqmod(Q, mulroot, -x) == mulmod(Q, mulroot, -x, -x) # signed arithmetic
end

@testset "sqmod: FQ2" begin
    x = (2, 3)
    @test sqmod(Q, mulroot, (0, 0)) == (0, 0) # additive identity
    @test sqmod(Q, mulroot, (1, 0)) == (1, 0) # multiplicative identity
    @test sqmod(Q, mulroot, x) == mulmod(Q, mulroot, x, x) # basic arithmetic and modulus
    xneg = mulmod(Q, mulroot, -1, x)
    @test sqmod(Q, mulroot, xneg) == mulmod(Q, mulroot, xneg, xneg) # signed arithmetic
end

@testset "sqmod: FQ3" begin
    x = (5, 2, 3)
    @test sqmod(Q, mulroot, (0, 0, 0)) == (0, 0, 0) # additive identity
    @test sqmod(Q, mulroot, (1, 0, 0)) == (1, 0, 0) # multiplicative identity
    @test sqmod(Q, mulroot, x) == mulmod(Q, mulroot, x, x) # basic arithmetic and modulus
    xneg = mulmod(Q, mulroot, -1, x)
    @test sqmod(Q, mulroot, xneg) == mulmod(Q, mulroot, xneg, xneg) # signed arithmetic
end

@testset "invmod: FQ1" begin
    x = 3
    @test invmod(Q, mulroot, 1) == 1 # multiplicative identity
    y = invmod(Q, mulroot, x)
    @test mulmod(Q, mulroot, x, y) == 1
end

@testset "invmod: FQ2" begin
    x = (2, 3)
    @test invmod(Q, mulroot, (1, 0)) == (1, 0) # multiplicative identity
    y = invmod(Q, mulroot, x)
    @test mulmod(Q, mulroot, x, y) == (1, 0)
end

@testset "invmod: FQ3" begin
    x = (2, 3, 4)
    @test invmod(Q, mulroot, (1, 0, 0)) == (1, 0, 0) # multiplicative identity
    y = invmod(Q, mulroot, x)
    @test mulmod(Q, mulroot, x, y) == (1, 0, 0)
end

@testset "powmod: FQ1" begin
    x, e = 3, 3
    @test powmod(Q, mulroot, 2, 0) == 1  # special exponent 0
    @test powmod(Q, mulroot, 2, 1) == 2  # special exponent 1
    @test powmod(Q, mulroot, x, 2) == sqmod(Q, mulroot, x)  # basic arithmetic and modulus
    @test powmod(Q, mulroot, x, Q - 1) == 1  # fermat's theorem
    y = mulmod(Q, mulroot, x, sqmod(Q, mulroot, x))
    @test powmod(Q, mulroot, x, e) == y  # basic arithmetic and modulus
    @test powmod(Q, mulroot, x, -e) == invmod(Q, mulroot, y)  # negative exponent
end

@testset "powmod: FQ2" begin
    x, e = (2, 3), 3
    @test powmod(Q, mulroot, x, 0) == (1, 0)  # special exponent 0
    @test powmod(Q, mulroot, x, 1) == x  # special exponent 1
    @test powmod(Q, mulroot, x, 2) == sqmod(Q, mulroot, x)  # basic arithmetic and modulus
    y = mulmod(Q, mulroot, x, sqmod(Q, mulroot, x))
    @test powmod(Q, mulroot, x, e) == y  # basic arithmetic and modulus
    @test powmod(Q, mulroot, x, -e) == invmod(Q, mulroot, y)  # negative exponent
end

@testset "powmod: FQ3" begin
    x, e = (2, 3, 4), 3
    @test powmod(Q, mulroot, x, 0) == (1, 0, 0)  # special exponent 0
    @test powmod(Q, mulroot, x, 1) == x  # special exponent 1
    @test powmod(Q, mulroot, x, 2) == sqmod(Q, mulroot, x)  # basic arithmetic and modulus
    y = mulmod(Q, mulroot, x, sqmod(Q, mulroot, x))
    @test powmod(Q, mulroot, x, e) == y  # basic arithmetic and modulus
    @test powmod(Q, mulroot, x, -e) == invmod(Q, mulroot, y)  # negative exponent
end

end


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

# The numeric type used to determine how the different
# versions of a package should be weighed
struct VersionWeight
    major::Int64
    minor::Int64
    patch::Int64
end
VersionWeight(major::Integer, minor::Integer) = VersionWeight(major, minor, 0)
VersionWeight(major::Integer) = VersionWeight(major, 0)
VersionWeight() = VersionWeight(0)
VersionWeight(vn::VersionNumber) = VersionWeight(vn.major, vn.minor, vn.patch)

Base.zero(::Type{VersionWeight}) = VersionWeight()

Base.typemin(::Type{VersionWeight}) = (x=typemin(Int64); VersionWeight(x, x, x))

Base.:(-)(a::VersionWeight, b::VersionWeight) =
    VersionWeight(a.major-b.major, a.minor-b.minor, a.patch-b.patch)

Base.:(+)(a::VersionWeight, b::VersionWeight) =
    VersionWeight(a.major+b.major, a.minor+b.minor, a.patch+b.patch)

Base.:(-)(a::VersionWeight) =
    VersionWeight(-a.major, -a.minor, -a.patch)

function Base.isless(a::VersionWeight, b::VersionWeight)
    (a.major, a.minor, a.patch) < (b.major, b.minor, b.patch)
end

Base.abs(a::VersionWeight) =
    VersionWeight(abs(a.major), abs(a.minor), abs(a.patch))

# This isn't nice, but it's for debugging only anyway
function Base.show(io::IO, a::VersionWeight)
    print(io, "(", a.major)
    a == VersionWeight(a.major) && @goto done
    print(io, ".", a.minor)
    a == VersionWeight(a.major, a.minor) && @goto done
    print(io, ".", a.patch)
    @label done
    print(io, ")")
end


text:
## Implementations of different raycasting search algorithms

# default raycast
Raycast(xs) = RaycastIncircleSkip(KDTree(xs))

struct RaycastBruteforce end

""" shooting a ray in the given direction, find the next connecting point.
This is the bruteforce variant, using a linear search to find the closest point """
function raycast(sig::Sigma, r, u, xs, searcher::RaycastBruteforce)
    (tau, ts) = [0; sig], Inf
    x0 = xs[sig[1]]

    c = maximum(dot(xs[g], u) for g in sig)
    skip(i) = (dot(xs[i], u) <= c) || i ∈ sig

    for i in 1:length(xs)
        skip(i) && continue
        x = xs[i]
        t = (sum(abs2, r .- x) - sum(abs2, r .- x0)) / (2 * u' * (x-x0))
        if 0 < t < ts
            (tau, ts) = vcat(sig, [i]), t
        end
    end

    return sort(tau), ts
end

struct RaycastBisection
    tree::KDTree
    tmax
    eps::Float64
end

""" shooting a ray in the given direction, find the next connecting point.
This variant (by Poliaski, Pokorny) uses a binary search """
function raycast(sig::Sigma, r::Point, u::Point, xs::Points, searcher::RaycastBisection)
    tau, tl, tr = [], 0, searcher.tmax
    x0 = xs[sig[1]]

    while tr-tl > searcher.eps
        tm = (tl+tr)/2
        i, _ = nn(searcher.tree, r+tm*u)
        x = xs[i]
        if i in sig
            tl = tm
        else
            tr = (sum(abs2, r .- x) - sum(abs2, r .- x0)) / (2 * u' * (x-x0))
            tau = vcat(sig, [i])

            # early stopping
            idxs, _ = knn(searcher.tree, r+tr*u, length(sig)+1, true)
            length(intersect(idxs, [sig; i])) == length(sig)+1 && break
        end
    end

    if tau == []
        tau = [0; sig]
        tr = Inf
    end

    return sort(tau), tr
end

struct RaycastIncircle
    tree::KDTree
    tmax::Float64
end

""" Shooting a ray in the given direction, find the next connecting point.
This variant uses an iterative NN search """
function raycast(sig::Sigma, r::Point, u::Point, xs::Points, searcher::RaycastIncircle)
    i = 0
    t = 1
    x0 = xs[sig[1]]
    local d, n

    # find a t large enough to include a non-boundary (sig) point
    while t < searcher.tmax
        n, d = nn(searcher.tree, r+t*u)
        if d==Inf
            warn("d==Inf in raycast expansion, this should never happen")
            return [0; sig], Inf
        end

        if n in sig
            t = t * 2
        else
            i = n
            break
        end
    end

    if i == 0
        return [0; sig], Inf
    end

    # sucessively reduce incircles unless nothing new is found
    while true
        x = xs[i]
        t = (sum(abs2, r - x) - sum(abs2, r - x0)) / (2 * u' * (x-x0))
        j, _ = nn(searcher.tree, r+t*u)
        if j in [sig; i]
            break
        else
            i = j
        end
    end

    tau = sort([i; sig])

    return tau, t
end

struct RaycastIncircleSkip
    tree::KDTree
end

function raycast(sig::Sigma, r::Point, u::Point, xs::Points, searcher::RaycastIncircleSkip)

    x0 = xs[sig[1]]

    c = maximum(dot(xs[g], u) for g in sig)

    # only consider points on the right side of the hyperplane
    skip(i) = (dot(xs[i], u) <= c) || i ∈ sig

    # try catch workaround for https://github.com/KristofferC/NearestNeighbors.jl/issues/127
    local i, t
    try
        i, t = nn(searcher.tree, r + u * (u' * (x0-r)), skip)
    catch
        return [0; sig], Inf
    end
    t == Inf && return [0; sig], Inf

    # sucessively reduce incircles unless nothing new is found
    while true
        x = xs[i]
        t = (sum(abs2, r - x) - sum(abs2, r - x0)) / (2 * u' * (x-x0))
        j, _ = nn(searcher.tree, r+t*u)
        if j in sig || j == i
            break
        else
            i = j
        end
    end

    tau = sort([i; sig])

    return tau, t
end

struct RaycastCompare
    tree::KDTree
    tmax
    eps
    timings
end

RaycastCompare(xs) = RaycastCompare(KDTree(xs), 1_000, 1e-8, zeros(4))

function raycast(sig::Sigma, r::Point, u::Point, xs::Points, searcher::RaycastCompare)
    s1 = RaycastBruteforce()
    s2 = RaycastBisection(searcher.tree, searcher.tmax, searcher.eps)
    s3 = RaycastIncircle(searcher.tree, searcher.tmax)
    s4 = RaycastIncircleSkip(searcher.tree)

    t1 = @elapsed r1 = raycast(sig, r, u, xs, s1)
    t2 = @elapsed r2 = raycast(sig, r, u, xs, s2)
    t3 = @elapsed r3 = raycast(sig, r, u, xs, s3)
    t4 = @elapsed r4 = raycast(sig, r, u, xs, s4)

    searcher.timings .+= [t1, t2, t3, t4]

    if !(r1[1]==r2[1]==r3[1]==r4[1]) && r3[2] < searcher.tmax
        @warn "raycast algorithms return different results" r1 r2 r3 r4 tuple(r...)
    end
    return r4
end


text:
module MusicVisualizations

using Reexport
@reexport using MusicManipulations
using PyPlot, DefaultApplication

include("noteplotter.jl")
include("musescore.jl")

end


text:
"""
---
 Add a white additive circular gaussian noise to input signal
Added noise is real if input signal is real and computedlex is input signal is complex
Noise level is controled by the second input parameter which is the signal to noise ratio (SNR)
Signal power powSig is computed based in the input sequence power (average power in time domain)
although a third parameter (theoretical power of input signal is given). In that case, snr is computed
based on the value powSig
output parameters are the signal with noise, and the noise samples
See the bang methods for non-buffer alloc.
# --- Syntax
[y,n]   = addNoise(x,snr,powSig);
# --- Input parameters
- x= Input signal [Array{Real{Float64}}, Array{Complex{Float64}}] of size N
- snr= Desired signal to noise ratio [Float64]
- powSig= Power of input signal. If not given, power is evaluated based on input signal x
# --- Output parameters
- y= Signal with noise [Array{Real{Float64}}, Array{Complex{Float6464}}] of size N
- n= noise samples [Array{Real{Float64}}, Array{Complex{Float64}}] of size N
# ---
# v 1.0 - Robin Gerzaguet.
"""
function addNoise(x::Array{T},snr::Any,powSig=0) where T
	# --- If powSig is equal to 0, power is computed with x input
	# Expectation is taken with respect to time
	if powSig == 0
		powSig  = sum(abs.(x).^2) / length(x);
	end
	# --- Evaluation of noise power
	powNoise  = sqrt(powSig) *  10^(-snr/20);
	# --- Create a complex random sequence as additive noise
	n		  = randn(T,length(x))* powNoise;
	# --- Create output signal
	y		  = x + n;
	return y,n
end

function addNoise!(y::Array{T},x::Array{T},snr::Any,powSig=0.0) where T
	# --- If powSig is equal to 0, power is computed with x input
	# Expectation is taken with respect to time
	if powSig == 0.0
		powSig  = sum(abs2.(x)) / length(x);
	end
	# --- Evaluation of noise power
	# Additional /sqrt(2) to divide power between I and Q paths
	# No sqrt(2)--> Complex randn is unitary variance in complex plan
	powNoise  = sqrt(powSig) * 10^(-snr/20);
	# --- Create a complex random sequence as additive noise
	y  .= x .+ randn!(y) .* powNoise;
end


text:
using Test
include("hello.jl")

hello_text = hello()
@testset "hello tests" begin
     @test hello_text == "hello"
end

hello_text = hello("Jackson")
@testset "hello name tests" begin
     @test hello_text == "hello Jackson"
end


text:
#using SurfaceGeometry

struct Zinchenko1997
    VertexRing
end

# function Zinchenko1997(points,faces,n;VertexRing=i -> VertexRing(i,faces))
#     Zinchenko1997(VertexRing)
# end

eps = 1e-6

function f(i::Int,ni::Array{Float64,1},points,v,ring)
    s = zeros(3)
    pi = points[:,i]
    vi = v[:,i]
    for j in ring
        xij = points[:,j] - pi
        vij = v[:,j] - vi
        s += dot(xij,vij)*xij
    end
    P = eye(3) - ni*ni'
    return P*s
end

function fvec(i,points,v,ring)
    s = zeros(3)
    pi = points[:,i]
    vi = v[:,i]
    for j in ring
        xij = points[:,j] - pi
        vij = v[:,j] - vi
        s += dot(xij,vij)*xij
    end
    return s
end

function F(points,faces,v,mc::Zinchenko1997)

    function f(v1,v2)
        xij = points[:,v1] - points[:,v2]
        vij = v[:,v1] - v[:,v2]
        return dot(xij,vij)^2
    end

    N = size(faces,2)
    s = 0
    for i in 1:N
        v1,v2,v3 = faces[:,i]
        s += v2>v1 ? f(v1,v2) : 0
        s += v3>v2 ? f(v2,v3) : 0
        s += v3>v1 ? f(v1,v3) : 0
    end
    return 4*s
end

# Returns ksi and eta for conjugate gradient iterations
function conjugrad(points,faces,va,vb,f)
    function A(i,j)
        xij = points[:,j] - points[:,i]
        vij = vb[:,j] - vb[:,i]
        return dot(xij,vij)
    end

    function B(i,j)
        xij = points[:,j] - points[:,i]
        fij = f[:,j] - f[:,i]
        return dot(xij,fij)
    end

    function C(i,j)
        xij = points[:,j] - points[:,i]
        Dvij = vb[:,j] - va[:,j] - (vb[:,i] - va[:,i])
        return dot(xij,Dvij)
    end

    S = zeros(2,2)
    P = zeros(2)

    function add!(i,j)
        a = A(i,j)
        b = B(i,j)
        c = C(i,j)

        S[1,1] += b^2
        S[1,2] += b*c
        S[2,1] += b*c
        S[2,2] += c^2

        P[1] += -a*b
        P[2] += -a*c
    end

    for i in 1:size(points,2)
        v1,v2,v3 = faces[:,i]

        if v2>v1
            add!(v1,v2)
        end

        if v3>v2
            add!(v3,v2)
        end

        if v3>v1
            add!(v1,v3)
        end
    end

    ksi, eta = S \ P
    return ksi,eta
end

# A simple conjugate gradient
function conjugrad0(points,faces,v,f)
    function A(i,j)
        xij = points[:,j] - points[:,i]
        vij = v[:,j] - v[:,i]
        return dot(xij,vij)
    end

    function B(i,j)
        xij = points[:,j] - points[:,i]
        fij = f[:,j] - f[:,i]
        return dot(xij,fij)
    end

    P = 0
    S = 0

    for i in 1:size(points,2)
        v1,v2,v3 = faces[:,i]

        if v2>v1
            a = A(v1,v2)
            b = B(v1,v2)
            S += b^2
            P += - a*b
        end

        if v3>v2
            a = A(v2,v3)
            b = B(v2,v3)
            S += b^2
            P += - a*b
        end

        if v3>v1
            a = A(v1,v3)
            b = B(v1,v3)
            S += b^2
            P += - a*b
        end
    end

    return P/S
end

function stabilise!(points,faces,n,va,mc::Zinchenko1997)

    VertexRing = mc.VertexRing

    ff = Array{Float64}(undef,size(points)...)
    for j in 1:size(points,2)
        ring = VertexRing(j)
        ff[:,j] = f(j,n[:,j],points,va,ring)
    end
    ksi0 = conjugrad0(points,faces,va,ff)
    vb = va + ksi0*ff
    vtemp = Array{Float64}(undef,size(va)...)

    Fitemp = Inf

    for i in 1:200

        for j in 1:size(points,2)
            ring = VertexRing(j)
            ff[:,j] = f(j,n[:,j],points,vb,ring)
        end

        ksi,eta = conjugrad(points,faces,va,vb,ff)

        vtemp[:,:] = vb[:,:]
        for j in 1:size(points,2)
            vb[:,j] = vb[:,j] + ksi*ff[:,j] + eta*(vb[:,j]-va[:,j])
        end
        va[:,:] = vtemp[:,:]

        Fi = F(points,faces,vb,mc)
        #println("F is $Fi and ksi is $ksi")

        if abs(Fitemp-Fi)<eps*Fi
            break

            if i>100
                warn("Stabilisation had $i iterations")
            end
        end
        Fitemp = Fi
    end
end


text:
include(joinpath("joint_degree_seq.jl")) # the joint degree distribution is retrieved from the joint degree sequence

"""
joint_degree_dist(N::UnipartiteNetwork)
    N: Unipartite directed simple network
Returns the proportion of species having a given number of preys and predators
"""
function joint_degree_dist(N::UnipartiteNetwork)
    S = richness(N) # number of species in N
    k = joint_degree_seq(N) # joint degree sequence of N

    # count the number of species having kin predators and kout preys
    k_count = zeros(Int64, S+1, S+1)
    for kin in 0:S
        for kout in 0:S
            k_count[kin+1, kout+1] = sum((k.kin .== kin) .& (k.kout .== kout))
        end
    end

    k_prop = k_count ./ S # proportion of species having kin predators and kout preys
    return k_prop
end


text:
#!/usr/bin/env julia

# Run the RADMC3D tausurf command to synthesize a visualization of the tau=1 surface.

using ArgParse

s = ArgParseSettings()
@add_arg_table s begin
    "--config"
    help = "a YAML configuration file"
    default = "config.yaml"
    "--tau"
    help = "The optical depth to visualize. Default=1.0"
    default = 1.0
end

parsed_args = parse_args(ARGS, s)

import YAML
config = YAML.load(open(parsed_args["config"]))

using DiskJockey.constants
using DiskJockey.model

species = config["species"]
transition = config["transition"]
lam0 = lam0s[species*transition]
model = config["model"]

pars = convert_dict(config["parameters"], config["model"])
npix = config["npix"] # number of pixels

tau = parsed_args["tau"]

# lambda should have already been written by DJInitialize.jl
tic()
run(`radmc3d tausurf $tau incl $(pars.incl) posang $(pars.PA) npix $npix loadlambda`)
println("Tausurf runtime")
toc()

max_stars_repo_name: elnjensen/DiskJockey

max_issues_repo_name: elnjensen/DiskJockey

max_forks_repo_name: elnjensen/DiskJockey


text:
using Base: Float64
using Zygote
using StaticArrays
const Position = SVector{3, Float64}
const Force = SVector{3, Float64}
abstract type Potential end

include("LennardJones.jl")
include("BornMayer.jl")
include("Coulomb.jl")
include("GaN.jl")
include("ZBL.jl")
include("SNAP-LAMMPS.jl")

"""
    potential_energy(p::Potential, atomic_positions::Vector{Position}, rcutfac::Float64)

Calculates the potential energy of a particular atomic configuration.
It is based on the atomic positions of the configuration, the rcutfac, and a
particular potential.
"""
function potential_energy(p::Potential, atomic_positions::Vector{Position}, rcutfac::Float64)
    acc = 0.0
    for i = 1:length(atomic_positions)
        for j = i:length(atomic_positions)
            r_diff = (atomic_positions[i] - atomic_positions[j])
            if norm(r_diff) <= rcutfac && norm(r_diff) > 0.0
                acc += potential_energy(p, r_diff, i, j) #atom_type(i), atom_type(j))
            end
        end
    end
    return acc
end

"""
    forces(p::Potential, atomic_positions::Vector{Position}, rcutfac::Float64)

Calculates the forces of each atom in an atomic configuration.
"""
function forces(p::Potential, atomic_positions::Vector{Position}, rcutfac::Float64)
    forces = Vector{Force}()
    for i = 1:length(atomic_positions)
        f_i = Force(0.0, 0.0, 0.0)
        for j = 1:length(atomic_positions)
            r_diff = atomic_positions[i] - atomic_positions[j]
            if norm(r_diff) <= rcutfac && norm(r_diff) > 0.0
                ∇potential_energy(p, r, i, j) =
                     gradient(r -> potential_energy(p, r_diff + r, i, j), r)[1]
                f_ij = -∇potential_energy(p, atomic_positions[i], atom_type(i),
                                                                  atom_type(j))
                f_i += f_ij
            end
        end
        push!(forces, f_i)
    end
    return forces
end

"""
    atom_type(i::Int64)

Returns the atom type of the i-th atom of the configuration.
"""
function atom_type(i::Int64)
    #TODO
    return i
end


text:
# Air Constants
const GAMMA_AIR = 1.4  # Adiabatic index or ratio of specific heats (dry air at 20º C)
const R_AIR = 287.05287  # Specific gas constant for dry air (J/(Kg·K))

# Air at sea level conditions h=0 (m)
const RHO0 = 1.225  # Density at sea level (kg/m3)
const P0 = 101325.0  # Pressure at sea level (Pa)
const T0 = 288.15  # Temperature at sea level (K)
const A0 = 340.293990543  # Sound speed at sea level (m/s)

# EARTH CONSTANTS
const GRAVITY_ACCEL = 9.80665  # Gravity of Ethe Earth (m/s^2)
# Standard Gravitational Parameter
# product of the gravitational constant G and the mass M of the body
# TODO: review values with
# Rogers, R. M. (2007). Applied mathematics in integrated navigation systems.
# American Institute of Aeronautics and Astronautics. (Page 76, table 4.1)
const ROT_VELOCITY = 7.292115e-5  # Angular velocity ω_i/e (rad/s)
const STD_GRAV_PARAMETER = 3.986004418e14  # (m³/s²)
const EARTH_MASS = 5.9722e24  # Mass of the Earth (kg)
const GRAV_CONSTANT = 6.67384e11  # Gravitational constant (N·m²/kg²)
const EARTH_MEAN_RADIUS = 6371000  # Mean radius of the Earth (m)

# Ellipsoids
struct Ellipsoid
    a :: Real  # semi-major axis
    finv :: Real  # inverse of flattening
    f :: Real  # flattening
    b :: Real  # semi-minor axis
    e2 :: Real  # eccentricity squared
    ϵ2 :: Real  # second eccentricity squared
end

Ellipsoid(a, finv) = begin
    f = 1.0 / finv
    b = a * (1.0 - f)
    e2 = 1.0 - (1.0 - f) ^ 2.0
    ϵ2 = a*a / (b*b) - 1.0
    Ellipsoid(a, finv, f, b, e2, ϵ2)
end

# Rogers, R. M. (2007). Applied mathematics in integrated navigation systems.
# American Institute of Aeronautics and Astronautics. (Page 76, table 4.1)
Clarke1866           = Ellipsoid(6378206.4  , 294.9786982)
Clarke1880           = Ellipsoid(6378249.145, 294.465)
International        = Ellipsoid(6378388.0  , 297.0)
Bessel               = Ellipsoid(6377397.155, 299.1528128)
Everest              = Ellipsoid(6377276.345, 300.8017)
ModifiedEverest      = Ellipsoid(6377304.063, 300.8017)
AustralianNational   = Ellipsoid(6378160.0  , 298.25)
SouthAmerican1969    = Ellipsoid(6378160.0  , 298.25)
Airy                 = Ellipsoid(6377564.396, 299.3249646)
ModifiedAiry         = Ellipsoid(6377340.189, 299.3249646)
Hough                = Ellipsoid(6378270.0  , 297.0)
Fischer1960SouthAsia = Ellipsoid(6378155.0  , 298.3)
Fischer1960Mercury   = Ellipsoid(6378166.0  , 298.3)
Fischer1968          = Ellipsoid(6378150.0  , 298.3)
WGS60                = Ellipsoid(6378165.0  , 298.3)
WGS66                = Ellipsoid(6378145.0  , 298.25)
WGS72                = Ellipsoid(6378135.0  , 298.26)
WGS84                = Ellipsoid(6378137.0  , 298.257223563)

# CONVERSIONS
const LB2KG = 0.453592  # Pounds (lb) to kilograms (kg)
const KG2LB = 2.20462  # Kilograms (kg) to pounds (lb)
const FT2M = 0.3048  # Feet (ft) to meters (m)
const M2FT = 3.28084  # Meters (m) to feet (ft)
const IN2M = 0.0254  # Inches (in) to meters (m)
const M2IN = 39.37007874  # meters (m) to inches(in)
const SLUG2KG = 14.5939  # Slug to kilograms (kg)
const SLUGFT2_2_KGM2 = 1.35581795  # Slug*feet^2 to kilograms*meters^2 (kg*m^2)
const SLUGFT3_2_KGM3 = SLUG2KG / FT2M^3  # Slug*feet^3 to kilograms*meters^3 (kg*m^3)
const KT2MS = 0.514444  # knots (kt) to meters/second (m/s)
const MS2KT = 1.94384  # meters/second (m/s) to knots (kt)
const DEG2RAD = pi / 180  # degrees to radians
const RAD2DEG = 180 / pi  # radians to degrees
const HP2WAT = 745.7  # horse power to Watts
const WAT2HP = 0.00134102  # Wat to horse power
const LBF2N = 4.44822  # pounds force (lbf) to N (Newton)
const PA2PSF = 0.02088543  # Pascal to Pounds per square foot
const PSF2PA = 47.880258  # Pounds per square foot to Pascal
const RANK2KEL = 0.555556  # Rankine to Kelvin
const KEL2RANK = 1.8  # Kelvin to Rankine


text:
export escapetime, meancollisiontime
export escapetime!, meancollisiontime!
export visited_obstacles, visited_obstacles!

"""
    escapetime([p,] bd, t; warning = false)
Calculate the escape time of a particle `p` in the billiard `bd`, which
is the time until colliding with any "door" in `bd`.
As a "door" is considered any [`FiniteWall`](@ref) with
field `isdoor = true`.

If the particle evolves for more than `t` (integer or float) without colliding with the
`Door` (i.e. escaping) the returned result is `Inf`.

A warning can be thrown if the result is `Inf`. Enable this using the keyword
`warning = true`.

If a particle is not given, a random one is picked through [`randominside`](@ref).
See [`parallelize`](@ref) for a parallelized version.
"""
escapetime(p, bd, t; warning = false) =
    escapetime!(copy(p), bd, t; warning = warning)
escapetime(bd::Billiard, t; kwargs...) =
    escapetime(randominside(bd), bd, t; kwargs...)

function escapetime!(p::AbstractParticle{T}, bd::Billiard{T}, t, raysplitters = nothing;
        warning::Bool=false)::T where {T<:AbstractFloat}

    ei = escapeind(bd)
    if length(ei) == 0
        error("""The billiard does not have any "doors"!""")
    end

    totalt = zero(T); count = zero(t); t_to_write = zero(T)
    isray = !isa(raysplitters, Nothing)
    isray && acceptable_raysplitter(raysplitters, bd)
    raysidx = raysplit_indices(bd, raysplitters)

    while count < t

        i, tmin, pos, vel = bounce!(p, bd, raysidx, raysplitters)
        t_to_write += tmin

        if isperiodic(i, bd)
            continue
        else
            totalt += t_to_write
            i ∈ ei &&  break # the collision happens with a Door!

            # set counter
            count += increment_counter(t, t_to_write)
            t_to_write = zero(T)
        end
    end#time, or collision number, loop
    if count ≥ t
        warning && warn("Particle did not escape within max-iter window.")
        return T(Inf)
    end
    return totalt
end

function escapeind(bd)
    j = Int[]
    for (i, obst) in enumerate(bd)
        if typeof(obst) <: FiniteWall && obst.isdoor == true
            push!(j, i)
        end
    end
    return j
end

"""
    meancollisiontime([p,] bd, t) → κ
Compute the mean collision time `κ` of the particle `p` in the billiard `bd` by
evolving for total amount `t` (either float for time or integer for collision number).

Collision times are counted only between obstacles that are *not*
[`PeriodicWall`](@ref).

If a particle is not given, a random one is picked through [`randominside`](@ref).
See [`parallelize`](@ref) for a parallelized version.
"""
meancollisiontime(p, bd, t) = meancollisiontime!(copy(p), bd, t)
meancollisiontime(bd::Billiard, t) = meancollisiontime(randominside(bd), bd, t)

function meancollisiontime!(p::AbstractParticle{T}, bd::Billiard{T}, t)::T where {T}

    ispinned(p, bd) && return Inf
    ismagnetic = typeof(p) <: MagneticParticle
    ismagnetic && (absω = abs(p.omega))
    tmin, i = next_collision(p, bd)
    tmin == Inf && return Inf

    κ = zero(T); count = zero(t); t_to_write = zero(T); colcount = 0

    while count < t
        i, tmin, pos, vel = bounce!(p, bd)

        t_to_write += tmin

        if isperiodic(bd) && i ∈ bd.peridx
            continue
        else
            κ += t_to_write
            colcount += 1
            # set counter
            count += increment_counter(t, t_to_write)
            t_to_write = zero(T)
        end
    end
    return κ/colcount
end

"""
    visited_obstacles(p, args...)
Same as [`visited_obstacles!`](@ref) but copies the particle instead.
"""
visited_obstacles(p::AbstractParticle, args...) =
    visited_obstacles!(copy(p), args...)
visited_obstacles(bd::Billiard, args...; kwargs...) =
    visited_obstacles!(randominside(bd), bd, args...; kwargs...)

"""
    visited_obstacles!([p::AbstractParticle,] bd::Billiard, t)
Evolve the given particle `p` inside the billiard `bd` exactly like
[`evolve!`](@ref). However return only:

* `ts::Vector{T}` : Vector of time points of when each collision occured.
* `obst::Vector{Int}` : Vector of obstacle indices in `bd` that the particle
  collided with at the time points in `ts`.

The first entries are `0.0` and `0`.
Similarly with [`evolve!`](@ref) the function does not
record collisions with periodic walls.

Currently does not support raysplitting. Returns empty arrays
for pinned particles.
"""
function visited_obstacles!(
    p::AbstractParticle{T}, bd::Billiard{T}, t) where {T<:AbstractFloat}

    if t ≤ 0
        throw(ArgumentError("cannot evolve backwards in time."))
    end
    if ispinned(p, bd)
        return T[], Int[]
    end

    ts = T[0.0]; obst = Int[0]

    count = zero(t); t_to_write = zero(T)
    if typeof(t) == Int
        for zzz in (ts, obst)
            sizehint!(zzz, t)
        end
    end

    while count < t
        i, tmin, pos, vel = bounce!(p, bd)
        t_to_write += tmin
        if isperiodic(i, bd)
            continue
        else
            count += increment_counter(t, tmin)
            push!(ts, t_to_write + ts[end]); push!(obst, i)
            t_to_write = zero(T)
        end
    end#time, or collision number, loop
    return ts, obst
end


text:
using LinearAlgebra # HIDE
using Random:seed!  # HIDE
seed!(0)            # HIDE
                    # HIDE
x = randn(5)
y = randn(5)

for i in 1:5
    println(rpad("*"^i, 10, '-'), round(dot(x, y), digits=1))
end

max_stars_repo_name: thanktua-spp/website

max_issues_repo_name: thanktua-spp/website

max_forks_repo_name: thanktua-spp/website


text:
"""
    getparent(model::AbstractModel)

Returns the parent model of `model`.
"""
function getparent end

"""
    getobjectiveconstraints(model::AbstractModel)

Returns an instance of `AbstractFunction` that when called with input `x` returns the objective and constraint values of `model` at `x` in a single vector.
"""
function getobjectiveconstraints end

"""
    getobjective(model::AbstractModel)

Returns a function that when called with input `x` returns the objective value of `model` at `x`.
"""
function getobjective end

"""
    getineqconstraint(model::AbstractModel, i::Integer)

Returns a function that when called with input `x` returns the constraint violation value of the `i`^th inequality constraint of `model` at `x`.
"""
function getineqconstraint end

"""
    geteqconstraint(model::AbstractModel, i::Integer)

Returns a function that when called with input `x` returns the constraint violation value of the `i`^th equality constraint of `model` at `x`.
"""
function geteqconstraint end

"""
    getineqconstraints(model::AbstractModel)

Returns a function that when called with input `x` returns the constraint violation values of all the inequality constraints of `model` at `x`.
"""
function getineqconstraints end

"""
    geteqconstraints(model::AbstractModel)

Returns a function that when called with input `x` returns the constraint violation values of all the equality constraints of `model` at `x`.
"""
function geteqconstraints end

"""
    get_objective_multiple(model::AbstractModel)

Returns the factor by which the objective of `model` was scaled. This is 1 by default.
"""
function get_objective_multiple end

"""
    set_objective_multiple!(model::AbstractModel, multiple::Number)

Set the objective's scaling factor of `model` to `multiple`.
"""
function set_objective_multiple! end

"""
    getnconstraints(model::AbstractModel)

Returns the total number of constraints in `model`.
"""
function getnconstraints end

"""
    getnineqconstraints(model::AbstractModel)

Returns the number of inequality constraints in `model`.
"""
function getnineqconstraints end

"""
    getneqconstraints(model::AbstractModel)

Returns the number of equality constraints in `model`.
"""
function getneqconstraints end

"""
    getnvars(model::AbstractModel)

Returns the number of variables in `model`.
"""
function getnvars end

"""
    getmin(model::AbstractModel)

Returns the variables' lower bounds of `model`.
"""
function getmin end

"""
    getmax(model::AbstractModel)

Returns the variables' upper bounds of `model`.
"""
function getmax end

"""
    setmin!(model::AbstractModel, min::Union{Number, AbstractVector})
    setmin!(model::AbstractModel, i::Integer, min::Number)

Sets the variables' lower bounds in `model` to `min`. Or if `i` is given, it sets the lower bound of the `i`^th variable in `model` to `min`.
"""
function setmin! end

"""
    setmax!(model::AbstractModel, max::Union{Number, AbstractVector})
    setmax!(model::AbstractModel, i::Integer, max::Number)

Sets the variables' upper bound in `model` to `max`. Or if `i` is given, it sets the upper bound of the `i`^th variable in `model` to `max`.
"""
function setmax! end

"""
    setbox!(model::AbstractModel, min::Union{Number, AbstractVector}, max::Union{Number, AbstractVector})
    setbox!(model::AbstractModel, i::Integer, min::Number, max::Number)

Sets the variables' lower and upper bounds in `model` to `min` and `max` respectively. Or if `i` is given, it sets the lower and upper bounds of the `i`^th variable in `model` to `min` and `max` respectively.
"""
function setbox! end

"""
    addvar!(model::AbstractModel, lb::Number, ub::Number)

Adds a new variable to `model` with lower and upper bounds `lb` and `ub`.
"""
function addvar! end

"""
    add_ineq_constraint!(model::AbstractModel, f::IneqConstraint)
    add_ineq_constraint!(model::AbstractModel, fs::Vector{<:IneqConstraint})

Adds a new constraint `f` or multiple new constraints `fs` to `model`.
"""
function add_ineq_constraint! end

"""
    init!(model::AbstractModel)

Initializes the model.
"""
function init! end


text:
# adapted from http://www.gis.usu.edu/~chrisg/python/2009/lectures/ospy_hw3b_mod.py
# and          http://www.gis.usu.edu/~chrisg/python/2009/lectures/ospy_hw3b.py

import GDALUtils; const GU = GDALUtils

"""
function to copy fields (not the data) from one layer to another
parameters:
  fromLayer: layer object that contains the fields to copy
  toLayer: layer object to copy the fields into
"""
function copyfields(fromlayer, tolayer)
    featuredefn = GU.getlayerdefn(fromlayer)
    for i in 0:(GU.nfield(featuredefn)-1)
        fd = GU.fetchfielddefn(featuredefn, i)
        if GU.gettype(fd) == GDAL.OFTReal
            # to deal with errors like
            # ERROR: GDALError (Warning, code 1):
            # Value 18740682.1600000001 of field SHAPE_AREA of
            # feature 1 not successfully written. Possibly due
            # to too larger number with respect to field width
            if GU.getwidth(fd) != 0
                GU.setwidth(fd, GU.getwidth(fd)+1)
            end
        end
        GU.createfield(tolayer, fd)
    end
end

"""
function to copy attributes from one feature to another
(this assumes the features have the same attribute fields!)
parameters:
  fromFeature: feature object that contains the data to copy
  toFeature: feature object that the data is to be copied into
"""
function copyattributes(fromfeature, tofeature)
    for i in 0:(GU.nfield(fromfeature)-1)
        if GU.isfieldset(fromfeature, i)
            try
                GU.setfield(tofeature, i, GU.fetchfield(fromfeature, i))
            catch
                println(fromfeature)
                println(tofeature)
                println("$i: $(GU.fetchfield(fromfeature, i))")
            end
        end
    end
end

# define the function
function reproject(inFN, inEPSG, outFN, outEPSG)
    inspatialref = GU.fromEPSG(inEPSG)
    outspatialref = GU.fromEPSG(outEPSG)
    coordtrans = GU.createcoordtrans(inspatialref, outspatialref)
    GU.read(inFN) do inDS
        GU.create(outFN, "ESRI Shapefile") do outDS
            inlayer = GU.fetchlayer(inDS, 0)
            outlayer = GU.createlayer(outDS,
                                      split(split(outFN, "/")[end], ".")[1],
                                      GU.getgeomtype(GU.getlayerdefn(inlayer)))
            copyfields(inlayer, outlayer)
            featuredefn = GU.getlayerdefn(outlayer)
            for infeature in inlayer
                geom = GU.getgeom(infeature)
                GU.transform(geom, coordtrans)
                GU.createfeature(featuredefn) do outfeature
                    GU.setgeom(outfeature, geom)
                    copyattributes(infeature, outfeature)
                    GU.createfeature(outlayer, outfeature)
                end
            end
        end
    end

    # create the *.prj file
    GU.morphtoesri(outspatialref)
    open(replace(outFN, ".shp", ".prj"), "w") do file
        write(file, GU.toWKT(outspatialref))
    end
end

GU.registerdrivers() do
    for inFN in readdir("./ospy/data3/")
        if endswith(inFN, ".shp")
            outFN = replace(inFN, ".shp", "_proj.shp")
            reproject("./ospy/data3/$(inFN)", 26912, "tmp/$(outFN)", 4269)
        end
    end
end


text:
# matlab estimate of isi = 0.0177
# julia/glfw estimate of isi = 0.0166 (monitor is at 60Hz. 1/60 = 0.016666...)
#
# a basic draw test was:
#	- draw 100 randomly placed ellipses, with random widths and heights
#	- make sure each ellipse has a randomly assigned fill color and stroke
#	  color
# for this test:
#	fastest matlab roundtrip time = ~0.007860 secs
#	fastest julia roundtrip time = ~0.001945 secs
#
# julia is faster (~4x faster) and its timing fluctuates much less than
# matlab's. plus, it appears that julia accurately syncs to vertical refresh,
# even on OS X.
#
# (however, i'm not sure if this is an illusion or a mistake on my part...)
#
# anyway, "test.tsv" contains timing data for Processing.jl that was generated
# by the script below. the times are how long it takes from the top of the
# animation loop to the screen being updated. if we have proper vsync, then
# this should always be 0.01666... secs. "test.tsv" shows that this is the
# case, at an average frame time of 0.016649 secs with a fluctuation error of
# ~0.0012 secs.
#
# note that, all of this here is without any of the special psychtoolbox tricks
# that try to make stuff sync with the monitor via tweaks. its just standard
# opengl and glfw commands, although we are using the commands that are some
# of the fastest for rendering.
#
# the julia code is also easier to write, understand, and maintain.

using Processing

window = Processing.screen()
ftbf = zeros(600)
ft = zeros(600)
x = 1
t = 0

image = Processing.loadImage(Pkg.dir()*"/Processing/test/image.png")
tex, w, h = Processing.texture(image)

@time while x < 600
	st = time_ns()
	Processing.background(0.94, 0.92, 0.9, 1.0)
	Processing.strokecol(0, 0, 0, 1)
	Processing.fillcol(0.7, 0.7, 0.7, 1.0)
	Processing.ellipse(0, 0, 0.3, 0.5)
	Processing.ellipse(-.5, .5, 0.2, 0.2)
	Processing.triangle(.3, .75, .58, .20, .86, .75)
	Processing.triangle(.3, .6, .58, .40, .86, .7)
	Processing.strokeWeight(5)
	Processing.point(randn(10), randn(10))
	Processing.text("Processing.jl", 0.25, -0.85)
	Processing.strokeWeight(1)
	Processing.fillcol(0, 0, 0.9, 1)
	Processing.quad(-.3, -.75, -.58, -.20, -.86, -.75, -.2, -.4)
	Processing.line(.5, -.4, .7, -.5)
	Processing.noFill()
	Processing.rect(-.6, -.4, .2, .5)
	Processing.line(.7, -.4, .5, -.5)
	Processing.strokecol(0.9, 0, 0, 1)
	Processing.arc(-.6, .6, .3, .3, 0.4pi, pi)
	Processing.strokecol(0, 0.9, 0, 1)
	Processing.fillcol(1.0, 1.0, 1.0, 1.0)
	Processing.ellipse(0, 0, 0.2, 0.2)
	Processing.fillcol(sin(t)/2+0.5, cos(t)/2+0.5, (sin(t)*cos(t))/2+0.5, 1.0)
	Processing.pushMatrix()
	Processing.rotateY(pi/10*t)
	Processing.rotateX(pi/10*t)
	Processing.translate(0.2, -0.5, 0)
	Processing.box(0.15)
	Processing.popMatrix()
	Processing.noStroke()
	Processing.fillcol(1, 1, 1, 1)
	Processing.rect(-0.1, 0.6, 0.2, 0.2, tex)
	if Processing.keyPress(window, GLFW.KEY_SPACE)
		Processing.save("screenshot.tiff")
		println("key pressed and screenshot saved.")
	end
	if Processing.mousePress(window, GLFW.MOUSE_BUTTON_LEFT)
		println("bye!")
		break
	end
	ftbf[Processing.frameCount()+1] = time_ns() - st
	Processing.animate(window)
	ft[Processing.frameCount()] = time_ns() - st
	t += 1/60
	x += 1
end

Processing.endDrawing(window)


text:
__precompile__(true)

module StochasticOptimization

using Compat: @compat
using Reexport
using LearnBase
import LearnBase: value, learn!, update!

@reexport using LearningStrategies
import LearningStrategies: pre_hook, iter_hook, finished, post_hook

export
    # LearningStrategy,
    # MetaLearner,
    # make_learner,
    #
    # MaxIter,
    # TimeLimit,
    # ConvergenceFunction,
    # IterFunction,
    # ShowStatus,
    # Tracer,
    # Converged,
    # ConvergedTo,

    GradientLearner,
    OnlineGradAvg,
    SearchDirection,
    GradientAverager,

    # pre_hook,
    # iter_hook,
    # post_hook,
    # finished,

    LearningRate,
    FixedLR,
    # AdaptiveLR,

    ParamUpdater,
    SGD,
    Adagrad,
    Adadelta,
    Adam,
    Adamax,
    RMSProp,

    @with

include("utils.jl")

"Enacts a strategy to adjust the learning rate"
@compat abstract type LearningRate end
include("learningrates.jl")

"An algorithm to update paramaters using a gradient (i.e. SGD, Adam, Adagrad, etc)"
@compat abstract type ParamUpdater end
include("paramupdaters.jl")
include("gradients/gradients.jl")
include("gradients/online_gradients.jl")

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

end # module

max_stars_repo_name: JuliaML/StochasticOptimization

max_issues_repo_name: JuliaML/StochasticOptimization

max_forks_repo_name: JuliaML/StochasticOptimization