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

"""
    accept_page(accept_code, accept_type, page_id)
    accept_page(accept_code, accept_type, page_id, params::Dict{String,<:Any})

Used to acknowledge an engagement to a contact channel during an incident.

# Arguments
- `accept_code`: The accept code is a 6-digit code used to acknowledge the page.
- `accept_type`: The type indicates if the page was DELIVERED or READ.
- `page_id`: The Amazon Resource Name (ARN) of the engagement to a contact channel.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ContactChannelId"`: The ARN of the contact channel.
- `"Note"`: Information provided by the user when the user acknowledges the page.
"""
accept_page(AcceptCode, AcceptType, PageId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("AcceptPage", Dict{String, Any}("AcceptCode"=>AcceptCode, "AcceptType"=>AcceptType, "PageId"=>PageId); aws_config=aws_config)
accept_page(AcceptCode, AcceptType, PageId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("AcceptPage", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("AcceptCode"=>AcceptCode, "AcceptType"=>AcceptType, "PageId"=>PageId), params)); aws_config=aws_config)

"""
    activate_contact_channel(activation_code, contact_channel_id)
    activate_contact_channel(activation_code, contact_channel_id, params::Dict{String,<:Any})

Activates a contact's contact channel. Incident Manager can't engage a contact until the
contact channel has been activated.

# Arguments
- `activation_code`: The code sent to the contact channel when it was created in the
  contact.
- `contact_channel_id`: The Amazon Resource Name (ARN) of the contact channel.

"""
activate_contact_channel(ActivationCode, ContactChannelId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ActivateContactChannel", Dict{String, Any}("ActivationCode"=>ActivationCode, "ContactChannelId"=>ContactChannelId); aws_config=aws_config)
activate_contact_channel(ActivationCode, ContactChannelId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ActivateContactChannel", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ActivationCode"=>ActivationCode, "ContactChannelId"=>ContactChannelId), params)); aws_config=aws_config)

"""
    create_contact(alias, plan, type)
    create_contact(alias, plan, type, params::Dict{String,<:Any})

Contacts are either the contacts that Incident Manager engages during an incident or the
escalation plans that Incident Manager uses to engage contacts in phases during an
incident.

# Arguments
- `alias`: The short name to quickly identify a contact or escalation plan. The contact
  alias must be unique and identifiable.
- `plan`: A list of stages. A contact has an engagement plan with stages that contact
  specified contact channels. An escalation plan uses stages that contact specified contacts.
- `type`: To create an escalation plan use ESCALATION. To create a contact use PERSONAL.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DisplayName"`: The full name of the contact or escalation plan.
- `"IdempotencyToken"`: A token ensuring that the action is called only once with the
  specified details.
- `"Tags"`: Adds a tag to the target. You can only tag resources created in the first
  Region of your replication set.
"""
create_contact(Alias, Plan, Type; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("CreateContact", Dict{String, Any}("Alias"=>Alias, "Plan"=>Plan, "Type"=>Type, "IdempotencyToken"=>string(uuid4())); aws_config=aws_config)
create_contact(Alias, Plan, Type, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("CreateContact", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Alias"=>Alias, "Plan"=>Plan, "Type"=>Type, "IdempotencyToken"=>string(uuid4())), params)); aws_config=aws_config)

"""
    create_contact_channel(contact_id, delivery_address, name, type)
    create_contact_channel(contact_id, delivery_address, name, type, params::Dict{String,<:Any})

A contact channel is the method that Incident Manager uses to engage your contact.

# Arguments
- `contact_id`: The Amazon Resource Name (ARN) of the contact you are adding the contact
  channel to.
- `delivery_address`: The details that Incident Manager uses when trying to engage the
  contact channel. The format is dependent on the type of the contact channel. The following
  are the expected formats:   SMS - '+' followed by the country code and phone number   VOICE
  - '+' followed by the country code and phone number   EMAIL - any standard email format
- `name`: The name of the contact channel.
- `type`: Incident Manager supports three types of contact channels:    SMS     VOICE
  EMAIL

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DeferActivation"`: If you want to activate the channel at a later time, you can choose
  to defer activation. Incident Manager can't engage your contact channel until it has been
  activated.
- `"IdempotencyToken"`: A token ensuring that the action is called only once with the
  specified details.
"""
create_contact_channel(ContactId, DeliveryAddress, Name, Type; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("CreateContactChannel", Dict{String, Any}("ContactId"=>ContactId, "DeliveryAddress"=>DeliveryAddress, "Name"=>Name, "Type"=>Type, "IdempotencyToken"=>string(uuid4())); aws_config=aws_config)
create_contact_channel(ContactId, DeliveryAddress, Name, Type, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("CreateContactChannel", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactId"=>ContactId, "DeliveryAddress"=>DeliveryAddress, "Name"=>Name, "Type"=>Type, "IdempotencyToken"=>string(uuid4())), params)); aws_config=aws_config)

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

To no longer receive Incident Manager engagements to a contact channel, you can deactivate
the channel.

# Arguments
- `contact_channel_id`: The Amazon Resource Name (ARN) of the contact channel you're
  deactivating.

"""
deactivate_contact_channel(ContactChannelId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("DeactivateContactChannel", Dict{String, Any}("ContactChannelId"=>ContactChannelId); aws_config=aws_config)
deactivate_contact_channel(ContactChannelId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("DeactivateContactChannel", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactChannelId"=>ContactChannelId), params)); aws_config=aws_config)

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

To remove a contact from Incident Manager, you can delete the contact. Deleting a contact
removes them from all escalation plans and related response plans. Deleting an escalation
plan removes it from all related response plans. You will have to recreate the contact and
its contact channels before you can use it again.

# Arguments
- `contact_id`: The Amazon Resource Name (ARN) of the contact that you're deleting.

"""
delete_contact(ContactId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("DeleteContact", Dict{String, Any}("ContactId"=>ContactId); aws_config=aws_config)
delete_contact(ContactId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("DeleteContact", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactId"=>ContactId), params)); aws_config=aws_config)

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

To no longer receive engagements on a contact channel, you can delete the channel from a
contact. Deleting the contact channel removes it from the contact's engagement plan. If you
delete the only contact channel for a contact, you won't be able to engage that contact
during an incident.

# Arguments
- `contact_channel_id`: The Amazon Resource Name (ARN) of the contact channel.

"""
delete_contact_channel(ContactChannelId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("DeleteContactChannel", Dict{String, Any}("ContactChannelId"=>ContactChannelId); aws_config=aws_config)
delete_contact_channel(ContactChannelId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("DeleteContactChannel", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactChannelId"=>ContactChannelId), params)); aws_config=aws_config)

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

Incident Manager uses engagements to engage contacts and escalation plans during an
incident. Use this command to describe the engagement that occurred during an incident.

# Arguments
- `engagement_id`: The Amazon Resource Name (ARN) of the engagement you want the details of.

"""
describe_engagement(EngagementId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("DescribeEngagement", Dict{String, Any}("EngagementId"=>EngagementId); aws_config=aws_config)
describe_engagement(EngagementId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("DescribeEngagement", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("EngagementId"=>EngagementId), params)); aws_config=aws_config)

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

Lists details of the engagement to a contact channel.

# Arguments
- `page_id`: The ID of the engagement to a contact channel.

"""
describe_page(PageId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("DescribePage", Dict{String, Any}("PageId"=>PageId); aws_config=aws_config)
describe_page(PageId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("DescribePage", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("PageId"=>PageId), params)); aws_config=aws_config)

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

Retrieves information about the specified contact or escalation plan.

# Arguments
- `contact_id`: The Amazon Resource Name (ARN) of the contact or escalation plan.

"""
get_contact(ContactId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("GetContact", Dict{String, Any}("ContactId"=>ContactId); aws_config=aws_config)
get_contact(ContactId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("GetContact", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactId"=>ContactId), params)); aws_config=aws_config)

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

List details about a specific contact channel.

# Arguments
- `contact_channel_id`: The Amazon Resource Name (ARN) of the contact channel you want
  information about.

"""
get_contact_channel(ContactChannelId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("GetContactChannel", Dict{String, Any}("ContactChannelId"=>ContactChannelId); aws_config=aws_config)
get_contact_channel(ContactChannelId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("GetContactChannel", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactChannelId"=>ContactChannelId), params)); aws_config=aws_config)

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

Retrieves the resource policies attached to the specified contact or escalation plan.

# Arguments
- `contact_arn`: The Amazon Resource Name (ARN) of the contact or escalation plan.

"""
get_contact_policy(ContactArn; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("GetContactPolicy", Dict{String, Any}("ContactArn"=>ContactArn); aws_config=aws_config)
get_contact_policy(ContactArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("GetContactPolicy", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactArn"=>ContactArn), params)); aws_config=aws_config)

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

Lists all contact channels for the specified contact.

# Arguments
- `contact_id`: The Amazon Resource Name (ARN) of the contact.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of contact channels per page.
- `"NextToken"`: The pagination token to continue to the next page of results.
"""
list_contact_channels(ContactId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListContactChannels", Dict{String, Any}("ContactId"=>ContactId); aws_config=aws_config)
list_contact_channels(ContactId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListContactChannels", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactId"=>ContactId), params)); aws_config=aws_config)

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

Lists all contacts and escalation plans in Incident Manager.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"AliasPrefix"`: Used to list only contacts who's aliases start with the specified prefix.
- `"MaxResults"`: The maximum number of contacts and escalation plans per page of results.
- `"NextToken"`: The pagination token to continue to the next page of results.
- `"Type"`: The type of contact. A contact is type PERSONAL and an escalation plan is type
  ESCALATION.
"""
list_contacts(; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListContacts"; aws_config=aws_config)
list_contacts(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListContacts", params; aws_config=aws_config)

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

Lists all engagements that have happened in an incident.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"IncidentId"`: The Amazon Resource Name (ARN) of the incident you're listing engagements
  for.
- `"MaxResults"`: The maximum number of engagements per page of results.
- `"NextToken"`: The pagination token to continue to the next page of results.
- `"TimeRangeValue"`: The time range to lists engagements for an incident.
"""
list_engagements(; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListEngagements"; aws_config=aws_config)
list_engagements(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListEngagements", params; aws_config=aws_config)

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

Lists all of the engagements to contact channels that have been acknowledged.

# Arguments
- `page_id`: The Amazon Resource Name (ARN) of the engagement to a specific contact channel.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of acknowledgements per page of results.
- `"NextToken"`: The pagination token to continue to the next page of results.
"""
list_page_receipts(PageId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListPageReceipts", Dict{String, Any}("PageId"=>PageId); aws_config=aws_config)
list_page_receipts(PageId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListPageReceipts", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("PageId"=>PageId), params)); aws_config=aws_config)

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

Lists the engagements to a contact's contact channels.

# Arguments
- `contact_id`: The Amazon Resource Name (ARN) of the contact you are retrieving
  engagements for.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of engagements to contact channels to list per page of
  results.
- `"NextToken"`: The pagination token to continue to the next page of results.
"""
list_pages_by_contact(ContactId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListPagesByContact", Dict{String, Any}("ContactId"=>ContactId); aws_config=aws_config)
list_pages_by_contact(ContactId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListPagesByContact", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactId"=>ContactId), params)); aws_config=aws_config)

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

Lists the engagements to contact channels that occurred by engaging a contact.

# Arguments
- `engagement_id`: The Amazon Resource Name (ARN) of the engagement.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of engagements to contact channels to list per page of
  results.
- `"NextToken"`: The pagination token to continue to the next page of results.
"""
list_pages_by_engagement(EngagementId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListPagesByEngagement", Dict{String, Any}("EngagementId"=>EngagementId); aws_config=aws_config)
list_pages_by_engagement(EngagementId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListPagesByEngagement", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("EngagementId"=>EngagementId), params)); aws_config=aws_config)

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

Lists the tags of an escalation plan or contact.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the contact or escalation plan.

"""
list_tags_for_resource(ResourceARN; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListTagsForResource", Dict{String, Any}("ResourceARN"=>ResourceARN); aws_config=aws_config)
list_tags_for_resource(ResourceARN, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("ListTagsForResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceARN"=>ResourceARN), params)); aws_config=aws_config)

"""
    put_contact_policy(contact_arn, policy)
    put_contact_policy(contact_arn, policy, params::Dict{String,<:Any})

Adds a resource to the specified contact or escalation plan.

# Arguments
- `contact_arn`: The Amazon Resource Name (ARN) of the contact or escalation plan.
- `policy`: Details of the resource policy.

"""
put_contact_policy(ContactArn, Policy; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("PutContactPolicy", Dict{String, Any}("ContactArn"=>ContactArn, "Policy"=>Policy); aws_config=aws_config)
put_contact_policy(ContactArn, Policy, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("PutContactPolicy", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactArn"=>ContactArn, "Policy"=>Policy), params)); aws_config=aws_config)

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

Sends an activation code to a contact channel. The contact can use this code to activate
the contact channel in the console or with the ActivateChannel action. Incident Manager
can't engage a contact channel until it has been activated.

# Arguments
- `contact_channel_id`: The Amazon Resource Name (ARN) of the contact channel.

"""
send_activation_code(ContactChannelId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("SendActivationCode", Dict{String, Any}("ContactChannelId"=>ContactChannelId); aws_config=aws_config)
send_activation_code(ContactChannelId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("SendActivationCode", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactChannelId"=>ContactChannelId), params)); aws_config=aws_config)

"""
    start_engagement(contact_id, content, sender, subject)
    start_engagement(contact_id, content, sender, subject, params::Dict{String,<:Any})

Starts an engagement to a contact or escalation plan. The engagement engages each contact
specified in the incident.

# Arguments
- `contact_id`: The Amazon Resource Name (ARN) of the contact being engaged.
- `content`: The secure content of the message that was sent to the contact. Use this field
  for engagements to VOICE or EMAIL.
- `sender`: The user that started the engagement.
- `subject`: The secure subject of the message that was sent to the contact. Use this field
  for engagements to VOICE or EMAIL.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"IdempotencyToken"`: A token ensuring that the action is called only once with the
  specified details.
- `"IncidentId"`: The ARN of the incident that the engagement is part of.
- `"PublicContent"`: The insecure content of the message that was sent to the contact. Use
  this field for engagements to SMS.
- `"PublicSubject"`: The insecure subject of the message that was sent to the contact. Use
  this field for engagements to SMS.
"""
start_engagement(ContactId, Content, Sender, Subject; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("StartEngagement", Dict{String, Any}("ContactId"=>ContactId, "Content"=>Content, "Sender"=>Sender, "Subject"=>Subject, "IdempotencyToken"=>string(uuid4())); aws_config=aws_config)
start_engagement(ContactId, Content, Sender, Subject, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("StartEngagement", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactId"=>ContactId, "Content"=>Content, "Sender"=>Sender, "Subject"=>Subject, "IdempotencyToken"=>string(uuid4())), params)); aws_config=aws_config)

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

Stops an engagement before it finishes the final stage of the escalation plan or engagement
plan. Further contacts aren't engaged.

# Arguments
- `engagement_id`: The Amazon Resource Name (ARN) of the engagement.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Reason"`: The reason that you're stopping the engagement.
"""
stop_engagement(EngagementId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("StopEngagement", Dict{String, Any}("EngagementId"=>EngagementId); aws_config=aws_config)
stop_engagement(EngagementId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("StopEngagement", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("EngagementId"=>EngagementId), params)); aws_config=aws_config)

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

Tags a contact or escalation plan. You can tag only contacts and escalation plans in the
first region of your replication set.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the contact or escalation plan.
- `tags`: A list of tags that you are adding to the contact or escalation plan.

"""
tag_resource(ResourceARN, Tags; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("TagResource", Dict{String, Any}("ResourceARN"=>ResourceARN, "Tags"=>Tags); aws_config=aws_config)
tag_resource(ResourceARN, Tags, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("TagResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceARN"=>ResourceARN, "Tags"=>Tags), params)); aws_config=aws_config)

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

Removes tags from the specified resource.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the contact or escalation plan.
- `tag_keys`: The key of the tag that you want to remove.

"""
untag_resource(ResourceARN, TagKeys; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("UntagResource", Dict{String, Any}("ResourceARN"=>ResourceARN, "TagKeys"=>TagKeys); aws_config=aws_config)
untag_resource(ResourceARN, TagKeys, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("UntagResource", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ResourceARN"=>ResourceARN, "TagKeys"=>TagKeys), params)); aws_config=aws_config)

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

Updates the contact or escalation plan specified.

# Arguments
- `contact_id`: The Amazon Resource Name (ARN) of the contact or escalation plan you're
  updating.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DisplayName"`: The full name of the contact or escalation plan.
- `"Plan"`: A list of stages. A contact has an engagement plan with stages for specified
  contact channels. An escalation plan uses these stages to contact specified contacts.
"""
update_contact(ContactId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("UpdateContact", Dict{String, Any}("ContactId"=>ContactId); aws_config=aws_config)
update_contact(ContactId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("UpdateContact", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactId"=>ContactId), params)); aws_config=aws_config)

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

Updates a contact's contact channel.

# Arguments
- `contact_channel_id`: The Amazon Resource Name (ARN) of the contact channel you want to
  update.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DeliveryAddress"`: The details that Incident Manager uses when trying to engage the
  contact channel.
- `"Name"`: The name of the contact channel
"""
update_contact_channel(ContactChannelId; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("UpdateContactChannel", Dict{String, Any}("ContactChannelId"=>ContactChannelId); aws_config=aws_config)
update_contact_channel(ContactChannelId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = ssm_contacts("UpdateContactChannel", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("ContactChannelId"=>ContactChannelId), params)); aws_config=aws_config)


text:
# kernel execution

export AbstractGPUBackend, AbstractKernelContext, gpu_call, synchronize, thread_blocks_heuristic

abstract type AbstractGPUBackend end

abstract type AbstractKernelContext end

"""
    backend(T::Type)
    backend(x)

Gets the GPUArrays back-end responsible for managing arrays of type `T`.
"""
backend(::Type) = error("This object is not a GPU array") # COV_EXCL_LINE
backend(x) = backend(typeof(x))

"""
    gpu_call(kernel::Function, arg0, args...; kwargs...)

Executes `kernel` on the device that backs `arg` (see [`backend`](@ref)), passing along any
arguments `args`. Additionally, the kernel will be passed the kernel execution context (see
[`AbstractKernelContext`]), so its signature should be `(ctx::AbstractKernelContext, arg0,
args...)`.

The keyword arguments `kwargs` are not passed to the function, but are interpreted on the
host to influence how the kernel is executed. The following keyword arguments are supported:

- `target::AbstractArray`: specify which array object to use for determining execution
  properties (defaults to the first argument `arg0`).
- `total_threads::Int`: how many threads should be launched _in total_. The actual number of
  threads and blocks is determined using a heuristic. Defaults to the length of `arg0` if
  no other keyword arguments that influence the launch configuration are specified.
- `threads::Int` and `blocks::Int`: configure exactly how many threads and blocks are
  launched. This cannot be used in combination with the `total_threads` argument.
- `name::String`: inform the back end about the name of the kernel to be executed.
  This can be used to emit better diagnostics, and is useful with anonymous kernels.
"""
function gpu_call(kernel::Base.Callable, args...;
                  target::AbstractArray=first(args),
                  total_threads::Union{Int,Nothing}=nothing,
                  threads::Union{Int,Nothing}=nothing,
                  blocks::Union{Int,Nothing}=nothing,
                  name::Union{String,Nothing}=nothing)
    # non-trivial default values for launch configuration
    if total_threads===nothing && threads===nothing && blocks===nothing
        total_threads = length(target)
    elseif total_threads===nothing
        if threads === nothing
            threads = 1
        end
        if blocks === nothing
            blocks = 1
        end
    elseif threads!==nothing || blocks!==nothing
        error("Cannot specify both total_threads and threads/blocks configuration")
    end

    if total_threads !== nothing
        gpu_call(backend(target), kernel, args, total_threads; name=name)
    else
        gpu_call(backend(target), kernel, args, threads, blocks; name=name)
    end
end

# gpu_call method with a simple launch configuration heuristic.
# this can be specialised if more sophisticated heuristics are available.
function gpu_call(backend::AbstractGPUBackend, kernel, args, total_threads::Int; kwargs...)
    threads = clamp(total_threads, 1, 256)
    blocks = max(ceil(Int, total_threads / threads), 1)

    gpu_call(backend, kernel, args, threads, blocks; kwargs...)
end

# bottom-line gpu_call method that is expected to be implemented by the back end
gpu_call(backend::AbstractGPUBackend, kernel, args, threads::Int, blocks::Int; kwargs...) = error("Not implemented") # COV_EXCL_LINE

"""
    synchronize(A::AbstractArray)

Blocks until all operations are finished on `A`
"""
function synchronize(A::AbstractArray)
    # fallback is a noop, for backends not needing synchronization. This
    # makes it easier to write generic code that also works for AbstractArrays
end

ext: jl


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

using Test
using REPL
import REPL.LineEdit
import REPL.LineEdit: edit_insert, buffer, content, setmark, getmark, region

include("FakeTerminals.jl")
import .FakeTerminals.FakeTerminal

# no need to have animation in tests
REPL.GlobalOptions.region_animation_duration=0.0001
# tests are inserting code much faster than humans
REPL.GlobalOptions.auto_indent_time_threshold = -0.0

## helper functions

function new_state()
    term = FakeTerminal(IOBuffer(), IOBuffer(), IOBuffer())
    LineEdit.init_state(term, LineEdit.ModalInterface([LineEdit.Prompt("test> ")]))
end

charseek(buf, i) = seek(buf, nextind(content(buf), 0, i+1)-1)
charpos(buf, pos=position(buf)) = length(content(buf), 1, pos)

function transform!(f, s, i = -1) # i is char-based (not bytes) buffer position
    buf = buffer(s)
    i >= 0 && charseek(buf, i)
    # simulate what happens in LineEdit.set_action!
    s isa LineEdit.MIState && (s.current_action = :unknown)
    status = f(s)
    if s isa LineEdit.MIState && status != :ignore
        # simulate what happens in LineEdit.prompt!
        s.last_action = s.current_action
    end
    content(s), charpos(buf), charpos(buf, getmark(buf))
end

function run_test(d,buf)
    global a_foo, b_foo, a_bar, b_bar
    a_foo = b_foo = a_bar = b_bar = 0
    while !eof(buf)
        LineEdit.match_input(d, nothing, buf)(nothing,nothing)
    end
end

a_foo = 0

const foo_keymap = Dict(
    'a' => (o...)->(global a_foo; a_foo += 1)
)

b_foo = 0

const foo2_keymap = Dict(
    'b' => (o...)->(global b_foo; b_foo += 1)
)

a_bar = 0
b_bar = 0

const bar_keymap = Dict(
    'a' => (o...)->(global a_bar; a_bar += 1),
    'b' => (o...)->(global b_bar; b_bar += 1)
)

test1_dict = LineEdit.keymap([foo_keymap])

run_test(test1_dict,IOBuffer("aa"))
@test a_foo == 2

test2_dict = LineEdit.keymap([foo2_keymap, foo_keymap])

run_test(test2_dict,IOBuffer("aaabb"))
@test a_foo == 3
@test b_foo == 2

test3_dict = LineEdit.keymap([bar_keymap, foo_keymap])

run_test(test3_dict,IOBuffer("aab"))
@test a_bar == 2
@test b_bar == 1

# Multiple spellings in the same keymap
const test_keymap_1 = Dict(
    "^C" => (o...)->1,
    "\\C-C" => (o...)->2
)

@test_throws ErrorException LineEdit.keymap([test_keymap_1])

a_foo = a_bar = 0

const test_keymap_2 = Dict(
    "abc" => (o...)->(global a_foo = 1)
)

const test_keymap_3 = Dict(
    "a"  => (o...)->(global a_foo = 2),
    "bc" => (o...)->(global a_bar = 3)
)

function keymap_fcn(keymaps)
    d = LineEdit.keymap(keymaps)
    f = buf->(LineEdit.match_input(d, nothing, buf)(nothing,nothing))
end

let f = keymap_fcn([test_keymap_3, test_keymap_2])
    buf = IOBuffer("abc")
    f(buf); f(buf)
    @test a_foo == 2
    @test a_bar == 3
    @test eof(buf)
end

# Eager redirection when the redirected-to behavior is changed.

a_foo = 0

const test_keymap_4 = Dict(
    "a" => (o...)->(global a_foo = 1),
    "b" => "a",
    "c" => (o...)->(global a_foo = 2),
)

const test_keymap_5 = Dict(
    "a" => (o...)->(global a_foo = 3),
    "d" => "c"
)

let f = keymap_fcn([test_keymap_5, test_keymap_4])
    buf = IOBuffer("abd")
    f(buf)
    @test a_foo == 3
    f(buf)
    @test a_foo == 1
    f(buf)
    @test a_foo == 2
    @test eof(buf)
end

# Eager redirection with cycles

const test_cycle = Dict(
    "a" => "b",
    "b" => "a"
)

@test_throws ErrorException LineEdit.keymap([test_cycle])

# Lazy redirection with Cycles

const level1 = Dict(
    "a" => LineEdit.KeyAlias("b")
)

const level2a = Dict(
    "b" => "a"
)

const level2b = Dict(
    "b" => LineEdit.KeyAlias("a")
)

@test_throws ErrorException LineEdit.keymap([level2a,level1])
@test_throws ErrorException LineEdit.keymap([level2b,level1])

# Lazy redirection functionality test

a_foo = 0

const test_keymap_6 = Dict(
    "a" => (o...)->(global a_foo = 1),
    "b" => LineEdit.KeyAlias("a"),
    "c" => (o...)->(global a_foo = 2),
)

const test_keymap_7 = Dict(
    "a" => (o...)->(global a_foo = 3),
    "d" => "c"
)

let f = keymap_fcn([test_keymap_7, test_keymap_6])
    buf = IOBuffer("abd")
    f(buf)
    @test a_foo == 3
    global a_foo = 0
    f(buf)
    @test a_foo == 3
    f(buf)
    @test a_foo == 2
    @test eof(buf)
end

# Test requiring postprocessing (see conflict fixing in LineEdit.jl )

global path1 = 0
global path2 = 0
global path3 = 0

const test_keymap_8 = Dict(
    "**" => (o...)->(global path1 += 1),
    "ab" => (o...)->(global path2 += 1),
    "cd" => (o...)->(global path3 += 1),
    "d" => (o...)->(error("This is not the key you're looking for"))
)

let f = keymap_fcn([test_keymap_8])
    buf = IOBuffer("bbabaccd")
    f(buf)
    @test path1 == 1
    f(buf)
    @test path2 == 1
    f(buf)
    @test path1 == 2
    f(buf)
    @test path3 == 1
    @test eof(buf)
end

global path1 = 0
global path2 = 0

const test_keymap_9 = Dict(
    "***" => (o...)->(global path1 += 1),
    "*a*" => (o...)->(global path2 += 1)
)

let f = keymap_fcn([test_keymap_9])
    buf = IOBuffer("abaaaa")
    f(buf)
    @test path1 == 1
    f(buf)
    @test path2 == 1
    @test eof(buf)
end

## edit_move{left,right} ##
buf = IOBuffer("a\na\na\n")
seek(buf, 0)
for i = 1:6
    @test LineEdit.edit_move_right(buf)
    @test position(buf) == i
end
@test eof(buf)
@test !LineEdit.edit_move_right(buf)
for i = 5:-1:0
    @test @inferred LineEdit.edit_move_left(buf)
    @test position(buf) == i
end

# skip unicode combining characters
buf = IOBuffer("ŷ")
seek(buf, 0)
@test LineEdit.edit_move_right(buf)
@test eof(buf)
@test LineEdit.edit_move_left(buf)
@test position(buf) == 0

## edit_move_{up,down} ##

buf = IOBuffer("type X\n    a::Int\nend")
for i = 0:6
    seek(buf,i)
    @test !LineEdit.edit_move_up(buf)
    @test position(buf) == i
    seek(buf,i)
    @test LineEdit.edit_move_down(buf)
    @test position(buf) == i+7
end
for i = 7:17
    seek(buf,i)
    @test LineEdit.edit_move_up(buf)
    @test position(buf) == min(i-7,6)
    seek(buf,i)
    @test LineEdit.edit_move_down(buf)
    @test position(buf) == min(i+11,21)
end
for i = 18:21
    seek(buf,i)
    @test LineEdit.edit_move_up(buf)
    @test position(buf) == i-11
    seek(buf,i)
    @test !LineEdit.edit_move_down(buf)
    @test position(buf) == i
end

buf = IOBuffer("type X\n\n")
seekend(buf)
@test LineEdit.edit_move_up(buf)
@test position(buf) == 7
@test LineEdit.edit_move_up(buf)
@test position(buf) == 0
@test !LineEdit.edit_move_up(buf)
@test position(buf) == 0
seek(buf,0)
@test LineEdit.edit_move_down(buf)
@test position(buf) == 7
@test LineEdit.edit_move_down(buf)
@test position(buf) == 8
@test !LineEdit.edit_move_down(buf)
@test position(buf) == 8

## edit_delete_prev_word ##

buf = IOBuffer("type X\n ")
seekend(buf)
@test !isempty(@inferred(LineEdit.edit_delete_prev_word(buf)))
@test position(buf) == 5
@test buf.size == 5
@test content(buf) == "type "

buf = IOBuffer("4 +aaa+ x")
seek(buf,8)
@test !isempty(LineEdit.edit_delete_prev_word(buf))
@test position(buf) == 3
@test buf.size == 4
@test content(buf) == "4 +x"

buf = IOBuffer("x = func(arg1,arg2 , arg3)")
seekend(buf)
LineEdit.char_move_word_left(buf)
@test position(buf) == 21
@test !isempty(@inferred(LineEdit.edit_delete_prev_word(buf)))
@test content(buf) == "x = func(arg1,arg3)"
@test !isempty(LineEdit.edit_delete_prev_word(buf))
@test content(buf) == "x = func(arg3)"
@test !isempty(LineEdit.edit_delete_prev_word(buf))
@test content(buf) == "x = arg3)"

# Unicode combining characters
let buf = IOBuffer()
    edit_insert(buf, "â")
    LineEdit.edit_move_left(buf)
    @test position(buf) == 0
    LineEdit.edit_move_right(buf)
    @test @inferred(bytesavailable(buf)) == 0
    @inferred(LineEdit.edit_backspace(buf, false, false))
    @test content(buf) == "a"
end

## edit_transpose_chars ##
let buf = IOBuffer()
    @inferred(edit_insert(buf, "abcde"))
    seek(buf,0)
    @inferred(LineEdit.edit_transpose_chars(buf))
    @test content(buf) == "abcde"
    @inferred Union{Char,Bool} LineEdit.char_move_right(buf)
    LineEdit.edit_transpose_chars(buf)
    @test content(buf) == "bacde"
    LineEdit.edit_transpose_chars(buf)
    @test content(buf) == "bcade"
    seekend(buf)
    LineEdit.edit_transpose_chars(buf)
    @test content(buf) == "bcaed"
    LineEdit.edit_transpose_chars(buf)
    @test content(buf) == "bcade"

    seek(buf, 0)
    @inferred(LineEdit.edit_clear(buf))
    edit_insert(buf, "αβγδε")
    seek(buf,0)
    LineEdit.edit_transpose_chars(buf)
    @test content(buf) == "αβγδε"
    LineEdit.char_move_right(buf)
    LineEdit.edit_transpose_chars(buf)
    @test content(buf) == "βαγδε"
    LineEdit.edit_transpose_chars(buf)
    @test content(buf) == "βγαδε"
    seekend(buf)
    LineEdit.edit_transpose_chars(buf)
    @test content(buf) == "βγαεδ"
    LineEdit.edit_transpose_chars(buf)
    @test content(buf) == "βγαδε"
end

@testset "edit_word_transpose" begin
    local buf, mode
    buf = IOBuffer()
    mode = Ref{Symbol}()
    transpose!(i) = transform!(buf -> LineEdit.edit_transpose_words(buf, mode[]),
                               buf, i)[1:2]

    mode[] = :readline
    edit_insert(buf, "àbç def  gh ")
    @test @inferred(transpose!(0)) == ("àbç def  gh ", 0)
    @test transpose!(1) == ("àbç def  gh ", 1)
    @test transpose!(2) == ("àbç def  gh ", 2)
    @test transpose!(3) == ("def àbç  gh ", 7)
    @test transpose!(4) == ("àbç def  gh ", 7)
    @test transpose!(5) == ("def àbç  gh ", 7)
    @test transpose!(6) == ("àbç def  gh ", 7)
    @test transpose!(7) == ("àbç gh  def ", 11)
    @test transpose!(10) == ("àbç def  gh ", 11)
    @test transpose!(11) == ("àbç gh   def", 12)
    @inferred(edit_insert(buf, " "))
    @test transpose!(13) == ("àbç def    gh", 13)

    take!(buf)
    mode[] = :emacs
    edit_insert(buf, "àbç def  gh ")
    @test transpose!(0) == ("def àbç  gh ", 7)
    @test transpose!(4) == ("àbç def  gh ", 7)
    @test transpose!(5) == ("àbç gh  def ", 11)
    @test transpose!(10) == ("àbç def   gh", 12)
    edit_insert(buf, " ")
    @test transpose!(13) == ("àbç gh    def", 13)
end

let s = new_state(),
    buf = buffer(s)

    @inferred Union{Int,LineEdit.InputAreaState} edit_insert(s,"first line\nsecond line\nthird line")
    @test content(buf) == "first line\nsecond line\nthird line"

    ## edit_move_line_start/end ##
    seek(buf, 0)
    LineEdit.move_line_end(s)
    @test position(buf) == sizeof("first line")
    LineEdit.move_line_end(s) # Only move to input end on repeated keypresses
    @test position(buf) == sizeof("first line")
    s.key_repeats = 1 # Manually flag a repeated keypress
    LineEdit.move_line_end(s)
    s.key_repeats = 0
    @test eof(buf)

    seekend(buf)
    LineEdit.move_line_start(s)
    @test position(buf) == sizeof("first line\nsecond line\n")
    LineEdit.move_line_start(s)
    @test position(buf) == sizeof("first line\nsecond line\n")
    s.key_repeats = 1 # Manually flag a repeated keypress
    LineEdit.move_line_start(s)
    s.key_repeats = 0
    @test position(buf) == 0

    ## edit_kill_line, edit_yank ##
    seek(buf, 0)
    @inferred Union{Symbol,LineEdit.InputAreaState} LineEdit.edit_kill_line(s)
    s.key_repeats = 1 # Manually flag a repeated keypress
    LineEdit.edit_kill_line(s)
    s.key_repeats = 0
    @test content(buf) == "second line\nthird line"
    LineEdit.move_line_end(s)
    LineEdit.edit_move_right(s)
    @inferred Union{Symbol,LineEdit.InputAreaState} LineEdit.edit_yank(s)
    @test content(buf) == "second line\nfirst line\nthird line"
end

# Issue 7845
# First construct a problematic string:
# julia> is 6 characters + 1 character for space,
# so the rest of the terminal is 73 characters
#########################################################################
let buf = IOBuffer(
        "begin\nprint(\"A very very very very very very very very very very very very ve\")\nend")
    seek(buf, 4)
    outbuf = IOBuffer()
    termbuf = REPL.Terminals.TerminalBuffer(outbuf)
    term = FakeTerminal(IOBuffer(), IOBuffer(), IOBuffer())
    s = @inferred LineEdit.refresh_multi_line(termbuf, term, buf,
        REPL.LineEdit.InputAreaState(0,0), "julia> ", indent = 7)
    @test s == REPL.LineEdit.InputAreaState(3,1)
end

@testset "function prompt indentation" begin
    local s, term, ps, buf, outbuf, termbuf
    s = new_state()
    term = @inferred REPL.AbstractTerminal REPL.LineEdit.terminal(s)
    # default prompt: PromptState.indent should not be set to a final fixed value
    ps::LineEdit.PromptState = @inferred LineEdit.ModeState s.mode_state[s.current_mode]
    @test ps.indent == -1
    # the prompt is modified afterwards to a function
    ps.p.prompt = let i = 0
        () -> ["Julia is Fun! > ", "> "][mod1(i+=1, 2)] # lengths are 16 and 2
    end
    buf = buffer(ps)
    write(buf, "begin\n    julia = :fun\nend")
    outbuf = IOBuffer()
    termbuf = REPL.Terminals.TerminalBuffer(outbuf)
    @inferred(LineEdit.refresh_multi_line(termbuf, term, ps))
    @test String(take!(outbuf)) ==
        "\r\e[0K\e[1mJulia is Fun! > \e[0m\r\e[16Cbegin\n" *
        "\r\e[16C    julia = :fun\n" *
        "\r\e[16Cend\r\e[19C"
    LineEdit.refresh_multi_line(termbuf, term, ps)
    @test String(take!(outbuf)) ==
        "\r\e[0K\e[1A\r\e[0K\e[1A\r\e[0K\e[1m> \e[0m\r\e[2Cbegin\n" *
        "\r\e[2C    julia = :fun\n" *
        "\r\e[2Cend\r\e[5C"
end

@testset "shift selection" begin
    s = new_state()
    edit_insert(s, "αä🐨") # for issue #28183
    s.current_action = :unknown
    @inferred Union{Bool, LineEdit.InputAreaState} LineEdit.edit_shift_move(s, LineEdit.edit_move_left)
    @test LineEdit.region(s) == (5=>9)
    LineEdit.edit_shift_move(s, LineEdit.edit_move_left)
    @test LineEdit.region(s) == (2=>9)
    LineEdit.edit_shift_move(s, LineEdit.edit_move_left)
    @test LineEdit.region(s) == (0=>9)
    @inferred Union{Bool, LineEdit.InputAreaState} LineEdit.edit_shift_move(s, LineEdit.edit_move_right)
    @test LineEdit.region(s) == (2=>9)
end

@testset "tab/backspace alignment feature" begin
    s = new_state()
    move_left(s, n) = for x = 1:n
        LineEdit.edit_move_left(s)
    end

    edit_insert(s, "for x=1:10\n")
    @inferred Union{Symbol,LineEdit.InputAreaState} LineEdit.edit_tab(s)
    @test content(s) == "for x=1:10\n    "
    @inferred Union{Nothing,LineEdit.InputAreaState} LineEdit.edit_backspace(s, true, false)
    @test content(s) == "for x=1:10\n"
    edit_insert(s, "  ")
    @test position(s) == 13
    LineEdit.edit_tab(s)
    @test content(s) == "for x=1:10\n    "
    edit_insert(s, "  ")
    LineEdit.edit_backspace(s, true, false)
    @test content(s) == "for x=1:10\n    "
    edit_insert(s, "éé=3   ")
    LineEdit.edit_tab(s)
    @test content(s) == "for x=1:10\n    éé=3    "
    LineEdit.edit_backspace(s, true, false)
    @test content(s) == "for x=1:10\n    éé=3"
    edit_insert(s, "\n    1∉x  ")
    LineEdit.edit_tab(s)
    @test content(s) == "for x=1:10\n    éé=3\n    1∉x     "
    LineEdit.edit_backspace(s, false, false)
    @test content(s) == "for x=1:10\n    éé=3\n    1∉x    "
    LineEdit.edit_backspace(s, true, false)
    @test content(s) == "for x=1:10\n    éé=3\n    1∉x "
    LineEdit.edit_move_word_left(s)
    LineEdit.edit_tab(s)
    @test content(s) == "for x=1:10\n    éé=3\n        1∉x "
    LineEdit.move_line_start(s)
    @test position(s) == 22
    LineEdit.edit_tab(s, true)
    @test content(s) == "for x=1:10\n    éé=3\n        1∉x "
    @test position(s) == 30
    LineEdit.edit_move_left(s)
    @test position(s) == 29
    LineEdit.edit_backspace(s, true, true)
    @test content(s) == "for x=1:10\n    éé=3\n    1∉x "
    @test position(s) == 26
    LineEdit.edit_tab(s, false) # same as edit_tab(s, true) here
    @test position(s) == 30
    move_left(s, 6)
    @test position(s) == 24
    LineEdit.edit_backspace(s, true, true)
    @test content(s) == "for x=1:10\n    éé=3\n    1∉x "
    @test position(s) == 22
    LineEdit.edit_kill_line(s)
    edit_insert(s, ' '^10)
    move_left(s, 7)
    @test content(s) == "for x=1:10\n    éé=3\n          "
    @test position(s) == 25
    LineEdit.edit_tab(s, true, false)
    @test position(s) == 32
    move_left(s, 7)
    LineEdit.edit_tab(s, true, true)
    @test position(s) == 26
    @test content(s) == "for x=1:10\n    éé=3\n    "
    # test again the same, when there is a next line
    edit_insert(s, "      \nend")
    move_left(s, 11)
    @test position(s) == 25
    LineEdit.edit_tab(s, true, false)
    @test position(s) == 32
    move_left(s, 7)
    LineEdit.edit_tab(s, true, true)
    @test position(s) == 26
    @test content(s) == "for x=1:10\n    éé=3\n    \nend"
end

@testset "newline alignment feature" begin
    s = new_state()
    edit_insert(s, "for x=1:10\n    é = 1")
    LineEdit.edit_insert_newline(s)
    @test content(s) == "for x=1:10\n    é = 1\n    "
    edit_insert(s, " b = 2")
    LineEdit.edit_insert_newline(s)
    @test content(s) == "for x=1:10\n    é = 1\n     b = 2\n     "
    # after an empty line, should still insert the expected number of spaces
    LineEdit.edit_insert_newline(s)
    @test content(s) == "for x=1:10\n    é = 1\n     b = 2\n     \n     "
    LineEdit.edit_insert_newline(s, 0)
    @test content(s) == "for x=1:10\n    é = 1\n     b = 2\n     \n     \n"
    LineEdit.edit_insert_newline(s, 2)
    @test content(s) == "for x=1:10\n    é = 1\n     b = 2\n     \n     \n\n  "
    # test when point before first letter of the line
    for i=6:10
        LineEdit.edit_clear(s)
        edit_insert(s, "begin\n    x")
        seek(LineEdit.buffer(s), i)
        LineEdit.edit_insert_newline(s)
        @test content(s) == "begin\n" * ' '^(i-6) * "\n    x"
    end
end

@testset "change case on the right" begin
    local buf = IOBuffer()
    edit_insert(buf, "aa bB CC")
    seekstart(buf)
    @inferred LineEdit.edit_upper_case(buf)
    @inferred LineEdit.edit_title_case(buf)
    @test String(take!(copy(buf))) == "AA Bb CC"
    @test position(buf) == 5
    @inferred LineEdit.edit_lower_case(buf)
    @test String(take!(copy(buf))) == "AA Bb cc"
end

@testset "kill ring" begin
    local buf
    s = new_state()
    buf = buffer(s)
    edit_insert(s, "ça ≡ nothing")
    @test @inferred transform!(LineEdit.edit_copy_region, s) == ("ça ≡ nothing", 12, 0)
    @test s.kill_ring[end] == "ça ≡ nothing"
    @test @inferred transform!(LineEdit.edit_exchange_point_and_mark, s)[2:3] == (0, 12)
    charseek(buf, 8); setmark(s)
    charseek(buf, 1)
    @test @inferred transform!(LineEdit.edit_kill_region, s) == ("çhing", 1, 1)
    @test s.kill_ring[end] == "a ≡ not"
    charseek(buf, 0)
    @test @inferred transform!(LineEdit.edit_yank, s) == ("a ≡ notçhing", 7, 0)
    s.last_action = :unknown
    # next action will fail, as yank-pop doesn't know a yank was just issued
    @test @inferred transform!(LineEdit.edit_yank_pop, s) == ("a ≡ notçhing", 7, 0)
    s.last_action = :edit_yank
    # now this should work:
    @test transform!(LineEdit.edit_yank_pop, s) == ("ça ≡ nothingçhing", 12, 0)
    @test s.kill_idx == 1
    LineEdit.edit_kill_line(s)
    @test s.kill_ring[end] == "çhing"
    @test s.kill_idx == 3
    # check that edit_yank_pop works when passing require_previous_yank=false (#23635)
    s.last_action = :unknown
    @test transform!(s->LineEdit.edit_yank_pop(s, false), s) == ("ça ≡ nothinga ≡ not", 19, 12)

    # repetition (concatenation of killed strings
    edit_insert(s, "A B  C")
    LineEdit.edit_delete_prev_word(s)
    s.key_repeats = 1
    LineEdit.edit_delete_prev_word(s)
    s.key_repeats = 0
    @test s.kill_ring[end] == "B  C"
    LineEdit.edit_yank(s)
    LineEdit.edit_werase(s)
    @test s.kill_ring[end] == "C"
    s.key_repeats = 1
    LineEdit.edit_werase(s)
    s.key_repeats = 0
    @test s.kill_ring[end] == "B  C"
    LineEdit.edit_yank(s)
    LineEdit.edit_move_word_left(s)
    LineEdit.edit_move_word_left(s)
    LineEdit.edit_delete_next_word(s)
    @test s.kill_ring[end] == "B"
    s.key_repeats = 1
    LineEdit.edit_delete_next_word(s)
    s.key_repeats = 0
    @test s.kill_ring[end] == "B  C"

    # edit_kill_line_backwards
    LineEdit.edit_clear(s)
    edit_insert(s, "begin\n  a=1\n  b=2")
    LineEdit.edit_kill_line_backwards(s)
    @test s.kill_ring[end] == "  b=2"
    s.key_repeats = 1
    LineEdit.edit_kill_line_backwards(s)
    @test s.kill_ring[end] == "\n  b=2"
    LineEdit.edit_kill_line_backwards(s)
    @test s.kill_ring[end] == "  a=1\n  b=2"
    s.key_repeats = 0
end

@testset "undo" begin
    s = new_state()
    edit!(f) = transform!(f, s)[1]
    edit_undo! = LineEdit.edit_undo!
    edit_redo! = LineEdit.edit_redo!

    edit_insert(s, "one two three")

    @test @inferred edit!(LineEdit.edit_delete_prev_word) == "one two "
    @test @inferred edit!(edit_undo!) == "one two three"
    @test edit!(edit_redo!) == "one two "
    @test edit!(edit_undo!) == "one two three"

    edit_insert(s, " four")
    @test @inferred edit!(s->edit_insert(s, " five")) == "one two three four five"
    @test edit!(edit_undo!) == "one two three four"
    @test edit!(edit_undo!) == "one two three"
    @test edit!(edit_redo!) == "one two three four"
    @test edit!(edit_redo!) == "one two three four five"
    @test edit!(edit_undo!) == "one two three four"
    @test edit!(edit_undo!) == "one two three"

    @test @inferred edit!(LineEdit.edit_clear) == ""
    @test edit!(LineEdit.edit_clear) == "" # should not be saved twice
    @test edit!(edit_undo!) == "one two three"

    @test @inferred edit!(LineEdit.edit_insert_newline) == "one two three\n"
    @test edit!(edit_undo!) == "one two three"

    LineEdit.edit_move_left(s)
    LineEdit.edit_move_left(s)
    @test @inferred edit!(LineEdit.edit_transpose_chars) == "one two there"
    @test edit!(edit_undo!) == "one two three"
    @test edit!(LineEdit.edit_transpose_words) == "one three two"
    @test edit!(edit_undo!) == "one two three"

    LineEdit.move_line_start(s)
    @test edit!(LineEdit.edit_kill_line) == ""
    @test edit!(edit_undo!) == "one two three"
    # undo stack not updated if killing nothing:
    LineEdit.move_line_start(s)
    LineEdit.edit_kill_line(s)
    LineEdit.edit_kill_line(s) # no effect
    @test edit!(edit_undo!) == "one two three"

    LineEdit.move_line_end(s)
    @test edit!(LineEdit.edit_kill_line_backwards) == ""
    @test edit!(edit_undo!) == "one two three"

    LineEdit.move_line_start(s)
    LineEdit.edit_kill_line(s)
    LineEdit.edit_yank(s)
    @test edit!(LineEdit.edit_yank) == "one two threeone two three"
    @test edit!(edit_undo!) == "one two three"
    @test edit!(edit_undo!) == ""
    @test edit!(edit_undo!) == "one two three"

    LineEdit.setmark(s)
    LineEdit.edit_move_word_right(s)
    @test edit!(LineEdit.edit_kill_region) == " two three"
    @test edit!(LineEdit.edit_yank) == "one two three"
    @test edit!(LineEdit.edit_yank_pop) == "one two three two three"
    @test edit!(edit_undo!) == "one two three"
    @test edit!(edit_undo!) == " two three"
    @test edit!(edit_undo!) == "one two three"

    LineEdit.move_line_end(s)
    LineEdit.edit_backspace(s, false, false)
    LineEdit.edit_backspace(s, false, false)
    @test edit!(s->LineEdit.edit_backspace(s, false, false)) == "one two th"
    @test edit!(edit_undo!) == "one two thr"
    @test edit!(edit_undo!) == "one two thre"
    @test edit!(edit_undo!) == "one two three"

    LineEdit.push_undo(s) # TODO: incorporate push_undo into edit_splice! ?
    LineEdit.edit_splice!(s, 4 => 7, "stott")
    @test content(s) == "one stott three"
    s.last_action = :not_undo
    @test edit!(edit_undo!) == "one two three"

    LineEdit.edit_move_left(s)
    LineEdit.edit_move_left(s)
    LineEdit.edit_move_left(s)
    @test edit!(LineEdit.edit_delete) == "one two thee"
    @test edit!(edit_undo!) == "one two three"

    LineEdit.edit_move_word_left(s)
    LineEdit.edit_werase(s)
    @test edit!(LineEdit.edit_delete_next_word) == "one "
    @test edit!(edit_undo!) == "one three"
    @test edit!(edit_undo!) == "one two three"
    @test edit!(edit_redo!) == "one three"
    @test edit!(edit_redo!) == "one "
    @test edit!(edit_redo!) == "one " # nothing more to redo (this "beeps")
    @test edit!(edit_undo!) == "one three"
    @test edit!(edit_undo!) == "one two three"

    LineEdit.move_line_start(s)
    @test edit!(LineEdit.edit_upper_case) == "ONE two three"
    LineEdit.move_line_start(s)
    @test edit!(LineEdit.edit_lower_case) == "one two three"
    @test edit!(LineEdit.edit_title_case) == "one Two three"
    @test edit!(edit_undo!) == "one two three"
    @test edit!(edit_undo!) == "ONE two three"
    @test edit!(edit_undo!) == "one two three"

    LineEdit.move_line_end(s)
    edit_insert(s, "  ")
    @test edit!(LineEdit.edit_tab) == "one two three   "
    @test edit!(edit_undo!) == "one two three  "
    @test edit!(edit_undo!) == "one two three"
    LineEdit.move_line_start(s)
    edit_insert(s, "  ")
    LineEdit.move_line_start(s)
    @test edit!(s->LineEdit.edit_tab(s, true, true)) == "  one two three" # tab moves cursor to position 2
    @test edit!(edit_undo!) == "one two three" # undo didn't record cursor movement
    # TODO: add tests for complete_line, which don't work directly

    # pop initial insert of "one two three"
    @test edit!(edit_undo!) == ""
    @test edit!(edit_undo!) == "" # nothing more to undo (this "beeps")
end

@testset "edit_indent_{left,right}" begin
    local buf = IOBuffer()
    write(buf, "1\n22\n333")
    seek(buf, 0)
    @test @inferred LineEdit.edit_indent(buf, -1, false) == false
    @test @inferred transform!(buf->LineEdit.edit_indent(buf, -1, false), buf) == ("1\n22\n333", 0, 0)
    @test transform!(buf->LineEdit.edit_indent(buf, +1, false), buf) == (" 1\n22\n333", 1, 0)
    @test transform!(buf->LineEdit.edit_indent(buf, +2, false), buf) == ("   1\n22\n333", 3, 0)
    @test transform!(buf->LineEdit.edit_indent(buf, -2, false), buf) == (" 1\n22\n333", 1, 0)
    seek(buf, 0) # if the cursor is already on the left column, it stays there
    @test transform!(buf->LineEdit.edit_indent(buf, -2, false), buf) == ("1\n22\n333", 0, 0)
    seek(buf, 3) # between the two "2"
    @test transform!(buf->LineEdit.edit_indent(buf, +3, false), buf) == ("1\n   22\n333", 6, 0)
    @test transform!(buf->LineEdit.edit_indent(buf, -9, false), buf) == ("1\n22\n333", 3, 0)
    seekend(buf) # position 8
    @test transform!(buf->LineEdit.edit_indent(buf, +3, false), buf) == ("1\n22\n   333", 11, 0)
    @test transform!(buf->LineEdit.edit_indent(buf, -1, false), buf) == ("1\n22\n  333", 10, 0)
    @test transform!(buf->LineEdit.edit_indent(buf, -2, false), buf) == ("1\n22\n333", 8, 0)
    @test transform!(buf->LineEdit.edit_indent(buf, -1, false), buf) == ("1\n22\n333", 8, 0)
    @test transform!(buf->LineEdit.edit_indent(buf, +3, false), buf) == ("1\n22\n   333", 11, 0)
    seek(buf, 5) # left column
    @test transform!(buf->LineEdit.edit_indent(buf, -2, false), buf) == ("1\n22\n 333", 5, 0)
    # multiline tests
    @test transform!(buf->LineEdit.edit_indent(buf, -2, true), buf) == ("1\n22\n 333", 5, 0)
    @test transform!(buf->LineEdit.edit_indent(buf, +2, true), buf) == ("  1\n  22\n   333", 11, 0)
    @test transform!(buf->LineEdit.edit_indent(buf, -1, true), buf) == (" 1\n 22\n  333", 8, 0)
    REPL.LineEdit.edit_exchange_point_and_mark(buf)
    seek(buf, 5)
    @test transform!(buf->LineEdit.edit_indent(buf, -1, true), buf) == (" 1\n22\n 333", 4, 6)

    # check that if the mark at the beginning of the line, it is moved when right-indenting,
    # which is more natural when the region is active
    seek(buf, 0)
    buf.mark = 0
#    @test transform!(buf->LineEdit.edit_indent(buf, +1, false), buf) == ("  1\n22\n 333", 1, 1)
end

@testset "edit_transpose_lines_{up,down}!" begin
    transpose_lines_up!(buf) = @inferred LineEdit.edit_transpose_lines_up!(buf, position(buf)=>position(buf))
    transpose_lines_up_reg!(buf) = @inferred LineEdit.edit_transpose_lines_up!(buf, region(buf))
    transpose_lines_down!(buf) = @inferred LineEdit.edit_transpose_lines_down!(buf, position(buf)=>position(buf))
    transpose_lines_down_reg!(buf) = @inferred LineEdit.edit_transpose_lines_down!(buf, region(buf))

    local buf
    buf = IOBuffer()

    write(buf, "l1\nl2\nl3")
    seek(buf, 0)
    @test transpose_lines_up!(buf) == false
    @test transform!(transpose_lines_up!, buf) == ("l1\nl2\nl3", 0, 0)
    @test transform!(transpose_lines_down!, buf) == ("l2\nl1\nl3", 3, 0)
    @test transpose_lines_down!(buf) == true
    @test String(take!(copy(buf))) == "l2\nl3\nl1"
    @test transpose_lines_down!(buf) == false
    @test String(take!(copy(buf))) == "l2\nl3\nl1" # no change
    LineEdit.edit_move_right(buf)
    @test transform!(transpose_lines_up!, buf) == ("l2\nl1\nl3", 4, 0)
    LineEdit.edit_move_right(buf)
    @test transform!(transpose_lines_up!, buf) == ("l1\nl2\nl3", 2, 0)

    # multiline
    @test transpose_lines_up_reg!(buf) == false
    @test transform!(transpose_lines_down_reg!, buf) == ("l2\nl1\nl3", 5, 0)
    REPL.LineEdit.edit_exchange_point_and_mark(buf)
    seek(buf, 1)
    @test transpose_lines_up_reg!(buf) == false
    @test transform!(transpose_lines_down_reg!, buf) == ("l3\nl2\nl1", 4, 8)

    # check that if the mark is at the beginning of the line, it is moved when transposing down,
    # which is necessary when the region is active: otherwise, the line which is moved up becomes
    # included in the region
    buf.mark = 0
    seek(buf, 1)
    @test transform!(transpose_lines_down_reg!, buf) == ("l2\nl3\nl1", 4, 3)
end

@testset "edit_insert_last_word" begin
    get_last_word(str::String) = @inferred LineEdit.get_last_word(IOBuffer(str))
    @test get_last_word("1+2") == "2"
    @test get_last_word("1+23") == "23"
    @test get_last_word("1+2") == "2"
    @test get_last_word(""" "a" * "b" """) == "b"
    @test get_last_word(""" "a" * 'b' """) == "b"
    @test get_last_word(""" "a" * `b` """) == "b"
    @test get_last_word("g()") == "g()"
    @test get_last_word("g(1, 2)") == "2"
    @test get_last_word("g(1, f())") == "f"
    @test get_last_word("a[1]") == "1"
    @test get_last_word("a[b[]]") == "b"
    @test get_last_word("a[]") == "a[]"
end

max_stars_repo_name: nilshg/julia

max_issues_repo_name: RadicalchAngel/julia

max_forks_repo_name: RadicalchAngel/julia


text:
struct Trace
  timestamps :: Vector{Float64}
  payloads :: Vector{Int64}
end

struct Workload
  τ :: Float64
  probs :: Vector{Float64}
  services :: Vector{Float64}
  function Workload(tr::Trace, τ::Float64, capacity::Float64)
    payloadtimes = Dict{Int64, Float64}()
    i = 1
    j = 1
    payload = 0
    while τ >= tr.timestamps[i]
      payload += tr.payloads[i]
      i += 1
    end
    timeₜ = tr.timestamps[end]
    timestamps = [tr.timestamps..., (tr.timestamps[1:i] .+ timeₜ)...]
    payloads = [tr.payloads..., tr.payloads[1:i]...]
    time = τ
    timeᵢ = timestamps[i]
    timeⱼ = timestamps[j] + τ
    timeₛ = timeₜ + τ
    while true
      #@show time timeᵢ timeⱼ timeₛ payload
      if timeₛ <= timeᵢ && timeₛ <= timeⱼ
        payloadtimes[payload] = get(payloadtimes, payload, 0) + timeₛ - time
        break
      end
      if timeⱼ <= timeᵢ
        payloadtimes[payload] = get(payloadtimes, payload, 0) + timeⱼ - time
        payload -= payloads[j]
        time = timeⱼ
        j += 1
        timeⱼ = timestamps[j] + τ
      else
        payloadtimes[payload] = get(payloadtimes, payload, 0) + timeᵢ - time
        payload += payloads[i]
        time = timeᵢ
        i += 1
        timeᵢ = timestamps[i]
      end
    end
    probs = Float64[]
    services = Float64[]
    for (payload, time) in payloadtimes
      push!(probs, time / timeₜ)
      push!(services, payload / capacity)
    end
    @show probs services
    new(τ, probs, services)
  end
end

function rate(work::Workload, θ::Float64, v::Float64)
  mgf = 0.0
  for (prob, service) in zip(work.probs, work.services)
    mgf += prob * exp(θ * service)
  end
  θ * (work.τ + v) - log(mgf)
end

function drate(work::Workload, θ::Float64, v::Float64)
  mgf = 0.0
  dmgf = 0.0
  ddmgf = 0.0
  for (prob, service) in zip(work.probs, work.services)
    tmp = prob * exp(θ * service)
    mgf += tmp
    dmgf += service * tmp
    dmgf += service^2 * tmp
  end
  work.τ + v - dmgf / mgf,
end

max_stars_repo_name: BenLauwens/WANPerformanceAnalyzer

max_issues_repo_name: BenLauwens/WANPerformanceAnalyzer

max_forks_repo_name: BenLauwens/WANPerformanceAnalyzer


text:
module SEED
using Dates, Printf, SeisIO, SeisIO.Formats
import SeisIO.Formats: formats, FmtVer, FormatDesc, HistVec
import SeisIO:
  BUF,
  InstrumentResponse,
  KW,
  SeedBlk,
  SeisIOBuf,
  TimeSpec,
  check_for_gap!,
  checkbuf!,
  checkbuf_8!,
  endtime,
  fix_units,
  is_u8_digit,
  buf_to_double,
  mktime,
  sμ,
  trunc_x!,
  buf_to_int,
  stream_int,
  y2μs,
  μs

const id_positions  = Int8[11, 12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const id_spacer     = 0x2e
const steim         = reverse(collect(0x00000000:0x00000002:0x0000001e), dims=1)
const responses     = Dict{Int64, Any}()
const units_lookup  = Dict{Int64, String}()
const comments      = Dict{Int64, String}()
const abbrev        = Dict{Int64, String}()

include("SEED/0_seed_read_utils.jl")
include("SEED/1_mSEEDblk.jl")
include("SEED/1_mSEEDdec.jl")
include("SEED/1_dataless_blk.jl")
include("SEED/2_parserec.jl")
include("SEED/dataless.jl")
include("SEED/mseed_support.jl")
include("SEED/readmseed.jl")
include("SEED/seed_resp.jl")

# exports
export  formats,
        mseed_support,
        parsemseed!,
        read_dataless,
        read_mseed_file,
        read_seed_resp!,
        read_seed_resp,
        seed_support
end


text:
function DTM2000(arg0::DTM2000InputParameters, arg1::PVCoordinatesProvider, arg2::BodyShape)
    return DTM2000((DTM2000InputParameters, PVCoordinatesProvider, BodyShape), arg0, arg1, arg2)
end

function DTM2000(arg0::DTM2000InputParameters, arg1::PVCoordinatesProvider, arg2::BodyShape, arg3::TimeScale)
    return DTM2000((DTM2000InputParameters, PVCoordinatesProvider, BodyShape, TimeScale), arg0, arg1, arg2, arg3)
end

function equals(obj::Object, arg0::Object)
    return jcall(obj, "equals", jboolean, (Object,), arg0)
end

function get_class(obj::Object)
    return jcall(obj, "getClass", Class, ())
end

function get_density(obj::DTM2000, arg0::AbsoluteDate, arg1::Vector3D, arg2::Frame)
    return jcall(obj, "getDensity", jdouble, (AbsoluteDate, Vector3D, Frame), arg0, arg1, arg2)
end

function get_density(obj::DTM2000, arg0::FieldAbsoluteDate, arg1::FieldVector3D, arg2::Frame)
    return jcall(obj, "getDensity", RealFieldElement, (FieldAbsoluteDate, FieldVector3D, Frame), arg0, arg1, arg2)
end

function get_density(obj::DTM2000, arg0::jint, arg1::RealFieldElement, arg2::RealFieldElement, arg3::RealFieldElement, arg4::RealFieldElement, arg5::jdouble, arg6::jdouble, arg7::jdouble, arg8::jdouble)
    return jcall(obj, "getDensity", RealFieldElement, (jint, RealFieldElement, RealFieldElement, RealFieldElement, RealFieldElement, jdouble, jdouble, jdouble, jdouble), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
end

function get_density(obj::DTM2000, arg0::jint, arg1::jdouble, arg2::jdouble, arg3::jdouble, arg4::jdouble, arg5::jdouble, arg6::jdouble, arg7::jdouble, arg8::jdouble)
    return jcall(obj, "getDensity", jdouble, (jint, jdouble, jdouble, jdouble, jdouble, jdouble, jdouble, jdouble, jdouble), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
end

function get_frame(obj::DTM2000)
    return jcall(obj, "getFrame", Frame, ())
end

function hash_code(obj::Object)
    return jcall(obj, "hashCode", jint, ())
end

function notify(obj::Object)
    return jcall(obj, "notify", void, ())
end

function notify_all(obj::Object)
    return jcall(obj, "notifyAll", void, ())
end

function to_string(obj::Object)
    return jcall(obj, "toString", JString, ())
end

function wait(obj::Object)
    return jcall(obj, "wait", void, ())
end

function wait(obj::Object, arg0::jlong)
    return jcall(obj, "wait", void, (jlong,), arg0)
end

function wait(obj::Object, arg0::jlong, arg1::jint)
    return jcall(obj, "wait", void, (jlong, jint), arg0, arg1)
end


text:
import Inflector, Genie

if ! isempty(Genie.config.inflector_irregulars)
  push!(Inflector.IRREGULAR_NOUNS, Genie.config.inflector_irregulars...)
end


text:
# -*- coding: utf-8 -*-
function compute_QΘ(G, N, D, XsI, κ, ωI, NΘ::Int=50, ttmax::Int=50, ϵ=1e-5, ρ=0.1, dt=1e-2)
    """
    Compute Q(θ)

    Args:
    - N = 2 # number of units
    - D   : Dimension of states; (Int)
    - Nθ  : The number of splitting phase for one period; (Int)

    Returns:
    - Q(θ)   :  ∈ R^N x NΘ x NΘ
    """

    X = zeros(N, D)
    Θ, Θ̃ = zeros(N), zeros(N)
    Θrange = range(0, 2π, length=NΘ)
    Qₜ = zeros(N, NΘ, NΘ)
    α = ρ*dt

    @showprogress "Computing P(θ₁, θ₂)..." for tt in 1:ttmax
        Qₜ₋₁ = copy(Qₜ)

        for m in 1:NΘ
            for n in 1:NΘ
                Θ = [Θrange[m], Θrange[n]]
                for s in 1:-dt:0
                    for i in 1:N
                        Θ̃[i] = mod(Θ[i] - κ[i] * ωI(Qₜ[i, m, n]) * s, 2π)
                    end
                    #Θ̃indices = clamp.(floor.(Int, Θ̃/(2π)*NΘ) .+ 1, 1, NΘ)
                    for i in 1:N
                        X[i, :] = [XsI[j](Θ̃[i], Qₜ[i, m, n]) for j in 1:D] # for approximation
                        #X[i, :] = [XsI[j](Θ̃[i], Qₜ[i, Θ̃indices...]) for j in 1:D]
                    end
                    Qₜ[:, m, n] += α*(G(X) - Qₜ[:, m, n]) # low-pass filter
                end
            end
        end
        if sum(abs.(Qₜ .- Qₜ₋₁))/(NΘ^2) < ϵ # check convergence
            break
        end
    end
    sitpQΘ = [scale(interpolate(Qₜ[i, :, :], BSpline(Cubic(Line(OnGrid())))), Θrange, Θrange) for i in 1:N]
    return sitpQΘ
end

function compute_IsΘ(G, N, D, XsI, NΘ::Int=50, ttmax::Int=50, ϵ=1e-5)
    """
    Compute I₀(θ)

    Args:
    - N = 2 # number of units
    - D   : Dimension of states; (Int)
    - Nθ  : The number of splitting phase for one period; (Int)

    Returns:
    - I₀(θ)   :  ∈ R^N x NΘ x NΘ
    """

    X = zeros(N, D)
    Θ = zeros(N)
    Θrange = range(0, 2π, length=NΘ)

    IΘ = zeros(N, NΘ, NΘ)

    @showprogress "Computing I₀(θ₁, θ₂)..." for m in 1:NΘ
        for n in 1:NΘ
            Θ = [Θrange[m], Θrange[n]]
            # initial I
            if n > 1
                Iₜ = copy(IΘ[:, m, n-1])
            else
                Iₜ = zeros(N)
            end

            for tt in 1:ttmax
                for i in 1:N
                    X[i, :] = [XsI[j](Θ[i], Iₜ[i]) for j in 1:D]
                end

                Iₜ₋₁ = copy(Iₜ)
                Iₜ = G(X) # update

                if sum(abs.(Iₜ .- Iₜ₋₁)) <  ϵ # check convergence
                    break
                end
            end

            IΘ[:, m, n] = Iₜ # save
        end
    end

    sitpIΘ = [scale(interpolate(IΘ[i, :, :], BSpline(Cubic(Line(OnGrid())))), Θrange, Θrange) for i in 1:N]
    return sitpIΘ
end

function conventinal_coupled_updateΘ(Θ, p, t)
    N, D, κ, G, ωI, ζθI, XsI = p
    return κ * ωI(0) + ζθI.(mod.(Θ, 2π), 0) .* G(hcat([[XsI[j](mod(θ, 2π), 0) for j in 1:D] for θ in Θ]...)')
end

function generalized_coupled_updateΘ_I(Θ, p, t)
    N, κ, IΘ, ωI, ξθI = p
    Θ = mod.(Θ, 2π) # θ ∈[0, 2π]
    inp = [IΘ[i](Θ...) for i in 1:N]
    ωΘ = [κ[i] * ωI(inp[i]) for i in 1:N]
    XiΘ = LinearAlgebra.I　- hcat([ξθI(Θ[i], inp[i]) * Interpolations.gradient(IΘ[i], Θ...) for i in 1:N]...)'
    dΘ = XiΘ \ ωΘ # generalized phase equation
    return dΘ
end

function generalized_coupled_updateΘ_PQ(Θ, p, t)
    N, D, κ, G, QΘ, ωI, ζθI, ξθI, XsI = p
    Θ = mod.(Θ, 2π) # θ ∈[0, 2π]
    q̂ = [QΘ[i](Θ...) for i in 1:N]
    p̂ = G(hcat([[XsI[j](Θ[i], q̂[i]) for j in 1:D] for i in 1:N]...)') - q̂
    ϕ = [κ[i] * ωI(q̂[i]) + ζθI(Θ[i], q̂[i])*p̂[i] for i in 1:N]
    XiΘ = LinearAlgebra.I - hcat([ξθI(Θ[i], q̂[i]) * Interpolations.gradient(QΘ[i], Θ...) for i in 1:N]...)'
    dΘ = XiΘ \ ϕ # generalized phase equation
    return dΘ
end

function phase2cum_phase(Θ, N)
    ΔΘ = Θ[2:end, :] - Θ[1:end-1, :]
    idx = ΔΘ .< -1.9π # detect phase jump point
    ΔΘ[idx] .= mod.(ΔΘ[idx], 2π);
    Θcumsum = cumsum(ΔΘ, dims=1);
    for i in 1:N
        Θcumsum[:, i] .+= Θ[1, i]
    end
    return Θcumsum = [Θ[1, :]'; Θcumsum]
end

# +
# for fixed time steps
function coupled_original_system(N::Int, D::Int, Nt::Int, dt::Float64, XsI, G, coupled_func, initθ, κ, alg=Tsit5())
    X = zeros(Nt, N, D)
    Θg, Θc = zeros(Nt, N), zeros(Nt, N);
    initX = hcat([[XsI[j](mod(θ, 2π), 0) for j in 1:D] for θ in initθ]...)'
    integrator = get_ode_integrator(coupled_func, initX, dt, (G, κ), alg)
    for tt in 1:Nt
        x = copy(integrator.u)
        X[tt, :, :] = x # memory
        Θg[tt, :] = mod.(atan.(x[:, 2], x[:, 1] - G(x)), 2π)
        Θc[tt, :] = mod.(atan.(x[:, 2], x[:, 1]), 2π)
        step!(integrator, dt, true)
    end
    Θg_cumsum = phase2cum_phase(Θg, N)
    Θc_cumsum = phase2cum_phase(Θc, N)
    return X, Θg_cumsum, Θc_cumsum
end

# for adaptive time step
function coupled_original_system(N::Int, D::Int, T::Float64, XsI, G, coupled_func, initθ, κ, alg=Tsit5())
    initX = hcat([[XsI[j](mod(θ, 2π), 0) for j in 1:D] for θ in initθ]...)'
    sol = get_ode_solution(coupled_func, initX, (0, T), nothing, (G, κ), alg)
    Nt = length(sol.u)
    X = zeros(Nt, N, D)
    Θg, Θc = zeros(Nt, N), zeros(Nt, N);
    for tt in 1:Nt
        x = sol.u[tt]
        X[tt, :, :] = x # memory
        Θg[tt, :] = mod.(atan.(x[:, 2], x[:, 1] - G(x)), 2π)
        Θc[tt, :] = mod.(atan.(x[:, 2], x[:, 1]), 2π)
    end
    Θg_cumsum = phase2cum_phase(Θg, N)
    Θc_cumsum = phase2cum_phase(Θc, N)

    return sol.t, X, Θg_cumsum, Θc_cumsum
end

# +
# for fixed time steps
function coupled_conventinal_phase_model(N::Int, D::Int, Nt::Int, dt::Float64, XsI, G, ωI, ζθI, initθ, κ, alg=Tsit5())
    X = zeros(Nt, N, D) # states
    Θ = zeros(Nt, N)    # phase
    integrator = get_ode_integrator(conventinal_coupled_updateΘ, initθ, dt, (N, D, κ, G, ωI, ζθI, XsI), alg)
    for tt in 1:Nt
        θ = mod.(copy(integrator.u), 2π)
        Θ[tt, :] = copy(integrator.u)
        for i in 1:N
            X[tt, i, :] = [XsI[j](θ[i], 0) for j in 1:D]
        end
        step!(integrator, dt, true) # update
    end
    return X, Θ
end

# for adaptive time step
function coupled_conventinal_phase_model(N::Int, D::Int, T::Float64, XsI, G, ωI, ζθI, initθ, κ, alg=Tsit5())
    sol = get_ode_solution(conventinal_coupled_updateΘ, initθ, (0, T), nothing, (N, D, κ, G, ωI, ζθI, XsI), alg);
    Θ = hcat(sol.u...)';
    Nt = length(sol.u)
    X = zeros(Nt, N, D)
    for tt in 1:Nt
        for i in 1:N
            X[tt, i, :] = [XsI[j](mod(Θ[tt, i], 2π), 0) for j in 1:D] # memory
        end
    end
    return sol.t, X, Θ
end

# +
# for fixed time steps
function coupled_generalized_phase_model_I(N::Int, D::Int, Nt::Int, dt::Float64, XsI, IΘ, ωI, ξθI, initθ, κ, alg=Tsit5())
    X = zeros(Nt, N, D) # states
    Θ = zeros(Nt, N)    # phase
    integrator = get_ode_integrator(generalized_coupled_updateΘ_I, initθ, dt, (N, κ, IΘ, ωI, ξθI), alg)
    for tt in 1:Nt
        θ = mod.(copy(integrator.u), 2π)
        Θ[tt, :] = copy(integrator.u)
        for i in 1:N
            X[tt, i, :] = [XsI[j](θ[i], IΘ[i](θ...)) for j in 1:D]
        end
        step!(integrator, dt, true) # update
    end
    return X, Θ
end

# for adaptive time step
function coupled_generalized_phase_model_I(N::Int, D::Int, T::Float64, XsI, IΘ, ωI, ξθI, initθ, κ, alg=Tsit5())
    sol = get_ode_solution(generalized_coupled_updateΘ_I, initθ, (0, T), nothing, (N, κ, IΘ, ωI, ξθI), alg);
    Θ = hcat(sol.u...)';
    Nt = length(sol.u)
    X = zeros(Nt, N, D)
    for tt in 1:Nt
        for i in 1:N
            X[tt, i, :] = [XsI[j](mod(Θ[tt, i], 2π), IΘ[i](mod.(Θ[tt, :], 2π)...)) for j in 1:D] # memory
        end
    end
    return sol.t, X, Θ
end

# +
# for fixed time steps
function coupled_generalized_phase_model_PQ(N::Int, D::Int, Nt::Int, dt::Float64, XsI, QΘ, ωI, ζθI, ξθI, initθ, κ, G, alg=Tsit5())
    X = zeros(Nt, N, D) # states
    Θ = zeros(Nt, N)    # phase
    integrator = get_ode_integrator(generalized_coupled_updateΘ_PQ, initθ, dt, (N, D, κ, G, QΘ, ωI, ζθI, ξθI, XsI), alg)
    for tt in 1:Nt
        θ = mod.(copy(integrator.u), 2π)
        Θ[tt, :] = copy(integrator.u)
        q̂ = [QΘ[i](θ...) for i in 1:N]
        Iext = G(hcat([[XsI[j](θ[i], q̂[i]) for j in 1:D] for i in 1:N]...)')
        for i in 1:N
            X[tt, i, :] = [XsI[j](θ[i], Iext[i]) for j in 1:D]
        end
        step!(integrator, dt, true) # update
    end
    return X, Θ
end

# for adaptive time step
function coupled_generalized_phase_model_PQ(N::Int, D::Int, T::Float64, XsI, QΘ, ωI, ζθI, ξθI, initθ, κ, G, alg=Tsit5())
    sol = get_ode_solution(generalized_coupled_updateΘ_PQ, initθ, (0, T), nothing, (N, D, κ, G, QΘ, ωI, ζθI, ξθI, XsI),
                           alg);
    Θ = hcat(sol.u...)';
    Nt = length(sol.u)
    X = zeros(Nt, N, D)
    for tt in 1:Nt
        θ = mod.(Θ[tt, :], 2π)
        q̂ = [QΘ[i](θ...) for i in 1:N]
        Iext = G(hcat([[XsI[j](θ[i], q̂[i]) for j in 1:D] for i in 1:N]...)')
        for i in 1:N
            X[tt, i, :] = [XsI[j](θ[i], Iext[i]) for j in 1:D]
        end
    end
    return sol.t, X, Θ
end


text:
using Distributions

function test_bernoulli_recon_loss_layer(backend::Backend, T, eps)
    println("-- Testing BernoulliReconLossLayer on $(typeof(backend)){$T}...")

    ############################################################
    # Prepare Data for Testing
    ############################################################
    dims = (3, 4, 5)
    tensor_dim = length(dims)
    D, N = prod(dims[1:end-1]), dims[end]
    ND = N * D
    println("        > $dims")

    ############################################################
    # Setup
    ############################################################
    layer = BernoulliReconLossLayer(bottoms=[:p, :x])

    p = min(1 - 1e-4, max(1e-4, rand(D, N)))
    x = round(rand(dims), 0)

    inputs = Blob[
        make_blob(backend, convert(Array{T}, p)),
        make_blob(backend, convert(Array{T}, x))]

    diffs = Blob[
        make_blob(backend, rand(T, size(inputs[1]))),  # gets overwritten
        NullBlob()]  # the data is fixed

    state = setup(backend, layer, inputs, diffs)

    ############################################################
    # Forward Propagation
    ############################################################
    forward(backend, state, inputs)

    loss = 0.
    for i in 1:ND
        Xi_given_zi = Bernoulli(p[i])  # a random var
        loss -= logpdf(Xi_given_zi, x[i])
    end
    loss /= N
    @test loss >= 0

    info("expected $loss; got $(state.loss)")
    @test -eps < loss - state.loss < eps

    ############################################################
    # Backward Propagation
    ############################################################
    backward(backend, state, inputs, diffs)

    input1 = Array(T, size(inputs[1]))
    copy!(input1, inputs[1])
    diff1 = Array(T, size(diffs[1]))
    copy!(diff1, diffs[1])

    for k in 1:D, j in 1:N
        x0 = input1[k, j]
        function f(x::FloatingPoint)
            input1[k, j] = x
            copy!(inputs[1], input1)
            forward(backend, state, inputs)
            input1[k, j] = x0
            copy!(inputs[1], input1)
            state.loss
        end
        test_deriv(f, x0, diff1[k, j])
    end

    ############################################################
    # Shutdown
    ############################################################
    shutdown(backend, state)
end

function test_bernoulli_hyperparameter(backend::Backend)
    # setup
    D = 3
    p = min(1 - 1e-4, max(1e-4, rand(D, 1)))
    s = rand(D, 1)

    ############################################################
    # Forward Propagation
    ############################################################

    # get claimed
    inputs = Blob[make_blob(backend, p), make_blob(backend, s)]
    layer = BernoulliReconLossLayer(bottoms=[:p, :x])
    diffs = Blob[
        make_blob(backend, rand(D, 1)),
        NullBlob()]
    state = setup(backend, layer, inputs, diffs)
    forward(backend, state, inputs)

    # get expected
    losses = Float64[]
    num_x_samples = 100_000
    X_given_z = [Bernoulli(p[i]) for i in 1:D]
    for k in 1:num_x_samples
        x_sample = round(rand(D) .< s, 0)
        loss = 0.
        for i in 1:D
            loss -= logpdf(X_given_z[i], x_sample[i])
        end
        push!(losses, loss)
    end
    ci_radius = 5std(losses) / sqrt(num_x_samples)

    # do test
    println("$(state.loss) == $(mean(losses)) +/- $ci_radius")
    @test mean(losses) - ci_radius <= state.loss <= mean(losses) + ci_radius

    ############################################################
    # Backward Propagation
    ############################################################
    backward(backend, state, inputs, diffs)

    input1 = Array(Float64, size(inputs[1]))
    copy!(input1, inputs[1])
    diff1 = Array(Float64, size(diffs[1]))
    copy!(diff1, diffs[1])

    for k in 1:D, j in 1:1
        x0 = input1[k, j]
        function f(x::FloatingPoint)
            input1[k, j] = x
            copy!(inputs[1], input1)
            forward(backend, state, inputs)
            input1[k, j] = x0
            copy!(inputs[1], input1)
            state.loss
        end
        test_deriv(f, x0, diff1[k, j])
    end

    ############################################################
    # Shutdown
    ############################################################
    shutdown(backend, state)
end

function test_bernoulli_recon_loss_layer(backend::Backend)
    test_bernoulli_recon_loss_layer(backend, Float64, 1e-8)
    test_bernoulli_hyperparameter(backend)
end

if test_cpu
    test_bernoulli_recon_loss_layer(backend_cpu)
end
if test_gpu
    test_bernoulli_recon_loss_layer(backend_gpu)
end


text:
__precompile__()

module Base58
export base58encode, base58decode, base58checkencode, base58checkdecode, alt
using SHA: sha256

if VERSION < v"0.7.0-DEV.3213"
    codeunits(x) = convert(Array{UInt8}, x)
end

struct NotInAlphabetException <: Exception end

const BASE58CHARS = (
    codeunits("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")...,
)
const SPACE = UInt8(' ')
const ZEROBASE58 = UInt8('1')

const REVBASE58CHARS = if VERSION < v"0.7.0-DEV.4455"
    ntuple(i -> findfirst(BASE58CHARS, UInt8(i)) |>
                x -> x == 0 ? typemax(UInt8) : UInt8(x - 1),
           typemax(UInt8))
else
    ntuple(i -> findfirst(isequal(UInt8(i)), BASE58CHARS) |>
                x -> x == nothing ? typemax(UInt8) : UInt8(x - 1),
           typemax(UInt8))
end

const BASE = 58

encode(x::UInt8) = @inbounds return BASE58CHARS[x + 1]

function base58encode(x::T) where T <: Union{DenseArray{UInt8, 1},
                                             NTuple{N, UInt8} where N}

    if length(x) == 0
        return UInt8[]
    end

    n_zeros = 0
    for c in x
        c != 0 && break
        n_zeros += 1
    end

    if n_zeros == length(x)
        return fill(ZEROBASE58, length(x))
    end

    length_result = ceil(Int64, length(x) * log(256) / log(BASE) + 1)

    res = zeros(UInt8, (length_result, ))
    l = 0

    i_x = 1
    @inbounds while i_x <= length(x)

        carry = UInt64(x[i_x])

        i = 0
        i_res = length_result
        while (carry != 0 || i < l) && i_res > 1
            carry += UInt64(0x100) * UInt64(res[i_res])
            carry, res[i_res] = divrem(carry, UInt64(BASE))

            i_res -= 1
            i += 1
        end

        @assert carry == 0
        l = i
        i_x += 1
    end

    i_res = 1
    @inbounds while i_res < length_result && res[i_res] == 0
        res[i_res] = 0
        i_res += 1
    end

    res = res[i_res - n_zeros:end]
    @inbounds for i in eachindex(res)
        res[i] = encode(res[i])
    end

    return res
end

function base58decode(x::T) where T <: Union{ DenseArray{UInt8, 1},
                                              NTuple{N, UInt8} where N }
    # Leading spaces will be ignored
    i = 1
    for xx in x
        if xx == SPACE
            i += 1
        else
            break
        end
    end

    n_zeros = 0
    @inbounds while i <= length(x) && x[i] == ZEROBASE58
        n_zeros += 1
        i += 1
    end

    out_size = ceil(Int64, (length(x) - n_zeros) * log(58) / log(256) + 1)
    res = zeros(UInt8, out_size)

    l = 0
    @inbounds while i <= length(x) && x[i] != SPACE

        carry = UInt64(REVBASE58CHARS[x[i]])
        if carry == UInt64(typemax(UInt8))
            throw(ArgumentError(
                "Letter " * Char(x[i]) * " not in Base58 alphabet"
            ))
        end

        j = 0
        k = out_size
        while (carry != 0 || j < l) && k > 0

            carry +=  UInt64(BASE) * res[k]
            carry, res[k] = divrem(carry, UInt64(256))

            k -= 1
            j += 1
        end

        @assert carry == 0

        l = i
        i += 1
    end

    @inbounds while i < length(x) && x[i] == SPACE
        i += 1
    end

    # The res = ...; return res is only for julia 0.6 compat
    @inbounds res = if out_size > 0

        i = 1
        while i <= out_size && res[i] == 0
            i += 1
        end

        if n_zeros > 0
            prepend!(res[i:end], zeros(UInt8, n_zeros))
        else
            res[i:end]
        end
    elseif n_zeros > 0
        zeros(UInt8, n_zeros)
    else
        res
    end
    return res
end

function base58checkencode(payload::T) where
    T <: Union{DenseArray{UInt8, 1}, NTuple{N, UInt8} where N}

    checksum = sha256(sha256(payload))[1:4]

    base58encode([payload..., checksum...])
end

function base58checkdecode(x::T, check::Bool = true) where
    T <: Union{DenseArray{UInt8, 1}, NTuple{N, UInt8} where N}

    dec = base58decode(x)
    payload = dec[1:end-4]
    checksum = dec[end-3:end]

    if check
        if sha256(sha256(payload))[1:4] != checksum
            throw(ArgumentError("Invalid address"))
        end
    end

    return payload
end

module alt

export base58encode, base58decode, base58checkencode

BASE58_ALPHABET = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

function base58encode(s::Union{Base.CodeUnits{UInt8,String},Array{UInt8,1}})
    if length(s) == 0
        return s
    end
    prefix = []
    for c in s
        if c == 0
            push!(prefix, 0x31)
        else
            break
        end
    end
    num = parse(BigInt, bytes2hex(s), base=16)
    result = []
    while num > 0
        num, i = divrem(num, 58)
        pushfirst!(result, BASE58_ALPHABET[i+1])
    end
    return AbstractArray{UInt8,1}(cat(prefix, result; dims=1))
end

function base58decode(a::AbstractArray{UInt8})
    result = ""
    i = 1
    while i <= length(a)
        result = string(result,Char(a[i]))
        i += 1
    end
    return result
end

function base58checkencode(h160::Union{Base.CodeUnits{UInt8,String},Array{UInt8,1}})
    checksum = sha256(sha256(h160))[1:4]
    base58bytes = alt_base58encode(cat(h160, checksum; dims=1))
    return alt_base58decode(base58bytes)
end

end  # alt module

end # module Base58


text:
"A lazy Jacobian `J` stores a map `m` and returns `J(x) = jacobian(m, x)`."
struct LazyJacobian{T,M} <: SimpleLazyMap{T}
	map	::	M
end

LazyJacobian(m) = LazyJacobian{domaintype(m),typeof(m)}(m)
applymap(m::LazyJacobian, x) = jacobian(supermap(m), x)

mapsize(m::LazyJacobian) = mapsize(supermap(m))

Display.displaystencil(m::LazyJacobian) = ["LazyJacobian(", supermap(m), ")"]
show(io::IO, mime::MIME"text/plain", m::LazyJacobian) = composite_show(io, mime, m)

"""
    jacobian(m::AbstractMap[, x])

Return the jacobian map. The two-argument version evaluates the jacobian
at a point `x`.
"""
jacobian(m::AbstractMap) = LazyJacobian(m)
jacobian!(y, m::AbstractMap, x) = y .= jacobian(m, x)

"A `DeterminantMap` returns the determinant of the result of a given map."
struct DeterminantMap{T,M} <: SimpleLazyMap{T}
    map ::  M
end

DeterminantMap(m) = DeterminantMap{domaintype(m)}(m)
DeterminantMap{T}(m) where {T} = DeterminantMap{T,typeof(m)}(m)
DeterminantMap{T}(m::Map{T}) where {T} = DeterminantMap{T,typeof(m)}(m)
DeterminantMap{T}(m::Map{S}) where {S,T} = DeterminantMap{T}(convert(Map{T}, m))

determinantmap(m::AbstractMap) = DeterminantMap(m)

applymap(m::DeterminantMap, x) = det(supermap(m)(x))

"""
    jacdet(m::AbstractMap[, x])

Return the determinant of the jacobian as a map. The two-argument version
evaluates the jacobian determinant at a point `x`.
"""
jacdet(m::AbstractMap) = determinantmap(jacobian(m))
jacdet(m::AbstractMap, x) = det(jacobian(m, x))

"An `AbsMap` returns the absolute value of the result of a given map."
struct AbsMap{T,M} <: SimpleLazyMap{T}
    map ::  M
end

AbsMap(m) = AbsMap{domaintype(m)}(m)
AbsMap{T}(m) where {T} = AbsMap{T,typeof(m)}(m)
AbsMap{T}(m::Map{T}) where {T} = AbsMap{T,typeof(m)}(m)
AbsMap{T}(m::Map{S}) where {S,T} = AbsMap{T}(convert(Map{T}, m))

absmap(m::AbstractMap) = AbsMap(m)

applymap(m::AbsMap, x) = abs(supermap(m)(x))

"A lazy volume element evaluates to `diffvolume(m, x)` on the fly."
struct LazyDiffVolume{T,M} <: SimpleLazyMap{T}
	map	::	M
end

LazyDiffVolume(m) = LazyDiffVolume{domaintype(m)}(m)
LazyDiffVolume{T}(m) where {T} = LazyDiffVolume{T,typeof(m)}(m)
LazyDiffVolume{T}(m::Map{T}) where {T} = LazyDiffVolume{T,typeof(m)}(m)
LazyDiffVolume{T}(m::Map{S}) where {S,T} = LazyDiffVolume{T}(convert(Map{T}, m))

applymap(m::LazyDiffVolume, x) = diffvolume(supermap(m), x)

Display.displaystencil(m::LazyDiffVolume) = ["LazyDiffVolume(", supermap(m), ")"]
show(io::IO, mime::MIME"text/plain", m::LazyDiffVolume) = composite_show(io, mime, m)

"""
    diffvolume(m[, x])

Compute the differential volume (at a point `x`). If `J` is the Jacobian matrix,
possibly rectangular, then the differential volume is `sqrt(det(J'*J))`.

If the map is square, then the differential volume is the absolute value of the
Jacobian determinant.
"""
function diffvolume(m)
	if issquaremap(m)
		if mapsize(m,1) > 1
			absmap(jacdet(m))
		else
			jacdet(m)
		end
	else
		LazyDiffVolume(m)
	end
end

function diffvolume(m, x)
	if issquaremap(m)
		if mapsize(m,1) > 1
			abs(jacdet(m, x))
		else
			jacdet(m, x)
		end
	else
		jac = jacobian(m, x)
		sqrt(det(adjoint(jac)*jac))
	end
end

const NumberLike = Union{Number,UniformScaling}

"""
    to_matrix(::Type{T}, A[, b])

Convert the `A` in the affine map `A*x` or `A*x+b` with domaintype `T` to a matrix.
"""
to_matrix(::Type{T}, A) where {T} = A
to_matrix(::Type{T}, A::AbstractMatrix) where {T} = A
to_matrix(::Type{T}, A::NumberLike) where {T<:Number} = A
to_matrix(::Type{SVector{N,T}}, A::Number) where {N,T} = A * one(SMatrix{N,N,T})
to_matrix(::Type{SVector{N,T}}, A::UniformScaling) where {N,T} = A.λ * one(SMatrix{N,N,T})
to_matrix(::Type{T}, A::Number) where {T<:AbstractVector} = A * I
to_matrix(::Type{T}, A::UniformScaling) where {T<:Number} = one(T)
to_matrix(::Type{T}, A::UniformScaling) where {T<:AbstractVector} = A

to_matrix(::Type{T}, A, b) where {T} = A
to_matrix(::Type{T}, A::AbstractMatrix, b) where {T} = A
to_matrix(::Type{T}, A::Number, b::Number) where {T<:Number} = A
to_matrix(::Type{T}, A::UniformScaling, b::Number) where {T<:Number} = A.λ
to_matrix(::Type{SVector{N,T}}, A::NumberLike, b::SVector{N,T}) where {N,T} = A * one(SMatrix{N,N,T})
to_matrix(::Type{T}, A::NumberLike, b::AbstractVector) where {S,T<:AbstractVector{S}} =
    A * Array{S,2}(I, length(b), length(b))

"""
    to_vector(::Type{T}, A[, b])

Convert the `b` in the affine map `A*x` or `A*x+b` with domaintype `T` to a vector.
"""
to_vector(::Type{T}, A) where {T} = zero(T)
to_vector(::Type{T}, A::SVector{M,S}) where {T,M,S} = zero(SVector{M,S})
to_vector(::Type{T}, A::SMatrix{M,N,S}) where {T<:AbstractVector,M,N,S} = zero(SVector{M,S})
to_vector(::Type{T}, A::AbstractArray) where {T<:AbstractVector} = zeros(eltype(T),size(A,1))
to_vector(::Type{T}, A, b) where {T} = b

"Return a zero matrix of the same size as the map."
zeromatrix(m::AbstractMap) = zeromatrix(m, domaintype(m), codomaintype(m))
zeromatrix(m, ::Type{T}, ::Type{U}) where {T,U} = zeros(numtype(T),mapsize(m))
zeromatrix(m, ::Type{T}, ::Type{U}) where {T<:Number,U<:Number} = zero(promote_type(T,U))
zeromatrix(m, ::Type{T}, ::Type{U}) where {N,T<:StaticVector{N},U<:Number} =
	transpose(zero(SVector{N,eltype(T)}))
zeromatrix(m, ::Type{T}, ::Type{U}) where {N,M,T<:StaticVector{N},U<:StaticVector{M}} =
	zero(SMatrix{M,N,promote_type(eltype(T),eltype(U))})
zeromatrix(m, ::Type{T}, ::Type{U}) where {T<:Number,M,U<:StaticVector{M}} =
	zero(SVector{M,promote_type(T,eltype(U))})
zeromatrix(m, ::Type{T}, ::Type{U}) where {T<:AbstractVector,U<:Number} =
	transpose(zeros(promote_type(eltype(T),U), mapsize(m,1)))

"Return a zero vector of the same size as the codomain of the map."
zerovector(m::AbstractMap) = zerovector(m, codomaintype(m))
zerovector(m::AbstractMap, ::Type{U}) where {U} = zero(U)
zerovector(m::AbstractMap, ::Type{StaticVector{M,T}}) where {M,T} = zero(SVector{M,T})
# If the output type is a vector, the map itself should store the size information.
zerovector(m::AbstractMap, ::Type{<:AbstractVector{T}}) where {T} = zeros(T, mapsize(m,1))

"Return an identity matrix with the same size as the map."
identitymatrix(m::AbstractMap) = identitymatrix(m, codomaintype(m))
identitymatrix(m::AbstractMap, ::Type{T}) where {T} = one(T)
identitymatrix(m::AbstractMap, ::Type{<:StaticVector{N,T}}) where {N,T} = one(SMatrix{N,N,T})
identitymatrix(m::AbstractMap, ::Type{<:AbstractVector{T}}) where {T} = Diagonal{T}(ones(mapsize(m,1)))


text:
using ExploringOceanData
@boilerplate

local_directory = "/mnt/podaac_drive/Version4/Release4/interp_monthly/SSH/1992/"
filename = "SSH_1992_01.nc"
ds = Dataset(local_directory * filename,"r")

η = ds["SSH"]

# 2D Plot

latitude = ds["latitude"]
longitude = ds["longitude"]
skip = 2
η_plot = η[begin:skip:end, begin:skip:end,1]
lat = latitude[begin:skip:end, 1]
lon = longitude[begin:skip:end, 1]

missing_value = 0.0
bools = η_plot .== missing_value

η_max = quantile(abs.(η_plot[:]), 0.99)
clims = quantile.(Ref(η_plot[:]), [0.1,0.9])
clims = (-η_max, η_max)

# for plotting make it a NaN
η_plot[bools] .= NaN
plt = heatmap(lat, lon, η_plot, colormap = :balance, colorrange = clims)
plt.axis.xlabel = "latitude"
plt.axis.ylabel = "longitude"
Colorbar(plt.figure[1, 2], plt.plot)
display(plt)

## 3D
x = [cosd(λ) * cosd(ϕ) for λ in lat, ϕ in lon]
y = [cosd(λ) * sind(ϕ) for λ in lat, ϕ in lon]
z = [sind(λ)  for λ in lat, ϕ in lon]

cutoff(x) = x > 0 ? 0 : x
tmp = cutoff.(η_plot') .+ 5e4
# surface(xs, ys, zs, axis=(type=Axis3,))
splt = surface(x, y, z, color=η_plot', colormap=:balance, colorrange=clims, show_axis=false, shading = false)

continents = Float32.(bools)
tmpbool = .!bools
continents[tmpbool] .= NaN
surface!(splt.figure[1,1], x  , y  , z , color = continents', colormap = :greys)
display(splt)


text:
# An example of the Burgers code for the propagation of Burgers equation in time
# plots u(x, t = t0) for a given t0
# studies the pointwise convergence order of a solution
# to Burgers equation as a function of resolution

using Burgers
using Printf
using PyPlot
include("Utils.jl")
using .Utils

function first_deriv(fun::FunArr{T, U})::FunArr{T, U} where {T, U}
	N     = fun.Ncells
	dudat = similar(fun.udat)

	# take first derivative of end-points
	dudat[1] = (fun.udat[2] - fun.udat[1]  ) / ufun.dx
	dudat[N] = (fun.udat[N] - fun.udat[N-1]) / ufun.dx

	# take the first derivative of all points in between
	for i in 2:(N-1)
		dudat[i] = (fun.udat[i+1] - fun.udat[i-1]) / (2*ufun.dx)
	end

	println(fun.Ncells, " ", fun.Nghost)
	FunArr{T, U}(dudat, fun.Ncells, fun.Nghost)
end

function second_deriv(fun::FunArr{T, U})::FunArr{T, U} where {T, U}
	N      = fun.Ncells
	d2udat = similar(fun.udat)

	# take second derivative of end-points
	d2udat[1] = (fun.udat[3] - 2.0*fun.udat[2]   + fun.udat[1])   / fun.dx^2
	d2udat[N] = (fun.udat[N] - 2.0*fun.udat[N-1] + fun.udat[N-2]) / fun.dx^2

	# take the second derivative of all points in between
	for i in 2:(N-1)
		d2udat[i] = (fun.udat[i+1] - 2*fun.udat[i] + fun.udat[i-1]) / fun.dx^2
	end

	println(fun.Ncells, " ", fun.Nghost)
	FunArr{T, U}(d2udat, fun.Ncells, fun.Nghost)
end

function plotsoln(fun::FunArr{T, U}, imagename::AbstractString, ylab::AbstractString) where {T, U}
	PyPlot.clf()
	xlabel("x")
	xlim(0, 1)
	xticks(range(0.0, 1.0, length = 10 + 1))

	ylabel(ylab)
	yticks(range(0.0, 0.7, length = 7 + 1))
	ylim(0, 0.7)
	plot(fun.xdat, fun.udat)
	savefig("images/" * imagename * ".png", dpi = 300)
end

# collect the command line arguments
t0, sc, imagename = commandlineparser(false)

# create the resolution
Ttot     = 2.0   # total duration
Nt_b     = 1024  # number of time divisions for lowest resolution
Ncells_b = 256   # number of position divisions for lowest resolution
Nghost   = 2     # padding on position divisions for boundary conditions
res = Resolution{Float64, Int64}(Ttot, Nt_b, Ncells_b, Nghost)
check_time(res, t0)

# find the evolved solution
ufun   = get_evolved_slice(get_sinewave, res, t0, sc)
dufun  = first_deriv(ufun)
d2ufun = second_deriv(ufun)

# plot u(x) and its derivatives and save the results
plotsoln(ufun  , imagename                 , "u(x)"  )
#plotsoln(dufun , imagename * "_firstderiv" , "du(x)" )
#plotsoln(d2ufun, imagename * "_secondderiv", "d2u(x)")